@yemi33/minions 0.1.1556 → 0.1.1558

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,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1558 (2026-04-27)
4
+
5
+ ### Fixes
6
+ - show Scan button in empty state for fresh installs
7
+
8
+ ## 0.1.1557 (2026-04-27)
9
+
10
+ ### Features
11
+ - × button on top-level project chips with optimistic removal
12
+
13
+ ### Fixes
14
+ - make PRD archive optimistic
15
+
3
16
  ## 0.1.1556 (2026-04-27)
4
17
 
5
18
  ### Other
@@ -2,15 +2,18 @@
2
2
 
3
3
  function renderProjects(projects) {
4
4
  const list = document.getElementById('projects-list');
5
- if (!projects.length) {
5
+ const visible = (projects || []).filter(p => typeof isDeleted === 'function' ? !isDeleted('project:' + p.name) : true);
6
+ if (!visible.length) {
6
7
  list.innerHTML = '<span style="color:var(--muted);font-style:italic">No projects linked.</span>' +
7
- '<span onclick="addProject()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--green);font-weight:500;cursor:pointer;border-style:dashed;margin-left:8px">+ Add Project</span>';
8
+ '<span onclick="addProject()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--green);font-weight:500;cursor:pointer;border-style:dashed;margin-left:8px">+ Add Project</span>' +
9
+ '<span onclick="openScanProjectsModal()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--blue);font-weight:500;cursor:pointer;border-style:dashed;font-size:10px">Scan</span>';
8
10
  return;
9
11
  }
10
- list.innerHTML = projects.map(p =>
11
- '<span title="' + escHtml(p.description || p.path || '') + '" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--blue);font-weight:500;cursor:help">' +
12
+ list.innerHTML = visible.map(p =>
13
+ '<span data-project="' + escHtml(p.name) + '" title="' + escHtml(p.description || p.path || '') + '" style="display:inline-flex;align-items:center;gap:6px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--blue);font-weight:500;cursor:help">' +
12
14
  escHtml(p.name) +
13
- (p.description ? '<span style="color:var(--muted);font-weight:400;margin-left:6px;font-size:10px">' + escHtml(p.description.slice(0, 60)) + (p.description.length > 60 ? '...' : '') + '</span>' : '') +
15
+ (p.description ? '<span style="color:var(--muted);font-weight:400;font-size:10px">' + escHtml(p.description.slice(0, 60)) + (p.description.length > 60 ? '...' : '') + '</span>' : '') +
16
+ '<span onclick="event.stopPropagation();projectChipRemove(\'' + escHtml(p.name) + '\')" title="Remove project (cancels pending work, archives data dir)" style="color:var(--muted);font-weight:600;cursor:pointer;padding:0 2px;line-height:1" onmouseover="this.style.color=\'var(--red)\'" onmouseout="this.style.color=\'var(--muted)\'">&times;</span>' +
14
17
  '</span>'
15
18
  ).join('') +
16
19
  '<span onclick="addProject()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--muted);font-weight:500;cursor:pointer;border-style:dashed">+ Add</span>' +
@@ -18,6 +21,39 @@ function renderProjects(projects) {
18
21
 
19
22
  }
20
23
 
24
+ async function projectChipRemove(name) {
25
+ if (!confirm('Remove project "' + name + '"? Pending work cancels, active agents are killed, data dir is archived to projects/.archived/.')) return;
26
+ markDeleted('project:' + name);
27
+ // Re-render immediately from cached state so the chip disappears without waiting on the API
28
+ if (window._lastStatus && Array.isArray(window._lastStatus.projects)) {
29
+ renderProjects(window._lastStatus.projects);
30
+ }
31
+ showToast('cmd-toast', 'Removing project "' + name + '"...', true);
32
+ try {
33
+ const res = await fetch('/api/projects/remove', {
34
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
35
+ body: JSON.stringify({ name })
36
+ });
37
+ const d = await res.json().catch(() => ({}));
38
+ if (!res.ok || !d.ok) {
39
+ // Revert: refresh restores the chip from server state
40
+ showToast('cmd-toast', 'Remove failed: ' + (d.error || 'unknown'), false);
41
+ if (typeof refresh === 'function') refresh();
42
+ return;
43
+ }
44
+ var parts = ['Removed "' + name + '"'];
45
+ if (d.cancelledItems) parts.push(d.cancelledItems + ' WI cancelled');
46
+ if (d.drainedDispatches) parts.push(d.drainedDispatches + ' dispatch drained');
47
+ if (d.archivedTo) parts.push('archived');
48
+ if (d.pipelineRefs?.length) parts.push('! pipelines still reference: ' + d.pipelineRefs.join(', '));
49
+ showToast('cmd-toast', parts.join(' — '), true);
50
+ if (typeof refresh === 'function') refresh();
51
+ } catch (e) {
52
+ showToast('cmd-toast', 'Error: ' + e.message, false);
53
+ if (typeof refresh === 'function') refresh();
54
+ }
55
+ }
56
+
21
57
  function renderMcpServers(servers) {
22
58
  const el = document.getElementById('mcp-list');
23
59
  const countEl = document.getElementById('mcp-count');
@@ -354,4 +390,4 @@ async function _addSelectedProjects() {
354
390
  }
355
391
  }
356
392
 
357
- window.MinionsOther = { renderProjects, renderMcpServers, renderMetrics, renderLlmPerf, renderTokenUsage, openScanProjectsModal };
393
+ window.MinionsOther = { renderProjects, projectChipRemove, renderMcpServers, renderMetrics, renderLlmPerf, renderTokenUsage, openScanProjectsModal };
@@ -602,11 +602,13 @@ async function planArchive(file, btn) {
602
602
  _stopPlanPoll();
603
603
  markDeleted('plan:' + file);
604
604
  if (isPrd) {
605
- var linkedPlan = (window._lastPlans || []).find(function(p) { return p.file === file && p.sourcePlan; });
606
- if (linkedPlan) markDeleted('plan:' + linkedPlan.sourcePlan);
605
+ var prdRecord = (window._lastPlans || []).find(function(p) { return p.file === file && p.sourcePlan; });
606
+ if (prdRecord) markDeleted('plan:' + prdRecord.sourcePlan);
607
607
  }
608
+ if (window._lastPlans) renderPlans(window._lastPlans);
609
+ if (typeof rerenderPrdFromCache === 'function') rerenderPrdFromCache();
608
610
  try { closeModal(); } catch { /* may not be open */ }
609
- showToast('cmd-toast', 'Archived', true);
611
+ showToast('cmd-toast', isPrd ? 'Archiving PRD and linked source plan...' : 'Archiving plan...', true);
610
612
  try {
611
613
  const res = await fetch('/api/plans/archive', {
612
614
  method: 'POST', headers: { 'Content-Type': 'application/json' },
@@ -17,9 +17,15 @@ function renderPrd(prd, prog) {
17
17
  const statusLabels = { 'completed': 'Completed', 'dispatched': 'In Progress', 'awaiting-approval': 'Awaiting Approval', 'paused': 'Paused', 'approved': 'Approved' };
18
18
 
19
19
  // Show per-PRD status summary in header when multiple PRDs exist
20
- const existing = prd.existing || [];
20
+ const existing = (prd.existing || []).filter(function(p) { return !isDeleted('plan:' + (p.file || '')); });
21
21
  const allWi = window._lastWorkItems || [];
22
- const prdItems = (prog?.items || []).filter(i => !i._archived);
22
+ const prdItems = (prog?.items || []).filter(i => !i._archived && !isDeleted('plan:' + (i.source || '')));
23
+
24
+ if (existing.length === 0 && prdItems.length === 0) {
25
+ section.innerHTML = '<p class="prd-pending" style="margin-bottom:0">No PRD found.</p>';
26
+ badge.innerHTML = '';
27
+ return;
28
+ }
23
29
 
24
30
  if (existing.length <= 1) {
25
31
  // Single PRD — show status + actions in header
@@ -78,9 +84,10 @@ function renderPrdProgress(prog) {
78
84
  const el = document.getElementById('prd-progress-content');
79
85
  const countEl = document.getElementById('prd-progress-count');
80
86
  if (!prog) { el.innerHTML = ''; countEl.textContent = '—'; return; }
87
+ const visibleItems = (prog.items || []).filter(i => !isDeleted('plan:' + (i.source || '')));
81
88
 
82
89
  // Compute overall progress from active (non-archived) items
83
- const activeItems = (prog.items || []).filter(i => !i._archived);
90
+ const activeItems = visibleItems.filter(i => !i._archived);
84
91
  if (activeItems.length > 0) {
85
92
  const activeDone = activeItems.filter(i => i.status === 'done').length;
86
93
  countEl.textContent = Math.round((activeDone / activeItems.length) * 100) + '%';
@@ -150,7 +157,7 @@ function renderPrdProgress(prog) {
150
157
 
151
158
  // Group items by source plan
152
159
  const grouped = {};
153
- for (const i of (prog.items || [])) {
160
+ for (const i of visibleItems) {
154
161
  const key = i.source || '_ungrouped';
155
162
  if (!grouped[key]) grouped[key] = { summary: i.planSummary || i.source || 'Items', _projects: [], file: i.source || '', items: [], archived: !!i._archived, planStatus: i.planStatus || 'active', sourcePlan: i.sourcePlan || '', branchStrategy: i.branchStrategy || 'parallel', planStale: i.planStale || false, lastSyncedFromPlan: i.lastSyncedFromPlan || null, prdUpdatedAt: i.prdUpdatedAt || null, completedAt: i.prdCompletedAt || '' };
156
163
  grouped[key].items.push(i);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1556",
3
+ "version": "0.1.1558",
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"