@yemi33/minions 0.1.389 → 0.1.390
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 +2 -1
- package/engine/pipeline.js +42 -42
- package/engine/shared.js +13 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.390 (2026-04-06)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
- Replace magic strings in pipeline.js with STAGE_TYPE/PIPELINE_STATUS/MEETING_STATUS constants (#244)
|
|
6
7
|
- Fix spawn-agent.js direct proc.kill() — use cross-platform helpers (#243)
|
|
7
8
|
|
|
8
9
|
## 0.1.388 (2026-04-06)
|
package/engine/pipeline.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const shared = require('./shared');
|
|
10
|
-
const { safeJson, safeWrite, safeRead, safeReadDir, uid, log, ts, dateStamp, mutateJsonFileLocked, WI_STATUS, WORK_TYPE, PLAN_STATUS, PR_STATUS, PIPELINE_STATUS, MEETING_STATUS } = shared;
|
|
10
|
+
const { safeJson, safeWrite, safeRead, safeReadDir, uid, log, ts, dateStamp, mutateJsonFileLocked, WI_STATUS, WORK_TYPE, PLAN_STATUS, PR_STATUS, PIPELINE_STATUS, STAGE_TYPE, MEETING_STATUS } = shared;
|
|
11
11
|
const { parseCronExpr, shouldRunNow } = require('./scheduler');
|
|
12
12
|
|
|
13
13
|
const PIPELINES_DIR = path.join(__dirname, '..', 'pipelines');
|
|
@@ -130,22 +130,22 @@ async function executeStage(stage, run, pipeline, config) {
|
|
|
130
130
|
const stageState = run.stages[stage.id];
|
|
131
131
|
|
|
132
132
|
switch (resolved.type) {
|
|
133
|
-
case
|
|
133
|
+
case STAGE_TYPE.TASK:
|
|
134
134
|
return executeTaskStage(resolved, stageState, run, config);
|
|
135
|
-
case
|
|
135
|
+
case STAGE_TYPE.MEETING:
|
|
136
136
|
return executeMeetingStage(resolved, stageState, run, config);
|
|
137
|
-
case
|
|
137
|
+
case STAGE_TYPE.PLAN:
|
|
138
138
|
return executePlanStage(resolved, stageState, run, config);
|
|
139
|
-
case
|
|
139
|
+
case STAGE_TYPE.API:
|
|
140
140
|
return executeApiStage(resolved, stageState, run);
|
|
141
|
-
case
|
|
141
|
+
case STAGE_TYPE.MERGE_PRS:
|
|
142
142
|
return executeMergePrsStage(resolved, stageState, run, config);
|
|
143
|
-
case
|
|
143
|
+
case STAGE_TYPE.SCHEDULE:
|
|
144
144
|
return executeScheduleStage(resolved, stageState, config);
|
|
145
|
-
case
|
|
145
|
+
case STAGE_TYPE.WAIT:
|
|
146
146
|
// wait stages just sit in waiting-human status until continued via API
|
|
147
147
|
return { status: PIPELINE_STATUS.WAITING_HUMAN };
|
|
148
|
-
case
|
|
148
|
+
case STAGE_TYPE.PARALLEL:
|
|
149
149
|
return executeParallelStage(resolved, stageState, run, pipeline, config);
|
|
150
150
|
default:
|
|
151
151
|
log('warn', `Pipeline: unknown stage type '${resolved.type}' in stage ${stage.id}`);
|
|
@@ -298,7 +298,7 @@ async function executePlanStage(stage, stageState, run, config) {
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
return {
|
|
301
|
-
status:
|
|
301
|
+
status: PIPELINE_STATUS.RUNNING,
|
|
302
302
|
artifacts: {
|
|
303
303
|
plans: [path.basename(filePath)],
|
|
304
304
|
workItems: [wiId],
|
|
@@ -355,33 +355,33 @@ function executeScheduleStage(stage, stageState, config) {
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
safeWrite(path.join(__dirname, '..', 'config.json'), config);
|
|
358
|
-
return { status:
|
|
358
|
+
return { status: PIPELINE_STATUS.COMPLETED, completedAt: ts() };
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
async function executeParallelStage(stage, stageState, run, pipeline, config) {
|
|
362
362
|
const subStages = stage.stages || [];
|
|
363
363
|
const subResults = {};
|
|
364
364
|
for (const sub of subStages) {
|
|
365
|
-
if (!run.stages[sub.id] || run.stages[sub.id].status ===
|
|
365
|
+
if (!run.stages[sub.id] || run.stages[sub.id].status === PIPELINE_STATUS.PENDING) {
|
|
366
366
|
const result = await executeStage(sub, run, pipeline, config);
|
|
367
367
|
subResults[sub.id] = result;
|
|
368
368
|
run.stages[sub.id] = { ...run.stages[sub.id] || {}, ...result, startedAt: ts() };
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
371
|
// Parent is running until all subs complete
|
|
372
|
-
return { status:
|
|
372
|
+
return { status: PIPELINE_STATUS.RUNNING, artifacts: { subStages: subStages.map(s => s.id) } };
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
// ── Stage Completion Checks ──────────────────────────────────────────────────
|
|
376
376
|
|
|
377
377
|
function isStageComplete(stage, stageState, run, config) {
|
|
378
|
-
if (stageState.status ===
|
|
379
|
-
if (stageState.status ===
|
|
378
|
+
if (stageState.status === PIPELINE_STATUS.COMPLETED || stageState.status === PIPELINE_STATUS.FAILED) return true;
|
|
379
|
+
if (stageState.status === PIPELINE_STATUS.PENDING || stageState.status === PIPELINE_STATUS.WAITING_HUMAN) return false;
|
|
380
380
|
|
|
381
381
|
const artifacts = stageState.artifacts || {};
|
|
382
382
|
|
|
383
383
|
switch (stage.type) {
|
|
384
|
-
case
|
|
384
|
+
case STAGE_TYPE.TASK: {
|
|
385
385
|
const wiPath = path.join(__dirname, '..', 'work-items.json');
|
|
386
386
|
const workItems = safeJson(wiPath) || [];
|
|
387
387
|
const ids = artifacts.workItems || [];
|
|
@@ -391,16 +391,16 @@ function isStageComplete(stage, stageState, run, config) {
|
|
|
391
391
|
return !wi || wi.status === WI_STATUS.DONE || wi.status === WI_STATUS.FAILED; // missing = treat as done
|
|
392
392
|
});
|
|
393
393
|
}
|
|
394
|
-
case
|
|
394
|
+
case STAGE_TYPE.MEETING: {
|
|
395
395
|
const { getMeeting } = require('./meeting');
|
|
396
396
|
const ids = artifacts.meetings || [];
|
|
397
397
|
if (ids.length === 0) return false;
|
|
398
398
|
return ids.every(id => {
|
|
399
399
|
const m = getMeeting(id);
|
|
400
|
-
return m && (m.status ===
|
|
400
|
+
return m && (m.status === MEETING_STATUS.COMPLETED || m.status === MEETING_STATUS.ARCHIVED);
|
|
401
401
|
});
|
|
402
402
|
}
|
|
403
|
-
case
|
|
403
|
+
case STAGE_TYPE.PLAN: {
|
|
404
404
|
// Plan stage completion: PRD conversion done + all materialized work items done
|
|
405
405
|
const wiPath = path.join(__dirname, '..', 'work-items.json');
|
|
406
406
|
const workItems = safeJson(wiPath) || [];
|
|
@@ -464,7 +464,7 @@ function isStageComplete(stage, stageState, run, config) {
|
|
|
464
464
|
return !wi || wi.status === WI_STATUS.DONE || wi.status === WI_STATUS.FAILED; // missing = treat as done
|
|
465
465
|
});
|
|
466
466
|
}
|
|
467
|
-
case
|
|
467
|
+
case STAGE_TYPE.MERGE_PRS: {
|
|
468
468
|
const prIds = artifacts.prs || [];
|
|
469
469
|
if (prIds.length === 0) return true; // nothing to merge
|
|
470
470
|
const projects = shared.getProjects(config);
|
|
@@ -477,16 +477,16 @@ function isStageComplete(stage, stageState, run, config) {
|
|
|
477
477
|
}
|
|
478
478
|
return true;
|
|
479
479
|
}
|
|
480
|
-
case
|
|
481
|
-
case
|
|
480
|
+
case STAGE_TYPE.API:
|
|
481
|
+
case STAGE_TYPE.SCHEDULE:
|
|
482
482
|
return true; // fire-and-forget
|
|
483
|
-
case
|
|
484
|
-
return stageState.status ===
|
|
485
|
-
case
|
|
483
|
+
case STAGE_TYPE.WAIT:
|
|
484
|
+
return stageState.status === PIPELINE_STATUS.COMPLETED;
|
|
485
|
+
case STAGE_TYPE.PARALLEL: {
|
|
486
486
|
const subIds = artifacts.subStages || [];
|
|
487
487
|
return subIds.every(id => {
|
|
488
488
|
const sub = run.stages[id];
|
|
489
|
-
return sub && (sub.status ===
|
|
489
|
+
return sub && (sub.status === PIPELINE_STATUS.COMPLETED || sub.status === PIPELINE_STATUS.FAILED);
|
|
490
490
|
});
|
|
491
491
|
}
|
|
492
492
|
default:
|
|
@@ -533,18 +533,18 @@ async function discoverPipelineWork(config) {
|
|
|
533
533
|
if (!stageState) continue;
|
|
534
534
|
|
|
535
535
|
// Check if running stage completed
|
|
536
|
-
if (stageState.status ===
|
|
536
|
+
if (stageState.status === PIPELINE_STATUS.RUNNING) {
|
|
537
537
|
if (isStageComplete(stage, stageState, activeRun, config)) {
|
|
538
538
|
// Collect output
|
|
539
539
|
let output = '';
|
|
540
|
-
if (stage.type ===
|
|
540
|
+
if (stage.type === STAGE_TYPE.TASK) {
|
|
541
541
|
const wiPath = path.join(__dirname, '..', 'work-items.json');
|
|
542
542
|
const workItems = safeJson(wiPath) || [];
|
|
543
543
|
output = (stageState.artifacts?.workItems || []).map(id => {
|
|
544
544
|
const wi = workItems.find(w => w.id === id);
|
|
545
545
|
return wi?.resultSummary || wi?.title || id;
|
|
546
546
|
}).join('\n');
|
|
547
|
-
} else if (stage.type ===
|
|
547
|
+
} else if (stage.type === STAGE_TYPE.MEETING) {
|
|
548
548
|
const { getMeeting } = require('./meeting');
|
|
549
549
|
output = (stageState.artifacts?.meetings || []).map(id => {
|
|
550
550
|
const m = getMeeting(id);
|
|
@@ -553,9 +553,9 @@ async function discoverPipelineWork(config) {
|
|
|
553
553
|
}
|
|
554
554
|
|
|
555
555
|
updateRunStage(pipeline.id, activeRun.runId, stage.id, {
|
|
556
|
-
status:
|
|
556
|
+
status: PIPELINE_STATUS.COMPLETED, completedAt: ts(), output
|
|
557
557
|
});
|
|
558
|
-
stageState.status =
|
|
558
|
+
stageState.status = PIPELINE_STATUS.COMPLETED;
|
|
559
559
|
stageState.output = output;
|
|
560
560
|
log('info', `Pipeline ${pipeline.id}: stage ${stage.id} completed`);
|
|
561
561
|
} else {
|
|
@@ -564,42 +564,42 @@ async function discoverPipelineWork(config) {
|
|
|
564
564
|
}
|
|
565
565
|
}
|
|
566
566
|
|
|
567
|
-
if (stageState.status ===
|
|
567
|
+
if (stageState.status === PIPELINE_STATUS.WAITING_HUMAN) { allComplete = false; continue; }
|
|
568
568
|
|
|
569
569
|
// Check if pending stage is ready to start
|
|
570
|
-
if (stageState.status ===
|
|
570
|
+
if (stageState.status === PIPELINE_STATUS.PENDING) {
|
|
571
571
|
allComplete = false;
|
|
572
572
|
const depsReady = (stage.dependsOn || []).every(depId => {
|
|
573
573
|
const dep = activeRun.stages[depId];
|
|
574
|
-
return dep && dep.status ===
|
|
574
|
+
return dep && dep.status === PIPELINE_STATUS.COMPLETED;
|
|
575
575
|
});
|
|
576
576
|
const depsFailed = (stage.dependsOn || []).some(depId => {
|
|
577
577
|
const dep = activeRun.stages[depId];
|
|
578
|
-
return dep && dep.status ===
|
|
578
|
+
return dep && dep.status === PIPELINE_STATUS.FAILED;
|
|
579
579
|
});
|
|
580
580
|
|
|
581
581
|
if (depsFailed) {
|
|
582
|
-
updateRunStage(pipeline.id, activeRun.runId, stage.id, { status:
|
|
583
|
-
stageState.status =
|
|
582
|
+
updateRunStage(pipeline.id, activeRun.runId, stage.id, { status: PIPELINE_STATUS.FAILED, error: 'dependency failed' });
|
|
583
|
+
stageState.status = PIPELINE_STATUS.FAILED;
|
|
584
584
|
anyFailed = true;
|
|
585
585
|
} else if (depsReady) {
|
|
586
586
|
const result = await executeStage(stage, activeRun, pipeline, config);
|
|
587
587
|
updateRunStage(pipeline.id, activeRun.runId, stage.id, { ...result, startedAt: ts() });
|
|
588
588
|
Object.assign(stageState, result, { startedAt: ts() });
|
|
589
|
-
if (result.status ===
|
|
589
|
+
if (result.status === PIPELINE_STATUS.RUNNING) anyRunning = true;
|
|
590
590
|
log('info', `Pipeline ${pipeline.id}: started stage ${stage.id} (${stage.type})`);
|
|
591
591
|
}
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
-
if (stageState.status ===
|
|
595
|
-
if (stageState.status !==
|
|
594
|
+
if (stageState.status === PIPELINE_STATUS.FAILED) anyFailed = true;
|
|
595
|
+
if (stageState.status !== PIPELINE_STATUS.COMPLETED) allComplete = false;
|
|
596
596
|
}
|
|
597
597
|
|
|
598
598
|
// Check if run is done
|
|
599
599
|
if (allComplete) {
|
|
600
|
-
completeRun(pipeline.id, activeRun.runId,
|
|
600
|
+
completeRun(pipeline.id, activeRun.runId, PIPELINE_STATUS.COMPLETED);
|
|
601
601
|
} else if (anyFailed && !anyRunning) {
|
|
602
|
-
completeRun(pipeline.id, activeRun.runId,
|
|
602
|
+
completeRun(pipeline.id, activeRun.runId, PIPELINE_STATUS.FAILED);
|
|
603
603
|
}
|
|
604
604
|
}
|
|
605
605
|
}
|
package/engine/shared.js
CHANGED
|
@@ -417,6 +417,18 @@ const PLAN_STATUS = {
|
|
|
417
417
|
};
|
|
418
418
|
const PR_STATUS = { ACTIVE: 'active', MERGED: 'merged', ABANDONED: 'abandoned', CLOSED: 'closed' };
|
|
419
419
|
const DISPATCH_RESULT = { SUCCESS: 'success', ERROR: 'error', TIMEOUT: 'timeout' };
|
|
420
|
+
const PIPELINE_STATUS = {
|
|
421
|
+
PENDING: 'pending', RUNNING: 'running', COMPLETED: 'completed',
|
|
422
|
+
FAILED: 'failed', PAUSED: 'paused', WAITING_HUMAN: 'waiting-human',
|
|
423
|
+
};
|
|
424
|
+
const STAGE_TYPE = {
|
|
425
|
+
TASK: 'task', MEETING: 'meeting', PLAN: 'plan', API: 'api',
|
|
426
|
+
MERGE_PRS: 'merge-prs', SCHEDULE: 'schedule', WAIT: 'wait', PARALLEL: 'parallel',
|
|
427
|
+
};
|
|
428
|
+
const MEETING_STATUS = {
|
|
429
|
+
INVESTIGATING: 'investigating', DEBATING: 'debating', CONCLUDING: 'concluding',
|
|
430
|
+
COMPLETED: 'completed', ARCHIVED: 'archived',
|
|
431
|
+
};
|
|
420
432
|
|
|
421
433
|
const DEFAULT_AGENTS = {
|
|
422
434
|
ripley: { name: 'Ripley', emoji: '\u{1F3D7}\uFE0F', role: 'Lead / Explorer', skills: ['architecture', 'codebase-exploration', 'design-review'] },
|
|
@@ -648,6 +660,7 @@ module.exports = {
|
|
|
648
660
|
classifyInboxItem,
|
|
649
661
|
ENGINE_DEFAULTS,
|
|
650
662
|
WI_STATUS, DONE_STATUSES, WORK_TYPE, PLAN_STATUS, PR_STATUS, DISPATCH_RESULT,
|
|
663
|
+
PIPELINE_STATUS, STAGE_TYPE, MEETING_STATUS,
|
|
651
664
|
DEFAULT_AGENTS,
|
|
652
665
|
DEFAULT_CLAUDE,
|
|
653
666
|
getProjects,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.390",
|
|
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"
|