@yemi33/minions 0.1.2000 → 0.1.2002
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/engine/dispatch.js +22 -1
- package/engine/github.js +7 -0
- package/engine/lifecycle.js +3 -0
- package/engine/pipeline.js +17 -9
- package/engine/playbook.js +68 -10
- package/engine/projects.js +32 -14
- package/engine/shared.js +7 -0
- package/engine.js +43 -6
- package/package.json +1 -1
- package/playbooks/ask.md +4 -0
- package/playbooks/build-and-test.md +4 -0
- package/playbooks/decompose.md +4 -0
- package/playbooks/docs.md +4 -0
- package/playbooks/explore.md +4 -0
- package/playbooks/fix.md +4 -0
- package/playbooks/implement-shared.md +4 -0
- package/playbooks/implement.md +4 -0
- package/playbooks/meeting-conclude.md +4 -0
- package/playbooks/meeting-debate.md +4 -0
- package/playbooks/meeting-investigate.md +4 -0
- package/playbooks/plan-to-prd.md +4 -0
- package/playbooks/plan.md +4 -0
- package/playbooks/qa-validate.md +4 -0
- package/playbooks/review.md +4 -0
- package/playbooks/setup.md +4 -0
- package/playbooks/shared-rules.md +4 -0
- package/playbooks/test.md +4 -0
- package/playbooks/verify.md +4 -0
- package/playbooks/work-item.md +4 -0
package/engine/dispatch.js
CHANGED
|
@@ -598,7 +598,28 @@ function completeDispatch(id, result = DISPATCH_RESULT.SUCCESS, reason = '', res
|
|
|
598
598
|
});
|
|
599
599
|
log('warn', `Demoted WI ${item.meta.item.id} from DONE → FAILED${classSuffix} — sidecar acceptance gate rejected after completion-report claimed success`);
|
|
600
600
|
}
|
|
601
|
-
} catch (e) {
|
|
601
|
+
} catch (e) {
|
|
602
|
+
// P-bf06-force-demote-observability — write failures during
|
|
603
|
+
// sidecar-rejection force-demote used to log at warn level only,
|
|
604
|
+
// so they were invisible to dashboards / inbox alerting. Surface
|
|
605
|
+
// them at error level with the full stack AND a synthetic
|
|
606
|
+
// agent-failure inbox alert so the failed write is debuggable.
|
|
607
|
+
// NOTE: do NOT call lifecycle().syncPrdItemStatus from this catch
|
|
608
|
+
// — the success-path PRD sync at line 688 owns that contract and
|
|
609
|
+
// adding it here would double-write PRD status under conflicting
|
|
610
|
+
// assumptions.
|
|
611
|
+
log('error', `force-demote on ${failureClass} failed: ${e.message}\n${e.stack}`, { stack: e.stack, failureClass });
|
|
612
|
+
try {
|
|
613
|
+
// Pass a shimmed dispatch id so writeToInbox's slug-based dedupe
|
|
614
|
+
// (see shared.writeToInbox prefix collision check) doesn't drop
|
|
615
|
+
// this alert against the prior agent-failure note that the
|
|
616
|
+
// ERROR branch already wrote at line 550.
|
|
617
|
+
const demoteItem = { ...item, id: `${item.id}-demote-write` };
|
|
618
|
+
writeFailedAgentReport(demoteItem, `force-demote write failed: ${e.message}`, e.stack || '', 'dispatch-demote-write-failed');
|
|
619
|
+
} catch (reportErr) {
|
|
620
|
+
log('error', `force-demote write failed-agent-report itself failed: ${reportErr.message}`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
602
623
|
} else {
|
|
603
624
|
log('info', `Dispatch error for ${item.meta.item.id} ignored — work item is already completed`);
|
|
604
625
|
}
|
package/engine/github.js
CHANGED
|
@@ -869,6 +869,13 @@ async function pollPrStatus(config) {
|
|
|
869
869
|
].filter(Boolean).join('\n') || buildFailReason, 80);
|
|
870
870
|
} else if (allDone && allPassed) {
|
|
871
871
|
buildStatus = 'passing';
|
|
872
|
+
} else if (allDone) {
|
|
873
|
+
// Terminal-but-not-passing conclusions (cancelled, action_required,
|
|
874
|
+
// stale, etc.) — map to 'none' rather than 'failing'. These are not
|
|
875
|
+
// actionable build failures, so we deliberately do not block merge or
|
|
876
|
+
// dispatch build-fix agents. Previously fell through to 'running'
|
|
877
|
+
// forever (P-bf02-github-cancelled-stuck).
|
|
878
|
+
buildStatus = 'none';
|
|
872
879
|
} else {
|
|
873
880
|
buildStatus = 'running';
|
|
874
881
|
}
|
package/engine/lifecycle.js
CHANGED
|
@@ -3465,6 +3465,9 @@ function handleDecompositionResult(stdout, meta, config, runtimeName) {
|
|
|
3465
3465
|
// Mark parent as decomposed
|
|
3466
3466
|
p.status = WI_STATUS.DECOMPOSED;
|
|
3467
3467
|
p._decomposed = true;
|
|
3468
|
+
// P-bf04: timestamp used by engine.js areDependenciesMet() to classify
|
|
3469
|
+
// zero-children failures as recent vs stale in logs (both cascade 'failed').
|
|
3470
|
+
p._decomposedAt = ts();
|
|
3468
3471
|
delete p._decomposing;
|
|
3469
3472
|
// Sync to PRD so dashboard shows decomposed status
|
|
3470
3473
|
if (p.sourcePlan) syncPrdItemStatus(p.id, WI_STATUS.DECOMPOSED, p.sourcePlan);
|
package/engine/pipeline.js
CHANGED
|
@@ -756,15 +756,23 @@ function executeMergePrsStage(stage, stageState, run, config) {
|
|
|
756
756
|
function executeScheduleStage(stage, stageState, config) {
|
|
757
757
|
// Create/update schedules in config
|
|
758
758
|
const schedules = stage.schedules || [{ id: stage.id + '-sched', cron: stage.cron, title: stage.title, type: routing.normalizeWorkType(stage.taskType, WORK_TYPE.IMPLEMENT) }];
|
|
759
|
-
//
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
759
|
+
// P-bf05-config-write-race — atomic locked write so concurrent
|
|
760
|
+
// addProject/removeProject/dashboard-settings writers can't clobber the
|
|
761
|
+
// schedules we just appended. The prior `safeWrite(CONFIG_PATH, config)`
|
|
762
|
+
// last-write-wins corrupted config.json on bootstrap (no `.backup`
|
|
763
|
+
// self-heal). Mutate the fresh on-disk snapshot inside the lock so we
|
|
764
|
+
// don't drop concurrent edits.
|
|
765
|
+
mutateJsonFileLocked(CONFIG_PATH, (cfg) => {
|
|
766
|
+
if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) return cfg;
|
|
767
|
+
for (const sched of schedules) {
|
|
768
|
+
const existing = (cfg.schedules || []).find(s => s.id === sched.id);
|
|
769
|
+
if (!existing) {
|
|
770
|
+
cfg.schedules = cfg.schedules || [];
|
|
771
|
+
cfg.schedules.push({ ...sched, enabled: true });
|
|
772
|
+
}
|
|
765
773
|
}
|
|
766
|
-
|
|
767
|
-
|
|
774
|
+
return cfg;
|
|
775
|
+
});
|
|
768
776
|
return { status: PIPELINE_STATUS.COMPLETED, completedAt: ts() };
|
|
769
777
|
}
|
|
770
778
|
|
|
@@ -1151,7 +1159,7 @@ module.exports = {
|
|
|
1151
1159
|
getPipelineRuns, getActiveRun, startRun, updateRunStage, completeRun,
|
|
1152
1160
|
discoverPipelineWork,
|
|
1153
1161
|
evaluateCondition, // exported for testing
|
|
1154
|
-
executeTaskStage, executePlanStage, isStageComplete, resolveTemplate, // exported for testing
|
|
1162
|
+
executeTaskStage, executePlanStage, executeScheduleStage, isStageComplete, resolveTemplate, // exported for testing
|
|
1155
1163
|
_resolvePipelineProjects, // exported for testing
|
|
1156
1164
|
_findMeetingsInRun, _findExistingPlanForMeeting, _findExistingPrdForPlan, // exported for testing
|
|
1157
1165
|
};
|
package/engine/playbook.js
CHANGED
|
@@ -467,18 +467,74 @@ function buildQaValidateContextBlock({ runId, runbook, target, artifactsDir }) {
|
|
|
467
467
|
|
|
468
468
|
// ─── Playbook Renderer ──────────────────────────────────────────────────────
|
|
469
469
|
|
|
470
|
+
/**
|
|
471
|
+
* Parse YAML-ish frontmatter at the top of a playbook file.
|
|
472
|
+
* Returns { meta: {key:value}, body: string }. Recognized values:
|
|
473
|
+
* true|yes|1 → boolean true
|
|
474
|
+
* false|no|0 → boolean false
|
|
475
|
+
* everything else → raw string
|
|
476
|
+
*/
|
|
477
|
+
function _parsePlaybookFrontmatter(content) {
|
|
478
|
+
const m = String(content || '').match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
479
|
+
if (!m) return { meta: {}, body: content || '' };
|
|
480
|
+
const meta = {};
|
|
481
|
+
for (const line of m[1].split(/\r?\n/)) {
|
|
482
|
+
const lm = line.match(/^([\w-]+):\s*(.*)$/);
|
|
483
|
+
if (!lm) continue;
|
|
484
|
+
const key = lm[1];
|
|
485
|
+
const raw = lm[2].trim();
|
|
486
|
+
if (/^(true|yes|1)$/i.test(raw)) meta[key] = true;
|
|
487
|
+
else if (/^(false|no|0)$/i.test(raw)) meta[key] = false;
|
|
488
|
+
else meta[key] = raw;
|
|
489
|
+
}
|
|
490
|
+
return { meta, body: m[2].replace(/^\r?\n+/, '') };
|
|
491
|
+
}
|
|
492
|
+
|
|
470
493
|
function renderPlaybook(type, vars) {
|
|
471
494
|
const projectName = vars.project_name || null;
|
|
472
495
|
const pbPath = resolvePlaybookPath(projectName, type);
|
|
473
|
-
let
|
|
474
|
-
try {
|
|
496
|
+
let rawContent;
|
|
497
|
+
try { rawContent = fs.readFileSync(pbPath, 'utf8'); } catch {
|
|
475
498
|
log('warn', `Playbook not found: ${type}`);
|
|
476
499
|
return null;
|
|
477
500
|
}
|
|
478
501
|
|
|
479
|
-
//
|
|
502
|
+
// P-bf07 — parse frontmatter and enforce requiresProjectContext before any
|
|
503
|
+
// substitution work. Hard-fail dispatch when the playbook requires a
|
|
504
|
+
// project but none is configured (i.e. fresh install) so the agent prompt
|
|
505
|
+
// can never expand {{project_name}} / {{repo_name}} / {{ado_org}} /
|
|
506
|
+
// {{github_org}} to empty strings or the bogus 'Unknown' defaults.
|
|
507
|
+
const { meta: playbookMeta, body: bodyAfterFm } = _parsePlaybookFrontmatter(rawContent);
|
|
508
|
+
let content = bodyAfterFm;
|
|
509
|
+
|
|
510
|
+
const configEarly = getConfig();
|
|
511
|
+
const projectsEarly = getProjects(configEarly);
|
|
512
|
+
const matchedProject = (vars.repo_id && projectsEarly.find(p => p.repositoryId === vars.repo_id))
|
|
513
|
+
|| (vars.repo_name && projectsEarly.find(p => p.repoName === vars.repo_name))
|
|
514
|
+
|| projectsEarly[0]
|
|
515
|
+
|| null;
|
|
516
|
+
// Callers (PR dispatches, fan-out, unit tests) may supply project context
|
|
517
|
+
// in vars even when on-disk config has zero projects. Treat that as
|
|
518
|
+
// "project context provided" — the only true bug is when buildBaseVars
|
|
519
|
+
// fell back to the placeholder defaults ('Unknown Project' / 'Unknown')
|
|
520
|
+
// because no project object was available.
|
|
521
|
+
const callerSuppliedProjectContext = !!(
|
|
522
|
+
vars.repo_id
|
|
523
|
+
|| (vars.repo_name && vars.repo_name !== 'Unknown')
|
|
524
|
+
|| (vars.project_name && vars.project_name !== 'Unknown Project')
|
|
525
|
+
);
|
|
526
|
+
if (!matchedProject && !callerSuppliedProjectContext && playbookMeta.requiresProjectContext === true) {
|
|
527
|
+
const err = new Error(`Playbook ${type} requires a project but none is configured. Add a project via \`minions project add\`.`);
|
|
528
|
+
err.code = 'PLAYBOOK_REQUIRES_PROJECT';
|
|
529
|
+
err.playbook = type;
|
|
530
|
+
throw err;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Inject shared rules (apply to all playbooks). Strip any frontmatter so the
|
|
534
|
+
// P-bf07 audit metadata doesn't leak into the rendered prompt.
|
|
480
535
|
try {
|
|
481
|
-
const
|
|
536
|
+
const sharedRulesRaw = fs.readFileSync(path.join(PLAYBOOKS_DIR, 'shared-rules.md'), 'utf8');
|
|
537
|
+
const { body: sharedRules } = _parsePlaybookFrontmatter(sharedRulesRaw);
|
|
482
538
|
if (sharedRules) content += '\n\n' + sharedRules;
|
|
483
539
|
} catch { /* optional — shared rules file may not exist */ }
|
|
484
540
|
|
|
@@ -625,12 +681,13 @@ function renderPlaybook(type, vars) {
|
|
|
625
681
|
content += `- **SOURCE REFERENCES for every finding** — file paths with line numbers, PR URLs, API endpoints, config keys. Format: \`(source: path/to/file.ts:42)\` or \`(source: PR-12345)\`. Without references, findings cannot be verified.\n\n`;
|
|
626
682
|
|
|
627
683
|
// Inject project-level variables from config
|
|
628
|
-
const config =
|
|
629
|
-
const projects =
|
|
630
|
-
// Find the specific project being dispatched (match by repo_id or repo_name from vars)
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
684
|
+
const config = configEarly;
|
|
685
|
+
const projects = projectsEarly;
|
|
686
|
+
// Find the specific project being dispatched (match by repo_id or repo_name from vars).
|
|
687
|
+
// P-bf07 — when no project resolves we keep the legacy `{}` fallback ONLY for
|
|
688
|
+
// playbooks that opted out (requiresProjectContext: false). Required-context
|
|
689
|
+
// playbooks already short-circuited above with a structured error.
|
|
690
|
+
const dispatchProject = matchedProject || {};
|
|
634
691
|
const renderProject = {
|
|
635
692
|
...dispatchProject,
|
|
636
693
|
adoOrg: vars.ado_org || vars.adoOrg || dispatchProject.adoOrg,
|
|
@@ -997,6 +1054,7 @@ module.exports = {
|
|
|
997
1054
|
validatePlaybookVars,
|
|
998
1055
|
PLAYBOOK_REQUIRED_VARS,
|
|
999
1056
|
PLAYBOOK_OPTIONAL_VARS,
|
|
1057
|
+
_parsePlaybookFrontmatter,
|
|
1000
1058
|
buildSystemPrompt,
|
|
1001
1059
|
buildAgentContext,
|
|
1002
1060
|
selectPlaybook,
|
package/engine/projects.js
CHANGED
|
@@ -203,16 +203,13 @@ function removeProject(target, options = {}) {
|
|
|
203
203
|
} catch (e) { summary.warnings.push('worktree cleanup: ' + e.message); }
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
// 4.
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
206
|
+
// 4. Schedule disables happen atomically with the project unlink in
|
|
207
|
+
// section 7's mutateJsonFileLocked callback so concurrent writers
|
|
208
|
+
// (addProject, dashboard settings update, pipeline schedule stage)
|
|
209
|
+
// don't clobber each other. The previous pattern mutated the unlocked
|
|
210
|
+
// in-memory `config` snapshot here and relied on the section 7 write
|
|
211
|
+
// to persist it — that lost concurrent updates that landed between
|
|
212
|
+
// the initial read and the write.
|
|
216
213
|
|
|
217
214
|
// 5. Archive plans + PRDs targeting this project so they don't keep
|
|
218
215
|
// showing in the dashboard after removal. Three signals:
|
|
@@ -277,10 +274,31 @@ function removeProject(target, options = {}) {
|
|
|
277
274
|
}
|
|
278
275
|
} catch { /* pipelines optional */ }
|
|
279
276
|
|
|
280
|
-
// 7. Remove from config.json
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
277
|
+
// 7. Remove from config.json and persist schedule disables atomically
|
|
278
|
+
// under the config.json file lock. P-bf05-config-write-race —
|
|
279
|
+
// the prior `fs.writeFileSync` (and section 4's unlocked in-memory
|
|
280
|
+
// mutation) raced with addProject, dashboard settings updates, and
|
|
281
|
+
// pipeline schedule-stage writers, corrupting config.json on fresh
|
|
282
|
+
// bootstrap (which has no `.backup` self-heal). Both mutations now
|
|
283
|
+
// run inside the same mutateJsonFileLocked callback against the
|
|
284
|
+
// fresh on-disk snapshot.
|
|
285
|
+
let writeError = null;
|
|
286
|
+
try {
|
|
287
|
+
shared.mutateJsonFileLocked(configPath, (cfg) => {
|
|
288
|
+
if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) return cfg;
|
|
289
|
+
cfg.projects = (cfg.projects || []).filter(p => !_sameProjectName(p?.name, project.name));
|
|
290
|
+
if (Array.isArray(cfg.schedules)) {
|
|
291
|
+
for (const s of cfg.schedules) {
|
|
292
|
+
if (_projectRefMatches(s.project, project, projects) && s.enabled !== false) {
|
|
293
|
+
s.enabled = false;
|
|
294
|
+
summary.disabledSchedules++;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return cfg;
|
|
299
|
+
});
|
|
300
|
+
} catch (e) { writeError = e; }
|
|
301
|
+
if (writeError) return { ...summary, error: 'Failed to write config: ' + writeError.message };
|
|
284
302
|
|
|
285
303
|
// 8. Move (or purge) projects/<name>/ — preserves PR/work-item history by
|
|
286
304
|
// default so a re-add can pick up where it left off.
|
package/engine/shared.js
CHANGED
|
@@ -1678,6 +1678,13 @@ const ENGINE_DEFAULTS = {
|
|
|
1678
1678
|
shutdownTimeout: 300000, // 5min — max wait for active agents during graceful shutdown
|
|
1679
1679
|
allowTempAgents: false, // opt-in: spawn ephemeral agents when all permanent agents are busy
|
|
1680
1680
|
autoDecompose: true, // auto-decompose implement:large items into sub-tasks
|
|
1681
|
+
// P-bf04-decompose-zero-children: when a DECOMPOSED parent has zero children
|
|
1682
|
+
// and no decompose dispatch is in flight, areDependenciesMet treats that as
|
|
1683
|
+
// a silent decompose failure and cascades `'failed'` to dependents. This
|
|
1684
|
+
// window splits the failure log into "recent" vs "stale" categories — both
|
|
1685
|
+
// return `'failed'`; the threshold is for monitoring/log classification only,
|
|
1686
|
+
// not behavior. See engine.js areDependenciesMet() DECOMPOSED branch.
|
|
1687
|
+
decomposeZeroChildrenStaleMinutes: 30,
|
|
1681
1688
|
autoApprovePlans: false, // auto-approve PRDs without waiting for human approval
|
|
1682
1689
|
autoArchive: false, // opt-in: auto-archive plans after verify completes (false = mark ready, user archives manually)
|
|
1683
1690
|
autoFixConflicts: true, // auto-dispatch fix agents when a PR has merge conflicts
|
package/engine.js
CHANGED
|
@@ -3061,7 +3061,43 @@ function areDependenciesMet(item, config) {
|
|
|
3061
3061
|
const children = allWorkItems.filter(w => w.parent_id === depId);
|
|
3062
3062
|
if (children.length > 0 && children.every(c => PRD_MET_STATUSES.has(c.status))) continue; // all children done
|
|
3063
3063
|
if (children.length > 0) return false; // children still in progress
|
|
3064
|
-
|
|
3064
|
+
|
|
3065
|
+
// P-bf04-decompose-zero-children: parent is DECOMPOSED but no children
|
|
3066
|
+
// exist. Previously this silently `continue`d (treat as met), so a crashed
|
|
3067
|
+
// decompose (parser error, empty output, race) cascaded into dependents
|
|
3068
|
+
// running against a parent whose work never happened. New three-branch logic:
|
|
3069
|
+
//
|
|
3070
|
+
// (1) IN-FLIGHT HEDGE — a decompose dispatch for this parent is active
|
|
3071
|
+
// or pending → return false (caller waits, no cascade)
|
|
3072
|
+
// (2) RECENT zero-children — decomposedAt within the last N min
|
|
3073
|
+
// (3) STALE zero-children — decomposedAt older than N min (or unknown)
|
|
3074
|
+
//
|
|
3075
|
+
// (2) and (3) both return 'failed'; the split exists for log/monitor
|
|
3076
|
+
// classification (and test scaffolding), not for caller behavior.
|
|
3077
|
+
// PLAN_TO_PRD dispatches are intentionally NOT consulted here — they
|
|
3078
|
+
// materialize plan items into work items, they do not decompose an
|
|
3079
|
+
// existing DECOMPOSED parent into children.
|
|
3080
|
+
try {
|
|
3081
|
+
const dispatch = queries.getDispatch();
|
|
3082
|
+
const inFlight = [...(dispatch.pending || []), ...(dispatch.active || [])]
|
|
3083
|
+
.some(d => d?.type === WORK_TYPE.DECOMPOSE && d?.meta?.item?.id === depId);
|
|
3084
|
+
if (inFlight || depItem._decomposing === true) {
|
|
3085
|
+
log('warn', `Dep ${depId} (DECOMPOSED, zero children) — decompose dispatch still in flight; treating as unmet`);
|
|
3086
|
+
return false;
|
|
3087
|
+
}
|
|
3088
|
+
} catch (e) { log('warn', `areDependenciesMet bf04 in-flight check failed: ${e.message}`); }
|
|
3089
|
+
|
|
3090
|
+
const staleMin = ENGINE_DEFAULTS.decomposeZeroChildrenStaleMinutes;
|
|
3091
|
+
const parsedDecomposedAt = depItem._decomposedAt ? Date.parse(depItem._decomposedAt) : NaN;
|
|
3092
|
+
const ageMs = Number.isFinite(parsedDecomposedAt) ? (Date.now() - parsedDecomposedAt) : null;
|
|
3093
|
+
const isRecent = ageMs !== null && ageMs < staleMin * 60000;
|
|
3094
|
+
if (isRecent) {
|
|
3095
|
+
log('warn', `Dep ${depId} (DECOMPOSED) produced zero children RECENTLY (${Math.round(ageMs / 60000)}m ago) — cascading dependency_failed to ${item.id}`);
|
|
3096
|
+
} else {
|
|
3097
|
+
const ageLabel = ageMs == null ? 'no _decomposedAt' : `${Math.round(ageMs / 60000)}m ago`;
|
|
3098
|
+
log('warn', `Dep ${depId} (DECOMPOSED) produced zero children STALE (${ageLabel}) — cascading dependency_failed to ${item.id}`);
|
|
3099
|
+
}
|
|
3100
|
+
return 'failed';
|
|
3065
3101
|
}
|
|
3066
3102
|
if (!PRD_MET_STATUSES.has(depItem.status)) return false; // Pending, dispatched, or retrying — wait
|
|
3067
3103
|
}
|
|
@@ -4077,7 +4113,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4077
4113
|
if (target && target.reviewStatus !== 'approved') target.reviewStatus = liveStatus;
|
|
4078
4114
|
return data;
|
|
4079
4115
|
});
|
|
4080
|
-
} catch {}
|
|
4116
|
+
} catch (e) { log('warn', `persist live vote-check for ${pr.id}: ${e.message}`); }
|
|
4081
4117
|
continue;
|
|
4082
4118
|
}
|
|
4083
4119
|
} catch (e) { log('warn', `Pre-dispatch vote check for ${pr.id}: ${e.message} — skipping dispatch`); continue; }
|
|
@@ -4237,7 +4273,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4237
4273
|
if (target && target.reviewStatus !== 'approved') target.reviewStatus = liveStatus;
|
|
4238
4274
|
return data;
|
|
4239
4275
|
});
|
|
4240
|
-
} catch {}
|
|
4276
|
+
} catch (e) { log('warn', `persist live re-review vote-check for ${pr.id}: ${e.message}`); }
|
|
4241
4277
|
continue;
|
|
4242
4278
|
}
|
|
4243
4279
|
} catch (e) { log('warn', `Pre-dispatch vote check for ${pr.id}: ${e.message} — skipping dispatch`); continue; }
|
|
@@ -4353,7 +4389,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4353
4389
|
target._buildStatusStale = true;
|
|
4354
4390
|
if (live.buildStatusDetail) target._buildStatusDetail = live.buildStatusDetail;
|
|
4355
4391
|
});
|
|
4356
|
-
} catch {}
|
|
4392
|
+
} catch (e) { log('warn', `persist live build-stale-marker for ${pr.id}: ${e.message}`); }
|
|
4357
4393
|
}
|
|
4358
4394
|
if (live && live.buildStatus && live.buildStatus !== 'failing') {
|
|
4359
4395
|
log('info', `Pre-dispatch build check: ${pr.id} build is ${live.buildStatus} (cached was failing) — skipping build-fix`);
|
|
@@ -4374,7 +4410,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4374
4410
|
}
|
|
4375
4411
|
}
|
|
4376
4412
|
});
|
|
4377
|
-
} catch {}
|
|
4413
|
+
} catch (e) { log('warn', `persist live build-status for ${pr.id}: ${e.message}`); }
|
|
4378
4414
|
continue;
|
|
4379
4415
|
}
|
|
4380
4416
|
} catch (e) { log('warn', `Pre-dispatch build check for ${pr.id}: ${e.message} — skipping dispatch`); continue; }
|
|
@@ -4452,7 +4488,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4452
4488
|
delete target._mergeConflict;
|
|
4453
4489
|
delete target._conflictFixedAt;
|
|
4454
4490
|
});
|
|
4455
|
-
} catch {}
|
|
4491
|
+
} catch (e) { log('warn', `persist live conflict-clear for ${pr.id}: ${e.message}`); }
|
|
4456
4492
|
liveSkip = true;
|
|
4457
4493
|
}
|
|
4458
4494
|
} catch (e) { log('warn', `Pre-dispatch conflict check for ${pr.id}: ${e.message} — skipping dispatch`); liveSkip = true; }
|
|
@@ -6626,6 +6662,7 @@ module.exports = {
|
|
|
6626
6662
|
|
|
6627
6663
|
// Shared helpers (used by lifecycle.js and tests)
|
|
6628
6664
|
reconcileItemsWithPrs, detectDependencyCycles,
|
|
6665
|
+
areDependenciesMet, // exported for testing (P-bf04-decompose-zero-children)
|
|
6629
6666
|
parseConflictFiles, pruneAncestorDeps, preflightMergeSimulation, // exported for testing
|
|
6630
6667
|
buildDepConflictFixItem, // exported for testing (W-mpcwojgr000a0244)
|
|
6631
6668
|
isWorktreeRetryableError, removeStaleIndexLock, syncReusedWorktree, assertCleanSharedWorktree, // exported for testing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2002",
|
|
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"
|
package/playbooks/ask.md
CHANGED
package/playbooks/decompose.md
CHANGED
package/playbooks/docs.md
CHANGED
package/playbooks/explore.md
CHANGED
package/playbooks/fix.md
CHANGED
package/playbooks/implement.md
CHANGED
package/playbooks/plan-to-prd.md
CHANGED
package/playbooks/plan.md
CHANGED
package/playbooks/qa-validate.md
CHANGED
package/playbooks/review.md
CHANGED
package/playbooks/setup.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
requiresProjectContext: false
|
|
3
|
+
---
|
|
4
|
+
|
|
1
5
|
## Operating Principle
|
|
2
6
|
|
|
3
7
|
Treat a Minions assignment like the user typed the same task directly into a capable CLI agent. Optimize for the requested outcome and use the repo's own tools, conventions, and acceptance criteria.
|
package/playbooks/test.md
CHANGED
package/playbooks/verify.md
CHANGED