@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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1708 (2026-05-04)
4
+
5
+ ### Fixes
6
+ - surface silent-discovery footgun when projects miss workSources
7
+
3
8
  ## 0.1.1706 (2026-05-04)
4
9
 
5
10
  ### Features
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-04T15:03:10.429Z"
4
+ "cachedAt": "2026-05-04T16:42:47.140Z"
5
5
  }
@@ -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) return [];
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) return [];
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.1706",
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"