@yemi33/minions 0.1.2080 → 0.1.2081

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 (2) hide show
  1. package/engine/pipeline.js +29 -4
  2. package/package.json +1 -1
@@ -299,11 +299,19 @@ function evaluateCondition(condition, ctx) {
299
299
 
300
300
  switch (cond.check) {
301
301
  case 'runSucceeded': {
302
- // True when the current/last run completed with all stages succeeded (none failed)
302
+ // P-bfa1e finding #21: tightened predicate.
303
+ // Previously this accepted PENDING as "succeeded" via `s.status === COMPLETED || s.status === PENDING`,
304
+ // which let `stopWhen`/`stop-pipeline` short-circuit fire while stages were still queued for the next
305
+ // dispatch cycle. A "succeeded" run is one where:
306
+ // 1. The run object exists (no run → nothing has succeeded).
307
+ // 2. At least one stage exists (vacuous-truth empty `.every()` would otherwise lie about success).
308
+ // 3. EVERY stage is COMPLETED — RUNNING/PENDING/WAITING_HUMAN/PAUSED/FAILED/STOPPED all fail the check.
309
+ // Any `stopWhen` or condition-stage `stop-pipeline` consumer wired to `runSucceeded` now sees `false`
310
+ // until the run is fully done, so it cannot prematurely terminate the pipeline.
303
311
  if (!run) return false;
304
- return Object.values(run.stages || {}).every(
305
- s => s.status === PIPELINE_STATUS.COMPLETED || s.status === PIPELINE_STATUS.PENDING
306
- );
312
+ const stages = Object.values(run.stages || {});
313
+ if (stages.length === 0) return false;
314
+ return stages.every(s => s && s.status === PIPELINE_STATUS.COMPLETED);
307
315
  }
308
316
  case 'noFailedItems': {
309
317
  // True when all work items created by the pipeline are done (not failed)
@@ -1156,6 +1164,23 @@ async function discoverPipelineWork(config) {
1156
1164
  // Condition stage signaled pipeline stop — complete the run immediately
1157
1165
  if (result._stopPipeline) {
1158
1166
  completeRun(pipeline.id, activeRun.runId, PIPELINE_STATUS.STOPPED);
1167
+ // P-bfa1e finding #24: the local `activeRun` reference still has
1168
+ // `status === RUNNING` because we captured it at L980 before any
1169
+ // completion writes. The post-loop `allComplete` block at L1138
1170
+ // guards with `activeRun.status !== PIPELINE_STATUS.STOPPED`
1171
+ // before re-calling `completeRun(..., COMPLETED)` — if we leave
1172
+ // the stale RUNNING status in place that guard fails and we
1173
+ // clobber the STOPPED status with COMPLETED. Refresh the local
1174
+ // reference from disk so downstream reads in this same tick see
1175
+ // STOPPED. `getActiveRun` excludes terminal runs, so fall back
1176
+ // to a defensive in-place status patch when the refresh comes
1177
+ // back empty.
1178
+ const refreshed = getActiveRun(pipeline.id);
1179
+ if (refreshed) {
1180
+ activeRun = refreshed;
1181
+ } else {
1182
+ activeRun.status = PIPELINE_STATUS.STOPPED;
1183
+ }
1159
1184
  allComplete = true;
1160
1185
  break;
1161
1186
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2080",
3
+ "version": "0.1.2081",
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"