@yemi33/minions 0.1.1718 → 0.1.1720

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.1720 (2026-05-04)
4
+
5
+ ### Features
6
+ - separate GitHub and ADO project fields (#2065)
7
+
3
8
  ## 0.1.1718 (2026-05-04)
4
9
 
5
10
  ### Features
package/dashboard.js CHANGED
@@ -4927,20 +4927,16 @@ What would you like to discuss or change? When you're happy, say "approve" and I
4927
4927
  return jsonReply(res, e.statusCode || 400, { error: e.message });
4928
4928
  }
4929
4929
 
4930
- const project = {
4931
- name, description, localPath: target.replace(/\\/g, '/'),
4932
- repoHost: detected.repoHost || 'ado', repositoryId: detected.repositoryId || '',
4933
- adoOrg: detected.org || '', adoProject: detected.project || '',
4934
- repoName: detected.repoName || name, mainBranch: detected.mainBranch || 'main',
4935
- prUrlBase: projectDiscovery.buildPrUrlBase({
4936
- repoHost: detected.repoHost,
4937
- org: detected.org,
4938
- project: detected.project,
4939
- repoName: detected.repoName,
4940
- prUrlBase: detected.prUrlBase,
4941
- }),
4942
- workSources: { pullRequests: { enabled: true, cooldownMinutes: 30 }, workItems: { enabled: true, cooldownMinutes: 0 } }
4943
- };
4930
+ const project = projectDiscovery.buildProjectEntry({
4931
+ name, description, localPath: target,
4932
+ repoHost: detected.repoHost || 'github',
4933
+ repositoryId: detected.repositoryId || '',
4934
+ org: detected.org || '',
4935
+ project: detected.project || '',
4936
+ repoName: detected.repoName || name,
4937
+ mainBranch: detected.mainBranch || 'main',
4938
+ prUrlBase: detected.prUrlBase,
4939
+ });
4944
4940
 
4945
4941
  config.projects.push(project);
4946
4942
  safeWrite(configPath, config);
package/engine/cli.js CHANGED
@@ -1181,8 +1181,9 @@ const commands = {
1181
1181
  project_name: targetProject.name || 'Unknown',
1182
1182
  project_path: targetProject.localPath || '',
1183
1183
  main_branch: targetProject.localPath ? shared.resolveMainBranch(targetProject.localPath, targetProject.mainBranch) : (targetProject.mainBranch || 'main'),
1184
- ado_org: targetProject.adoOrg || 'Unknown',
1185
- ado_project: targetProject.adoProject || 'Unknown',
1184
+ ado_org: targetProject.repoHost === 'ado' ? (targetProject.adoOrg || 'Unknown') : '',
1185
+ ado_project: targetProject.repoHost === 'ado' ? (targetProject.adoProject || 'Unknown') : '',
1186
+ github_org: targetProject.repoHost === 'github' ? (targetProject.githubOrg || targetProject.adoOrg || '') : '',
1186
1187
  repo_name: targetProject.repoName || 'Unknown',
1187
1188
  team_root: MINIONS_DIR,
1188
1189
  date: e.dateStamp(),
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-04T23:02:50.359Z"
4
+ "cachedAt": "2026-05-04T23:05:59.485Z"
5
5
  }
package/engine/github.js CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  const shared = require('./shared');
8
- const { exec, execAsync, getProjects, projectPrPath, projectWorkItemsPath, safeJson, safeWrite, mutateJsonFileLocked, MINIONS_DIR, getPrLinks, backfillPrPrdItems, log, ts, dateStamp, PR_STATUS, PR_POLLABLE_STATUSES, createThrottleTracker } = shared;
8
+ const { exec, execAsync, getProjects, projectPrPath, projectWorkItemsPath, safeJson, safeWrite, mutateJsonFileLocked, MINIONS_DIR, getPrLinks, backfillPrPrdItems, log, ts, dateStamp, PR_STATUS, PR_POLLABLE_STATUSES, createThrottleTracker, getProjectOrg } = shared;
9
9
  const { getPrs } = require('./queries');
10
10
  const path = require('path');
11
11
 
@@ -33,7 +33,7 @@ function isGitHub(project) {
33
33
 
34
34
  /** Get GitHub owner/repo slug from project config (e.g. "x3-design/Bebop_Workspaces") */
35
35
  function getRepoSlug(project) {
36
- const org = project.adoOrg || '';
36
+ const org = getProjectOrg(project);
37
37
  const repo = project.repoName || '';
38
38
  if (!org || !repo) return null;
39
39
  return `${org}/${repo}`;
@@ -10,7 +10,7 @@ const path = require('path');
10
10
  const shared = require('./shared');
11
11
  const queries = require('./queries');
12
12
 
13
- const { safeJson, safeRead, getProjects, log, ts, dateStamp, truncateTextBytes, ENGINE_DEFAULTS, WI_STATUS, WORK_TYPE, PR_STATUS, DISPATCH_RESULT } = shared;
13
+ const { safeJson, safeRead, getProjects, log, ts, dateStamp, truncateTextBytes, ENGINE_DEFAULTS, WI_STATUS, WORK_TYPE, PR_STATUS, DISPATCH_RESULT, getProjectOrg } = shared;
14
14
  const { getConfig, getDispatch, getNotes, getAgentCharter, getPrs, getKnowledgeBaseIndex, AGENTS_DIR } = queries;
15
15
 
16
16
  const MINIONS_DIR = shared.MINIONS_DIR;
@@ -29,7 +29,7 @@ function getPrCreateInstructions(project) {
29
29
  const host = getRepoHost(project);
30
30
  const repoId = project?.repositoryId || '';
31
31
  if (host === 'github') {
32
- const org = project?.adoOrg || '';
32
+ const org = getProjectOrg(project);
33
33
  const repo = project?.repoName || '';
34
34
  const mainBranch = project?.localPath ? shared.resolveMainBranch(project.localPath, project.mainBranch) : (project?.mainBranch || 'main');
35
35
  return `Use \`gh pr create\` to create a pull request:\n` +
@@ -56,7 +56,7 @@ function getPrCommentInstructions(project) {
56
56
  const host = getRepoHost(project);
57
57
  const repoId = project?.repositoryId || '';
58
58
  if (host === 'github') {
59
- const org = project?.adoOrg || '';
59
+ const org = getProjectOrg(project);
60
60
  const repo = project?.repoName || '';
61
61
  return `Use \`gh pr comment\` to post a comment on the PR:\n` +
62
62
  `- Write the Markdown comment to a temporary file, then run: \`gh pr comment <number> --body-file <body-file.md> --repo ${org}/${repo}\`\n` +
@@ -75,7 +75,7 @@ function getPrCommentInstructions(project) {
75
75
  function getPrFetchInstructions(project) {
76
76
  const host = getRepoHost(project);
77
77
  if (host === 'github') {
78
- const org = project?.adoOrg || '';
78
+ const org = getProjectOrg(project);
79
79
  const repo = project?.repoName || '';
80
80
  const mainBranch = project?.localPath ? shared.resolveMainBranch(project.localPath, project.mainBranch) : (project?.mainBranch || 'main');
81
81
  return `Use \`gh pr view\` to fetch PR status:\n` +
@@ -100,7 +100,7 @@ function getPrVoteInstructions(project) {
100
100
  const host = getRepoHost(project);
101
101
  const repoId = project?.repositoryId || '';
102
102
  if (host === 'github') {
103
- const org = project?.adoOrg || '';
103
+ const org = getProjectOrg(project);
104
104
  const repo = project?.repoName || '';
105
105
  return `**IMPORTANT: GitHub blocks self-approval** — all agents share the same credentials, so \`--approve\` and \`--request-changes\` will fail with "can't approve your own PR." Use \`--comment\` instead.\n\n` +
106
106
  `Submit your review verdict using \`gh pr review\` with \`--comment\`:\n` +
@@ -411,13 +411,15 @@ function renderPlaybook(type, vars) {
411
411
  ...dispatchProject,
412
412
  adoOrg: vars.ado_org || vars.adoOrg || dispatchProject.adoOrg,
413
413
  adoProject: vars.ado_project || vars.adoProject || dispatchProject.adoProject,
414
+ githubOrg: vars.github_org || vars.githubOrg || dispatchProject.githubOrg,
414
415
  repoName: vars.repo_name || vars.repoName || dispatchProject.repoName,
415
416
  repoHost: vars.repo_host || vars.repoHost || dispatchProject.repoHost,
416
417
  };
417
418
  const repoHost = getRepoHost(renderProject);
418
419
  const projectVars = {
419
420
  project_name: renderProject.name || 'Unknown Project',
420
- ado_org: renderProject.adoOrg || 'Unknown',
421
+ ado_org: repoHost === 'ado' ? (renderProject.adoOrg || 'Unknown') : '',
422
+ github_org: repoHost === 'github' ? getProjectOrg(renderProject) : '',
421
423
  ado_project: renderProject.adoProject || 'Unknown',
422
424
  repo_name: renderProject.repoName || 'Unknown',
423
425
  repo_host: repoHost,
@@ -503,7 +505,7 @@ function buildSystemPrompt(agentId, config, project) {
503
505
 
504
506
  // Project context (fixed size)
505
507
  prompt += `## Project: ${project.name || 'Unknown Project'}\n\n`;
506
- prompt += `- Repo: ${project.repoName || 'Unknown'} (${project.adoOrg || 'Unknown'}/${project.adoProject || 'Unknown'})\n`;
508
+ prompt += `- Repo: ${project.repoName || 'Unknown'} (${getProjectOrg(project) || 'Unknown'}${project.repoHost === 'ado' ? '/' + (project.adoProject || 'Unknown') : ''})\n`;
507
509
  prompt += `- Repo ID: ${project.repositoryId || ''}\n`;
508
510
  prompt += `- Repo host: ${getRepoHostLabel(project)}\n`;
509
511
  prompt += `- Main branch: ${project.mainBranch || 'main'}\n\n`;
@@ -648,8 +650,9 @@ function buildBaseVars(agentId, config, project) {
648
650
  team_root: MINIONS_DIR,
649
651
  repo_id: project?.repositoryId || '',
650
652
  project_name: project?.name || 'Unknown Project',
651
- ado_org: project?.adoOrg || 'Unknown',
652
- ado_project: project?.adoProject || 'Unknown',
653
+ ado_org: project?.repoHost === 'ado' ? (project?.adoOrg || 'Unknown') : '',
654
+ ado_project: project?.repoHost === 'ado' ? (project?.adoProject || 'Unknown') : '',
655
+ github_org: project?.repoHost === 'github' ? getProjectOrg(project) : '',
653
656
  repo_name: project?.repoName || 'Unknown',
654
657
  repo_host: getRepoHost(project),
655
658
  main_branch: project?.mainBranch || 'main',
@@ -332,17 +332,20 @@ function buildPrUrlBase({ repoHost, org, project, repoName, prUrlBase }) {
332
332
 
333
333
  function buildProjectEntry({ name, description, localPath, repoHost, repositoryId, org, project, repoName, mainBranch, prUrlBase }) {
334
334
  const safeName = (name || 'project').replace(/[^a-zA-Z0-9._-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 60) || 'project';
335
+ const host = repoHost || 'github';
336
+ const isAdo = host === 'ado';
335
337
  return {
336
338
  name: safeName,
337
339
  description: description || '',
338
340
  localPath: (localPath || '').replace(/\\/g, '/'),
339
- repoHost: repoHost || 'github',
340
- repositoryId: repositoryId || '',
341
- adoOrg: org || '',
342
- adoProject: project || '',
341
+ repoHost: host,
342
+ repositoryId: isAdo ? (repositoryId || '') : '',
343
+ adoOrg: isAdo ? (org || '') : '',
344
+ adoProject: isAdo ? (project || '') : '',
345
+ githubOrg: !isAdo ? (org || '') : '',
343
346
  repoName: repoName || name,
344
347
  mainBranch: mainBranch || 'main',
345
- prUrlBase: buildPrUrlBase({ repoHost, org, project, repoName, prUrlBase }),
348
+ prUrlBase: buildPrUrlBase({ repoHost: host, org, project, repoName, prUrlBase }),
346
349
  workSources: {
347
350
  pullRequests: { enabled: true, cooldownMinutes: 30 },
348
351
  workItems: { enabled: true, cooldownMinutes: 0 },
@@ -50,6 +50,11 @@ function _safeWriteJson(p, obj) {
50
50
  try { fs.writeFileSync(p, JSON.stringify(obj, null, 2)); } catch { /* best effort */ }
51
51
  }
52
52
 
53
+ function _inferClaudeNativeFromBin(claudeBin) {
54
+ const ext = path.extname(claudeBin).toLowerCase();
55
+ return isWin ? ext === '.exe' : ext !== '.js';
56
+ }
57
+
53
58
  function _probeClaudePackage(pkgDir) {
54
59
  const nativeBin = path.join(pkgDir, 'bin', isWin ? 'claude.exe' : 'claude');
55
60
  if (fs.existsSync(nativeBin)) return { bin: nativeBin, native: true };
@@ -89,7 +94,14 @@ function resolveBinary({ env = process.env, config = null } = {}) {
89
94
  // 1. Cache hit — fastest path
90
95
  const cached = _safeJson(CAPS_FILE);
91
96
  if (cached?.claudeBin && fs.existsSync(cached.claudeBin)) {
92
- return { bin: cached.claudeBin, native: !!cached.claudeIsNative, leadingArgs: [] };
97
+ const native = cached.claudeIsNative != null
98
+ ? !!cached.claudeIsNative
99
+ : _inferClaudeNativeFromBin(cached.claudeBin);
100
+ if (cached.claudeIsNative == null) {
101
+ cached.claudeIsNative = native;
102
+ _safeWriteJson(CAPS_FILE, cached);
103
+ }
104
+ return { bin: cached.claudeBin, native, leadingArgs: [] };
93
105
  }
94
106
 
95
107
  // 2. PATH lookup → probe the resolved path's neighbouring node_modules dir
package/engine/shared.js CHANGED
@@ -1477,6 +1477,13 @@ function nextWorkItemId(items, prefix) {
1477
1477
 
1478
1478
  // ── ADO URL ──────────────────────────────────────────────────────────────────
1479
1479
 
1480
+ /** Return the org/owner for a project regardless of host. Prefers host-specific field, falls back to adoOrg for backward compat. */
1481
+ function getProjectOrg(project) {
1482
+ if (!project) return '';
1483
+ if (project.repoHost === 'github') return project.githubOrg || project.adoOrg || '';
1484
+ return project.adoOrg || '';
1485
+ }
1486
+
1480
1487
  function getAdoOrgBase(project) {
1481
1488
  if (project.prUrlBase) {
1482
1489
  const devAzure = project.prUrlBase.match(/^(https?:\/\/dev\.azure\.com\/[^/]+)/i);
@@ -1922,7 +1929,7 @@ function getProjectPrScope(project) {
1922
1929
  if (host === 'github') {
1923
1930
  const parsed = parseGitHubPrUrl(project.prUrlBase || '');
1924
1931
  if (parsed?.scope) return parsed.scope;
1925
- const owner = normalizePrScopeSegment(project.adoOrg);
1932
+ const owner = normalizePrScopeSegment(getProjectOrg(project));
1926
1933
  const repo = normalizePrScopeSegment(project.repoName);
1927
1934
  return owner && repo ? `github:${owner}/${repo}` : '';
1928
1935
  }
@@ -2680,6 +2687,7 @@ module.exports = {
2680
2687
  mergePrLinkItems, // exported for testing
2681
2688
  upsertPullRequestRecord,
2682
2689
  nextWorkItemId,
2690
+ getProjectOrg,
2683
2691
  getAdoOrgBase,
2684
2692
  sanitizePath,
2685
2693
  sanitizeBranch,
package/engine.js CHANGED
@@ -271,17 +271,72 @@ function _runtimeLogger() {
271
271
  };
272
272
  }
273
273
 
274
+ function _collectAgentFailureSignal(rawOutput) {
275
+ const text = rawOutput == null ? '' : String(rawOutput);
276
+ if (!text) return '';
277
+
278
+ const signals = [];
279
+ let sawJsonLine = false;
280
+ for (const rawLine of text.split('\n')) {
281
+ const line = rawLine.trim();
282
+ if (!line) continue;
283
+ if (!line.startsWith('{')) {
284
+ signals.push(line);
285
+ continue;
286
+ }
287
+ let obj;
288
+ try { obj = JSON.parse(line); } catch { continue; }
289
+ if (!obj || typeof obj !== 'object') continue;
290
+ sawJsonLine = true;
291
+
292
+ const type = String(obj.type || '');
293
+ const subtype = String(obj.subtype || '');
294
+ const eventType = String(obj.event?.type || '');
295
+ const isErrorEvent = type === 'error'
296
+ || eventType === 'error'
297
+ || subtype.startsWith('error')
298
+ || obj.is_error === true
299
+ || obj.error != null;
300
+ if (!isErrorEvent) continue;
301
+
302
+ for (const value of [
303
+ subtype,
304
+ obj.error,
305
+ obj.message,
306
+ obj.stderr,
307
+ obj.result,
308
+ obj.event?.error,
309
+ obj.event?.message,
310
+ ]) {
311
+ if (typeof value === 'string' && value.trim()) signals.push(value.trim());
312
+ }
313
+ }
314
+
315
+ if (signals.length > 0) return signals.join('\n');
316
+ return sawJsonLine ? '' : text;
317
+ }
318
+
319
+ function _stdoutForFallbackClassification(rawStdout, failureSignal) {
320
+ if (failureSignal) return failureSignal;
321
+ const text = rawStdout == null ? '' : String(rawStdout);
322
+ if (!text.trim()) return '';
323
+ return 'agent produced non-empty stdout without a terminal runtime error signal';
324
+ }
325
+
274
326
  function _classifyAgentFailure(runtime, code, stdout, stderr) {
327
+ const failureSignal = _collectAgentFailureSignal(stdout);
328
+ const fallbackStdout = _stdoutForFallbackClassification(stdout, failureSignal);
275
329
  if (runtime && typeof runtime.classifyFailure === 'function') {
276
330
  const classified = runtime.classifyFailure({
277
331
  code,
278
- stdout,
332
+ stdout: failureSignal,
279
333
  stderr,
280
- fallback: classifyFailureFallback,
334
+ fallback: (fallbackCode, _stdout, fallbackStderr) =>
335
+ classifyFailureFallback(fallbackCode, fallbackStdout, fallbackStderr),
281
336
  });
282
337
  if (classified && classified.failureClass) return classified;
283
338
  }
284
- return { failureClass: classifyFailureFallback(code, stdout, stderr) };
339
+ return { failureClass: classifyFailureFallback(code, fallbackStdout, stderr) };
285
340
  }
286
341
 
287
342
  function ackPendingSteeringFiles(agentId, procInfo, rawOutput, observedAtMs = Date.now()) {
@@ -3136,7 +3191,9 @@ function buildProjectContext(projects, assignedProject, isFanOut, agentName, age
3136
3191
  const projectList = projects.map(p => {
3137
3192
  let line = `### ${p.name}\n`;
3138
3193
  line += `- **Path:** ${p.localPath}\n`;
3139
- line += `- **Repo:** ${p.adoOrg}/${p.adoProject}/${p.repoName} (ID: ${p.repositoryId || 'unknown'}, host: ${getRepoHostLabel(p)})\n`;
3194
+ line += p.repoHost === 'github'
3195
+ ? `- **Repo:** ${p.githubOrg || p.adoOrg || ''}/${p.repoName} (host: ${getRepoHostLabel(p)})\n`
3196
+ : `- **Repo:** ${p.adoOrg}/${p.adoProject}/${p.repoName} (ID: ${p.repositoryId || 'unknown'}, host: ${getRepoHostLabel(p)})\n`;
3140
3197
  if (p.description) line += `- **What it is:** ${p.description}\n`;
3141
3198
  return line;
3142
3199
  }).join('\n');
@@ -4409,7 +4466,7 @@ module.exports = {
4409
4466
  reconcileItemsWithPrs, detectDependencyCycles,
4410
4467
  parseConflictFiles, pruneAncestorDeps, preflightMergeSimulation, // exported for testing
4411
4468
  isWorktreeRetryableError, removeStaleIndexLock, // exported for testing
4412
- _maxTurnsForType, buildProjectContext, normalizeAc, _buildAgentSpawnFlags, // exported for testing
4469
+ _maxTurnsForType, buildProjectContext, normalizeAc, _buildAgentSpawnFlags, _classifyAgentFailure, // exported for testing
4413
4470
 
4414
4471
  // Playbooks
4415
4472
  renderPlaybook, validatePlaybookVars, PLAYBOOK_REQUIRED_VARS, buildWorkItemDispatchVars,
package/minions.js CHANGED
@@ -183,8 +183,12 @@ function listProjects() {
183
183
  console.log(` ${p.name}`);
184
184
  if (p.description) console.log(` Desc: ${p.description}`);
185
185
  console.log(` Path: ${p.localPath} ${exists ? '' : '(NOT FOUND)'}`);
186
- console.log(` Repo: ${p.adoOrg}/${p.adoProject}/${p.repoName} (${p.repoHost || 'ado'})`);
187
- console.log(` ID: ${p.repositoryId || 'none'}`);
186
+ if (p.repoHost === 'github') {
187
+ console.log(` Repo: ${p.githubOrg || p.adoOrg || ''}/${p.repoName} (github)`);
188
+ } else {
189
+ console.log(` Repo: ${p.adoOrg}/${p.adoProject}/${p.repoName} (${p.repoHost || 'ado'})`);
190
+ console.log(` ID: ${p.repositoryId || 'none'}`);
191
+ }
188
192
  console.log('');
189
193
  }
190
194
  rl.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1718",
3
+ "version": "0.1.1720",
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"