@yemi33/minions 0.1.84 → 0.1.86

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.86 (2026-03-31)
4
+
5
+ ### Dashboard
6
+ - dashboard/js/render-prd.js
7
+
8
+ ## 0.1.85 (2026-03-31)
9
+
10
+ ### Dashboard
11
+ - dashboard.js
12
+
3
13
  ## 0.1.84 (2026-03-31)
4
14
 
5
15
  ### Dashboard
@@ -13,37 +13,54 @@ function renderPrd(prd, prog) {
13
13
  return;
14
14
  }
15
15
 
16
- // Derive status from work items
17
- const allWi = window._lastWorkItems || [];
18
- const prdItems = (prog?.items || []).filter(i => !i._archived);
19
- const implementItems = allWi.filter(w => prdItems.some(pi => pi.id === w.id));
20
- const allDone = implementItems.length > 0 && implementItems.every(w => w.status === 'done' || w.status === 'in-pr' || w.status === 'implemented' || w.status === 'complete');
21
- const hasActive = implementItems.some(w => w.status === 'pending' || w.status === 'dispatched');
22
-
23
- // Find the active PRD file for action buttons
24
- const prdFile = prd.existing?.[0]?.file || '';
25
- const prdStatus = prd.existing?.[0]?.status || '';
26
- const effectiveStatus = allDone && !hasActive ? 'completed' : hasActive ? 'in-progress' : prdStatus || 'active';
27
-
28
16
  const statusColors = { 'completed': 'var(--green)', 'in-progress': 'var(--blue)', 'awaiting-approval': 'var(--yellow)', 'paused': 'var(--muted)', 'approved': 'var(--green)' };
29
17
  const statusLabels = { 'completed': 'Completed', 'in-progress': 'In Progress', 'awaiting-approval': 'Awaiting Approval', 'paused': 'Paused', 'approved': 'Approved' };
30
18
 
31
- let actions = '';
32
- if (prdFile) {
33
- if (effectiveStatus === 'awaiting-approval') {
34
- 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>';
35
- } else if (effectiveStatus === 'completed') {
36
- actions = ' <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>' +
37
- ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--muted);border-color:var(--border);margin-left:4px" onclick="planDelete(\'' + escHtml(prdFile) + '\')">Archive</button>';
38
- } else if (effectiveStatus === 'in-progress') {
39
- 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>';
40
- } else if (effectiveStatus === 'paused') {
41
- 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>';
19
+ // Show per-PRD status summary in header when multiple PRDs exist
20
+ const existing = prd.existing || [];
21
+ const allWi = window._lastWorkItems || [];
22
+ const prdItems = (prog?.items || []).filter(i => !i._archived);
23
+
24
+ if (existing.length <= 1) {
25
+ // Single PRD show status + actions in header
26
+ const implementItems = allWi.filter(w => prdItems.some(pi => pi.id === w.id));
27
+ const allDone = implementItems.length > 0 && implementItems.every(w => w.status === 'done' || w.status === 'in-pr' || w.status === 'implemented' || w.status === 'complete');
28
+ const hasActive = implementItems.some(w => w.status === 'pending' || w.status === 'dispatched');
29
+ const prdFile = existing[0]?.file || '';
30
+ const prdStatus = existing[0]?.status || '';
31
+ const effectiveStatus = allDone && !hasActive ? 'completed' : hasActive ? 'in-progress' : prdStatus || 'active';
32
+
33
+ let actions = '';
34
+ if (prdFile) {
35
+ if (effectiveStatus === 'awaiting-approval') {
36
+ 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>';
37
+ } else if (effectiveStatus === 'completed') {
38
+ actions = ' <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>' +
39
+ ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--muted);border-color:var(--border);margin-left:4px" onclick="planDelete(\'' + escHtml(prdFile) + '\')">Archive</button>';
40
+ } else if (effectiveStatus === 'in-progress') {
41
+ 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>';
42
+ } else if (effectiveStatus === 'paused') {
43
+ 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>';
44
+ }
45
+ }
46
+ badge.innerHTML = '<span style="font-weight:600;font-size:11px;color:' + (statusColors[effectiveStatus] || 'var(--muted)') + '">' + (statusLabels[effectiveStatus] || effectiveStatus) + '</span>' +
47
+ ' <span style="color:var(--muted);font-size:10px">' + (prd.age || '') + '</span>' + actions;
48
+ } else {
49
+ // Multiple PRDs — show count summary, per-PRD details are in renderPrdProgress groups
50
+ const counts = { completed: 0, 'in-progress': 0, 'awaiting-approval': 0, paused: 0 };
51
+ for (const p of existing) {
52
+ const items = prdItems.filter(i => i.source === p.file);
53
+ const wiForPrd = allWi.filter(w => items.some(pi => pi.id === w.id));
54
+ const allDone = wiForPrd.length > 0 && wiForPrd.every(w => w.status === 'done' || w.status === 'in-pr' || w.status === 'implemented' || w.status === 'complete');
55
+ const hasActive = wiForPrd.some(w => w.status === 'pending' || w.status === 'dispatched');
56
+ const s = allDone && !hasActive ? 'completed' : hasActive ? 'in-progress' : p.status || 'active';
57
+ counts[s] = (counts[s] || 0) + 1;
42
58
  }
59
+ const parts = Object.entries(counts).filter(([, n]) => n > 0).map(([s, n]) =>
60
+ '<span style="font-size:10px;color:' + (statusColors[s] || 'var(--muted)') + '">' + n + ' ' + (statusLabels[s] || s).toLowerCase() + '</span>'
61
+ );
62
+ badge.innerHTML = '<span style="font-weight:600;font-size:11px;color:var(--text)">' + existing.length + ' PRDs</span> ' + parts.join(' · ');
43
63
  }
44
-
45
- badge.innerHTML = '<span style="font-weight:600;font-size:11px;color:' + (statusColors[effectiveStatus] || 'var(--muted)') + '">' + (statusLabels[effectiveStatus] || effectiveStatus) + '</span>' +
46
- ' <span style="color:var(--muted);font-size:10px">' + (prd.age || '') + '</span>' + actions;
47
64
  section.innerHTML = '';
48
65
  }
49
66
 
@@ -52,10 +69,10 @@ function renderPrdProgress(prog) {
52
69
  const countEl = document.getElementById('prd-progress-count');
53
70
  if (!prog) { el.innerHTML = ''; countEl.textContent = '—'; return; }
54
71
 
55
- // Compute progress from active (non-archived) items only
72
+ // Compute overall progress from active (non-archived) items
56
73
  const activeItems = (prog.items || []).filter(i => !i._archived);
57
74
  if (activeItems.length > 0) {
58
- const activeDone = activeItems.filter(i => i.status === 'done' || i.status === 'implemented' || i.status === 'in-pr').length; // in-pr counted as done for backward compat
75
+ const activeDone = activeItems.filter(i => i.status === 'done' || i.status === 'implemented' || i.status === 'in-pr').length;
59
76
  countEl.textContent = Math.round((activeDone / activeItems.length) * 100) + '%';
60
77
  } else {
61
78
  countEl.textContent = '—';
@@ -159,7 +176,7 @@ function renderPrdProgress(prog) {
159
176
  (prLinks ? '<span>' + prLinks + '</span>' : '') +
160
177
  '<span class="prd-item-priority ' + (i.priority || '') + '">' + escHtml(i.priority || '') + '</span>' +
161
178
  '<span onclick="event.stopPropagation();prdItemRemove(\'' + src + '\',\'' + iid + '\')" style="color:var(--red);cursor:pointer;font-size:10px;padding:0 4px" title="Remove item">x</span>' +
162
- (i.description ? '<div style="width:100%;font-size:11px;color:var(--muted);padding:2px 0 2px 42px;line-height:1.4">' + escHtml(i.description) + '</div>' : '') +
179
+ (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>' : '') +
163
180
  '</div>';
164
181
  };
165
182
 
@@ -220,6 +237,9 @@ function renderPrdProgress(prog) {
220
237
  : isCompleted
221
238
  ? '<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>'
222
239
  : '<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>';
240
+ const archiveBtn = isCompleted
241
+ ? '<span onclick="event.stopPropagation();planDelete(\'' + escHtml(g.file) + '\')" style="color:var(--muted);cursor:pointer;font-size:9px;padding:1px 6px;background:var(--surface);border:1px solid var(--border);border-radius:3px">Archive</span>'
242
+ : '';
223
243
  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>';
224
244
  const sourcePlanLink = g.sourcePlan
225
245
  ? '<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>'
@@ -244,6 +264,7 @@ function renderPrdProgress(prog) {
244
264
  : '<span style="color:var(--muted);font-weight:400;font-size:10px;margin-left:auto;display:flex;align-items:center;gap:6px">' +
245
265
  sourcePlanLink +
246
266
  pauseResumeBtn +
267
+ archiveBtn +
247
268
  deleteBtn +
248
269
  '</span>') +
249
270
  staleRecovery +
package/dashboard.js CHANGED
@@ -259,7 +259,7 @@ setInterval(() => {
259
259
  // ── Command Center: session state + helpers ─────────────────────────────────
260
260
 
261
261
  const CC_SESSION_EXPIRY_MS = 2 * 60 * 60 * 1000; // 2 hours
262
- const CC_SESSION_MAX_TURNS = 50;
262
+ const CC_SESSION_MAX_TURNS = Infinity;
263
263
  let ccSession = { sessionId: null, createdAt: null, lastActiveAt: null, turnCount: 0 };
264
264
  let ccInFlight = false;
265
265
  let ccInFlightSince = 0; // timestamp — auto-release stuck guard
@@ -538,7 +538,7 @@ function updateSession(store, key, sessionId, existing) {
538
538
  * @param {number} opts.maxTurns - Max tool-use turns
539
539
  * @param {string} opts.allowedTools - Comma-separated tool list
540
540
  */
541
- async function ccCall(message, { store = 'cc', sessionKey, extraContext, label = 'command-center', timeout = 900000, maxTurns = 25, allowedTools = 'Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch', skipStatePreamble = false, model = 'sonnet' } = {}) {
541
+ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label = 'command-center', timeout = 900000, maxTurns = 50, allowedTools = 'Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch', skipStatePreamble = false, model = 'sonnet' } = {}) {
542
542
  const existing = resolveSession(store, sessionKey);
543
543
  let sessionId = existing ? existing.sessionId : null;
544
544
 
@@ -623,7 +623,7 @@ async function ccDocCall({ message, document, title, filePath, selection, canEdi
623
623
  store: 'doc', sessionKey: filePath || title,
624
624
  extraContext: docContext, label: 'doc-chat',
625
625
  timeout: isRich ? 300000 : 60000,
626
- maxTurns: isRich ? 10 : 1,
626
+ maxTurns: isRich ? 50 : 1,
627
627
  model: isRich ? 'sonnet' : 'haiku',
628
628
  allowedTools: isRich ? 'Read,Glob,Grep' : '',
629
629
  skipStatePreamble: !isRich,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.84",
3
+ "version": "0.1.86",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"