@yemi33/minions 0.1.1003 → 0.1.1005
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 +3 -2
- package/dashboard.js +13 -3
- package/engine/ado-status.js +2 -1
- package/engine/ado.js +22 -21
- package/engine/consolidation.js +2 -2
- package/engine/dispatch.js +4 -3
- package/engine/github.js +11 -20
- package/engine/lifecycle.js +102 -55
- package/engine/pipeline.js +1 -1
- package/engine/queries.js +39 -16
- package/engine/shared.js +287 -12
- package/engine/teams.js +1 -1
- package/engine/watches.js +10 -6
- package/engine.js +52 -42
- package/package.json +1 -1
package/engine.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
const fs = require('fs');
|
|
25
25
|
const path = require('path');
|
|
26
26
|
const shared = require('./engine/shared');
|
|
27
|
-
const { exec, execAsync, execSilent, runFile, ts, ENGINE_DEFAULTS
|
|
27
|
+
const { exec, execAsync, execSilent, runFile, ts, ENGINE_DEFAULTS,
|
|
28
28
|
WI_STATUS, DONE_STATUSES, WORK_TYPE, PLAN_STATUS, PRD_ITEM_STATUS, PRD_MATERIALIZABLE, PR_STATUS, DISPATCH_RESULT, AGENT_STATUS,
|
|
29
29
|
FAILURE_CLASS } = shared;
|
|
30
30
|
const queries = require('./engine/queries');
|
|
@@ -241,8 +241,8 @@ function _maxTurnsForType(type, engineConfig) {
|
|
|
241
241
|
// Priority: per-type config override → global config override → built-in per-type default → global default
|
|
242
242
|
const perType = engineConfig.maxTurnsByType || {};
|
|
243
243
|
if (perType[type]) return perType[type];
|
|
244
|
-
const globalOverride = engineConfig.maxTurns && engineConfig.maxTurns !==
|
|
245
|
-
return globalOverride || _MAX_TURNS_BY_TYPE[type] ||
|
|
244
|
+
const globalOverride = engineConfig.maxTurns && engineConfig.maxTurns !== ENGINE_DEFAULTS.maxTurns ? engineConfig.maxTurns : null;
|
|
245
|
+
return globalOverride || _MAX_TURNS_BY_TYPE[type] || ENGINE_DEFAULTS.maxTurns;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
// Resolve dependency plan item IDs to their PR branches
|
|
@@ -373,8 +373,8 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
373
373
|
let cwd = rootDir;
|
|
374
374
|
let worktreePath = null;
|
|
375
375
|
let branchName = meta?.branch ? sanitizeBranch(meta.branch) : null;
|
|
376
|
-
const worktreeCreateTimeout = Math.max(60000, Number(engineConfig.worktreeCreateTimeout) ||
|
|
377
|
-
const worktreeCreateRetries = Math.max(0, Math.min(3, Number(engineConfig.worktreeCreateRetries) ||
|
|
376
|
+
const worktreeCreateTimeout = Math.max(60000, Number(engineConfig.worktreeCreateTimeout) || ENGINE_DEFAULTS.worktreeCreateTimeout);
|
|
377
|
+
const worktreeCreateRetries = Math.max(0, Math.min(3, Number(engineConfig.worktreeCreateRetries) || ENGINE_DEFAULTS.worktreeCreateRetries));
|
|
378
378
|
const _gitOpts = { stdio: 'pipe', timeout: 30000, windowsHide: true, env: shared.gitEnv() };
|
|
379
379
|
const _worktreeGitOpts = { ..._gitOpts, timeout: worktreeCreateTimeout };
|
|
380
380
|
|
|
@@ -1021,7 +1021,7 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1021
1021
|
// Build resume args
|
|
1022
1022
|
const resumeArgs = [
|
|
1023
1023
|
'--output-format', claudeConfig?.outputFormat || 'stream-json',
|
|
1024
|
-
'--max-turns', String(engineConfig?.maxTurns ||
|
|
1024
|
+
'--max-turns', String(engineConfig?.maxTurns || ENGINE_DEFAULTS.maxTurns),
|
|
1025
1025
|
'--verbose',
|
|
1026
1026
|
'--permission-mode', claudeConfig?.permissionMode || 'bypassPermissions',
|
|
1027
1027
|
'--resume', steerSessionId,
|
|
@@ -1427,7 +1427,7 @@ function reconcileItemsWithPrs(items, allPrs, { onlyIds } = {}) {
|
|
|
1427
1427
|
|
|
1428
1428
|
let exactPr = allPrs.find(pr => (pr.prdItems || []).includes(wi.id));
|
|
1429
1429
|
if (!exactPr) {
|
|
1430
|
-
const linkedPrId = Object.keys(prLinks).find(prId => prLinks[prId]
|
|
1430
|
+
const linkedPrId = Object.keys(prLinks).find(prId => (prLinks[prId] || []).includes(wi.id));
|
|
1431
1431
|
if (linkedPrId) exactPr = allPrs.find(pr => pr.id === linkedPrId) || { id: linkedPrId };
|
|
1432
1432
|
}
|
|
1433
1433
|
// Branch-based matching: PR branch contains the work item ID (e.g. work/P-k7m2v9a1)
|
|
@@ -1878,7 +1878,7 @@ function clearPendingHumanFeedbackFlag(projectMeta, prId) {
|
|
|
1878
1878
|
try {
|
|
1879
1879
|
const prsPath = projectPrPath(projectMeta);
|
|
1880
1880
|
mutatePullRequests(prsPath, prs => {
|
|
1881
|
-
const target =
|
|
1881
|
+
const target = shared.findPrRecord(prs, prId, projectMeta);
|
|
1882
1882
|
if (!target?.humanFeedback?.pendingFix) return;
|
|
1883
1883
|
target.humanFeedback.pendingFix = false;
|
|
1884
1884
|
});
|
|
@@ -1892,28 +1892,38 @@ async function discoverFromPrs(config, project) {
|
|
|
1892
1892
|
const src = project?.workSources?.pullRequests || config.workSources?.pullRequests;
|
|
1893
1893
|
if (!src?.enabled) return [];
|
|
1894
1894
|
|
|
1895
|
-
const prs =
|
|
1895
|
+
const prs = queries.getPrs(project);
|
|
1896
1896
|
const cooldownMs = (src.cooldownMinutes || 30) * 60 * 1000;
|
|
1897
1897
|
const newWork = [];
|
|
1898
1898
|
|
|
1899
1899
|
const projMeta = { name: project?.name, localPath: project?.localPath };
|
|
1900
|
+
const projectsByName = new Map(shared.getProjects(config).map(p => [p.name, p]));
|
|
1900
1901
|
|
|
1901
1902
|
// Resolve poll-enabled per project — stale reviewStatus is untrustworthy without poller
|
|
1902
1903
|
const isAdoProject = project?.repoHost !== 'github';
|
|
1903
1904
|
const pollEnabled = isAdoProject
|
|
1904
|
-
? (config.engine?.adoPollEnabled ??
|
|
1905
|
-
: (config.engine?.ghPollEnabled ??
|
|
1905
|
+
? (config.engine?.adoPollEnabled ?? ENGINE_DEFAULTS.adoPollEnabled)
|
|
1906
|
+
: (config.engine?.ghPollEnabled ?? ENGINE_DEFAULTS.ghPollEnabled);
|
|
1906
1907
|
const evalLoopEnabled = config.engine?.evalLoop !== false;
|
|
1907
1908
|
|
|
1908
1909
|
// Collect active PR dispatches to prevent simultaneous review+fix on same PR
|
|
1909
1910
|
const dispatch = getDispatch();
|
|
1910
1911
|
const activePrIds = new Set(
|
|
1911
|
-
(dispatch.active || [])
|
|
1912
|
+
(dispatch.active || [])
|
|
1913
|
+
.filter(d => d.meta?.pr?.id)
|
|
1914
|
+
.map(d => {
|
|
1915
|
+
const dispatchProject = d.meta?.project?.name
|
|
1916
|
+
? (projectsByName.get(d.meta.project.name) || d.meta.project)
|
|
1917
|
+
: (d.meta?.project || null);
|
|
1918
|
+
return shared.getCanonicalPrId(dispatchProject, d.meta.pr, d.meta.pr?.url || '');
|
|
1919
|
+
})
|
|
1920
|
+
.filter(Boolean)
|
|
1912
1921
|
);
|
|
1913
1922
|
|
|
1914
1923
|
const knownAgents = new Set(Object.keys(config.agents || {}));
|
|
1915
1924
|
for (const pr of prs) {
|
|
1916
1925
|
if (pr.status !== PR_STATUS.ACTIVE || pr._contextOnly) continue;
|
|
1926
|
+
const prDisplayId = shared.getPrDisplayId(pr);
|
|
1917
1927
|
if (activePrIds.has(pr.id)) continue; // Skip PRs with active dispatch (prevent race)
|
|
1918
1928
|
// Branch mutex: skip if PR branch is locked by any active dispatch (cross-type collision)
|
|
1919
1929
|
if (pr.branch && isBranchActive(pr.branch)) {
|
|
@@ -1925,7 +1935,7 @@ async function discoverFromPrs(config, project) {
|
|
|
1925
1935
|
const isAgentPr = knownAgents.has((pr.agent || '').toLowerCase()) || (pr.prdItems && pr.prdItems.length > 0) || pr._autoObserve;
|
|
1926
1936
|
if (!isAgentPr) continue;
|
|
1927
1937
|
|
|
1928
|
-
const prNumber = (pr
|
|
1938
|
+
const prNumber = shared.getPrNumber(pr);
|
|
1929
1939
|
// Use reviewStatus as single source of truth (synced from ADO/GitHub votes)
|
|
1930
1940
|
// minionsReview tracks metadata (reviewer, note) but not the authoritative status
|
|
1931
1941
|
const reviewStatus = pr.reviewStatus || 'pending';
|
|
@@ -1935,17 +1945,17 @@ async function discoverFromPrs(config, project) {
|
|
|
1935
1945
|
const awaitingReReview = reviewStatus === 'waiting' && !!pr.minionsReview?.fixedAt;
|
|
1936
1946
|
|
|
1937
1947
|
// Review→fix cycle cap — stop review/fix dispatch after N iterations, but allow build fixes and conflict fixes
|
|
1938
|
-
const evalMax = config.engine?.evalMaxIterations ??
|
|
1948
|
+
const evalMax = config.engine?.evalMaxIterations ?? ENGINE_DEFAULTS.evalMaxIterations;
|
|
1939
1949
|
const evalCycles = pr._reviewFixCycles || 0;
|
|
1940
1950
|
const evalEscalated = evalCycles >= evalMax;
|
|
1941
1951
|
if (evalEscalated && !pr._evalEscalated) {
|
|
1942
|
-
writeInboxAlert(`eval-escalated-${pr.agent || 'unassigned'}-${
|
|
1952
|
+
writeInboxAlert(`eval-escalated-${pr.agent || 'unassigned'}-${prDisplayId}`,
|
|
1943
1953
|
`# Review Loop Escalation\n\n**PR ${pr.id}**: ${pr.title || ''} on branch \`${pr.branch || 'unknown'}\` has gone through **${evalCycles}** review→fix cycles without approval.\n\n` +
|
|
1944
1954
|
`Last review: ${pr.minionsReview?.note ? pr.minionsReview.note.slice(0, 200) : 'See PR thread'}\n\n` +
|
|
1945
1955
|
`Auto-dispatch of reviews and fixes has been suspended. Please review the PR manually.`);
|
|
1946
1956
|
try {
|
|
1947
1957
|
mutatePullRequests(projectPrPath(project), prs => {
|
|
1948
|
-
const target =
|
|
1958
|
+
const target = shared.findPrRecord(prs, pr, project);
|
|
1949
1959
|
if (target) target._evalEscalated = true;
|
|
1950
1960
|
});
|
|
1951
1961
|
} catch (e) { log('warn', 'mark eval escalated: ' + e.message); }
|
|
@@ -1957,7 +1967,7 @@ async function discoverFromPrs(config, project) {
|
|
|
1957
1967
|
const alreadyReviewed = pr.lastReviewedAt && (!pr.lastPushedAt || pr.lastPushedAt <= pr.lastReviewedAt);
|
|
1958
1968
|
const needsReview = reviewEnabled && reviewStatus === 'pending' && !alreadyReviewed && !evalEscalated;
|
|
1959
1969
|
if (needsReview) {
|
|
1960
|
-
const key = `review-${project?.name || 'default'}-${
|
|
1970
|
+
const key = `review-${project?.name || 'default'}-${prDisplayId}`;
|
|
1961
1971
|
if (isAlreadyDispatched(key) || isOnCooldown(key, cooldownMs)) continue;
|
|
1962
1972
|
|
|
1963
1973
|
// Pre-dispatch live vote check — cached reviewStatus may be stale (poll lag ~6 min)
|
|
@@ -1972,7 +1982,7 @@ async function discoverFromPrs(config, project) {
|
|
|
1972
1982
|
try {
|
|
1973
1983
|
mutateJsonFileLocked(projectPrPath(project), data => {
|
|
1974
1984
|
if (!Array.isArray(data)) return data;
|
|
1975
|
-
const target =
|
|
1985
|
+
const target = shared.findPrRecord(data, pr, project);
|
|
1976
1986
|
if (target && target.reviewStatus !== 'approved') target.reviewStatus = liveStatus;
|
|
1977
1987
|
return data;
|
|
1978
1988
|
});
|
|
@@ -1998,7 +2008,7 @@ async function discoverFromPrs(config, project) {
|
|
|
1998
2008
|
const needsReReview = reviewEnabled && reviewStatus === 'waiting' &&
|
|
1999
2009
|
fixedAfterReview && !evalEscalated;
|
|
2000
2010
|
if (needsReReview) {
|
|
2001
|
-
const key = `rereview-${project?.name || 'default'}-${
|
|
2011
|
+
const key = `rereview-${project?.name || 'default'}-${prDisplayId}`;
|
|
2002
2012
|
// Skip isAlreadyDispatched — fixedAfterReview/lastReviewedAt already dedupe; the 1hr
|
|
2003
2013
|
// completed-dispatch window would block legitimate re-reviews within the hour after a fix
|
|
2004
2014
|
if (isOnCooldown(key, cooldownMs)) continue;
|
|
@@ -2013,7 +2023,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2013
2023
|
try {
|
|
2014
2024
|
mutateJsonFileLocked(projectPrPath(project), data => {
|
|
2015
2025
|
if (!Array.isArray(data)) return data;
|
|
2016
|
-
const target =
|
|
2026
|
+
const target = shared.findPrRecord(data, pr, project);
|
|
2017
2027
|
if (target && target.reviewStatus !== 'approved') target.reviewStatus = liveStatus;
|
|
2018
2028
|
return data;
|
|
2019
2029
|
});
|
|
@@ -2036,7 +2046,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2036
2046
|
// Gate on evalLoopEnabled — the review→fix cycle is the eval loop
|
|
2037
2047
|
let fixDispatched = false;
|
|
2038
2048
|
if (evalLoopEnabled && reviewStatus === 'changes-requested' && !awaitingReReview && !evalEscalated) {
|
|
2039
|
-
const key = `fix-${project?.name || 'default'}-${
|
|
2049
|
+
const key = `fix-${project?.name || 'default'}-${prDisplayId}`;
|
|
2040
2050
|
if (isAlreadyDispatched(key) || isOnCooldown(key, cooldownMs)) continue;
|
|
2041
2051
|
const agentId = resolveAgent('fix', config, pr.agent);
|
|
2042
2052
|
if (!agentId) continue;
|
|
@@ -2050,7 +2060,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2050
2060
|
// Increment review→fix cycle counter
|
|
2051
2061
|
try {
|
|
2052
2062
|
mutatePullRequests(projectPrPath(project), prs => {
|
|
2053
|
-
const target =
|
|
2063
|
+
const target = shared.findPrRecord(prs, pr, project);
|
|
2054
2064
|
if (target) target._reviewFixCycles = (target._reviewFixCycles || 0) + 1;
|
|
2055
2065
|
});
|
|
2056
2066
|
} catch (e) { log('warn', 'increment review-fix cycles: ' + e.message); }
|
|
@@ -2058,7 +2068,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2058
2068
|
}
|
|
2059
2069
|
|
|
2060
2070
|
// PRs with pending human feedback (skip if review-fix already dispatched above)
|
|
2061
|
-
const humanFixKey = `human-fix-${project?.name || 'default'}-${
|
|
2071
|
+
const humanFixKey = `human-fix-${project?.name || 'default'}-${prDisplayId}`;
|
|
2062
2072
|
const hasCoalescedFeedback = (dispatchCooldowns.get(humanFixKey)?.pendingContexts || []).length > 0;
|
|
2063
2073
|
if ((pr.humanFeedback?.pendingFix || hasCoalescedFeedback) && !awaitingReReview && !fixDispatched) {
|
|
2064
2074
|
const key = humanFixKey;
|
|
@@ -2099,17 +2109,17 @@ async function discoverFromPrs(config, project) {
|
|
|
2099
2109
|
// Grace period: after a build fix push, wait for CI to run before re-dispatching
|
|
2100
2110
|
// Skip if build hasn't transitioned since last fix (still showing the old failure)
|
|
2101
2111
|
if (pr._buildFixPushedAt && pr.buildStatus === 'failing') {
|
|
2102
|
-
const gracePeriodMs = config.engine?.buildFixGracePeriod ??
|
|
2112
|
+
const gracePeriodMs = config.engine?.buildFixGracePeriod ?? ENGINE_DEFAULTS.buildFixGracePeriod;
|
|
2103
2113
|
if (Date.now() - new Date(pr._buildFixPushedAt).getTime() < gracePeriodMs) continue;
|
|
2104
2114
|
}
|
|
2105
|
-
const autoFixBuilds = config.engine?.autoFixBuilds ??
|
|
2115
|
+
const autoFixBuilds = config.engine?.autoFixBuilds ?? ENGINE_DEFAULTS.autoFixBuilds;
|
|
2106
2116
|
if (autoFixBuilds && pr.status === PR_STATUS.ACTIVE && pr.buildStatus === 'failing') {
|
|
2107
|
-
const maxBuildFix = config.engine?.maxBuildFixAttempts ??
|
|
2117
|
+
const maxBuildFix = config.engine?.maxBuildFixAttempts ?? ENGINE_DEFAULTS.maxBuildFixAttempts;
|
|
2108
2118
|
|
|
2109
2119
|
// Check if max retry cap reached — escalate to human instead of dispatching another fix
|
|
2110
2120
|
if ((pr.buildFixAttempts || 0) >= maxBuildFix) {
|
|
2111
2121
|
if (!pr.buildFixEscalated) {
|
|
2112
|
-
writeInboxAlert(`build-fix-escalated-${pr.agent || 'unassigned'}-${
|
|
2122
|
+
writeInboxAlert(`build-fix-escalated-${pr.agent || 'unassigned'}-${prDisplayId}`,
|
|
2113
2123
|
`# Build Fix Escalation\n\n` +
|
|
2114
2124
|
`**PR ${pr.id}**: ${pr.title || ''} on branch \`${pr.branch || 'unknown'}\` has failed **${pr.buildFixAttempts}** consecutive auto-fix attempts.\n` +
|
|
2115
2125
|
`**Last failure:** ${pr.buildFailReason || 'Check CI pipeline for details'}\n\n` +
|
|
@@ -2118,7 +2128,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2118
2128
|
try {
|
|
2119
2129
|
const prPath = projectPrPath(project);
|
|
2120
2130
|
mutatePullRequests(prPath, prs => {
|
|
2121
|
-
const target =
|
|
2131
|
+
const target = shared.findPrRecord(prs, pr, project);
|
|
2122
2132
|
if (target) target.buildFixEscalated = true;
|
|
2123
2133
|
});
|
|
2124
2134
|
} catch (e) { log('warn', 'mark build fix escalated: ' + e.message); }
|
|
@@ -2127,7 +2137,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2127
2137
|
continue;
|
|
2128
2138
|
}
|
|
2129
2139
|
|
|
2130
|
-
const key = `build-fix-${project?.name || 'default'}-${
|
|
2140
|
+
const key = `build-fix-${project?.name || 'default'}-${prDisplayId}`;
|
|
2131
2141
|
if (isAlreadyDispatched(key) || isOnCooldown(key, cooldownMs)) continue;
|
|
2132
2142
|
const agentId = resolveAgent('fix', config, pr.agent);
|
|
2133
2143
|
if (!agentId) continue;
|
|
@@ -2147,7 +2157,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2147
2157
|
try {
|
|
2148
2158
|
const prPath = projectPrPath(project);
|
|
2149
2159
|
mutatePullRequests(prPath, prs => {
|
|
2150
|
-
const target =
|
|
2160
|
+
const target = shared.findPrRecord(prs, pr, project);
|
|
2151
2161
|
if (target) {
|
|
2152
2162
|
target.buildFixAttempts = (target.buildFixAttempts || 0) + 1;
|
|
2153
2163
|
target._buildFixPushedAt = ts();
|
|
@@ -2167,12 +2177,12 @@ async function discoverFromPrs(config, project) {
|
|
|
2167
2177
|
alertBody += `**Error preview:**\n\`\`\`\n${logPreview}\n\`\`\`\n\n`;
|
|
2168
2178
|
}
|
|
2169
2179
|
alertBody += `A fix agent has been dispatched to address this. Review the fix when complete.\n`;
|
|
2170
|
-
writeInboxAlert(`build-fail-${pr.agent}-${
|
|
2180
|
+
writeInboxAlert(`build-fail-${pr.agent}-${prDisplayId}`, alertBody);
|
|
2171
2181
|
// Mark notified to prevent duplicate alerts
|
|
2172
2182
|
try {
|
|
2173
2183
|
const prPath = projectPrPath(project);
|
|
2174
2184
|
mutatePullRequests(prPath, prs => {
|
|
2175
|
-
const target =
|
|
2185
|
+
const target = shared.findPrRecord(prs, pr, project);
|
|
2176
2186
|
if (target) {
|
|
2177
2187
|
target._buildFailNotified = true;
|
|
2178
2188
|
}
|
|
@@ -2182,9 +2192,9 @@ async function discoverFromPrs(config, project) {
|
|
|
2182
2192
|
}
|
|
2183
2193
|
|
|
2184
2194
|
// PRs with merge conflicts — dispatch fix to resolve (gated by autoFixConflicts)
|
|
2185
|
-
const autoFixConflicts = config.engine?.autoFixConflicts ??
|
|
2195
|
+
const autoFixConflicts = config.engine?.autoFixConflicts ?? ENGINE_DEFAULTS.autoFixConflicts;
|
|
2186
2196
|
if (autoFixConflicts && pr.status === PR_STATUS.ACTIVE && pr._mergeConflict && !fixDispatched) {
|
|
2187
|
-
const key = `conflict-fix-${project?.name || 'default'}-${
|
|
2197
|
+
const key = `conflict-fix-${project?.name || 'default'}-${prDisplayId}`;
|
|
2188
2198
|
// Suppress re-dispatch for 10 min after last attempt — ADO/GitHub recomputes
|
|
2189
2199
|
// mergeStatus asynchronously (1–5 min lag), so the flag may stay set even after
|
|
2190
2200
|
// a successful push. _conflictFixedAt is cleared when the poller confirms clean status.
|
|
@@ -2203,7 +2213,7 @@ async function discoverFromPrs(config, project) {
|
|
|
2203
2213
|
// Record dispatch timestamp so re-dispatch is suppressed during ADO lag window
|
|
2204
2214
|
try {
|
|
2205
2215
|
mutatePullRequests(projectPrPath(project), prs => {
|
|
2206
|
-
const target =
|
|
2216
|
+
const target = shared.findPrRecord(prs, pr, project);
|
|
2207
2217
|
if (target) target._conflictFixedAt = new Date().toISOString();
|
|
2208
2218
|
});
|
|
2209
2219
|
} catch (e) { log('warn', `conflict-fix timestamp: ${e.message}`); }
|
|
@@ -2808,7 +2818,7 @@ function discoverCentralWorkItems(config) {
|
|
|
2808
2818
|
meta: {
|
|
2809
2819
|
dispatchKey: fanKey, source: 'central-work-item-fanout', item, parentKey: key,
|
|
2810
2820
|
branch: fanBranch,
|
|
2811
|
-
deadline: item.timeout ? Date.now() + item.timeout : Date.now() + (config.engine?.fanOutTimeout || config.engine?.agentTimeout ||
|
|
2821
|
+
deadline: item.timeout ? Date.now() + item.timeout : Date.now() + (config.engine?.fanOutTimeout || config.engine?.agentTimeout || ENGINE_DEFAULTS.agentTimeout)
|
|
2812
2822
|
}
|
|
2813
2823
|
});
|
|
2814
2824
|
}
|
|
@@ -3088,7 +3098,7 @@ async function discoverWork(config) {
|
|
|
3088
3098
|
);
|
|
3089
3099
|
if (hasIncompleteImplements) {
|
|
3090
3100
|
const activeCount = (getDispatch().active || []).length;
|
|
3091
|
-
const maxConcurrent = config.engine?.maxConcurrent ??
|
|
3101
|
+
const maxConcurrent = config.engine?.maxConcurrent ?? ENGINE_DEFAULTS.maxConcurrent;
|
|
3092
3102
|
const freeSlots = Math.max(0, maxConcurrent - activeCount);
|
|
3093
3103
|
if (freeSlots === 0) {
|
|
3094
3104
|
if (allReviews.length > 0) {
|
|
@@ -3210,10 +3220,10 @@ async function tickInner() {
|
|
|
3210
3220
|
});
|
|
3211
3221
|
}
|
|
3212
3222
|
|
|
3213
|
-
const adoPollEnabled = config.engine?.adoPollEnabled ??
|
|
3214
|
-
const ghPollEnabled = config.engine?.ghPollEnabled ??
|
|
3215
|
-
const adoPollStatusEvery = Math.max(1, Number(config.engine?.adoPollStatusEvery) ||
|
|
3216
|
-
const adoPollCommentsEvery = Math.max(1, Number(config.engine?.adoPollCommentsEvery) ||
|
|
3223
|
+
const adoPollEnabled = config.engine?.adoPollEnabled ?? ENGINE_DEFAULTS.adoPollEnabled;
|
|
3224
|
+
const ghPollEnabled = config.engine?.ghPollEnabled ?? ENGINE_DEFAULTS.ghPollEnabled;
|
|
3225
|
+
const adoPollStatusEvery = Math.max(1, Number(config.engine?.adoPollStatusEvery) || ENGINE_DEFAULTS.adoPollStatusEvery);
|
|
3226
|
+
const adoPollCommentsEvery = Math.max(1, Number(config.engine?.adoPollCommentsEvery) || ENGINE_DEFAULTS.adoPollCommentsEvery);
|
|
3217
3227
|
|
|
3218
3228
|
// 2.6. Poll PR status: build, review, merge (every adoPollStatusEvery ticks, default ~6 minutes)
|
|
3219
3229
|
// Awaited so PR state is consistent before discoverWork reads it
|
|
@@ -3416,7 +3426,7 @@ async function tickInner() {
|
|
|
3416
3426
|
if (busyAgents.has(item.agent)) {
|
|
3417
3427
|
// Agent busy reassignment: if item has been waiting on a busy agent past the threshold,
|
|
3418
3428
|
// try to find an alternative agent via routing. Skip explicitly assigned items.
|
|
3419
|
-
const reassignMs = config.engine?.agentBusyReassignMs ??
|
|
3429
|
+
const reassignMs = config.engine?.agentBusyReassignMs ?? ENGINE_DEFAULTS.agentBusyReassignMs;
|
|
3420
3430
|
const isExplicitReassign = !!item.meta?.item?.agent;
|
|
3421
3431
|
if (!isExplicitReassign && reassignMs > 0 && item._agentBusySince) {
|
|
3422
3432
|
const busySinceMs = new Date(item._agentBusySince).getTime();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1005",
|
|
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"
|