@yemi33/minions 0.1.1706 → 0.1.1708
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 +5 -0
- package/engine/copilot-models.json +1 -1
- package/engine/preflight.js +18 -0
- package/engine/shared.js +66 -0
- package/engine.js +28 -2
- package/minions.js +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/engine/preflight.js
CHANGED
|
@@ -226,6 +226,24 @@ function runPreflight(opts = {}) {
|
|
|
226
226
|
results.push({ name: `Runtime config (${w.id})`, ok: 'warn', message: w.message });
|
|
227
227
|
}
|
|
228
228
|
} catch { /* defensive — preflight must never throw */ }
|
|
229
|
+
|
|
230
|
+
// Project workSources warnings — catches the silent-discovery footgun
|
|
231
|
+
// where a project (often added by a hand-rolled config or by cloning the
|
|
232
|
+
// repo without `minions init`) has no workSources block, so engine.js
|
|
233
|
+
// discoverFromWorkItems / discoverFromPrs return [] without logging.
|
|
234
|
+
try {
|
|
235
|
+
const projectWarns = shared.projectWorkSourceWarnings(opts.config, (project) => {
|
|
236
|
+
const wiPath = shared.projectWorkItemsPath(project);
|
|
237
|
+
const prPath = shared.projectPrPath(project);
|
|
238
|
+
const safeJson = shared.safeJson;
|
|
239
|
+
const wi = (() => { try { const a = safeJson(wiPath); return Array.isArray(a) ? a.length : 0; } catch { return 0; } })();
|
|
240
|
+
const pr = (() => { try { const a = safeJson(prPath); return Array.isArray(a) ? a.length : 0; } catch { return 0; } })();
|
|
241
|
+
return { workItems: wi, pullRequests: pr };
|
|
242
|
+
});
|
|
243
|
+
for (const w of projectWarns) {
|
|
244
|
+
results.push({ name: `Project config (${w.id})`, ok: 'warn', message: w.message });
|
|
245
|
+
}
|
|
246
|
+
} catch { /* defensive */ }
|
|
229
247
|
}
|
|
230
248
|
|
|
231
249
|
return { passed: allOk, results };
|
package/engine/shared.js
CHANGED
|
@@ -1120,6 +1120,71 @@ function runtimeConfigWarnings(config, registeredRuntimes) {
|
|
|
1120
1120
|
return warnings;
|
|
1121
1121
|
}
|
|
1122
1122
|
|
|
1123
|
+
/**
|
|
1124
|
+
* Detect projects whose discovery would silently no-op because the
|
|
1125
|
+
* `workSources` block is missing or its sub-flags are disabled. Catches the
|
|
1126
|
+
* common "I cloned the repo and ran it without `minions init`" footgun where
|
|
1127
|
+
* `engine.js` `discoverFromWorkItems` / `discoverFromPrs` bail on
|
|
1128
|
+
* `if (!src?.enabled) return [];` with no log output.
|
|
1129
|
+
*
|
|
1130
|
+
* Pure helper — pass `getDataCounts(project) → { workItems: N, pullRequests: N }`
|
|
1131
|
+
* so the caller controls disk reads (preflight reads files; tests inject counts).
|
|
1132
|
+
* If `getDataCounts` is omitted, every project with a missing/disabled source
|
|
1133
|
+
* is reported (caller decides whether to surface).
|
|
1134
|
+
*
|
|
1135
|
+
* Returns: `{ id, message, project }[]` — `id` is one of:
|
|
1136
|
+
* - `project-worksources-missing` — no workSources block at all
|
|
1137
|
+
* - `project-worksources-disabled` — block exists but a sub-source is disabled
|
|
1138
|
+
*/
|
|
1139
|
+
function projectWorkSourceWarnings(config, getDataCounts) {
|
|
1140
|
+
const warnings = [];
|
|
1141
|
+
if (!config || typeof config !== 'object') return warnings;
|
|
1142
|
+
const projects = Array.isArray(config.projects) ? config.projects : [];
|
|
1143
|
+
const topSources = config.workSources || null;
|
|
1144
|
+
for (const project of projects) {
|
|
1145
|
+
if (!project || typeof project !== 'object') continue;
|
|
1146
|
+
const projSources = project.workSources || null;
|
|
1147
|
+
const counts = (typeof getDataCounts === 'function')
|
|
1148
|
+
? (getDataCounts(project) || {})
|
|
1149
|
+
: { workItems: Infinity, pullRequests: Infinity };
|
|
1150
|
+
const wiCount = Number(counts.workItems) || 0;
|
|
1151
|
+
const prCount = Number(counts.pullRequests) || 0;
|
|
1152
|
+
|
|
1153
|
+
// Case 1: project has no workSources AND no top-level fallback. Discovery
|
|
1154
|
+
// will return [] for everything. This is the cloned-repo footgun.
|
|
1155
|
+
if (!projSources && !topSources) {
|
|
1156
|
+
if (wiCount > 0 || prCount > 0) {
|
|
1157
|
+
warnings.push({
|
|
1158
|
+
id: 'project-worksources-missing',
|
|
1159
|
+
project: project.name,
|
|
1160
|
+
message: `Project "${project.name}" has no workSources block — work-item and PR discovery are silently disabled (${wiCount} work item(s), ${prCount} PR(s) waiting). Run \`minions init\` if you cloned the repo directly, or re-link the project: \`minions add ${project.localPath || project.name}\`.`,
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// Case 2: workSources exists but a sub-source is disabled while data sits
|
|
1167
|
+
// unprocessed. Could be intentional, but worth surfacing.
|
|
1168
|
+
const wiSrc = projSources?.workItems || topSources?.workItems;
|
|
1169
|
+
if ((!wiSrc || wiSrc.enabled === false) && wiCount > 0) {
|
|
1170
|
+
warnings.push({
|
|
1171
|
+
id: 'project-worksources-disabled',
|
|
1172
|
+
project: project.name,
|
|
1173
|
+
message: `Project "${project.name}" has ${wiCount} unprocessed work item(s) but workSources.workItems.enabled is not true — engine will not dispatch them. Toggle in Dashboard → Settings → Project, or set \`workSources.workItems.enabled: true\` in config.json.`,
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
const prSrc = projSources?.pullRequests || topSources?.pullRequests;
|
|
1177
|
+
if ((!prSrc || prSrc.enabled === false) && prCount > 0) {
|
|
1178
|
+
warnings.push({
|
|
1179
|
+
id: 'project-worksources-disabled',
|
|
1180
|
+
project: project.name,
|
|
1181
|
+
message: `Project "${project.name}" has ${prCount} pull-request record(s) but workSources.pullRequests.enabled is not true — engine will not poll or review them. Toggle in Dashboard → Settings → Project, or set \`workSources.pullRequests.enabled: true\` in config.json.`,
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return warnings;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1123
1188
|
// ─── Status & Type Constants ─────────────────────────────────────────────────
|
|
1124
1189
|
|
|
1125
1190
|
const WI_STATUS = {
|
|
@@ -2515,6 +2580,7 @@ module.exports = {
|
|
|
2515
2580
|
resolveAgentMaxBudget, resolveAgentBareMode,
|
|
2516
2581
|
applyLegacyCcModelMigration, _resetLegacyCcModelMigrationFlag,
|
|
2517
2582
|
runtimeConfigWarnings,
|
|
2583
|
+
projectWorkSourceWarnings,
|
|
2518
2584
|
WI_STATUS, DONE_STATUSES, PLAN_TERMINAL_STATUSES, WORK_TYPE, PLAN_STATUS, PRD_ITEM_STATUS, PRD_MATERIALIZABLE, PR_STATUS, PR_POLLABLE_STATUSES, PR_PENDING_REASON, DISPATCH_RESULT, trackReviewMetric, queuePlanToPrd,
|
|
2519
2585
|
WATCH_STATUS, WATCH_TARGET_TYPE, WATCH_CONDITION, WATCH_ABSOLUTE_CONDITIONS,
|
|
2520
2586
|
PIPELINE_STATUS, STAGE_TYPE, MEETING_STATUS, AGENT_STATUS,
|
package/engine.js
CHANGED
|
@@ -2252,12 +2252,35 @@ function ensurePrBranchForDispatch(project, pr, automationType) {
|
|
|
2252
2252
|
}
|
|
2253
2253
|
|
|
2254
2254
|
|
|
2255
|
+
// Tracks per-process which silent-discovery warnings have already been logged
|
|
2256
|
+
// so we don't spam the log every tick. Cleared on process exit (no need to
|
|
2257
|
+
// persist — the warning is for the operator at engine startup/run time).
|
|
2258
|
+
const _warnedSilentDiscovery = new Set();
|
|
2259
|
+
|
|
2260
|
+
function _warnSilentDiscoveryOnce(kind, project, dataPath, config) {
|
|
2261
|
+
const key = `${kind}:${project?.name || project?.localPath || 'default'}`;
|
|
2262
|
+
if (_warnedSilentDiscovery.has(key)) return;
|
|
2263
|
+
let count = 0;
|
|
2264
|
+
try { const arr = safeJson(dataPath); if (Array.isArray(arr)) count = arr.length; } catch {}
|
|
2265
|
+
if (count <= 0) return; // empty file is fine — no warning worth surfacing
|
|
2266
|
+
_warnedSilentDiscovery.add(key);
|
|
2267
|
+
const projName = project?.name || '(unnamed)';
|
|
2268
|
+
const hasBlock = !!(project?.workSources?.[kind] || config?.workSources?.[kind]);
|
|
2269
|
+
const hint = hasBlock
|
|
2270
|
+
? `Toggle in Dashboard → Settings → Project, or set \`workSources.${kind}.enabled: true\` in config.json.`
|
|
2271
|
+
: `Run \`minions doctor\` to inspect, \`minions init\` if you cloned the repo without setup, or re-link the project: \`minions add ${project?.localPath || projName}\`.`;
|
|
2272
|
+
log('warn', `Silent-discovery footgun: project "${projName}" has ${count} record(s) in ${path.basename(dataPath)} but workSources.${kind}.enabled is not true — engine will not pick them up. ${hint}`);
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2255
2275
|
/**
|
|
2256
2276
|
* Scan pull-requests.json for PRs needing review or fixes
|
|
2257
2277
|
*/
|
|
2258
2278
|
async function discoverFromPrs(config, project) {
|
|
2259
2279
|
const src = project?.workSources?.pullRequests || config.workSources?.pullRequests;
|
|
2260
|
-
if (!src?.enabled)
|
|
2280
|
+
if (!src?.enabled) {
|
|
2281
|
+
_warnSilentDiscoveryOnce('pullRequests', project, projectPrPath(project), config);
|
|
2282
|
+
return [];
|
|
2283
|
+
}
|
|
2261
2284
|
|
|
2262
2285
|
const prs = queries.getPrs(project);
|
|
2263
2286
|
const cooldownMs = (src.cooldownMinutes || 30) * 60 * 1000;
|
|
@@ -2757,7 +2780,10 @@ function refreshDeferredWorkItemPrompt(item, config) {
|
|
|
2757
2780
|
|
|
2758
2781
|
function discoverFromWorkItems(config, project) {
|
|
2759
2782
|
const src = project?.workSources?.workItems || config.workSources?.workItems;
|
|
2760
|
-
if (!src?.enabled)
|
|
2783
|
+
if (!src?.enabled) {
|
|
2784
|
+
_warnSilentDiscoveryOnce('workItems', project, projectWorkItemsPath(project), config);
|
|
2785
|
+
return [];
|
|
2786
|
+
}
|
|
2761
2787
|
|
|
2762
2788
|
const root = project?.localPath ? path.resolve(project.localPath) : path.resolve(MINIONS_DIR, '..');
|
|
2763
2789
|
const items = safeJson(projectWorkItemsPath(project)) || [];
|
package/minions.js
CHANGED
|
@@ -173,6 +173,13 @@ function buildProjectEntry({ name, description, localPath, repoHost, repositoryI
|
|
|
173
173
|
repoName: repoName || name,
|
|
174
174
|
mainBranch: mainBranch || 'main',
|
|
175
175
|
prUrlBase: buildPrUrlBase({ repoHost, org, project, repoName }),
|
|
176
|
+
// Discovery defaults must mirror dashboard.js POST /api/projects — without
|
|
177
|
+
// these, discoverFromWorkItems / discoverFromPrs silently no-op (the engine
|
|
178
|
+
// looks healthy but never dispatches anything).
|
|
179
|
+
workSources: {
|
|
180
|
+
pullRequests: { enabled: true, cooldownMinutes: 30 },
|
|
181
|
+
workItems: { enabled: true, cooldownMinutes: 0 },
|
|
182
|
+
},
|
|
176
183
|
};
|
|
177
184
|
}
|
|
178
185
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1708",
|
|
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"
|