@yemi33/minions 0.1.1878 → 0.1.1879

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,8 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1878 (2026-05-12)
3
+ ## 0.1.1879 (2026-05-12)
4
4
 
5
5
  ### Fixes
6
+ - reconcile stale failed plan follow-ups (#2366) (#2371)
6
7
  - Copilot resolver picks POSIX shim on Windows (#2370) (#2372)
7
8
 
8
9
  ## 0.1.1877 (2026-05-11)
@@ -61,12 +61,60 @@ async function refreshPlans() {
61
61
  } catch (e) { console.error('plans refresh:', e.message); }
62
62
  }
63
63
 
64
+ /**
65
+ * Returns true when a failed plan follow-up work item's intended outcome has
66
+ * been satisfied by a later/alternate path — so the stale failure should not
67
+ * drive the plan's top-level "has failures" badge.
68
+ *
69
+ * Reconciliation rules (issue #2366):
70
+ * - Failed `itemType: 'pr'` (Create PR for plan): satisfied when a PR linked
71
+ * to the same plan exists in any non-terminated state (active/merged/linked).
72
+ * The original failure is preserved on the WI for audit; it just doesn't
73
+ * count toward the rollup once a PR actually got created.
74
+ * - Failed `itemType: 'verify'`: satisfied when a newer verify WI for the
75
+ * same plan + project exists and is done OR in-flight (pending/dispatched).
76
+ *
77
+ * Returns false when the outcome cannot be confirmed satisfied — failure
78
+ * remains live and drives the badge.
79
+ */
80
+ function isFollowUpOutcomeSatisfied(wi, allWorkItems, allPrs) {
81
+ if (!wi || wi.status !== 'failed') return false;
82
+ if (wi.itemType === 'pr') {
83
+ // PR for this plan was created on any non-terminated path.
84
+ // "abandoned" / "closed" are terminal failures; everything else counts as
85
+ // the desired outcome being reached.
86
+ return (allPrs || []).some(pr =>
87
+ pr && pr.sourcePlan === wi.sourcePlan &&
88
+ pr.status !== 'abandoned' && pr.status !== 'closed'
89
+ );
90
+ }
91
+ if (wi.itemType === 'verify') {
92
+ // A newer verify WI for the same plan + project that is in flight or done.
93
+ const wiCreated = wi.created || '';
94
+ return (allWorkItems || []).some(other =>
95
+ other && other !== wi && other.itemType === 'verify' &&
96
+ other.sourcePlan === wi.sourcePlan &&
97
+ (other.project || '') === (wi.project || '') &&
98
+ (other.status === 'done' || other.status === 'pending' || other.status === 'dispatched') &&
99
+ (other.created || '') > wiCreated
100
+ );
101
+ }
102
+ return false;
103
+ }
104
+
64
105
  /**
65
106
  * Derive effective plan/PRD status from work items (single source of truth).
66
107
  * PRD JSON status is treated as user intent (approved, paused, rejected),
67
108
  * but completion/progress is always derived from actual work item state.
109
+ *
110
+ * opts.allPrs — optional PR records used to reconcile stale failed follow-up
111
+ * tasks (issue #2366). Falls back to window._lastStatus.pullRequests in the
112
+ * browser. Pass `[]` to disable reconciliation.
68
113
  */
69
- function derivePlanStatus(prdFile, mdFile, prdJsonStatus, workItems) {
114
+ function derivePlanStatus(prdFile, mdFile, prdJsonStatus, workItems, opts) {
115
+ const allPrs = (opts && opts.allPrs)
116
+ || (typeof window !== 'undefined' && window._lastStatus && window._lastStatus.pullRequests)
117
+ || [];
70
118
  const wi = workItems.filter(w =>
71
119
  w.sourcePlan === prdFile || w.sourcePlan === mdFile ||
72
120
  (w.type === 'plan-to-prd' && (w.planFile === prdFile || w.planFile === mdFile))
@@ -74,8 +122,18 @@ function derivePlanStatus(prdFile, mdFile, prdJsonStatus, workItems) {
74
122
  const implementWi = wi.filter(w => w.type !== 'plan-to-prd' && w.type !== 'verify');
75
123
  const hasPendingPrd = wi.some(w => w.type === 'plan-to-prd' && (w.status === 'pending' || w.status === 'dispatched'));
76
124
  const hasActiveWork = implementWi.some(w => w.status === 'pending' || w.status === 'dispatched');
77
- const allDone = implementWi.length > 0 && implementWi.every(w => w.status === 'done' || w.status === 'decomposed');
78
- const hasFailed = implementWi.some(w => w.status === 'failed');
125
+ // A WI is "effectively done" when it succeeded normally OR when it is a
126
+ // reconciled follow-up failure (intended outcome satisfied elsewhere — #2366).
127
+ // The original failure record is preserved on the WI for audit; it just
128
+ // stops blocking plan completion and stops driving the red badge.
129
+ const isReconciledFailure = (w) =>
130
+ w.status === 'failed' &&
131
+ (w.itemType === 'pr' || w.itemType === 'verify') &&
132
+ isFollowUpOutcomeSatisfied(w, workItems, allPrs);
133
+ const isEffectivelyDone = (w) =>
134
+ w.status === 'done' || w.status === 'decomposed' || isReconciledFailure(w);
135
+ const allDone = implementWi.length > 0 && implementWi.every(isEffectivelyDone);
136
+ const hasFailed = implementWi.some(w => w.status === 'failed' && !isReconciledFailure(w));
79
137
 
80
138
  // User-set statuses take priority when no work has started
81
139
  if (prdJsonStatus === 'rejected') return 'rejected';
@@ -897,4 +955,4 @@ async function planUnarchive(file, btn) {
897
955
  } catch (e) { showToast('cmd-toast', 'Error: ' + e.message, false); refresh(); }
898
956
  }
899
957
 
900
- window.MinionsPlans = { openCreatePlanModal, refreshPlans, derivePlanStatus, renderPlans, openArchivedPlansModal, planExecute, planReexecuteModal, planReexecuteSubmit, planSubmitRevise, planShowRevise, planHideRevise, planView, planApprove, planArchive, planUnarchive, planDelete, planPause, planReject, planDiscuss, planOpenInDocChat, planRegeneratePRD, openVerifyGuide, triggerVerify };
958
+ window.MinionsPlans = { openCreatePlanModal, refreshPlans, derivePlanStatus, isFollowUpOutcomeSatisfied, renderPlans, openArchivedPlansModal, planExecute, planReexecuteModal, planReexecuteSubmit, planSubmitRevise, planShowRevise, planHideRevise, planView, planApprove, planArchive, planUnarchive, planDelete, planPause, planReject, planDiscuss, planOpenInDocChat, planRegeneratePRD, openVerifyGuide, triggerVerify };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1878",
3
+ "version": "0.1.1879",
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"