@yemi33/minions 0.1.767 → 0.1.769

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,11 +1,13 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.767 (2026-04-10)
3
+ ## 0.1.769 (2026-04-10)
4
4
 
5
5
  ### Features
6
6
  - id/kill endpoint
7
7
 
8
8
  ### Fixes
9
+ - ADO build detection uses builds API, not unreliable status checks
10
+ - handle work type names as action aliases for dispatch
9
11
  - align Agent Usage and Engine Usage table columns
10
12
  - harden agent kill endpoint — use killGracefully, clean steer.md, remove dead var
11
13
 
@@ -683,9 +683,15 @@ async function ccExecuteAction(action) {
683
683
 
684
684
  try {
685
685
  switch (action.type) {
686
- case 'dispatch': {
686
+ case 'dispatch':
687
+ case 'fix':
688
+ case 'implement':
689
+ case 'explore':
690
+ case 'review':
691
+ case 'test': {
692
+ var workType = action.workType || (action.type !== 'dispatch' ? action.type : 'implement');
687
693
  var res = await _ccFetch('/api/work-items', {
688
- title: action.title, type: action.workType || 'implement',
694
+ title: action.title, type: workType,
689
695
  priority: action.priority || 'medium', description: action.description || '',
690
696
  project: action.project || '', agents: action.agents || [],
691
697
  });
package/engine/ado.js CHANGED
@@ -101,13 +101,14 @@ const BUILD_ERROR_LOG_MAX_LINES = 150;
101
101
  */
102
102
  async function fetchAdoBuildErrorLog(orgBase, project, failedStatus, token, pr, seenBuildIds) {
103
103
  try {
104
- // Try extracting buildId from targetUrl (e.g. .../_build/results?buildId=12345)
105
- const targetUrl = failedStatus?.targetUrl || '';
106
- let buildId = null;
107
- const buildIdMatch = targetUrl.match(/buildId=(\d+)/);
108
- if (buildIdMatch) {
109
- buildId = buildIdMatch[1];
110
- } else {
104
+ // Use pre-resolved buildId if available (from builds API query), else parse from targetUrl
105
+ let buildId = failedStatus?._buildId || null;
106
+ if (!buildId) {
107
+ const targetUrl = failedStatus?.targetUrl || '';
108
+ const buildIdMatch = targetUrl.match(/buildId=(\d+)/);
109
+ if (buildIdMatch) buildId = buildIdMatch[1];
110
+ }
111
+ if (!buildId) {
111
112
  // Fallback: query recent failed builds for this PR's source branch
112
113
  try {
113
114
  const branch = pr?.branch || pr?.sourceRefName?.replace('refs/heads/', '');
@@ -281,7 +282,8 @@ async function pollPrStatus(config) {
281
282
  }
282
283
 
283
284
  // Track head commit changes to detect new pushes (used for review re-dispatch gating)
284
- const headCommit = prData.lastMergeSourceCommit?.commitId || prData.sourceRefName || '';
285
+ // Use lastMergeCommit (the merge commit), not lastMergeSourceCommit (source branch tip)
286
+ const headCommit = prData.lastMergeCommit?.commitId || prData.lastMergeSourceCommit?.commitId || '';
285
287
  if (headCommit && pr._adoHeadCommit !== headCommit) {
286
288
  if (pr._adoHeadCommit) { // skip first detection — only track changes
287
289
  pr.lastPushedAt = ts();
@@ -344,38 +346,45 @@ async function pollPrStatus(config) {
344
346
 
345
347
  if (newStatus !== PR_STATUS.ACTIVE) return updated;
346
348
 
347
- const statusData = await adoFetch(`${repoBase}/statuses?api-version=7.1`, token);
348
-
349
- const latest = new Map();
350
- for (const s of statusData.value || []) {
351
- const key = (s.context?.genre || '') + '/' + (s.context?.name || '');
352
- if (!latest.has(key)) latest.set(key, s);
353
- }
354
-
355
- const buildStatuses = [...latest.values()].filter(s => {
356
- const ctx = ((s.context?.genre || '') + '/' + (s.context?.name || '')).toLowerCase();
357
- return /\bcodecoverage\b/.test(ctx) || /\bbuild\b/.test(ctx) ||
358
- /\bdeploy\b/.test(ctx) || /(?:^|\/)ci(?:\/|$)/.test(ctx);
359
- });
360
-
349
+ // Query builds API directly — status checks (/statuses) are unreliable (stale codecoverage postbacks)
350
+ // Use the merge commit hash to find builds for this PR
351
+ const mergeCommitId = prData.lastMergeCommit?.commitId;
361
352
  let buildStatus = 'none';
362
353
  let buildFailReason = '';
354
+ let buildStatuses = []; // for error log fetching
363
355
 
364
- if (buildStatuses.length > 0) {
365
- const states = buildStatuses.map(s => s.state).filter(Boolean);
366
- const hasFailed = states.some(s => s === 'failed' || s === 'error');
367
- const allDone = states.every(s => s === 'succeeded' || s === 'notApplicable');
368
- const hasQueued = buildStatuses.some(s => !s.state);
369
-
370
- if (hasFailed) {
371
- buildStatus = 'failing';
372
- const failed = buildStatuses.find(s => s.state === 'failed' || s.state === 'error');
373
- buildFailReason = failed?.description || failed?.context?.name || 'Build failed';
374
- } else if (allDone && !hasQueued) {
375
- buildStatus = 'passing';
376
- } else {
377
- buildStatus = 'running';
378
- }
356
+ if (mergeCommitId) {
357
+ try {
358
+ // Find builds where sourceVersion matches the PR's merge commit
359
+ const buildsUrl = `${orgBase}/${project.adoProject}/_apis/build/builds?$top=10&api-version=7.1`;
360
+ const buildsData = await adoFetch(buildsUrl, token);
361
+ const prBuilds = (buildsData?.value || []).filter(b =>
362
+ b.sourceVersion === mergeCommitId || b.sourceBranch === prData.sourceRefName
363
+ );
364
+
365
+ if (prBuilds.length > 0) {
366
+ // partiallySucceeded = warnings, not failures — counts as passing
367
+ const hasFailed = prBuilds.some(b => b.result === 'failed' || b.result === 'canceled');
368
+ const allDone = prBuilds.every(b => b.status === 'completed');
369
+ const allPassed = prBuilds.every(b => b.result === 'succeeded' || b.result === 'partiallySucceeded');
370
+ const hasRunning = prBuilds.some(b => b.status === 'inProgress' || b.status === 'notStarted');
371
+
372
+ if (hasFailed && allDone) {
373
+ buildStatus = 'failing';
374
+ const failed = prBuilds.find(b => b.result === 'failed');
375
+ buildFailReason = failed?.definition?.name || 'Build failed';
376
+ // Build fake status objects for error log fetching
377
+ buildStatuses = prBuilds.filter(b => b.result === 'failed').map(b => ({
378
+ state: 'failed', targetUrl: `${orgBase}/${project.adoProject}/_build/results?buildId=${b.id}`,
379
+ _buildId: String(b.id),
380
+ }));
381
+ } else if (allDone && allPassed) {
382
+ buildStatus = 'passing';
383
+ } else if (hasRunning) {
384
+ buildStatus = 'running';
385
+ }
386
+ }
387
+ } catch (e) { log('warn', `ADO build query for ${pr.id}: ${e.message}`); }
379
388
  }
380
389
 
381
390
  if (pr.buildStatus !== buildStatus) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.767",
3
+ "version": "0.1.769",
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"