@yemi33/minions 0.1.1555 → 0.1.1557

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.1557 (2026-04-27)
4
+
5
+ ### Features
6
+ - × button on top-level project chips with optimistic removal
7
+
8
+ ### Fixes
9
+ - make PRD archive optimistic
10
+
11
+ ## 0.1.1556 (2026-04-27)
12
+
13
+ ### Other
14
+ - docs: document comprehensive minions remove
15
+
3
16
  ## 0.1.1555 (2026-04-27)
4
17
 
5
18
  ### Features
package/README.md CHANGED
@@ -129,7 +129,7 @@ minions work "Explore the codebase and document the architecture"
129
129
  | `minions version` | Show installed vs package version |
130
130
  | `minions scan [dir] [depth]` | Scan for git repos and multi-select to add (default: ~, depth 3) |
131
131
  | `minions add <dir>` | Link a single project (auto-detects settings from git, prompts to confirm) |
132
- | `minions remove <dir>` | Unlink a project |
132
+ | `minions remove <dir-or-name> [--keep-data \| --purge --force]` | Unlink a project: cancels pending work items, drains dispatch + kills active agents, cleans worktrees, disables linked schedules, archives `projects/<name>/` to `projects/.archived/<name>-YYYYMMDD/`. Use `--keep-data` to leave the data dir in place, or `--purge --force` to delete it. |
133
133
  | `minions list` | List all linked projects with descriptions |
134
134
  | `minions start` | Start engine daemon (ticks every 60s, auto-syncs MCP servers) |
135
135
  | `minions stop` | Stop the engine |
@@ -2,15 +2,17 @@
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
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>';
8
9
  return;
9
10
  }
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">' +
11
+ list.innerHTML = visible.map(p =>
12
+ '<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
13
  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>' : '') +
14
+ (p.description ? '<span style="color:var(--muted);font-weight:400;font-size:10px">' + escHtml(p.description.slice(0, 60)) + (p.description.length > 60 ? '...' : '') + '</span>' : '') +
15
+ '<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
16
  '</span>'
15
17
  ).join('') +
16
18
  '<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 +20,39 @@ function renderProjects(projects) {
18
20
 
19
21
  }
20
22
 
23
+ async function projectChipRemove(name) {
24
+ if (!confirm('Remove project "' + name + '"? Pending work cancels, active agents are killed, data dir is archived to projects/.archived/.')) return;
25
+ markDeleted('project:' + name);
26
+ // Re-render immediately from cached state so the chip disappears without waiting on the API
27
+ if (window._lastStatus && Array.isArray(window._lastStatus.projects)) {
28
+ renderProjects(window._lastStatus.projects);
29
+ }
30
+ showToast('cmd-toast', 'Removing project "' + name + '"...', true);
31
+ try {
32
+ const res = await fetch('/api/projects/remove', {
33
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
34
+ body: JSON.stringify({ name })
35
+ });
36
+ const d = await res.json().catch(() => ({}));
37
+ if (!res.ok || !d.ok) {
38
+ // Revert: refresh restores the chip from server state
39
+ showToast('cmd-toast', 'Remove failed: ' + (d.error || 'unknown'), false);
40
+ if (typeof refresh === 'function') refresh();
41
+ return;
42
+ }
43
+ var parts = ['Removed "' + name + '"'];
44
+ if (d.cancelledItems) parts.push(d.cancelledItems + ' WI cancelled');
45
+ if (d.drainedDispatches) parts.push(d.drainedDispatches + ' dispatch drained');
46
+ if (d.archivedTo) parts.push('archived');
47
+ if (d.pipelineRefs?.length) parts.push('! pipelines still reference: ' + d.pipelineRefs.join(', '));
48
+ showToast('cmd-toast', parts.join(' — '), true);
49
+ if (typeof refresh === 'function') refresh();
50
+ } catch (e) {
51
+ showToast('cmd-toast', 'Error: ' + e.message, false);
52
+ if (typeof refresh === 'function') refresh();
53
+ }
54
+ }
55
+
21
56
  function renderMcpServers(servers) {
22
57
  const el = document.getElementById('mcp-list');
23
58
  const countEl = document.getElementById('mcp-count');
@@ -354,4 +389,4 @@ async function _addSelectedProjects() {
354
389
  }
355
390
  }
356
391
 
357
- window.MinionsOther = { renderProjects, renderMcpServers, renderMetrics, renderLlmPerf, renderTokenUsage, openScanProjectsModal };
392
+ 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.1555",
3
+ "version": "0.1.1557",
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"