@yemi33/minions 0.1.2029 → 0.1.2030
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 -2
- package/engine.js +16 -18
- package/package.json +1 -1
package/engine/dispatch.js
CHANGED
|
@@ -7,7 +7,7 @@ const fs = require('fs');
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const shared = require('./shared');
|
|
9
9
|
const queries = require('./queries');
|
|
10
|
-
const { setCooldownFailure } = require('./cooldown');
|
|
10
|
+
const { setCooldown, setCooldownFailure } = require('./cooldown');
|
|
11
11
|
|
|
12
12
|
const { safeJson, mutateJsonFileLocked, mutateWorkItems,
|
|
13
13
|
mutatePullRequests, getProjects, projectWorkItemsPath, projectPrPath, log, ts, dateStamp,
|
|
@@ -170,7 +170,27 @@ function addToDispatch(item) {
|
|
|
170
170
|
added = true;
|
|
171
171
|
return dispatch;
|
|
172
172
|
});
|
|
173
|
-
if (added)
|
|
173
|
+
if (added) {
|
|
174
|
+
log('info', `Queued dispatch: ${item.id} (${item.type} → ${item.agent})`);
|
|
175
|
+
// W-mph8xt88000ke0fc — Stamp the dispatch cooldown ONLY when the item
|
|
176
|
+
// actually survives the queue-time dedup gauntlet. Discover-side blocks
|
|
177
|
+
// (discoverFromPrs build-failure / review-feedback / merge-conflict,
|
|
178
|
+
// discoverFromWorkItems, discoverCentralWorkItems) used to call
|
|
179
|
+
// setCooldown(key) inline the instant a candidate item was built,
|
|
180
|
+
// BEFORE addToDispatch ran the prDedupeKey / workItem-id / dispatchKey
|
|
181
|
+
// dedup checks. The losing candidate left an orphan cooldown that
|
|
182
|
+
// blocked re-dispatch of that cause for `cooldownMinutes || 30` minutes
|
|
183
|
+
// even though no agent ever ran (live repro:
|
|
184
|
+
// ado:office/iss/constellation#5227109 on 2026-05-22 — build-fix and
|
|
185
|
+
// human-fix landed within 38 ms; only the human-fix ran but the orphan
|
|
186
|
+
// build-fix cooldown blocked the next 24 min of retries).
|
|
187
|
+
//
|
|
188
|
+
// Callers opt in by setting `item.meta.cooldownKey`. When absent (e.g.
|
|
189
|
+
// lifecycle.js auto-redispatches that intentionally bypass the cooldown
|
|
190
|
+
// ladder), no stamp fires — same as the pre-fix behavior for those
|
|
191
|
+
// paths.
|
|
192
|
+
if (item.meta?.cooldownKey) setCooldown(item.meta.cooldownKey);
|
|
193
|
+
}
|
|
174
194
|
return item.id;
|
|
175
195
|
}
|
|
176
196
|
|
package/engine.js
CHANGED
|
@@ -4315,7 +4315,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4315
4315
|
const item = buildPrDispatch(agentId, config, project, pr, 'review', {
|
|
4316
4316
|
pr_id: pr.id, pr_number: prNumber, pr_title: pr.title || '', pr_branch: prBranch,
|
|
4317
4317
|
pr_author: pr.agent || '', pr_url: pr.url || '',
|
|
4318
|
-
}, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4318
|
+
}, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4319
4319
|
if (item) { newWork.push(item); fixDispatched = true; }
|
|
4320
4320
|
}
|
|
4321
4321
|
|
|
@@ -4424,7 +4424,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4424
4424
|
pr_id: pr.id, pr_number: prNumber, pr_title: pr.title || '', pr_branch: prBranch,
|
|
4425
4425
|
reviewer: 'Human Reviewer',
|
|
4426
4426
|
review_note: reviewNote,
|
|
4427
|
-
}, `Fix ${pr.id}: ${pr.title || ''} — human feedback`, { dispatchKey: key, automationCauseKey: humanCauseKey, source: 'pr-human-feedback', pr, branch: prBranch, project: projMeta });
|
|
4427
|
+
}, `Fix ${pr.id}: ${pr.title || ''} — human feedback`, { dispatchKey: key, cooldownKey: key, automationCauseKey: humanCauseKey, source: 'pr-human-feedback', pr, branch: prBranch, project: projMeta });
|
|
4428
4428
|
if (item) { newWork.push(item); fixDispatched = true; }
|
|
4429
4429
|
} // end if (!skipHumanFeedback) — cause-local guard for #2632
|
|
4430
4430
|
}
|
|
@@ -4478,7 +4478,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4478
4478
|
pr_id: pr.id, pr_number: prNumber, pr_title: pr.title || '', pr_branch: prBranch,
|
|
4479
4479
|
pr_author: pr.agent || '', pr_url: pr.url || '',
|
|
4480
4480
|
}, `Review ${pr.id}: ${pr.title}`, {
|
|
4481
|
-
dispatchKey: key, source: 'pr', pr, branch: prBranch, project: projMeta,
|
|
4481
|
+
dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta,
|
|
4482
4482
|
deferReviewerResolution: true,
|
|
4483
4483
|
});
|
|
4484
4484
|
if (deferred) {
|
|
@@ -4492,7 +4492,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4492
4492
|
const item = buildPrDispatch(agentId, config, project, pr, 'review', {
|
|
4493
4493
|
pr_id: pr.id, pr_number: prNumber, pr_title: pr.title || '', pr_branch: prBranch,
|
|
4494
4494
|
pr_author: pr.agent || '', pr_url: pr.url || '',
|
|
4495
|
-
}, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4495
|
+
}, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4496
4496
|
if (item) { newWork.push(item); }
|
|
4497
4497
|
}
|
|
4498
4498
|
|
|
@@ -4513,7 +4513,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4513
4513
|
pr_id: pr.id, pr_branch: prBranch,
|
|
4514
4514
|
review_note: pr.minionsReview?.note || pr.reviewNote || 'See PR thread comments',
|
|
4515
4515
|
}, `Fix ${pr.id}: ${pr.title || ''} — review feedback`, {
|
|
4516
|
-
dispatchKey: key, automationCauseKey: reviewCauseKey, source: 'pr', pr, branch: prBranch, project: projMeta,
|
|
4516
|
+
dispatchKey: key, cooldownKey: key, automationCauseKey: reviewCauseKey, source: 'pr', pr, branch: prBranch, project: projMeta,
|
|
4517
4517
|
// W-mpg58wv3 — closure-loop binding. Carries the originating minion review
|
|
4518
4518
|
// WI id (and any ADO thread ids it cited) onto the fix WI so the
|
|
4519
4519
|
// post-completion path in lifecycle.js can auto-dispatch a re-review
|
|
@@ -4523,7 +4523,7 @@ async function discoverFromPrs(config, project) {
|
|
|
4523
4523
|
addresses_threads: Array.isArray(pr.minionsReview?.threads) ? pr.minionsReview.threads.slice() : [],
|
|
4524
4524
|
});
|
|
4525
4525
|
if (item) {
|
|
4526
|
-
newWork.push(item);
|
|
4526
|
+
newWork.push(item); fixDispatched = true;
|
|
4527
4527
|
}
|
|
4528
4528
|
}
|
|
4529
4529
|
|
|
@@ -4635,9 +4635,9 @@ async function discoverFromPrs(config, project) {
|
|
|
4635
4635
|
const item = buildPrDispatch(agentId, config, project, pr, 'fix', {
|
|
4636
4636
|
pr_id: pr.id, pr_branch: prBranch,
|
|
4637
4637
|
review_note: reviewNote,
|
|
4638
|
-
}, `Fix build failure on ${pr.id}: ${pr.title || ''}`, { dispatchKey: key, automationCauseKey: buildCauseKey, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4638
|
+
}, `Fix build failure on ${pr.id}: ${pr.title || ''}`, { dispatchKey: key, cooldownKey: key, automationCauseKey: buildCauseKey, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4639
4639
|
if (item) {
|
|
4640
|
-
newWork.push(item);
|
|
4640
|
+
newWork.push(item); fixDispatched = true;
|
|
4641
4641
|
try {
|
|
4642
4642
|
const prPath = projectPrPath(project);
|
|
4643
4643
|
mutatePullRequests(prPath, prs => {
|
|
@@ -4707,10 +4707,9 @@ async function discoverFromPrs(config, project) {
|
|
|
4707
4707
|
const item = buildPrDispatch(agentId, config, project, pr, 'fix', {
|
|
4708
4708
|
pr_id: pr.id, pr_branch: prBranch,
|
|
4709
4709
|
review_note: `This PR has merge conflicts with the target branch. Inspect the live PR and repository history, choose the safest merge/rebase/update strategy, resolve all conflicts, validate the result, and push the branch.`,
|
|
4710
|
-
}, `Fix merge conflicts on ${pr.id}: ${pr.title || ''}`, { dispatchKey: key, automationCauseKey: conflictCauseKey, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4710
|
+
}, `Fix merge conflicts on ${pr.id}: ${pr.title || ''}`, { dispatchKey: key, cooldownKey: key, automationCauseKey: conflictCauseKey, source: 'pr', pr, branch: prBranch, project: projMeta });
|
|
4711
4711
|
if (item) {
|
|
4712
4712
|
newWork.push(item);
|
|
4713
|
-
setCooldown(key);
|
|
4714
4713
|
// Record dispatch timestamp so re-dispatch is suppressed during ADO lag window
|
|
4715
4714
|
try {
|
|
4716
4715
|
mutatePullRequests(projectPrPath(project), prs => {
|
|
@@ -5123,10 +5122,9 @@ function discoverFromWorkItems(config, project) {
|
|
|
5123
5122
|
agentRole: config.agents[agentId]?.role || tempAgents.get(agentId)?.role || 'Agent',
|
|
5124
5123
|
task: `[${project?.name || 'project'}] ${item.title || item.description?.slice(0, 80) || item.id}`,
|
|
5125
5124
|
prompt,
|
|
5126
|
-
meta: { dispatchKey: key, source: 'work-item', branch: branchName, branchStrategy: item.branchStrategy || 'parallel', useExistingBranch: !!(isPrTargeted || (item.branchStrategy === 'shared-branch' && item.featureBranch)), item: promptItem, project: { name: project?.name, localPath: project?.localPath }, deferAgentResolution: deferredAgentResolution, ...(linkedPr ? { pr: linkedPr } : {}) }
|
|
5125
|
+
meta: { dispatchKey: key, cooldownKey: key, source: 'work-item', branch: branchName, branchStrategy: item.branchStrategy || 'parallel', useExistingBranch: !!(isPrTargeted || (item.branchStrategy === 'shared-branch' && item.featureBranch)), item: promptItem, project: { name: project?.name, localPath: project?.localPath }, deferAgentResolution: deferredAgentResolution, ...(linkedPr ? { pr: linkedPr } : {}) }
|
|
5127
5126
|
});
|
|
5128
5127
|
|
|
5129
|
-
setCooldown(key);
|
|
5130
5128
|
} catch (err) { log('warn', `discoverFromWorkItems: skipping ${item.id}: ${err.message}`); }
|
|
5131
5129
|
}
|
|
5132
5130
|
|
|
@@ -5567,7 +5565,7 @@ function discoverCentralWorkItems(config) {
|
|
|
5567
5565
|
task: `[fan-out] ${item.title} → ${agent.name}${assignedProject ? ' → ' + assignedProject.name : ''}`,
|
|
5568
5566
|
prompt,
|
|
5569
5567
|
meta: {
|
|
5570
|
-
dispatchKey: fanKey, source: 'central-work-item-fanout', item, parentKey: key,
|
|
5568
|
+
dispatchKey: fanKey, cooldownKey: key, source: 'central-work-item-fanout', item, parentKey: key,
|
|
5571
5569
|
branch: fanBranch,
|
|
5572
5570
|
deadline: item.timeout ? Date.now() + item.timeout : Date.now() + (config.engine?.fanOutTimeout || config.engine?.agentTimeout || ENGINE_DEFAULTS.agentTimeout)
|
|
5573
5571
|
}
|
|
@@ -5579,7 +5577,6 @@ function discoverCentralWorkItems(config) {
|
|
|
5579
5577
|
scope: 'fan-out',
|
|
5580
5578
|
fanOutAgents: idleAgents.map(a => a.id),
|
|
5581
5579
|
});
|
|
5582
|
-
setCooldown(key);
|
|
5583
5580
|
log('info', `Fan-out: ${item.id} queued for ${idleAgents.length} agents: ${idleAgents.map(a => a.name).join(', ')}`);
|
|
5584
5581
|
|
|
5585
5582
|
} else {
|
|
@@ -5793,10 +5790,8 @@ function discoverCentralWorkItems(config) {
|
|
|
5793
5790
|
agentRole,
|
|
5794
5791
|
task: item.title || item.description?.slice(0, 80) || item.id,
|
|
5795
5792
|
prompt,
|
|
5796
|
-
meta: { dispatchKey: key, source: 'central-work-item', item: { ...item, ...mutations.get(item.id) }, planFileName: item.planFile || mutations.get(item.id)?._planFileName || null, branch: centralBranch, ...(targetProject ? { project: { name: targetProject.name, localPath: targetProject.localPath } } : {}) }
|
|
5793
|
+
meta: { dispatchKey: key, cooldownKey: key, source: 'central-work-item', item: { ...item, ...mutations.get(item.id) }, planFileName: item.planFile || mutations.get(item.id)?._planFileName || null, branch: centralBranch, ...(targetProject ? { project: { name: targetProject.name, localPath: targetProject.localPath } } : {}) }
|
|
5797
5794
|
});
|
|
5798
|
-
|
|
5799
|
-
setCooldown(key);
|
|
5800
5795
|
}
|
|
5801
5796
|
} catch (err) { log('warn', `discoverCentralWorkItems: skipping ${item.id}: ${err.message}`); }
|
|
5802
5797
|
}
|
|
@@ -6004,7 +5999,10 @@ async function discoverWork(config) {
|
|
|
6004
5999
|
|
|
6005
6000
|
for (const item of allWork) {
|
|
6006
6001
|
await addToDispatchWithValidation(item, { config });
|
|
6007
|
-
|
|
6002
|
+
// W-mph8xt88000ke0fc — Cooldowns are stamped by addToDispatch ONLY on
|
|
6003
|
+
// successful append (post-dedup). Stamping unconditionally here used to
|
|
6004
|
+
// leave orphan cooldowns for items collapsed by prDedupeKey / workItem-id
|
|
6005
|
+
// / dispatchKey dedup or routed to the pre-dispatch review queue.
|
|
6008
6006
|
if (item.meta?.source === 'pr-human-feedback') {
|
|
6009
6007
|
clearPendingHumanFeedbackFlag(item.meta.project, item.meta.pr?.id);
|
|
6010
6008
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2030",
|
|
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"
|