@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
@@ -45,7 +45,7 @@ async function _savePrdDesc(source, itemId) {
45
45
  if (res.ok) {
46
46
  _prdDescRawCache = newDesc;
47
47
  // eslint-disable-next-line no-unsanitized/property -- reason: renderMd() escapes all user-controlled fields before assembling HTML (see dashboard/js/utils.js)
48
- view.innerHTML = newDesc ? renderMd(newDesc) : '<span style="color:var(--muted);font-size:11px">No description</span>';
48
+ view.innerHTML = newDesc ? renderMd(newDesc) : '<span style="color:var(--muted);font-size:var(--text-base)">No description</span>';
49
49
  view.style.display = '';
50
50
  editor.style.display = 'none';
51
51
  document.getElementById('prd-desc-edit-btn').style.display = '';
@@ -105,21 +105,21 @@ function renderPrd(prd, prog) {
105
105
  let actions = '';
106
106
  if (prdFile && !headerStale) {
107
107
  if (effectiveStatus === 'awaiting-approval') {
108
- actions = ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="planApprove(\'' + escHtml(prdFile) + '\',this)">Approve</button>';
108
+ actions = ' <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="planApprove(\'' + escHtml(prdFile) + '\',this)">Approve</button>';
109
109
  } else if (effectiveStatus === 'completed') {
110
110
  const hasVerifyWi = allWi.some(w => w.itemType === 'verify' && w.sourcePlan === prdFile);
111
- actions = (hasVerifyWi ? '' : ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="triggerVerify(\'' + escHtml(prdFile) + '\',this)">Verify</button>') +
112
- ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;margin-left:4px" onclick="planArchive(\'' + escHtml(prdFile) + '\',this)">Archive</button>';
111
+ actions = (hasVerifyWi ? '' : ' <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="triggerVerify(\'' + escHtml(prdFile) + '\',this)">Verify</button>') +
112
+ ' <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;margin-left:4px" onclick="planArchive(\'' + escHtml(prdFile) + '\',this)">Archive</button>';
113
113
  } else if (effectiveStatus === 'dispatched') {
114
- actions = ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--yellow);border-color:var(--yellow);margin-left:4px" onclick="planPause(\'' + escHtml(prdFile) + '\',this)">Pause</button>';
114
+ actions = ' <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="planPause(\'' + escHtml(prdFile) + '\',this)">Pause</button>';
115
115
  } else if (effectiveStatus === 'paused') {
116
- actions = ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="planApprove(\'' + escHtml(prdFile) + '\',this)">Resume</button>' +
117
- ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;margin-left:4px" onclick="planArchive(\'' + escHtml(prdFile) + '\',this)">Archive</button>';
116
+ actions = ' <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="planApprove(\'' + escHtml(prdFile) + '\',this)">Resume</button>' +
117
+ ' <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;margin-left:4px" onclick="planArchive(\'' + escHtml(prdFile) + '\',this)">Archive</button>';
118
118
  }
119
119
  }
120
120
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: PRD file; status label/color and age text are derived UI state)
121
- badge.innerHTML = '<span style="font-weight:600;font-size:11px;color:' + (statusColors[effectiveStatus] || 'var(--muted)') + '">' + (statusLabels[effectiveStatus] || effectiveStatus) + '</span>' +
122
- ' <span style="color:var(--muted);font-size:10px">' + (prd.age || '') + '</span>' + actions;
121
+ badge.innerHTML = '<span style="font-weight:600;font-size:var(--text-base);color:' + (statusColors[effectiveStatus] || 'var(--muted)') + '">' + (statusLabels[effectiveStatus] || effectiveStatus) + '</span>' +
122
+ ' <span style="color:var(--muted);font-size:var(--text-sm)">' + (prd.age || '') + '</span>' + actions;
123
123
  } else {
124
124
  // Multiple PRDs — show count summary, per-PRD details are in renderPrdProgress groups
125
125
  const counts = { completed: 0, 'dispatched': 0, 'awaiting-approval': 0, paused: 0 };
@@ -134,10 +134,10 @@ function renderPrd(prd, prog) {
134
134
  counts[s] = (counts[s] || 0) + 1;
135
135
  }
136
136
  const parts = Object.entries(counts).filter(([, n]) => n > 0).map(([s, n]) =>
137
- '<span style="font-size:10px;color:' + (statusColors[s] || 'var(--muted)') + '">' + n + ' ' + (statusLabels[s] || s).toLowerCase() + '</span>'
137
+ '<span style="font-size:var(--text-sm);color:' + (statusColors[s] || 'var(--muted)') + '">' + n + ' ' + (statusLabels[s] || s).toLowerCase() + '</span>'
138
138
  );
139
139
  // eslint-disable-next-line no-unsanitized/property -- reason: composed from compile-time constants (no user data flows in)
140
- badge.innerHTML = '<span style="font-weight:600;font-size:11px;color:var(--text)">' + existing.length + ' PRDs</span> ' + parts.join(' · ');
140
+ badge.innerHTML = '<span style="font-weight:600;font-size:var(--text-base);color:var(--text)">' + existing.length + ' PRDs</span> ' + parts.join(' · ');
141
141
  }
142
142
  section.innerHTML = '';
143
143
  }
@@ -224,7 +224,7 @@ function renderPrdProgress(prog) {
224
224
  const labels = { 'done': 'DONE', 'in-progress': 'WIP', 'failed': 'FAIL', 'paused': 'PAUSED', 'missing': '\u2014', 'updated': 'REDO' };
225
225
  const style = styles[s] || 'background:var(--surface);color:var(--muted)';
226
226
  const label = labels[s] || '—';
227
- return '<span style="font-size:9px;font-weight:700;padding:2px 6px;border-radius:3px;letter-spacing:0.5px;white-space:nowrap;' + style + '">' + label + '</span>';
227
+ return '<span style="font-size:var(--text-xs);font-weight:700;padding:2px 6px;border-radius:3px;letter-spacing:0.5px;white-space:nowrap;' + style + '">' + label + '</span>';
228
228
  };
229
229
 
230
230
  // Build work item lookup by actual work item ID.
@@ -258,13 +258,13 @@ function renderPrdProgress(prog) {
258
258
  const wi = wiById[workItemId] || wiById[i.id];
259
259
  const wiAgent = wi?.dispatched_to ? (agentData.find(a => a.id === wi.dispatched_to) || {}) : null;
260
260
  const wiLabel = _renderPrdWorkItemIdBadge(wi ? wi.id : workItemId, i.id);
261
- const agentLabel = wiAgent ? '<span style="font-size:9px;color:var(--muted)" title="' + escHtml(wiAgent.name || wi.dispatched_to) + '">' +
261
+ const agentLabel = wiAgent ? '<span style="font-size:var(--text-xs);color:var(--muted)" title="' + escHtml(wiAgent.name || wi.dispatched_to) + '">' +
262
262
  (wiAgent.emoji || '') + ' ' + escHtml(wiAgent.name || wi.dispatched_to) + '</span>' : '';
263
263
 
264
264
  // Branch label — show the target branch for this item
265
265
  const wiBranch = wi ? (wi.branch || wi.featureBranch || (wi._artifacts && wi._artifacts.branch) || '') : '';
266
266
  const branchLabel = wiBranch
267
- ? '<span style="font-size:9px;color:var(--muted);background:var(--surface);padding:1px 5px;border-radius:3px;border:1px solid var(--border);font-family:monospace;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;vertical-align:middle" title="Branch: ' + escHtml(wiBranch) + '">&#x1F33F; ' + escHtml(wiBranch) + '</span>'
267
+ ? '<span style="font-size:var(--text-xs);color:var(--muted);background:var(--surface);padding:1px 5px;border-radius:3px;border:1px solid var(--border);font-family:monospace;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;vertical-align:middle" title="Branch: ' + escHtml(wiBranch) + '">&#x1F33F; ' + escHtml(wiBranch) + '</span>'
268
268
  : '';
269
269
 
270
270
  // Requeue button for failed items or PRD items with no work item (orphaned/deleted)
@@ -273,19 +273,19 @@ function renderPrdProgress(prog) {
273
273
  const requeueState = getPrdRequeueState(wi ? wi.id : i.id);
274
274
  let requeueBtn = '';
275
275
  if (requeueState && requeueState.status === 'pending') {
276
- requeueBtn = '<span style="color:var(--yellow);cursor:wait;font-size:9px;padding:1px 5px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.35);border-radius:3px" title="Retry request in progress">requeuing…</span>';
276
+ requeueBtn = '<span style="color:var(--yellow);cursor:wait;font-size:var(--text-xs);padding:1px 5px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.35);border-radius:3px" title="Retry request in progress">requeuing…</span>';
277
277
  } else if (requeueState && requeueState.status === 'queued') {
278
- requeueBtn = '<span style="color:var(--green);cursor:default;font-size:9px;padding:1px 5px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.35);border-radius:3px" title="Successfully requeued">requeued</span>';
278
+ requeueBtn = '<span style="color:var(--green);cursor:default;font-size:var(--text-xs);padding:1px 5px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.35);border-radius:3px" title="Successfully requeued">requeued</span>';
279
279
  } else if (requeueState && requeueState.status === 'error') {
280
- requeueBtn = '<span style="color:var(--red);cursor:default;font-size:9px;padding:1px 5px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.35);border-radius:3px" title="' + escHtml(requeueState.message || 'Retry failed') + '">retry failed</span>';
280
+ requeueBtn = '<span style="color:var(--red);cursor:default;font-size:var(--text-xs);padding:1px 5px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.35);border-radius:3px" title="' + escHtml(requeueState.message || 'Retry failed') + '">retry failed</span>';
281
281
  } else if (canRequeue) {
282
- requeueBtn = '<span onclick="event.stopPropagation();prdItemRequeue(\'' + escHtml(wi ? wi.id : i.id) + '\',\'' + escHtml(wi ? (wi._source || '') : '') + '\',\'' + escHtml(i.source || '') + '\')" style="color:var(--green);cursor:pointer;font-size:9px;padding:1px 5px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px" title="Requeue this work item">retry</span>';
282
+ requeueBtn = '<span onclick="event.stopPropagation();prdItemRequeue(\'' + escHtml(wi ? wi.id : i.id) + '\',\'' + escHtml(wi ? (wi._source || '') : '') + '\',\'' + escHtml(i.source || '') + '\')" style="color:var(--green);cursor:pointer;font-size:var(--text-xs);padding:1px 5px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px" title="Requeue this work item">retry</span>';
283
283
  }
284
284
 
285
285
  // Re-open button for done items — sets PRD item to "updated" so engine re-dispatches
286
286
  const isDone = i.status === 'done' || (wi && wi.status === 'done');
287
287
  const reopenBtn = isDone
288
- ? '<span onclick="event.stopPropagation();prdItemReopen(\'' + escHtml(i.source || '') + '\',\'' + escHtml(i.id) + '\')" style="color:var(--blue);cursor:pointer;font-size:9px;padding:1px 5px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="Re-open: set to updated so engine re-dispatches on existing branch">re-open</span>'
288
+ ? '<span onclick="event.stopPropagation();prdItemReopen(\'' + escHtml(i.source || '') + '\',\'' + escHtml(i.id) + '\')" style="color:var(--blue);cursor:pointer;font-size:var(--text-xs);padding:1px 5px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="Re-open: set to updated so engine re-dispatches on existing branch">re-open</span>'
289
289
  : '';
290
290
 
291
291
  return '<div class="prd-item-row st-' + (i.status || 'missing') + '" style="flex-wrap:wrap;cursor:pointer" onclick="if(shouldIgnoreSelectionClick(event))return;prdItemEdit(\'' + src + '\',\'' + iid + '\')">' +
@@ -300,8 +300,8 @@ function renderPrdProgress(prog) {
300
300
  (prLinks ? '<span>' + prLinks + '</span>' : '') +
301
301
  branchLabel +
302
302
  '<span class="prd-item-priority ' + (i.priority || '') + '">' + escHtml(i.priority || '') + '</span>' +
303
- '<span onclick="event.stopPropagation();prdItemRemove(\'' + src + '\',\'' + iid + '\')" style="color:var(--red);cursor:pointer;font-size:10px;padding:0 4px" title="Remove item">x</span>' +
304
- (i.description ? '<div style="width:100%;font-size:11px;color:var(--muted);padding:2px 0 2px 42px;line-height:1.4">' + renderMd(i.description) + '</div>' : '') +
303
+ '<span onclick="event.stopPropagation();prdItemRemove(\'' + src + '\',\'' + iid + '\')" style="color:var(--red);cursor:pointer;font-size:var(--text-sm);padding:0 4px" title="Remove item">x</span>' +
304
+ (i.description ? '<div style="width:100%;font-size:var(--text-base);color:var(--muted);padding:2px 0 2px 42px;line-height:1.4">' + renderMd(i.description) + '</div>' : '') +
305
305
  // Show decomposed children inline
306
306
  (i.status === 'decomposed' ? (function() {
307
307
  const children = (window._lastWorkItems || []).filter(w => w.parent_id === i.id);
@@ -309,11 +309,11 @@ function renderPrdProgress(prog) {
309
309
  return '<div style="width:100%;padding:4px 0 4px 42px;display:flex;flex-direction:column;gap:2px">' +
310
310
  children.map(c => {
311
311
  const childAgent = c.dispatched_to ? (agentData.find(a => a.id === c.dispatched_to) || {}) : null;
312
- return '<div style="font-size:10px;display:flex;align-items:center;gap:6px;color:var(--text);padding:2px 6px;background:var(--surface);border-radius:4px;border:1px solid var(--border)">' +
312
+ return '<div style="font-size:var(--text-sm);display:flex;align-items:center;gap:6px;color:var(--text);padding:2px 6px;background:var(--surface);border-radius:4px;border:1px solid var(--border)">' +
313
313
  statusBadge(c.status) +
314
- '<span style="color:var(--muted);font-size:9px">' + escHtml(c.id) + '</span>' +
314
+ '<span style="color:var(--muted);font-size:var(--text-xs)">' + escHtml(c.id) + '</span>' +
315
315
  '<span style="flex:1">' + escHtml((c.title || '').replace('Implement: ', '').slice(0, 60)) + '</span>' +
316
- (childAgent ? '<span style="font-size:9px;color:var(--muted)">' + (childAgent.emoji || '') + ' ' + escHtml(childAgent.name || c.dispatched_to) + '</span>' : '') +
316
+ (childAgent ? '<span style="font-size:var(--text-xs);color:var(--muted)">' + (childAgent.emoji || '') + ' ' + escHtml(childAgent.name || c.dispatched_to) + '</span>' : '') +
317
317
  '</div>';
318
318
  }).join('') +
319
319
  '</div>';
@@ -351,64 +351,64 @@ function renderPrdProgress(prog) {
351
351
  const end = t.allDone && t.lastCompleted ? t.lastCompleted : isBlocked ? (t.lastCompleted || t.firstDispatched) : Date.now();
352
352
  const elapsed = end - t.firstDispatched;
353
353
  const icon = t.allDone ? '&#x2713;' : isBlocked ? '&#x23F8;' : '&#x23F1;';
354
- runtimeLabel = '<span style="color:' + (t.allDone ? 'var(--green)' : isBlocked ? 'var(--muted)' : 'var(--yellow)') + ';font-weight:400;font-size:10px">' +
354
+ runtimeLabel = '<span style="color:' + (t.allDone ? 'var(--green)' : isBlocked ? 'var(--muted)' : 'var(--yellow)') + ';font-weight:400;font-size:var(--text-sm)">' +
355
355
  icon + ' ' + formatDuration(elapsed) + (t.allDone ? '' : isAwaitingApproval ? ' (awaiting approval)' : isPaused ? ' (paused)' : ' elapsed') + '</span>';
356
356
  }
357
357
 
358
358
  const pausedLabel = isAwaitingApproval
359
- ? '<span style="color:var(--yellow);font-weight:600;font-size:10px;padding:1px 6px;border:1px solid var(--yellow);border-radius:3px">AWAITING APPROVAL</span>'
359
+ ? '<span style="color:var(--yellow);font-weight:600;font-size:var(--text-sm);padding:1px 6px;border:1px solid var(--yellow);border-radius:3px">AWAITING APPROVAL</span>'
360
360
  : isPaused
361
- ? '<span style="color:var(--muted);font-weight:600;font-size:10px;padding:1px 6px;border:1px solid var(--muted);border-radius:3px">PAUSED</span>'
361
+ ? '<span style="color:var(--muted);font-weight:600;font-size:var(--text-sm);padding:1px 6px;border:1px solid var(--muted);border-radius:3px">PAUSED</span>'
362
362
  : '';
363
363
  const showStale = (!isBlocked || isPaused) && g.planStale;
364
364
  const staleLabel = showStale
365
- ? '<span style="color:var(--orange);font-weight:700;font-size:10px;padding:1px 6px;border:1px solid var(--orange);border-radius:3px;background:rgba(210,153,34,0.12)" title="Source plan changed after this PRD was generated">STALE</span>'
365
+ ? '<span style="color:var(--orange);font-weight:700;font-size:var(--text-sm);padding:1px 6px;border:1px solid var(--orange);border-radius:3px;background:rgba(210,153,34,0.12)" title="Source plan changed after this PRD was generated">STALE</span>'
366
366
  : '';
367
367
  const staleRecovery = showStale
368
368
  ? '<div style="width:100%;margin-top:4px;padding:6px 8px;border:1px solid rgba(210,153,34,0.35);border-radius:4px;background:rgba(210,153,34,0.08);display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
369
- '<span style="color:var(--orange);font-size:10px;font-weight:600">&#x26A0;&#xFE0F; Source plan was revised. This PRD may be outdated.</span>' +
370
- '<span onclick="event.stopPropagation();prdRegenerate(\'' + escHtml(g.file) + '\')" style="color:var(--green);cursor:pointer;font-size:10px;font-weight:700;padding:2px 8px;background:rgba(63,185,80,0.12);border:1px solid rgba(63,185,80,0.35);border-radius:4px" title="Compare revised plan against existing PRD and update items">Regenerate PRD</span>' +
371
- '<span onclick="event.stopPropagation();prdResumeWithoutRegen(\'' + escHtml(g.file) + '\')" style="color:var(--muted);cursor:pointer;font-size:10px;padding:2px 8px;background:var(--surface);border:1px solid var(--border);border-radius:4px" title="Resume without regenerating — use current PRD as-is">Resume as-is</span>' +
372
- '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan || g.file) + '\')" style="color:var(--blue);cursor:pointer;font-size:10px;padding:2px 8px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:4px" title="Review latest plan changes">Review plan</span>' +
369
+ '<span style="color:var(--orange);font-size:var(--text-sm);font-weight:600">&#x26A0;&#xFE0F; Source plan was revised. This PRD may be outdated.</span>' +
370
+ '<span onclick="event.stopPropagation();prdRegenerate(\'' + escHtml(g.file) + '\')" style="color:var(--green);cursor:pointer;font-size:var(--text-sm);font-weight:700;padding:2px 8px;background:rgba(63,185,80,0.12);border:1px solid rgba(63,185,80,0.35);border-radius:4px" title="Compare revised plan against existing PRD and update items">Regenerate PRD</span>' +
371
+ '<span onclick="event.stopPropagation();prdResumeWithoutRegen(\'' + escHtml(g.file) + '\')" style="color:var(--muted);cursor:pointer;font-size:var(--text-sm);padding:2px 8px;background:var(--surface);border:1px solid var(--border);border-radius:4px" title="Resume without regenerating — use current PRD as-is">Resume as-is</span>' +
372
+ '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan || g.file) + '\')" style="color:var(--blue);cursor:pointer;font-size:var(--text-sm);padding:2px 8px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:4px" title="Review latest plan changes">Review plan</span>' +
373
373
  '</div>'
374
374
  : '';
375
375
  const isCompleted = done > 0 && done === g.items.length;
376
376
  // Hide regular action buttons when stale banner is showing — stale banner has its own actions
377
377
  const isStale = showStale;
378
378
  const pauseResumeBtn = isStale ? '' : isAwaitingApproval
379
- ? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Approve</span>'
379
+ ? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:var(--text-xs);padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Approve</span>'
380
380
  : isPaused
381
- ? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Resume</span>'
381
+ ? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:var(--text-xs);padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Resume</span>'
382
382
  : isCompleted && !(window._lastWorkItems || []).some(w => w.itemType === 'verify' && w.sourcePlan === g.file)
383
- ? '<span onclick="event.stopPropagation();triggerVerify(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Verify</span>'
384
- : isCompleted ? '' : '<span onclick="event.stopPropagation();planPause(\'' + escHtml(g.file) + '\',this)" style="color:var(--yellow);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.3);border-radius:3px">Pause</span>';
385
- const archiveBtn = (!isStale && (isCompleted || isPaused)) ? '<span onclick="event.stopPropagation();planArchive(\'' + escHtml(g.file) + '\',this)" style="color:var(--muted);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(139,148,158,0.1);border:1px solid rgba(139,148,158,0.3);border-radius:3px">Archive</span>' : '';
386
- const deleteBtn = '<span onclick="event.stopPropagation();planDelete(\'' + escHtml(g.file) + '\')" style="color:var(--red);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.3);border-radius:3px">Delete</span>';
383
+ ? '<span onclick="event.stopPropagation();triggerVerify(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:var(--text-xs);padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Verify</span>'
384
+ : isCompleted ? '' : '<span onclick="event.stopPropagation();planPause(\'' + escHtml(g.file) + '\',this)" style="color:var(--yellow);cursor:pointer;font-size:var(--text-xs);padding:1px 6px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.3);border-radius:3px">Pause</span>';
385
+ const archiveBtn = (!isStale && (isCompleted || isPaused)) ? '<span onclick="event.stopPropagation();planArchive(\'' + escHtml(g.file) + '\',this)" style="color:var(--muted);cursor:pointer;font-size:var(--text-xs);padding:1px 6px;background:rgba(139,148,158,0.1);border:1px solid rgba(139,148,158,0.3);border-radius:3px">Archive</span>' : '';
386
+ const deleteBtn = '<span onclick="event.stopPropagation();planDelete(\'' + escHtml(g.file) + '\')" style="color:var(--red);cursor:pointer;font-size:var(--text-xs);padding:1px 6px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.3);border-radius:3px">Delete</span>';
387
387
  const sourcePlanLink = g.sourcePlan
388
- ? '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan) + '\')" style="color:var(--blue);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="View source plan">&#x1F4C4; Plan</span>'
388
+ ? '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan) + '\')" style="color:var(--blue);cursor:pointer;font-size:var(--text-xs);padding:1px 6px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="View source plan">&#x1F4C4; Plan</span>'
389
389
  : '';
390
390
 
391
- return '<div style="font-size:11px;font-weight:600;color:var(--blue);margin-bottom:4px;padding:6px 8px;background:var(--surface2);border-radius:4px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
391
+ return '<div style="font-size:var(--text-base);font-weight:600;color:var(--blue);margin-bottom:4px;padding:6px 8px;background:var(--surface2);border-radius:4px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
392
392
  (g._projects.length > 0 ? g._projects.map(function(p) { return '<span class="prd-project-badge">' + escHtml(p) + '</span>'; }).join(' ') : '') +
393
393
  '<span style="color:var(--text)">' + escHtml(summary || g.file) + '</span>' +
394
394
  (g.branchStrategy === 'shared-branch'
395
- ? '<span style="font-size:9px;padding:1px 5px;border-radius:3px;background:rgba(210,153,34,0.15);color:var(--yellow);font-weight:400" title="All items commit to a single shared feature branch">&#x1F333; shared branch</span>'
396
- : '<span style="font-size:9px;padding:1px 5px;border-radius:3px;background:rgba(56,139,253,0.12);color:var(--blue);font-weight:400" title="Each item gets its own branch (work/P-xxx) and PR">&#x1F500; parallel branches</span>') +
395
+ ? '<span style="font-size:var(--text-xs);padding:1px 5px;border-radius:3px;background:rgba(210,153,34,0.15);color:var(--yellow);font-weight:400" title="All items commit to a single shared feature branch">&#x1F333; shared branch</span>'
396
+ : '<span style="font-size:var(--text-xs);padding:1px 5px;border-radius:3px;background:rgba(56,139,253,0.12);color:var(--blue);font-weight:400" title="Each item gets its own branch (work/P-xxx) and PR">&#x1F500; parallel branches</span>') +
397
397
  pausedLabel +
398
398
  staleLabel +
399
- '<span style="font-weight:700;font-size:11px;color:' + (done === g.items.length && g.items.length > 0 ? 'var(--green)' : 'var(--text)') + '">' + (g.items.length > 0 ? Math.round((done / g.items.length) * 100) : 0) + '%</span>' +
400
- '<span style="color:var(--muted);font-weight:400;font-size:10px">' + g.items.length + ' items' +
399
+ '<span style="font-weight:700;font-size:var(--text-base);color:' + (done === g.items.length && g.items.length > 0 ? 'var(--green)' : 'var(--text)') + '">' + (g.items.length > 0 ? Math.round((done / g.items.length) * 100) : 0) + '%</span>' +
400
+ '<span style="color:var(--muted);font-weight:400;font-size:var(--text-sm)">' + g.items.length + ' items' +
401
401
  (done ? ' · ' + done + ' done' : '') + (wip ? ' · ' + wip + ' active' : '') +
402
402
  '</span>' +
403
- (g.prdUpdatedAt ? '<span style="color:var(--muted);font-weight:400;font-size:10px" title="PRD last updated: ' + g.prdUpdatedAt + '">PRD updated ' + timeAgo(g.prdUpdatedAt) + '</span>' : '') +
403
+ (g.prdUpdatedAt ? '<span style="color:var(--muted);font-weight:400;font-size:var(--text-sm)" title="PRD last updated: ' + g.prdUpdatedAt + '">PRD updated ' + timeAgo(g.prdUpdatedAt) + '</span>' : '') +
404
404
  runtimeLabel +
405
405
  (g.archived
406
- ? '<span style="color:var(--muted);font-weight:400;font-size:10px;margin-left:auto;display:flex;align-items:center;gap:6px">' +
406
+ ? '<span style="color:var(--muted);font-weight:400;font-size:var(--text-sm);margin-left:auto;display:flex;align-items:center;gap:6px">' +
407
407
  (g.sourcePlan
408
- ? '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan) + '\')" style="color:var(--blue);cursor:pointer;font-size:10px;text-decoration:underline" title="View source plan">&#x1F4C4; ' + escHtml(g.sourcePlan) + '</span>'
408
+ ? '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan) + '\')" style="color:var(--blue);cursor:pointer;font-size:var(--text-sm);text-decoration:underline" title="View source plan">&#x1F4C4; ' + escHtml(g.sourcePlan) + '</span>'
409
409
  : '<span>' + escHtml(g.file) + '</span>') +
410
410
  '</span>'
411
- : '<span style="color:var(--muted);font-weight:400;font-size:10px;margin-left:auto;display:flex;align-items:center;gap:6px">' +
411
+ : '<span style="color:var(--muted);font-weight:400;font-size:var(--text-sm);margin-left:auto;display:flex;align-items:center;gap:6px">' +
412
412
  sourcePlanLink +
413
413
  pauseResumeBtn +
414
414
  archiveBtn +
@@ -470,7 +470,7 @@ function renderPrdProgress(prog) {
470
470
  const col = columns[d] || [];
471
471
  const colLabel = d === 0 ? 'Root' : 'Wave ' + d;
472
472
  html += '<div style="flex:1;min-width:0">' +
473
- '<div style="font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px;text-align:center">' + colLabel + '</div>';
473
+ '<div style="font-size:var(--text-xs);color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px;text-align:center">' + colLabel + '</div>';
474
474
  for (const i of col) {
475
475
  const borderColor = statusColor(i.status, i.id);
476
476
  const src = escHtml(i.source || '');
@@ -485,49 +485,49 @@ function renderPrdProgress(prog) {
485
485
  const wiIdBadge = _renderPrdWorkItemIdBadge(wiForCard ? wiForCard.id : workItemId, i.id, '8px', '1px 4px');
486
486
  const isDoneCard = i.status === 'done' || (wiForCard && wiForCard.status === 'done');
487
487
  const reopenBtnGraph = isDoneCard
488
- ? '<span onclick="event.stopPropagation();prdItemReopen(\'' + src + '\',\'' + iid + '\')" style="font-size:8px;color:var(--blue);cursor:pointer;padding:1px 4px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="Re-open: set to updated so engine re-dispatches on existing branch">re-open</span>'
488
+ ? '<span onclick="event.stopPropagation();prdItemReopen(\'' + src + '\',\'' + iid + '\')" style="font-size:var(--text-xs);color:var(--blue);cursor:pointer;padding:1px 4px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="Re-open: set to updated so engine re-dispatches on existing branch">re-open</span>'
489
489
  : '';
490
490
  const cardTitle = i.description ? escHtml(i.name + ' — ' + i.description) : escHtml(i.name || '');
491
491
  html += '<div onclick="prdItemEdit(\'' + src + '\',\'' + iid + '\')" ' +
492
492
  'title="' + cardTitle + '" ' +
493
493
  'style="background:var(--surface2);border:1px solid var(--border);border-left:3px solid ' + borderColor + ';' + wipAnim +
494
- 'border-radius:4px;padding:6px 8px;margin-bottom:6px;cursor:pointer;font-size:11px">' +
494
+ 'border-radius:4px;padding:6px 8px;margin-bottom:6px;cursor:pointer;font-size:var(--text-base)">' +
495
495
  '<div style="display:flex;align-items:center;gap:4px;margin-bottom:2px">' +
496
496
  statusBadge(i.status, i.id) +
497
497
  '<span style="font-weight:600;color:var(--text)">' + escHtml(i.id) + '</span>' +
498
498
  wiIdBadge +
499
- '<span onclick="event.stopPropagation();prdItemRemove(\'' + src + '\',\'' + iid + '\')" style="margin-left:auto;color:var(--red);cursor:pointer;font-size:10px;padding:0 4px;line-height:1" title="Remove item">x</span>' +
499
+ '<span onclick="event.stopPropagation();prdItemRemove(\'' + src + '\',\'' + iid + '\')" style="margin-left:auto;color:var(--red);cursor:pointer;font-size:var(--text-sm);padding:0 4px;line-height:1" title="Remove item">x</span>' +
500
500
  '</div>' +
501
- '<div style="color:var(--text);font-size:11px;line-height:1.3;margin-bottom:3px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical">' + escHtml(i.name) + '</div>' +
501
+ '<div style="color:var(--text);font-size:var(--text-base);line-height:1.3;margin-bottom:3px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical">' + escHtml(i.name) + '</div>' +
502
502
  '<div style="display:flex;gap:4px;flex-wrap:wrap;align-items:center">' +
503
- '<span class="prd-item-priority ' + (i.priority || '') + '" style="font-size:8px;padding:1px 4px">' + escHtml(i.priority || '') + '</span>' +
504
- (agentDisplay ? '<span style="font-size:8px;color:var(--muted)">' + agentDisplay + '</span>' : '') +
503
+ '<span class="prd-item-priority ' + (i.priority || '') + '" style="font-size:var(--text-xs);padding:1px 4px">' + escHtml(i.priority || '') + '</span>' +
504
+ (agentDisplay ? '<span style="font-size:var(--text-xs);color:var(--muted)">' + agentDisplay + '</span>' : '') +
505
505
  (function() {
506
506
  const w = wi[i.id];
507
507
  const rqId = w ? w.id : i.id;
508
508
  const rq = getPrdRequeueState(rqId);
509
509
  if (rq && rq.status === 'pending') {
510
- return '<span style="font-size:8px;color:var(--yellow);cursor:wait;padding:1px 4px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.35);border-radius:3px">requeuing…</span>';
510
+ return '<span style="font-size:var(--text-xs);color:var(--yellow);cursor:wait;padding:1px 4px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.35);border-radius:3px">requeuing…</span>';
511
511
  }
512
512
  if (rq && rq.status === 'queued') {
513
- return '<span style="font-size:8px;color:var(--green);cursor:default;padding:1px 4px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.35);border-radius:3px">requeued</span>';
513
+ return '<span style="font-size:var(--text-xs);color:var(--green);cursor:default;padding:1px 4px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.35);border-radius:3px">requeued</span>';
514
514
  }
515
515
  if (rq && rq.status === 'error') {
516
- return '<span style="font-size:8px;color:var(--red);cursor:default;padding:1px 4px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.35);border-radius:3px" title="' + escHtml(rq.message || 'Retry failed') + '">failed</span>';
516
+ return '<span style="font-size:var(--text-xs);color:var(--red);cursor:default;padding:1px 4px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.35);border-radius:3px" title="' + escHtml(rq.message || 'Retry failed') + '">failed</span>';
517
517
  }
518
518
  // Show retry for failed items, or PRD items with no work item (orphaned/deleted)
519
519
  const canRetry = (w && i.status === 'failed') ||
520
520
  (!w && i.status && i.status !== 'missing' && i.status !== 'done' && i.status !== 'planned');
521
521
  if (!canRetry) return '';
522
- return '<span onclick="event.stopPropagation();prdItemRequeue(\'' + escHtml(rqId) + '\',\'' + escHtml(w ? (w._source || '') : '') + '\',\'' + escHtml(i.source || '') + '\')" style="font-size:8px;color:var(--green);cursor:pointer;padding:1px 4px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">retry</span>';
522
+ return '<span onclick="event.stopPropagation();prdItemRequeue(\'' + escHtml(rqId) + '\',\'' + escHtml(w ? (w._source || '') : '') + '\',\'' + escHtml(i.source || '') + '\')" style="font-size:var(--text-xs);color:var(--green);cursor:pointer;padding:1px 4px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">retry</span>';
523
523
  })() +
524
524
  reopenBtnGraph +
525
- (deps ? '<span style="font-size:8px;color:var(--muted)" title="Depends on: ' + escHtml(deps) + '">deps: ' + escHtml(deps) + '</span>' : '') +
525
+ (deps ? '<span style="font-size:var(--text-xs);color:var(--muted)" title="Depends on: ' + escHtml(deps) + '">deps: ' + escHtml(deps) + '</span>' : '') +
526
526
  (function() {
527
527
  var w = wi[i.id];
528
528
  var b = w ? (w.branch || w.featureBranch || (w._artifacts && w._artifacts.branch) || '') : '';
529
529
  if (!b) return '';
530
- return '<span style="font-size:8px;color:var(--muted);font-family:monospace;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;vertical-align:middle" title="Branch: ' + escHtml(b) + '">&#x1F33F; ' + escHtml(b) + '</span>';
530
+ return '<span style="font-size:var(--text-xs);color:var(--muted);font-family:monospace;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;vertical-align:middle" title="Branch: ' + escHtml(b) + '">&#x1F33F; ' + escHtml(b) + '</span>';
531
531
  })() +
532
532
  '</div>' +
533
533
  ((i.prs || []).length ? '<div style="margin-top:3px">' + (i.prs || []).map(function(pr) { return _renderPrLink(pr, { size: '9px' }); }).join(' ') + '</div>' : '') +
@@ -537,10 +537,10 @@ function renderPrdProgress(prog) {
537
537
  return '<div style="margin-top:4px;border-top:1px solid var(--border);padding-top:4px">' +
538
538
  children.map(function(c) {
539
539
  var cAgent = c.dispatched_to ? (agentData.find(function(a) { return a.id === c.dispatched_to; }) || {}) : null;
540
- return '<div style="font-size:9px;display:flex;align-items:center;gap:4px;padding:1px 0">' +
540
+ return '<div style="font-size:var(--text-xs);display:flex;align-items:center;gap:4px;padding:1px 0">' +
541
541
  statusBadge(c.status) +
542
542
  '<span style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + escHtml((c.title || '').replace('Implement: ', '').slice(0, 40)) + '</span>' +
543
- (cAgent ? '<span style="font-size:8px;color:var(--muted)">' + (cAgent.emoji || '') + '</span>' : '') +
543
+ (cAgent ? '<span style="font-size:var(--text-xs);color:var(--muted)">' + (cAgent.emoji || '') + '</span>' : '') +
544
544
  '</div>';
545
545
  }).join('') +
546
546
  '</div>';
@@ -548,7 +548,7 @@ function renderPrdProgress(prog) {
548
548
  '</div>';
549
549
  }
550
550
  html += '</div>';
551
- if (d < maxDepth) html += '<div style="display:flex;align-items:center;color:var(--border);font-size:14px;padding:0 2px">&#x2192;</div>';
551
+ if (d < maxDepth) html += '<div style="display:flex;align-items:center;color:var(--border);font-size:var(--text-xl);padding:0 2px">&#x2192;</div>';
552
552
  }
553
553
  html += '</div>';
554
554
  return html;
@@ -560,8 +560,8 @@ function renderPrdProgress(prog) {
560
560
  const renderViewToggle = () => {
561
561
  const isGraph = window._prdViewMode === 'graph';
562
562
  return '<div style="display:flex;gap:4px;margin-bottom:8px;padding:0 8px">' +
563
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;' + (isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._prdViewMode=\'graph\';rerenderPrdFromCache()">Graph</button>' +
564
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;' + (!isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._prdViewMode=\'list\';rerenderPrdFromCache()">List</button>' +
563
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;' + (isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._prdViewMode=\'graph\';rerenderPrdFromCache()">Graph</button>' +
564
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;' + (!isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._prdViewMode=\'list\';rerenderPrdFromCache()">List</button>' +
565
565
  '</div>';
566
566
  };
567
567
 
@@ -597,22 +597,22 @@ function renderPrdProgress(prog) {
597
597
  if (prs.length === 0 && !guide) return '';
598
598
  let html = '<div style="margin:6px 0 10px;padding:6px 10px;background:rgba(56,139,253,0.08);border:1px solid rgba(56,139,253,0.25);border-radius:4px">';
599
599
  if (prs.length > 0) {
600
- html += '<div style="font-size:10px;font-weight:600;color:var(--blue);margin-bottom:4px">E2E Aggregate PRs</div>';
600
+ html += '<div style="font-size:var(--text-sm);font-weight:600;color:var(--blue);margin-bottom:4px">E2E Aggregate PRs</div>';
601
601
  html += prs.map(pr => {
602
602
  const statusColor = pr.status === 'active' ? 'var(--green)' : pr.status === 'merged' ? 'var(--purple)' : 'var(--muted)';
603
- return '<div style="display:flex;align-items:center;gap:6px;padding:2px 0;font-size:11px">' +
604
- '<span style="color:' + statusColor + ';font-size:8px;font-weight:600;padding:1px 4px;border:1px solid;border-radius:3px">' + escHtml(pr.status || 'active') + '</span>' +
603
+ return '<div style="display:flex;align-items:center;gap:6px;padding:2px 0;font-size:var(--text-base)">' +
604
+ '<span style="color:' + statusColor + ';font-size:var(--text-xs);font-weight:600;padding:1px 4px;border:1px solid;border-radius:3px">' + escHtml(pr.status || 'active') + '</span>' +
605
605
  '<a href="' + escHtml(pr.url || '#') + '" target="_blank" rel="noopener" style="color:var(--blue);text-decoration:underline;font-weight:500">' + escHtml(pr.id) + '</a>' +
606
606
  '<span style="color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + escHtml(pr.title || '') + '</span>' +
607
- '<span style="color:var(--muted);font-size:9px">' + escHtml(pr._project || '') + '</span>' +
607
+ '<span style="color:var(--muted);font-size:var(--text-xs)">' + escHtml(pr._project || '') + '</span>' +
608
608
  '</div>';
609
609
  }).join('');
610
610
  }
611
611
  if (guide) {
612
- html += '<div style="display:flex;align-items:center;gap:6px;padding:' + (prs.length ? '4px' : '0') + ' 0 0;font-size:11px">' +
613
- '<span style="font-size:8px;color:var(--green);font-weight:600;padding:1px 4px;border:1px solid var(--green);border-radius:3px">GUIDE</span>' +
612
+ html += '<div style="display:flex;align-items:center;gap:6px;padding:' + (prs.length ? '4px' : '0') + ' 0 0;font-size:var(--text-base)">' +
613
+ '<span style="font-size:var(--text-xs);color:var(--green);font-weight:600;padding:1px 4px;border:1px solid var(--green);border-radius:3px">GUIDE</span>' +
614
614
  '<span onclick="openVerifyGuide(\'' + escHtml(guide.file) + '\')" style="color:var(--blue);cursor:pointer;text-decoration:underline;font-weight:500">Manual Testing Guide</span>' +
615
- '<span style="color:var(--muted);font-size:9px">Build instructions, test steps, known issues</span>' +
615
+ '<span style="color:var(--muted);font-size:var(--text-xs)">Build instructions, test steps, known issues</span>' +
616
616
  '</div>';
617
617
  }
618
618
  html += '</div>';
@@ -647,7 +647,7 @@ function renderPrdProgress(prog) {
647
647
  window._archivedPrdRenderGroupStats = renderGroupStats;
648
648
  window._archivedPrdRenderE2eSection = renderE2eSection;
649
649
  html += '<div style="margin-top:8px;text-align:right;position:relative" data-file="prd-archives">' +
650
- '<button class="pr-pager-btn" style="font-size:10px;padding:3px 10px;color:var(--muted)" onclick="openArchivedPrdModal()">' +
650
+ '<button class="pr-pager-btn" style="font-size:var(--text-sm);padding:3px 10px;color:var(--muted)" onclick="openArchivedPrdModal()">' +
651
651
  'View Archives (' + archivedKeys.length + ')' +
652
652
  '</button>' +
653
653
  '</div>';
@@ -678,13 +678,13 @@ function openArchivedPrdModal() {
678
678
  return;
679
679
  } else {
680
680
  // Picker: list archived plans, click to expand
681
- html = '<div style="margin-bottom:12px;font-size:12px;color:var(--muted)">Select an archived PRD to view:</div>';
681
+ html = '<div style="margin-bottom:12px;font-size:var(--text-md);color:var(--muted)">Select an archived PRD to view:</div>';
682
682
  html += groups.map((g, i) => {
683
683
  const done = g.items.filter(it => it.status === 'done').length;
684
684
  const failed = g.items.filter(it => it.status === 'failed').length;
685
685
  const completed = g.completedAt ? formatLocalDate(g.completedAt) : '';
686
686
  return '<div class="plan-card" style="cursor:pointer;margin-bottom:8px" onclick="if(shouldIgnoreSelectionClick(event))return;showArchivedPrdDetail(\'' + escHtml(g.file) + '\')">' +
687
- '<div class="plan-card-title" style="font-size:13px">' + escHtml(g.summary || g.file) + '</div>' +
687
+ '<div class="plan-card-title" style="font-size:var(--text-lg)">' + escHtml(g.summary || g.file) + '</div>' +
688
688
  '<div class="plan-card-meta">' +
689
689
  (g._projects.length > 0 ? g._projects.map(function(p) { return '<span>' + escHtml(p) + '</span>'; }).join(' ') : '') +
690
690
  '<span>' + g.items.length + ' items</span>' +
@@ -713,11 +713,11 @@ function showArchivedPrdDetail(idxOrFile) {
713
713
  // View mode toggle for archived
714
714
  const isGraph = window._archivedPrdViewMode !== 'list';
715
715
  const toggleHtml = '<div style="display:flex;gap:4px;margin-bottom:8px">' +
716
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;' + (isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._archivedPrdViewMode=\'graph\';showArchivedPrdDetail(\'' + escHtml(g.file) + '\')">Graph</button>' +
717
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;' + (!isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._archivedPrdViewMode=\'list\';showArchivedPrdDetail(\'' + escHtml(g.file) + '\')">List</button>' +
718
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);margin-left:auto" onclick="triggerVerify(\'' + escHtml(g.file) + '\')">Trigger Verify</button>' +
719
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" onclick="planUnarchive(\'' + escHtml(g.file) + '\',this)">Unarchive</button>' +
720
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" onclick="openArchivedPrdModal()">Back</button>' +
716
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;' + (isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._archivedPrdViewMode=\'graph\';showArchivedPrdDetail(\'' + escHtml(g.file) + '\')">Graph</button>' +
717
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;' + (!isGraph ? 'background:var(--blue);color:#fff;border-color:var(--blue)' : '') + '" onclick="window._archivedPrdViewMode=\'list\';showArchivedPrdDetail(\'' + escHtml(g.file) + '\')">List</button>' +
718
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green);margin-left:auto" onclick="triggerVerify(\'' + escHtml(g.file) + '\')">Trigger Verify</button>' +
719
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" onclick="planUnarchive(\'' + escHtml(g.file) + '\',this)">Unarchive</button>' +
720
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" onclick="openArchivedPrdModal()">Back</button>' +
721
721
  '</div>';
722
722
 
723
723
  // Render directly from the archived group data (not from stale renderGroup closure)
@@ -777,7 +777,7 @@ async function prdItemEdit(source, itemId) {
777
777
  }
778
778
  typeValue = (typeValue || '').toString().toLowerCase();
779
779
  const typePillHtml = typeValue
780
- ? '<span style="font-size:10px;font-weight:600;padding:2px 6px;border-radius:3px;background:var(--surface-alt,var(--surface));border:1px solid var(--border);color:var(--muted);text-transform:lowercase">' + escHtml(typeValue) + '</span>'
780
+ ? '<span style="font-size:var(--text-sm);font-weight:600;padding:2px 6px;border-radius:3px;background:var(--surface-alt,var(--surface));border:1px solid var(--border);color:var(--muted);text-transform:lowercase">' + escHtml(typeValue) + '</span>'
781
781
  : '';
782
782
 
783
783
  // Build completion summary section
@@ -799,14 +799,14 @@ async function prdItemEdit(source, itemId) {
799
799
 
800
800
  completionHtml = '<div style="background:var(--surface);border:1px solid var(--border);border-left:3px solid ' + statusColor + ';border-radius:4px;padding:10px 12px;margin-bottom:12px">' +
801
801
  '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">' +
802
- (wi ? '<a href="#" onclick="event.preventDefault();event.stopPropagation();openWorkItemDetail(\'' + escHtml(wi.id) + '\')" title="Open ' + escHtml(wi.id) + ' detail" style="font-size:11px;font-weight:700;color:' + statusColor + ';text-decoration:none;cursor:pointer" onmouseover="this.style.textDecoration=\'underline\'" onmouseout="this.style.textDecoration=\'none\'">' + statusLabel + ' &rarr;</a>' : '<span style="font-size:11px;font-weight:700;color:' + statusColor + '">' + statusLabel + '</span>') +
802
+ (wi ? '<a href="#" onclick="event.preventDefault();event.stopPropagation();openWorkItemDetail(\'' + escHtml(wi.id) + '\')" title="Open ' + escHtml(wi.id) + ' detail" style="font-size:var(--text-base);font-weight:700;color:' + statusColor + ';text-decoration:none;cursor:pointer" onmouseover="this.style.textDecoration=\'underline\'" onmouseout="this.style.textDecoration=\'none\'">' + statusLabel + ' &rarr;</a>' : '<span style="font-size:var(--text-base);font-weight:700;color:' + statusColor + '">' + statusLabel + '</span>') +
803
803
  typePillHtml +
804
- (agent ? '<span style="font-size:11px;color:var(--muted)">by ' + escHtml(agent) + '</span>' : '') +
805
- (completedAt ? '<span style="font-size:10px;color:var(--muted)">' + escHtml(completedAt.slice(0, 16).replace('T', ' ')) + '</span>' : '') +
804
+ (agent ? '<span style="font-size:var(--text-base);color:var(--muted)">by ' + escHtml(agent) + '</span>' : '') +
805
+ (completedAt ? '<span style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(completedAt.slice(0, 16).replace('T', ' ')) + '</span>' : '') +
806
806
  '</div>' +
807
- (prLinks ? '<div style="font-size:11px;margin-bottom:6px">PR: ' + prLinks + '</div>' : '') +
808
- (summary ? '<div style="font-size:12px;color:var(--text);line-height:1.5;white-space:pre-wrap;max-height:300px;overflow-y:auto">' + escHtml(summary) + '</div>' : '') +
809
- (isFailed && completedEntry?.reason ? '<div style="font-size:11px;color:var(--red);margin-top:4px">' + escHtml(completedEntry.reason) + '</div>' : '') +
807
+ (prLinks ? '<div style="font-size:var(--text-base);margin-bottom:6px">PR: ' + prLinks + '</div>' : '') +
808
+ (summary ? '<div style="font-size:var(--text-md);color:var(--text);line-height:1.5;white-space:pre-wrap;max-height:300px;overflow-y:auto">' + escHtml(summary) + '</div>' : '') +
809
+ (isFailed && completedEntry?.reason ? '<div style="font-size:var(--text-base);color:var(--red);margin-top:4px">' + escHtml(completedEntry.reason) + '</div>' : '') +
810
810
  '</div>';
811
811
  }
812
812
 
@@ -817,26 +817,26 @@ async function prdItemEdit(source, itemId) {
817
817
  const html = '<div style="padding:8px 0">' +
818
818
  completionHtml +
819
819
  standaloneTypePillHtml +
820
- '<label style="font-size:11px;color:var(--muted);display:block;margin-bottom:4px">Name</label>' +
821
- '<input id="prd-edit-name" value="' + escHtml(item.name || '') + '" style="width:100%;padding:6px 10px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:13px;margin-bottom:10px">' +
820
+ '<label style="font-size:var(--text-base);color:var(--muted);display:block;margin-bottom:4px">Name</label>' +
821
+ '<input id="prd-edit-name" value="' + escHtml(item.name || '') + '" style="width:100%;padding:6px 10px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:var(--text-lg);margin-bottom:10px">' +
822
822
  '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">' +
823
- '<label style="font-size:11px;color:var(--muted)">Description</label>' +
823
+ '<label style="font-size:var(--text-base);color:var(--muted)">Description</label>' +
824
824
  '<div style="display:flex;gap:6px">' +
825
- '<button id="prd-desc-edit-btn" type="button" class="pr-pager-btn" aria-label="Edit description" style="font-size:10px;padding:2px 10px" onclick="_togglePrdDescEdit()">Edit</button>' +
826
- '<button id="prd-desc-save-btn" type="button" class="pr-pager-btn" aria-label="Save description" style="font-size:10px;padding:2px 10px;color:var(--green);border-color:var(--green);display:none" onclick="_savePrdDesc(\'' + escHtml(source) + '\',\'' + escHtml(itemId) + '\')">Save</button>' +
827
- '<button id="prd-desc-cancel-btn" type="button" class="pr-pager-btn" aria-label="Cancel description edit" style="font-size:10px;padding:2px 10px;display:none" onclick="_cancelPrdDescEdit()">Cancel</button>' +
825
+ '<button id="prd-desc-edit-btn" type="button" class="pr-pager-btn" aria-label="Edit description" style="font-size:var(--text-sm);padding:2px 10px" onclick="_togglePrdDescEdit()">Edit</button>' +
826
+ '<button id="prd-desc-save-btn" type="button" class="pr-pager-btn" aria-label="Save description" style="font-size:var(--text-sm);padding:2px 10px;color:var(--green);border-color:var(--green);display:none" onclick="_savePrdDesc(\'' + escHtml(source) + '\',\'' + escHtml(itemId) + '\')">Save</button>' +
827
+ '<button id="prd-desc-cancel-btn" type="button" class="pr-pager-btn" aria-label="Cancel description edit" style="font-size:var(--text-sm);padding:2px 10px;display:none" onclick="_cancelPrdDescEdit()">Cancel</button>' +
828
828
  '</div>' +
829
829
  '</div>' +
830
- '<div id="prd-desc-view" style="margin-bottom:10px;padding:8px 10px;background:var(--surface);border:1px solid var(--border);border-radius:4px;min-height:32px">' + (item.description ? renderMd(item.description) : '<span style="color:var(--muted);font-size:11px">No description</span>') + '</div>' +
831
- '<textarea id="prd-edit-desc" rows="4" style="display:none;width:100%;padding:6px 10px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:12px;resize:vertical;margin-bottom:10px">' + escHtml(item.description || '') + '</textarea>' +
830
+ '<div id="prd-desc-view" style="margin-bottom:10px;padding:8px 10px;background:var(--surface);border:1px solid var(--border);border-radius:4px;min-height:32px">' + (item.description ? renderMd(item.description) : '<span style="color:var(--muted);font-size:var(--text-base)">No description</span>') + '</div>' +
831
+ '<textarea id="prd-edit-desc" rows="4" style="display:none;width:100%;padding:6px 10px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:var(--text-md);resize:vertical;margin-bottom:10px">' + escHtml(item.description || '') + '</textarea>' +
832
832
  '<div style="display:flex;gap:12px;margin-bottom:12px">' +
833
- '<div><label style="font-size:11px;color:var(--muted);display:block;margin-bottom:4px">Priority</label>' +
833
+ '<div><label style="font-size:var(--text-base);color:var(--muted);display:block;margin-bottom:4px">Priority</label>' +
834
834
  '<select id="prd-edit-priority" style="padding:4px 8px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text)">' +
835
835
  '<option value="high"' + (item.priority === 'high' ? ' selected' : '') + '>High</option>' +
836
836
  '<option value="medium"' + (item.priority === 'medium' ? ' selected' : '') + '>Medium</option>' +
837
837
  '<option value="low"' + (item.priority === 'low' ? ' selected' : '') + '>Low</option>' +
838
838
  '</select></div>' +
839
- '<div><label style="font-size:11px;color:var(--muted);display:block;margin-bottom:4px">Complexity</label>' +
839
+ '<div><label style="font-size:var(--text-base);color:var(--muted);display:block;margin-bottom:4px">Complexity</label>' +
840
840
  '<select id="prd-edit-complexity" style="padding:4px 8px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text)">' +
841
841
  '<option value="small"' + ((item.estimated_complexity || item.complexity) === 'small' ? ' selected' : '') + '>Small</option>' +
842
842
  '<option value="medium"' + ((item.estimated_complexity || item.complexity) === 'medium' ? ' selected' : '') + '>Medium</option>' +
@@ -983,7 +983,7 @@ function openArchive(i) {
983
983
 
984
984
  // Summary
985
985
  if (a.summary) {
986
- html += '<div class="archive-detail-section"><h4>Summary</h4><p style="font-size:12px;color:var(--muted);line-height:1.6">' + escHtml(a.summary) + '</p></div>';
986
+ html += '<div class="archive-detail-section"><h4>Summary</h4><p style="font-size:var(--text-md);color:var(--muted);line-height:1.6">' + escHtml(a.summary) + '</p></div>';
987
987
  }
988
988
 
989
989
  // Existing features
@@ -1011,7 +1011,7 @@ function openArchive(i) {
1011
1011
  html += '<div class="archive-feature">' +
1012
1012
  '<span class="feat-id">' + escHtml(f.id) + '</span> ' +
1013
1013
  '<span class="prd-item-priority ' + pClass + '">' + escHtml(f.priority || '') + '</span>' +
1014
- (f.status ? ' <span class="pr-badge ' + (f.status === 'done' ? 'approved' : 'draft') + '" style="font-size:9px">' + escHtml(f.status) + '</span>' : '') +
1014
+ (f.status ? ' <span class="pr-badge ' + (f.status === 'done' ? 'approved' : 'draft') + '" style="font-size:var(--text-xs)">' + escHtml(f.status) + '</span>' : '') +
1015
1015
  '<div class="feat-name">' + escHtml(f.name) + '</div>' +
1016
1016
  '<div class="feat-desc">' + escHtml(f.description || '') + '</div>' +
1017
1017
  (f.rationale ? '<div class="feat-desc" style="margin-top:4px;color:var(--yellow)">Rationale: ' + escHtml(f.rationale) + '</div>' : '') +