@yemi33/minions 0.1.2109 → 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 (40) 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/docs/onboarding.md +2 -2
  39. package/engine.js +52 -6
  40. package/package.json +1 -1
@@ -172,25 +172,25 @@ function renderWatches(watchesData, opts) {
172
172
  '<td><span class="pr-id">' + escHtml(w.id) + '</span></td>' +
173
173
  '<td style="max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escHtml(w.description || w.target) + '">' + escHtml(w.target) + '</td>' +
174
174
  '<td><span class="dispatch-type explore">' + escHtml(targetLabel) + '</span></td>' +
175
- '<td><span style="font-size:11px;color:var(--blue)">' + escHtml(condLabel) + '</span></td>' +
176
- '<td><span style="font-size:10px">' + actionLabel + '</span></td>' +
177
- '<td><span style="font-size:10px;color:var(--muted)">' + escHtml(_intervalToHuman(w.interval)) + '</span></td>' +
175
+ '<td><span style="font-size:var(--text-base);color:var(--blue)">' + escHtml(condLabel) + '</span></td>' +
176
+ '<td><span style="font-size:var(--text-sm)">' + actionLabel + '</span></td>' +
177
+ '<td><span style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(_intervalToHuman(w.interval)) + '</span></td>' +
178
178
  '<td><span class="pr-agent">' + escHtml(w.owner || 'human') + '</span></td>' +
179
179
  '<td>' + statusBadge + '</td>' +
180
- '<td title="Last triggered: ' + escHtml(lastTriggered) + '"><span style="font-size:11px">' + escHtml(triggerInfo) + '</span></td>' +
180
+ '<td title="Last triggered: ' + escHtml(lastTriggered) + '"><span style="font-size:var(--text-base)">' + escHtml(triggerInfo) + '</span></td>' +
181
181
  '<td><span class="pr-date">' + escHtml(lastChecked) + '</span></td>' +
182
182
  '<td style="white-space:nowrap">';
183
183
 
184
184
  // Pause/Resume button (F7: marks as `disabled` while POST in flight)
185
185
  var pauseBusyCls = _watchToggleInFlight.has(w.id) ? ' disabled' : '';
186
186
  if (w.status === 'active') {
187
- html += '<button class="pr-pager-btn' + pauseBusyCls + '" style="font-size:9px;padding:1px 6px;color:var(--yellow);border-color:var(--yellow);margin-right:4px" onclick="event.stopPropagation();toggleWatchPause(\'' + escHtml(w.id) + '\',true)" title="Pause">&#x23F8;</button>';
187
+ html += '<button class="pr-pager-btn' + pauseBusyCls + '" style="font-size:var(--text-xs);padding:1px 6px;color:var(--yellow);border-color:var(--yellow);margin-right:4px" onclick="event.stopPropagation();toggleWatchPause(\'' + escHtml(w.id) + '\',true)" title="Pause">&#x23F8;</button>';
188
188
  } else if (w.status === 'paused') {
189
- html += '<button class="pr-pager-btn' + pauseBusyCls + '" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-right:4px" onclick="event.stopPropagation();toggleWatchPause(\'' + escHtml(w.id) + '\',false)" title="Resume">&#x25B6;</button>';
189
+ html += '<button class="pr-pager-btn' + pauseBusyCls + '" style="font-size:var(--text-xs);padding:1px 6px;color:var(--green);border-color:var(--green);margin-right:4px" onclick="event.stopPropagation();toggleWatchPause(\'' + escHtml(w.id) + '\',false)" title="Resume">&#x25B6;</button>';
190
190
  }
191
191
 
192
192
  // Delete button
193
- html += '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="event.stopPropagation();deleteWatch(\'' + escHtml(w.id) + '\')" title="Delete">&#x2715;</button>';
193
+ html += '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="event.stopPropagation();deleteWatch(\'' + escHtml(w.id) + '\')" title="Delete">&#x2715;</button>';
194
194
  html += '</td></tr>';
195
195
  }
196
196
 
@@ -226,18 +226,18 @@ function _renderWatchActionDetail(action) {
226
226
  if (action.length === 0) return '';
227
227
  var stepHtml = action.map(function(step, i) {
228
228
  return '<div style="margin-top:4px;padding:8px;background:var(--surface2);border-radius:4px">' +
229
- '<div style="font-size:11px;color:var(--muted)">Step ' + (i + 1) + '</div>' +
230
- '<div style="font-size:12px"><strong>Type:</strong> <span class="dispatch-type explore">' + escHtml(step && step.type ? step.type : '?') + '</span></div>' +
231
- (step && step.guard && step.guard.expr ? '<div style="font-size:11px;margin-top:2px"><strong>Guard:</strong> <code>' + escHtml(step.guard.expr) + '</code></div>' : '') +
232
- (step && step.params && Object.keys(step.params).length ? '<div style="margin-top:4px;font-size:11px;font-family:monospace;white-space:pre-wrap">' + escHtml(JSON.stringify(step.params, null, 2)) + '</div>' : '') +
229
+ '<div style="font-size:var(--text-base);color:var(--muted)">Step ' + (i + 1) + '</div>' +
230
+ '<div style="font-size:var(--text-md)"><strong>Type:</strong> <span class="dispatch-type explore">' + escHtml(step && step.type ? step.type : '?') + '</span></div>' +
231
+ (step && step.guard && step.guard.expr ? '<div style="font-size:var(--text-base);margin-top:2px"><strong>Guard:</strong> <code>' + escHtml(step.guard.expr) + '</code></div>' : '') +
232
+ (step && step.params && Object.keys(step.params).length ? '<div style="margin-top:4px;font-size:var(--text-base);font-family:monospace;white-space:pre-wrap">' + escHtml(JSON.stringify(step.params, null, 2)) + '</div>' : '') +
233
233
  '</div>';
234
234
  }).join('');
235
235
  return '<div><strong style="color:var(--muted)">Follow-up Action Chain (' + action.length + ' step' + (action.length === 1 ? '' : 's') + '):</strong>' + stepHtml + '</div>';
236
236
  }
237
237
  if (action.type) {
238
238
  return '<div><strong style="color:var(--muted)">Follow-up Action:</strong> <span class="dispatch-type explore">' + escHtml(action.type) + '</span>' +
239
- (action.guard && action.guard.expr ? '<div style="font-size:11px;margin-top:2px"><strong>Guard:</strong> <code>' + escHtml(action.guard.expr) + '</code></div>' : '') +
240
- (action.params && Object.keys(action.params).length ? '<div style="margin-top:4px;padding:8px;background:var(--surface2);border-radius:4px;font-size:11px;font-family:monospace;white-space:pre-wrap">' + escHtml(JSON.stringify(action.params, null, 2)) + '</div>' : '') +
239
+ (action.guard && action.guard.expr ? '<div style="font-size:var(--text-base);margin-top:2px"><strong>Guard:</strong> <code>' + escHtml(action.guard.expr) + '</code></div>' : '') +
240
+ (action.params && Object.keys(action.params).length ? '<div style="margin-top:4px;padding:8px;background:var(--surface2);border-radius:4px;font-size:var(--text-base);font-family:monospace;white-space:pre-wrap">' + escHtml(JSON.stringify(action.params, null, 2)) + '</div>' : '') +
241
241
  '</div>';
242
242
  }
243
243
  return '';
@@ -248,7 +248,7 @@ function _renderWatchActionDetail(action) {
248
248
  function _renderWatchRequiresDetail(requires) {
249
249
  if (!Array.isArray(requires) || requires.length === 0) return '';
250
250
  var rows = requires.map(function(r, i) {
251
- return '<div style="margin-top:4px;padding:6px 8px;background:var(--surface2);border-radius:4px;font-size:11px">' +
251
+ return '<div style="margin-top:4px;padding:6px 8px;background:var(--surface2);border-radius:4px;font-size:var(--text-base)">' +
252
252
  '<span style="color:var(--muted)">[' + (i + 1) + ']</span> ' +
253
253
  escHtml(r && r.target ? r.target : '?') +
254
254
  ' <span class="dispatch-type explore">' + escHtml(r && r.targetType ? r.targetType : '?') + '</span>' +
@@ -267,7 +267,7 @@ function _renderWatchRequiresDetail(requires) {
267
267
  // watches that were created before Phase 6.2 don't show a half-empty table.
268
268
  function _renderWatchHistoryDetail(history) {
269
269
  if (!Array.isArray(history) || history.length === 0) {
270
- return '<div style="color:var(--muted);font-style:italic;font-size:11px">no history yet — watch has not been checked, or pre-dates the history feature</div>';
270
+ return '<div style="color:var(--muted);font-style:italic;font-size:var(--text-base)">no history yet — watch has not been checked, or pre-dates the history feature</div>';
271
271
  }
272
272
  // Render newest-first for readability — the engine stores oldest-first.
273
273
  var entries = history.slice().reverse();
@@ -285,7 +285,7 @@ function _renderWatchHistoryDetail(history) {
285
285
  '</tr>';
286
286
  }).join('');
287
287
  return '<div><strong style="color:var(--muted)">Evaluation History (' + history.length + ' check' + (history.length === 1 ? '' : 's') + ', newest first):</strong>' +
288
- '<table style="margin-top:4px;font-size:11px;border-collapse:collapse;width:100%"><tbody>' + rows + '</tbody></table>' +
288
+ '<table style="margin-top:4px;font-size:var(--text-base);border-collapse:collapse;width:100%"><tbody>' + rows + '</tbody></table>' +
289
289
  '</div>';
290
290
  }
291
291
 
@@ -302,12 +302,12 @@ function openWatchDetail(id) {
302
302
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: watch description/target/id)
303
303
  document.getElementById('modal-title').innerHTML = escHtml(w.description || w.target) +
304
304
  ' <div style="display:flex;gap:4px;margin-top:4px">' +
305
- (w.status === 'active' ? '<button class="pr-pager-btn" style="font-size:10px;padding:2px 10px;color:var(--yellow)" onclick="toggleWatchPause(\'' + escHtml(w.id) + '\',true);closeModal()">Pause</button>' : '') +
306
- (w.status === 'paused' ? '<button class="pr-pager-btn" style="font-size:10px;padding:2px 10px;color:var(--green)" onclick="toggleWatchPause(\'' + escHtml(w.id) + '\',false);closeModal()">Resume</button>' : '') +
307
- '<button class="pr-pager-btn" style="font-size:10px;padding:2px 10px;color:var(--red)" onclick="deleteWatch(\'' + escHtml(w.id) + '\');closeModal()">Delete</button>' +
305
+ (w.status === 'active' ? '<button class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 10px;color:var(--yellow)" onclick="toggleWatchPause(\'' + escHtml(w.id) + '\',true);closeModal()">Pause</button>' : '') +
306
+ (w.status === 'paused' ? '<button class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 10px;color:var(--green)" onclick="toggleWatchPause(\'' + escHtml(w.id) + '\',false);closeModal()">Resume</button>' : '') +
307
+ '<button class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 10px;color:var(--red)" onclick="deleteWatch(\'' + escHtml(w.id) + '\');closeModal()">Delete</button>' +
308
308
  '</div>';
309
309
 
310
- var body = '<div style="display:flex;flex-direction:column;gap:10px;font-size:12px;line-height:1.6">' +
310
+ var body = '<div style="display:flex;flex-direction:column;gap:10px;font-size:var(--text-md);line-height:1.6">' +
311
311
  '<div><strong style="color:var(--muted)">ID:</strong> ' + escHtml(w.id) + '</div>' +
312
312
  '<div><strong style="color:var(--muted)">Target:</strong> ' + escHtml(w.target) + '</div>' +
313
313
  '<div><strong style="color:var(--muted)">Target Type:</strong> <span class="dispatch-type explore">' + escHtml(targetLabel) + '</span></div>' +
@@ -330,14 +330,14 @@ function openWatchDetail(id) {
330
330
  '<div><strong style="color:var(--muted)">Created:</strong> ' + escHtml(createdAt) + '</div>' +
331
331
  '<div><strong style="color:var(--muted)">Last Checked:</strong> ' + escHtml(lastChecked) + '</div>' +
332
332
  '<div><strong style="color:var(--muted)">Last Triggered:</strong> ' + escHtml(lastTriggered) + '</div>' +
333
- (w._lastTriggerMessage ? '<div><strong style="color:var(--muted)">Last Trigger Message:</strong><div style="margin-top:4px;padding:8px;background:var(--surface2);border-radius:4px;font-size:11px">' + escHtml(w._lastTriggerMessage) + '</div></div>' : '') +
333
+ (w._lastTriggerMessage ? '<div><strong style="color:var(--muted)">Last Trigger Message:</strong><div style="margin-top:4px;padding:8px;background:var(--surface2);border-radius:4px;font-size:var(--text-base)">' + escHtml(w._lastTriggerMessage) + '</div></div>' : '') +
334
334
  (w.project ? '<div><strong style="color:var(--muted)">Project:</strong> ' + escHtml(w.project) + '</div>' : '') +
335
335
  (w.description ? '<div><strong style="color:var(--muted)">Description:</strong> ' + escHtml(w.description) + '</div>' : '') +
336
336
  // P-w15f1d4b — Phase 7.2: reserve a placeholder for the lazily-fetched
337
337
  // evaluation history table. The fetch below populates it once
338
338
  // /api/watches/:id/history resolves; failures fall back to the inline
339
339
  // _history copy from /api/watches (best-effort) or a "no history" hint.
340
- '<div id="watch-history-' + escHtml(w.id) + '"><div style="color:var(--muted);font-style:italic;font-size:11px">Loading history…</div></div>' +
340
+ '<div id="watch-history-' + escHtml(w.id) + '"><div style="color:var(--muted);font-style:italic;font-size:var(--text-base)">Loading history…</div></div>' +
341
341
  '</div>';
342
342
 
343
343
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() by watch detail renderers (fields: watch id/target/owner/description/action params/requires/history/result messages)
@@ -459,29 +459,29 @@ function _watchFormHtml() {
459
459
  var projOpts = '<option value="">Any</option>' + (cmdProjects || []).map(function(p) { return '<option value="' + escHtml(p.name) + '">' + escHtml(p.name) + '</option>'; }).join('');
460
460
 
461
461
  return '<div style="display:flex;flex-direction:column;gap:12px;font-family:inherit">' +
462
- '<div id="watch-form-error" style="display:none;color:var(--red);font-size:12px;padding:6px 10px;background:rgba(255,50,50,0.1);border-radius:var(--radius-sm)"></div>' +
462
+ '<div id="watch-form-error" style="display:none;color:var(--red);font-size:var(--text-md);padding:6px 10px;background:rgba(255,50,50,0.1);border-radius:var(--radius-sm)"></div>' +
463
463
  '<label style="color:var(--text);font-size:var(--text-md)">Target (e.g. PR number, work item ID, meeting/plan/schedule/pipeline/dispatch/agent ID)<input id="watch-edit-target" placeholder="e.g. 1057, W-abc123, M-xyz, schedule-42" style="' + inputStyle + '"></label>' +
464
464
  '<label style="color:var(--text);font-size:var(--text-md)">Target Type<select id="watch-edit-target-type" style="' + inputStyle + '" onchange="_updateWatchConditionOptions()">' + ttOpts + '</select></label>' +
465
465
  '<label style="color:var(--text);font-size:var(--text-md)">Condition<select id="watch-edit-condition" style="' + inputStyle + '">' + condOpts + '</select></label>' +
466
- '<label style="color:var(--text);font-size:var(--text-md)">Check Interval <span style="font-size:10px;color:var(--muted)">(e.g. 5m, 15m, 1h — default 5m)</span><input id="watch-edit-interval" placeholder="5m" style="' + inputStyle + '"></label>' +
466
+ '<label style="color:var(--text);font-size:var(--text-md)">Check Interval <span style="font-size:var(--text-sm);color:var(--muted)">(e.g. 5m, 15m, 1h — default 5m)</span><input id="watch-edit-interval" placeholder="5m" style="' + inputStyle + '"></label>' +
467
467
  '<label style="color:var(--text);font-size:var(--text-md)">Owner (who gets notified)<select id="watch-edit-owner" style="' + inputStyle + '">' + agentOpts + '</select></label>' +
468
468
  '<label style="color:var(--text);font-size:var(--text-md)">Project<select id="watch-edit-project" style="' + inputStyle + '">' + projOpts + '</select></label>' +
469
469
  '<label style="color:var(--text);font-size:var(--text-md)">Description<input id="watch-edit-desc" placeholder="Optional description" style="' + inputStyle + '"></label>' +
470
- '<label style="color:var(--text);font-size:var(--text-md)">Stop After N Triggers <span style="font-size:10px;color:var(--muted)">(0 = run forever, 1 = expire on first match)</span><input id="watch-edit-stop-after" type="number" value="0" min="0" style="' + inputStyle + '"></label>' +
470
+ '<label style="color:var(--text);font-size:var(--text-md)">Stop After N Triggers <span style="font-size:var(--text-sm);color:var(--muted)">(0 = run forever, 1 = expire on first match)</span><input id="watch-edit-stop-after" type="number" value="0" min="0" style="' + inputStyle + '"></label>' +
471
471
  '<label style="color:var(--text);font-size:var(--text-md)">On Each Poll (if condition not met)<select id="watch-edit-on-not-met" style="' + inputStyle + '"><option value="">None — do nothing</option><option value="notify">Notify — write to inbox each poll</option></select></label>' +
472
472
  // P-w14e7a8c — Phase 7.1: action chain editor (step list + add/remove)
473
473
  '<div style="border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px;display:flex;flex-direction:column;gap:8px">' +
474
474
  '<div style="color:var(--text);font-size:var(--text-md);display:flex;align-items:center;justify-content:space-between">' +
475
- '<span>Follow-up Action(s) <span style="font-size:10px;color:var(--muted)">(runs after the inbox notification when the watch fires; 1 step = single, 2+ = chain)</span></span>' +
476
- '<button type="button" class="pr-pager-btn" style="font-size:10px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_addWatchStepRow()">+ Add step</button>' +
475
+ '<span>Follow-up Action(s) <span style="font-size:var(--text-sm);color:var(--muted)">(runs after the inbox notification when the watch fires; 1 step = single, 2+ = chain)</span></span>' +
476
+ '<button type="button" class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_addWatchStepRow()">+ Add step</button>' +
477
477
  '</div>' +
478
478
  '<div id="watch-edit-steps"></div>' +
479
479
  '</div>' +
480
480
  // P-w14e7a8c — Phase 7.1: requires editor (cross-target AND-join rows)
481
481
  '<div style="border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px;display:flex;flex-direction:column;gap:8px">' +
482
482
  '<div style="color:var(--text);font-size:var(--text-md);display:flex;align-items:center;justify-content:space-between">' +
483
- '<span>Requires <span style="font-size:10px;color:var(--muted)">(cross-target AND-join — every requirement must also be true to fire)</span></span>' +
484
- '<button type="button" class="pr-pager-btn" style="font-size:10px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_addRequireRow()">+ Add requirement</button>' +
483
+ '<span>Requires <span style="font-size:var(--text-sm);color:var(--muted)">(cross-target AND-join — every requirement must also be true to fire)</span></span>' +
484
+ '<button type="button" class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_addRequireRow()">+ Add requirement</button>' +
485
485
  '</div>' +
486
486
  '<div id="watch-edit-requires"></div>' +
487
487
  '</div>' +
@@ -518,12 +518,12 @@ function _addWatchStepRow(initial) {
518
518
  row.innerHTML =
519
519
  '<div style="display:flex;align-items:center;justify-content:space-between;gap:8px">' +
520
520
  '<select id="watch-step-' + idx + '-type" style="' + inputStyle + ';margin-top:0;flex:1" onchange="_updateWatchStepParamsHint(' + idx + ')">' + actionOpts + '</select>' +
521
- '<button type="button" class="pr-pager-btn" style="font-size:10px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_removeWatchStepRow(' + idx + ')">Remove</button>' +
521
+ '<button type="button" class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_removeWatchStepRow(' + idx + ')">Remove</button>' +
522
522
  '</div>' +
523
- '<label style="color:var(--text);font-size:11px">Params (JSON) <span style="font-size:10px;color:var(--muted)" id="watch-step-' + idx + '-params-hint"></span>' +
523
+ '<label style="color:var(--text);font-size:var(--text-base)">Params (JSON) <span style="font-size:var(--text-sm);color:var(--muted)" id="watch-step-' + idx + '-params-hint"></span>' +
524
524
  '<textarea id="watch-step-' + idx + '-params" rows="3" placeholder=\'{"title": "Re-check {{target}} after merge"}\' style="' + inputStyle + ';font-family:monospace"></textarea>' +
525
525
  '</label>' +
526
- '<label style="color:var(--text);font-size:11px">Guard expression <span style="font-size:10px;color:var(--muted)">(optional — skip step if expr is false; e.g. <code>newState.mergeable === true</code>)</span>' +
526
+ '<label style="color:var(--text);font-size:var(--text-base)">Guard expression <span style="font-size:var(--text-sm);color:var(--muted)">(optional — skip step if expr is false; e.g. <code>newState.mergeable === true</code>)</span>' +
527
527
  '<input id="watch-step-' + idx + '-guard" placeholder="" style="' + inputStyle + ';font-family:monospace">' +
528
528
  '</label>';
529
529
  container.appendChild(row);
@@ -579,10 +579,10 @@ function _addRequireRow(initial) {
579
579
  row.style.cssText = 'display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:6px;align-items:end';
580
580
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: target type registry values/labels)
581
581
  row.innerHTML =
582
- '<label style="color:var(--text);font-size:11px;margin:0">Target<input id="watch-require-' + idx + '-target" placeholder="e.g. PR-123, pipeline-X" style="' + inputStyle + '"></label>' +
583
- '<label style="color:var(--text);font-size:11px;margin:0">Target Type<select id="watch-require-' + idx + '-target-type" style="' + inputStyle + '" onchange="_updateRequireConditionOptions(' + idx + ')">' + ttOpts + '</select></label>' +
584
- '<label style="color:var(--text);font-size:11px;margin:0">Condition<select id="watch-require-' + idx + '-condition" style="' + inputStyle + '"></select></label>' +
585
- '<button type="button" class="pr-pager-btn" style="font-size:10px;padding:6px 8px;color:var(--red);border-color:var(--red)" onclick="_removeRequireRow(' + idx + ')">Remove</button>';
582
+ '<label style="color:var(--text);font-size:var(--text-base);margin:0">Target<input id="watch-require-' + idx + '-target" placeholder="e.g. PR-123, pipeline-X" style="' + inputStyle + '"></label>' +
583
+ '<label style="color:var(--text);font-size:var(--text-base);margin:0">Target Type<select id="watch-require-' + idx + '-target-type" style="' + inputStyle + '" onchange="_updateRequireConditionOptions(' + idx + ')">' + ttOpts + '</select></label>' +
584
+ '<label style="color:var(--text);font-size:var(--text-base);margin:0">Condition<select id="watch-require-' + idx + '-condition" style="' + inputStyle + '"></select></label>' +
585
+ '<button type="button" class="pr-pager-btn" style="font-size:var(--text-sm);padding:6px 8px;color:var(--red);border-color:var(--red)" onclick="_removeRequireRow(' + idx + ')">Remove</button>';
586
586
  container.appendChild(row);
587
587
  if (initTarget) document.getElementById('watch-require-' + idx + '-target').value = initTarget;
588
588
  if (initTT) document.getElementById('watch-require-' + idx + '-target-type').value = initTT;
@@ -625,7 +625,7 @@ function _updateWatchConditionOptions() {
625
625
 
626
626
  function _renderCreateWatchModal() {
627
627
  document.getElementById('modal-title').innerHTML = 'Create Watch' +
628
- ' <button class="pr-pager-btn" style="font-size:10px;padding:2px 12px;color:var(--green);border-color:var(--green);margin-left:8px" onclick="submitWatch()">Create</button>';
628
+ ' <button class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 12px;color:var(--green);border-color:var(--green);margin-left:8px" onclick="submitWatch()">Create</button>';
629
629
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() by _watchFormHtml() (fields: target/action registries, project names, agent ids/names)
630
630
  document.getElementById('modal-body').innerHTML = _watchFormHtml();
631
631
  document.getElementById('modal-body').style.whiteSpace = 'normal';
@@ -87,15 +87,15 @@ function getWiRetryState(id) {
87
87
  function wiRetryBtn(item) {
88
88
  const rs = getWiRetryState(item.id);
89
89
  if (rs && rs.status === 'pending') {
90
- return '<span style="font-size:9px;padding:1px 6px;color:var(--yellow);border:1px solid rgba(210,153,34,0.35);background:rgba(210,153,34,0.1);border-radius:3px;cursor:wait;margin-left:4px">Retrying\u2026</span>';
90
+ return '<span style="font-size:var(--text-xs);padding:1px 6px;color:var(--yellow);border:1px solid rgba(210,153,34,0.35);background:rgba(210,153,34,0.1);border-radius:3px;cursor:wait;margin-left:4px">Retrying\u2026</span>';
91
91
  }
92
92
  if (rs && rs.status === 'done') {
93
- return '<span style="font-size:9px;padding:1px 6px;color:var(--green);border:1px solid rgba(63,185,80,0.35);background:rgba(63,185,80,0.1);border-radius:3px;margin-left:4px">Requeued</span>';
93
+ return '<span style="font-size:var(--text-xs);padding:1px 6px;color:var(--green);border:1px solid rgba(63,185,80,0.35);background:rgba(63,185,80,0.1);border-radius:3px;margin-left:4px">Requeued</span>';
94
94
  }
95
95
  if (rs && rs.status === 'error') {
96
- return '<span style="font-size:9px;padding:1px 6px;color:var(--red);border:1px solid rgba(248,81,73,0.35);background:rgba(248,81,73,0.1);border-radius:3px;margin-left:4px;cursor:pointer" title="' + escapeHtml(rs.message || 'Retry failed') + ' — click to try again" onclick="event.stopPropagation();retryWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')">Retry failed</span>';
96
+ return '<span style="font-size:var(--text-xs);padding:1px 6px;color:var(--red);border:1px solid rgba(248,81,73,0.35);background:rgba(248,81,73,0.1);border-radius:3px;margin-left:4px;cursor:pointer" title="' + escapeHtml(rs.message || 'Retry failed') + ' — click to try again" onclick="event.stopPropagation();retryWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')">Retry failed</span>';
97
97
  }
98
- return '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--yellow);border-color:var(--yellow);margin-left:4px" onclick="event.stopPropagation();retryWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')">Retry</button>';
98
+ return '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--yellow);border-color:var(--yellow);margin-left:4px" onclick="event.stopPropagation();retryWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')">Retry</button>';
99
99
  }
100
100
 
101
101
  function wiRow(item) {
@@ -106,9 +106,9 @@ function wiRow(item) {
106
106
  const typeBadge = (t) => '<span class="dispatch-type ' + (t || 'implement') + '">' + escapeHtml(t || 'implement') + '</span>';
107
107
  const priBadge = (p) => '<span class="prd-item-priority ' + (p || '') + '">' + escapeHtml(p || 'medium') + '</span>';
108
108
  const prLink = item._pr
109
- ? '<a class="pr-title" href="' + escapeHtml(item._prUrl || '#') + '" target="_blank" style="font-size:10px">' + escapeHtml(item._pr) + '</a>'
109
+ ? '<a class="pr-title" href="' + escapeHtml(item._prUrl || '#') + '" target="_blank" style="font-size:var(--text-sm)">' + escapeHtml(item._pr) + '</a>'
110
110
  : (item.branchStrategy === 'shared-branch' && item.status === 'done')
111
- ? '<span style="font-size:9px;color:var(--muted)" title="Part of shared branch — aggregate PR created at verify stage">shared branch</span>'
111
+ ? '<span style="font-size:var(--text-xs);color:var(--muted)" title="Part of shared branch — aggregate PR created at verify stage">shared branch</span>'
112
112
  : '<span style="color:var(--muted)">—</span>';
113
113
  // PR follow-up chip (W-mpej3cox00099466) — surfaced when the WI was spun
114
114
  // off from a PR comment via meta.pr_followup. Links to the parent PR.
@@ -118,21 +118,21 @@ function wiRow(item) {
118
118
  var prRef = prFollowup.parent_pr_id || prFollowup.parent_pr_url;
119
119
  var prNumMatch = String(prRef).match(/(\d+)(?!.*\d)/);
120
120
  var prLabel = prNumMatch ? ('PR #' + prNumMatch[1]) : 'parent PR';
121
- followupChip = ' <a class="pr-badge draft" style="font-size:8px;text-decoration:none" target="_blank" rel="noopener" href="' + escapeHtml(prFollowup.parent_pr_url) + '" title="Follow-up dispatched from ' + escapeHtml(prRef) + (prFollowup.parent_comment_author ? ' by ' + escapeHtml(prFollowup.parent_comment_author) : '') + '" onclick="event.stopPropagation()">&#8617; from ' + escapeHtml(prLabel) + '</a>';
121
+ followupChip = ' <a class="pr-badge draft" style="font-size:var(--text-xs);text-decoration:none" target="_blank" rel="noopener" href="' + escapeHtml(prFollowup.parent_pr_url) + '" title="Follow-up dispatched from ' + escapeHtml(prRef) + (prFollowup.parent_comment_author ? ' by ' + escapeHtml(prFollowup.parent_comment_author) : '') + '" onclick="event.stopPropagation()">&#8617; from ' + escapeHtml(prLabel) + '</a>';
122
122
  }
123
123
  return '<tr data-wi-id="' + escapeHtml(item.id) + '" style="cursor:pointer" onclick="if(shouldIgnoreSelectionClick(event))return;openWorkItemDetail(\'' + escapeHtml(item.id) + '\')">' +
124
124
  '<td><span class="pr-id">' + escapeHtml(item.id || '') + '</span></td>' +
125
125
  '<td style="max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escapeHtml((item.title || '').slice(0, 200)) + '">' + escapeHtml(item.title || '') + followupChip + '</td>' +
126
- '<td><span style="font-size:10px;color:var(--muted)">' + escapeHtml(item._source || '') + '</span>' +
127
- (item.scope === 'fan-out' ? ' <span class="pr-badge ' + (item.status === 'done' || item.status === 'failed' ? 'draft' : 'building') + '" style="font-size:8px">fan-out</span>' : '') + '</td>' +
126
+ '<td><span style="font-size:var(--text-sm);color:var(--muted)">' + escapeHtml(item._source || '') + '</span>' +
127
+ (item.scope === 'fan-out' ? ' <span class="pr-badge ' + (item.status === 'done' || item.status === 'failed' ? 'draft' : 'building') + '" style="font-size:var(--text-xs)">fan-out</span>' : '') + '</td>' +
128
128
  '<td>' + typeBadge(item.type) + '</td>' +
129
129
  '<td>' + priBadge(item.priority) + '</td>' +
130
130
  '<td>' + statusBadge(item.status || 'pending') +
131
- (item._reopened ? ' <span style="font-size:9px;color:var(--purple);margin-left:4px" title="This item was reopened from a previously completed state">reopened</span>' : '') +
132
- (item._pendingReason && item.status === 'pending' && item._pendingReason !== 'already_dispatched' ? ' <span style="font-size:9px;color:var(--muted);margin-left:4px" title="Pending reason: ' + escapeHtml(item._pendingReason) + '">' + escapeHtml(item._pendingReason.replace(/_/g, ' ')) + '</span>' : '') +
133
- (item._pendingReason === 'already_dispatched' && item.status === 'pending' ? ' <span style="font-size:9px;color:var(--blue);margin-left:4px" title="In dispatch queue, waiting to be assigned">queued</span>' : '') +
131
+ (item._reopened ? ' <span style="font-size:var(--text-xs);color:var(--purple);margin-left:4px" title="This item was reopened from a previously completed state">reopened</span>' : '') +
132
+ (item._pendingReason && item.status === 'pending' && item._pendingReason !== 'already_dispatched' ? ' <span style="font-size:var(--text-xs);color:var(--muted);margin-left:4px" title="Pending reason: ' + escapeHtml(item._pendingReason) + '">' + escapeHtml(item._pendingReason.replace(/_/g, ' ')) + '</span>' : '') +
133
+ (item._pendingReason === 'already_dispatched' && item.status === 'pending' ? ' <span style="font-size:var(--text-xs);color:var(--blue);margin-left:4px" title="In dispatch queue, waiting to be assigned">queued</span>' : '') +
134
134
  (item._managedSpawnPartial && Array.isArray(item._managedSpawnPartial.failed) && item._managedSpawnPartial.failed.length
135
- ? ' <span style="font-size:9px;color:var(--yellow);margin-left:4px;border:1px solid var(--yellow);padding:0 4px;border-radius:6px" title="managed-spawn: '
135
+ ? ' <span style="font-size:var(--text-xs);color:var(--yellow);margin-left:4px;border:1px solid var(--yellow);padding:0 4px;border-radius:6px" title="managed-spawn: '
136
136
  + escapeHtml(((item._managedSpawnPartial.healthy || []).length) + '/' + (((item._managedSpawnPartial.healthy || []).length) + item._managedSpawnPartial.failed.length))
137
137
  + ' healthy — failed: '
138
138
  + escapeHtml(item._managedSpawnPartial.failed.map(function(f){ return (f && f.name) || '?'; }).join(', '))
@@ -140,18 +140,18 @@ function wiRow(item) {
140
140
  + escapeHtml(((item._managedSpawnPartial.healthy || []).length) + '/' + (((item._managedSpawnPartial.healthy || []).length) + item._managedSpawnPartial.failed.length))
141
141
  + ' healthy</span>'
142
142
  : '') +
143
- (item._skipReason && item.status === 'pending' ? ' <span style="font-size:9px;color:var(--yellow);margin-left:4px" title="Dispatch blocked: ' + escapeHtml(item._skipReason) + (item._blockedBy ? ' (by ' + escapeHtml(item._blockedBy) + ')' : '') + '">' + escapeHtml(item._skipReason.replace(/_/g, ' ')) + (item._blockedBy ? ' <span style="color:var(--muted)">(' + escapeHtml(item._blockedBy) + ')</span>' : '') + '</span>' : '') +
143
+ (item._skipReason && item.status === 'pending' ? ' <span style="font-size:var(--text-xs);color:var(--yellow);margin-left:4px" title="Dispatch blocked: ' + escapeHtml(item._skipReason) + (item._blockedBy ? ' (by ' + escapeHtml(item._blockedBy) + ')' : '') + '">' + escapeHtml(item._skipReason.replace(/_/g, ' ')) + (item._blockedBy ? ' <span style="color:var(--muted)">(' + escapeHtml(item._blockedBy) + ')</span>' : '') + '</span>' : '') +
144
144
  (item.status === 'failed' ? ' ' + wiRetryBtn(item) : '') +
145
145
  '</td>' +
146
146
  '<td>' +
147
147
  (item.completedAgents && item.completedAgents.length > 0
148
148
  ? '<span class="pr-agent">' + escapeHtml(item.completedAgents.join(', ')) + '</span>'
149
149
  : '<span class="pr-agent">' + escapeHtml(item.dispatched_to || item.agent || '—') + '</span>') +
150
- (item.failReason ? '<span style="display:block;font-size:9px;color:var(--red)" title="' + escapeHtml(item.failReason) + '">' + escapeHtml(item.failReason.slice(0, 30)) + '</span>' : '') +
150
+ (item.failReason ? '<span style="display:block;font-size:var(--text-xs);color:var(--red)" title="' + escapeHtml(item.failReason) + '">' + escapeHtml(item.failReason.slice(0, 30)) + '</span>' : '') +
151
151
  '</td>' +
152
152
  '<td>' + prLink + '</td>' +
153
153
  '<td><span class="pr-date">' + escapeHtml((item.created || '').slice(0, 16).replace('T', ' ')) + '</span></td>' +
154
- '<td style="white-space:nowrap;font-size:9px;color:var(--muted)">' +
154
+ '<td style="white-space:nowrap;font-size:var(--text-xs);color:var(--muted)">' +
155
155
  (function() {
156
156
  // /api/status slims the full arrays into integer counts
157
157
  // (dashboard.js:1796-1797: referencesCount / acceptanceCriteriaCount).
@@ -168,11 +168,11 @@ function wiRow(item) {
168
168
  })() +
169
169
  '</td>' +
170
170
  '<td style="white-space:nowrap">' +
171
- ((item.status === 'pending' || item.status === 'failed') ? '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--blue);border-color:var(--blue);margin-right:4px" onclick="event.stopPropagation();editWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Edit work item">&#x270E;</button>' : '') +
172
- ((item.status === 'done' || item.status === 'failed') ? '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--muted);border-color:var(--border);margin-right:4px" onclick="event.stopPropagation();archiveWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Archive work item">&#x1F4E6;</button>' : '') +
173
- ((item.status === 'done' || item.status === 'failed') && !item._humanFeedback ? '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-right:4px" onclick="event.stopPropagation();feedbackWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Give feedback">&#x1F44D;&#x1F44E;</button>' : (item._humanFeedback ? '<span style="font-size:9px" title="Feedback given">' + (item._humanFeedback.rating === 'up' ? '&#x1F44D;' : '&#x1F44E;') + '</span> ' : '')) +
174
- ((item.status === 'pending' || item.status === 'dispatched' || item.status === 'queued' || item.status === 'failed') ? '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--orange);border-color:var(--orange);margin-right:4px" onclick="event.stopPropagation();cancelWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Cancel work item and kill agent">&#x1F6AB;</button>' : '') +
175
- '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="event.stopPropagation();deleteWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Delete work item and kill agent">&#x2715;</button>' +
171
+ ((item.status === 'pending' || item.status === 'failed') ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--blue);border-color:var(--blue);margin-right:4px" onclick="event.stopPropagation();editWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Edit work item">&#x270E;</button>' : '') +
172
+ ((item.status === 'done' || item.status === 'failed') ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--muted);border-color:var(--border);margin-right:4px" onclick="event.stopPropagation();archiveWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Archive work item">&#x1F4E6;</button>' : '') +
173
+ ((item.status === 'done' || item.status === 'failed') && !item._humanFeedback ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--green);border-color:var(--green);margin-right:4px" onclick="event.stopPropagation();feedbackWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Give feedback">&#x1F44D;&#x1F44E;</button>' : (item._humanFeedback ? '<span style="font-size:var(--text-xs)" title="Feedback given">' + (item._humanFeedback.rating === 'up' ? '&#x1F44D;' : '&#x1F44E;') + '</span> ' : '')) +
174
+ ((item.status === 'pending' || item.status === 'dispatched' || item.status === 'queued' || item.status === 'failed') ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--orange);border-color:var(--orange);margin-right:4px" onclick="event.stopPropagation();cancelWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Cancel work item and kill agent">&#x1F6AB;</button>' : '') +
175
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="event.stopPropagation();deleteWorkItem(\'' + escapeHtml(item.id) + '\',\'' + escapeHtml(item._source || '') + '\')" title="Delete work item and kill agent">&#x2715;</button>' +
176
176
  '</td>' +
177
177
  '</tr>';
178
178
  }
@@ -393,7 +393,7 @@ async function toggleWorkItemArchive() {
393
393
  const items = await fetch('/api/work-items/archive').then(r => r.json());
394
394
  if (!items.length) { el.innerHTML = '<p class="empty">No archived work items.</p>'; return; }
395
395
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escapeHtml() (fields: archived work item id/title/type/status/agent)
396
- el.innerHTML = '<div style="font-size:10px;color:var(--muted);margin-bottom:6px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Archived (' + items.length + ')</div>' +
396
+ el.innerHTML = '<div style="font-size:var(--text-sm);color:var(--muted);margin-bottom:6px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Archived (' + items.length + ')</div>' +
397
397
  '<div class="pr-table-wrap"><table class="pr-table"><thead><tr><th>ID</th><th>Title</th><th>Type</th><th>Status</th><th>Agent</th><th>Archived</th></tr></thead><tbody>' +
398
398
  items.map(function(i) {
399
399
  return '<tr style="opacity:0.6">' +
@@ -447,8 +447,8 @@ function feedbackWorkItem(id, source) {
447
447
  document.getElementById('modal-body').innerHTML =
448
448
  '<div style="display:flex;flex-direction:column;gap:16px">' +
449
449
  '<div style="display:flex;gap:16px;justify-content:center">' +
450
- '<button id="fb-up" onclick="_selectRating(\'up\')" style="font-size:36px;background:none;border:2px solid var(--border);border-radius:12px;padding:12px 20px;cursor:pointer;transition:all 0.2s">&#x1F44D;</button>' +
451
- '<button id="fb-down" onclick="_selectRating(\'down\')" style="font-size:36px;background:none;border:2px solid var(--border);border-radius:12px;padding:12px 20px;cursor:pointer;transition:all 0.2s">&#x1F44E;</button>' +
450
+ '<button id="fb-up" onclick="_selectRating(\'up\')" style="font-size:var(--text-display);background:none;border:2px solid var(--border);border-radius:12px;padding:12px 20px;cursor:pointer;transition:all 0.2s">&#x1F44D;</button>' +
451
+ '<button id="fb-down" onclick="_selectRating(\'down\')" style="font-size:var(--text-display);background:none;border:2px solid var(--border);border-radius:12px;padding:12px 20px;cursor:pointer;transition:all 0.2s">&#x1F44E;</button>' +
452
452
  '</div>' +
453
453
  '<textarea id="feedback-comment" rows="3" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-family:inherit;resize:vertical" placeholder="What was good or needs improvement?"></textarea>' +
454
454
  '<div style="display:flex;justify-content:flex-end;gap:8px">' +
@@ -587,14 +587,14 @@ async function _submitCreateWorkItem(e) {
587
587
  }
588
588
 
589
589
  function _wiRenderDetail(item) {
590
- const field = (label, value) => value ? '<div style="margin-bottom:8px"><span style="color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:0.5px">' + label + '</span><div style="margin-top:2px">' + value + '</div></div>' : '';
590
+ const field = (label, value) => value ? '<div style="margin-bottom:8px"><span style="color:var(--muted);font-size:var(--text-sm);text-transform:uppercase;letter-spacing:0.5px">' + label + '</span><div style="margin-top:2px">' + value + '</div></div>' : '';
591
591
  const badge = (cls, text) => '<span class="pr-badge ' + cls + '">' + escapeHtml(text) + '</span>';
592
592
  const statusCls = item.status === 'failed' ? 'rejected' : item.status === 'dispatched' ? 'building' : item.status === 'done' ? 'approved' : 'active';
593
593
 
594
- let html = '<div style="display:flex;flex-direction:column;gap:4px;font-size:13px">';
594
+ let html = '<div style="display:flex;flex-direction:column;gap:4px;font-size:var(--text-lg)">';
595
595
  html += '<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px">' +
596
596
  badge(statusCls, item.status || 'pending') +
597
- (item._reopened ? ' <span style="font-size:9px;color:var(--purple);margin-left:4px" title="This item was reopened from a previously completed state">reopened</span>' : '') + ' ' +
597
+ (item._reopened ? ' <span style="font-size:var(--text-xs);color:var(--purple);margin-left:4px" title="This item was reopened from a previously completed state">reopened</span>' : '') + ' ' +
598
598
  '<span class="dispatch-type ' + (item.type || 'implement') + '">' + escapeHtml(item.type || 'implement') + '</span>' +
599
599
  '<span class="prd-item-priority ' + (item.priority || '') + '">' + escapeHtml(item.priority || 'medium') + '</span>' +
600
600
  '</div>';
@@ -611,7 +611,7 @@ function _wiRenderDetail(item) {
611
611
  } else {
612
612
  _descHtml = escapeHtml(item.title || '—');
613
613
  }
614
- html += field('Description', '<div id="wi-detail-desc" style="font-size:12px;max-height:320px;overflow-y:auto;padding:8px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm)">' + _descHtml + '</div>');
614
+ html += field('Description', '<div id="wi-detail-desc" style="font-size:var(--text-md);max-height:320px;overflow-y:auto;padding:8px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm)">' + _descHtml + '</div>');
615
615
  html += field('Agent', escapeHtml(item.dispatched_to || item.agent || 'Auto'));
616
616
  html += field('Source', escapeHtml(item._source || 'central'));
617
617
  if (item.created) html += field('Created', escapeHtml(formatLocalDateTime(item.created)));
@@ -623,7 +623,7 @@ function _wiRenderDetail(item) {
623
623
  var _msp = item._managedSpawnPartial;
624
624
  var _mspHealthy = Array.isArray(_msp.healthy) ? _msp.healthy : [];
625
625
  var _mspTotal = _mspHealthy.length + _msp.failed.length;
626
- var _mspBody = '<div style="color:var(--yellow);font-size:11px;margin-bottom:6px">'
626
+ var _mspBody = '<div style="color:var(--yellow);font-size:var(--text-base);margin-bottom:6px">'
627
627
  + escapeHtml(_mspHealthy.length + '/' + _mspTotal) + ' specs healthy. Failed: '
628
628
  + escapeHtml(_msp.failed.map(function(f){ return (f && f.name) || '?'; }).join(', '))
629
629
  + (_msp.evaluated_at ? ' <span style="color:var(--muted)">(evaluated ' + escapeHtml(_msp.evaluated_at) + ')</span>' : '')
@@ -632,8 +632,8 @@ function _wiRenderDetail(item) {
632
632
  var name = escapeHtml((f && f.name) || '?');
633
633
  var reason = escapeHtml((f && f.reason) || 'unknown');
634
634
  var tail = (f && f.log_tail) || '';
635
- return '<details style="margin-bottom:6px"><summary style="cursor:pointer;font-size:11px"><strong>' + name + '</strong> — ' + reason + '</summary>'
636
- + '<pre style="font-size:10px;max-height:240px;overflow:auto;padding:6px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm);margin:4px 0 0 0">'
635
+ return '<details style="margin-bottom:6px"><summary style="cursor:pointer;font-size:var(--text-base)"><strong>' + name + '</strong> — ' + reason + '</summary>'
636
+ + '<pre style="font-size:var(--text-sm);max-height:240px;overflow:auto;padding:6px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm);margin:4px 0 0 0">'
637
637
  + escapeHtml(tail || '(no log tail captured)')
638
638
  + '</pre></details>';
639
639
  }).join('');
@@ -659,7 +659,7 @@ function _wiRenderDetail(item) {
659
659
  }
660
660
  var refs = Array.isArray(item.references) ? item.references.filter(r => r && typeof r === 'object' && r.url) : [];
661
661
  if (refs.length) {
662
- html += field('References', refs.map(r => '<a href="' + escapeHtml(r.url) + '" target="_blank" style="color:var(--blue)">' + escapeHtml(r.title || r.url) + '</a>' + (r.type ? ' <span style="color:var(--muted);font-size:10px">(' + escapeHtml(r.type) + ')</span>' : '')).join('<br>'));
662
+ html += field('References', refs.map(r => '<a href="' + escapeHtml(r.url) + '" target="_blank" style="color:var(--blue)">' + escapeHtml(r.title || r.url) + '</a>' + (r.type ? ' <span style="color:var(--muted);font-size:var(--text-sm)">(' + escapeHtml(r.type) + ')</span>' : '')).join('<br>'));
663
663
  } else if (item.referencesCount > 0) {
664
664
  html += field('References', '<span style="color:var(--muted)">' + item.referencesCount + ' reference(s) — loading…</span>');
665
665
  }
@@ -669,7 +669,7 @@ function _wiRenderDetail(item) {
669
669
  // Artifacts — output log, branch, skills, etc.
670
670
  var arts = item._artifacts || {};
671
671
  var artPills = '';
672
- var pillStyle = 'display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:10px;font-size:10px;cursor:pointer;background:var(--surface2);border:1px solid var(--border);color:var(--text)';
672
+ var pillStyle = 'display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:10px;font-size:var(--text-sm);cursor:pointer;background:var(--surface2);border:1px solid var(--border);color:var(--text)';
673
673
  // Output log pill removed — raw stream-json output is not human-readable
674
674
  var artBackFn = "pushModalBack(function(){openWorkItemDetail('" + escapeHtml(item.id) + "')});";
675
675
  if (arts.branch) artPills += '<span style="' + pillStyle + ';cursor:default">🌿 ' + escapeHtml(arts.branch) + '</span> ';
@@ -687,7 +687,7 @@ function _wiRenderDetail(item) {
687
687
  artPills += '<span onclick="' + artBackFn + 'kbOpenItem(\'' + escapeHtml(kbCat) + '\',\'' + escapeHtml(kbFile) + '\')" style="' + pillStyle + '">📚 ' + escapeHtml(kbLabel) + '</span> ';
688
688
  } else if (noteFile.startsWith('archive:')) {
689
689
  var archLabel = noteFile.slice(8).replace(/\.md$/, '').replace(/^\d{4}-\d{2}-\d{2}-/, '').slice(0, 30);
690
- artPills += '<span onclick="' + artBackFn + 'openInboxNote(\'' + escapeHtml(noteFile.slice(8)) + '\')" style="' + pillStyle + ';opacity:0.7">📄 ' + escapeHtml(archLabel) + ' <span style="font-size:8px">(archived)</span></span> ';
690
+ artPills += '<span onclick="' + artBackFn + 'openInboxNote(\'' + escapeHtml(noteFile.slice(8)) + '\')" style="' + pillStyle + ';opacity:0.7">📄 ' + escapeHtml(archLabel) + ' <span style="font-size:var(--text-xs)">(archived)</span></span> ';
691
691
  } else {
692
692
  var noteLabel = noteFile.replace(/\.md$/, '').slice(0, 30);
693
693
  artPills += '<span onclick="' + artBackFn + 'openInboxNote(\'' + escapeHtml(noteFile) + '\')" style="' + pillStyle + '">📝 ' + escapeHtml(noteLabel) + '</span> ';
@@ -247,7 +247,7 @@ function _renderMdCore(s) {
247
247
  // 1. Extract code blocks and inline code into placeholders (protect from other transforms)
248
248
  const codeSlots = [];
249
249
  html = html.replace(/```(\w*)\n([\s\S]*?)```/g, function(_, lang, code) {
250
- codeSlots.push('<pre style="background:var(--bg);padding:8px;border-radius:4px;overflow-x:auto;font-size:11px;margin:4px 0"><code>' + code + '</code></pre>');
250
+ codeSlots.push('<pre style="background:var(--bg);padding:8px;border-radius:4px;overflow-x:auto;font-size:var(--text-base);margin:4px 0"><code>' + code + '</code></pre>');
251
251
  return '\x00CB' + (codeSlots.length - 1) + '\x00';
252
252
  });
253
253
 
@@ -343,7 +343,7 @@ function _renderMdCore(s) {
343
343
  i++;
344
344
  }
345
345
  i--; // back up one since the for loop will increment
346
- var tableHtml = '<div class="md-table-wrap"><table style="font-size:11px"><thead><tr>';
346
+ var tableHtml = '<div class="md-table-wrap"><table style="font-size:var(--text-base)"><thead><tr>';
347
347
  if (tableRows.length > 0) {
348
348
  tableRows[0].forEach(function(c) { tableHtml += '<th>' + c + '</th>'; });
349
349
  tableHtml += '</tr></thead><tbody>';
@@ -446,7 +446,7 @@ function _renderMdChunked(fullText) {
446
446
  var uid = '_mdChunk' + (++_mdChunkUid);
447
447
  if (chunks.length <= 1) return firstHtml;
448
448
 
449
- var sentinel = '<div id="' + uid + '" style="padding:12px 0;color:var(--muted);font-size:11px">Loading more content...</div>';
449
+ var sentinel = '<div id="' + uid + '" style="padding:12px 0;color:var(--muted);font-size:var(--text-base)">Loading more content...</div>';
450
450
 
451
451
  setTimeout(function() {
452
452
  var el = document.getElementById(uid);
@@ -493,7 +493,7 @@ function openBugReport() {
493
493
  var container = document.createElement('div');
494
494
  container.style.cssText = 'display:flex;flex-direction:column;gap:12px';
495
495
  var intro = document.createElement('p');
496
- intro.style.cssText = 'color:var(--muted);font-size:12px;margin:0';
496
+ intro.style.cssText = 'color:var(--muted);font-size:var(--text-md);margin:0';
497
497
  intro.textContent = 'File a bug on the Minions repo (yemi33/minions).';
498
498
 
499
499
  var titleLabel = document.createElement('label');
@@ -559,7 +559,7 @@ async function submitBugReport() {
559
559
  var container = document.createElement('div');
560
560
  container.style.cssText = 'padding:24px;text-align:center';
561
561
  var icon = document.createElement('div');
562
- icon.style.cssText = 'font-size:32px;margin-bottom:12px';
562
+ icon.style.cssText = 'font-size:var(--text-display);margin-bottom:12px';
563
563
  icon.textContent = '\u{1F41B}';
564
564
  var heading = document.createElement('div');
565
565
  heading.style.cssText = 'color:var(--green);font-weight:600;margin-bottom:8px';
@@ -571,12 +571,12 @@ async function submitBugReport() {
571
571
  link.href = safeUrl(d.url);
572
572
  link.target = '_blank';
573
573
  link.rel = 'noopener noreferrer';
574
- link.style.cssText = 'color:var(--blue);font-size:13px';
574
+ link.style.cssText = 'color:var(--blue);font-size:var(--text-lg)';
575
575
  link.textContent = 'View issue on GitHub';
576
576
  container.appendChild(link);
577
577
  } else {
578
578
  var msg = document.createElement('span');
579
- msg.style.cssText = 'color:var(--muted);font-size:12px';
579
+ msg.style.cssText = 'color:var(--muted);font-size:var(--text-md)';
580
580
  msg.textContent = 'Issue created on yemi33/minions';
581
581
  container.appendChild(msg);
582
582
  }
@@ -596,7 +596,7 @@ async function submitBugReport() {
596
596
  if (!errDiv) {
597
597
  errDiv = document.createElement('div');
598
598
  errDiv.id = 'bug-error';
599
- errDiv.style.cssText = 'color:var(--red);font-size:12px;padding:8px;background:rgba(248,81,73,0.1);border-radius:4px';
599
+ errDiv.style.cssText = 'color:var(--red);font-size:var(--text-md);padding:8px;background:rgba(248,81,73,0.1);border-radius:4px';
600
600
  btn?.parentElement?.parentElement?.appendChild(errDiv);
601
601
  }
602
602
  errDiv.textContent = 'Error: ' + e.message;