@yemi33/minions 0.1.202 → 0.1.204

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/minions.js +43 -18
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.204 (2026-04-02)
4
+
5
+ ### Other
6
+ - minions.js
7
+
8
+ ## 0.1.203 (2026-04-02)
9
+
10
+ ### Other
11
+ - minions.js
12
+
3
13
  ## 0.1.202 (2026-04-02)
4
14
 
5
15
  ### Other
package/minions.js CHANGED
@@ -129,17 +129,20 @@ function buildPrUrlBase({ repoHost, org, project, repoName }) {
129
129
  if (repoHost === 'github') {
130
130
  return org && repoName ? `https://github.com/${org}/${repoName}/pull/` : '';
131
131
  }
132
- return org && project && repoName
133
- ? `https://${org}.visualstudio.com/DefaultCollection/${project}/_git/${repoName}/pullrequest/`
134
- : '';
132
+ if (repoHost === 'ado' && org && project && repoName) {
133
+ return `https://dev.azure.com/${org}/${project}/_git/${repoName}/pullrequest/`;
134
+ }
135
+ return '';
135
136
  }
136
137
 
137
138
  function buildProjectEntry({ name, description, localPath, repoHost, repositoryId, org, project, repoName, mainBranch }) {
139
+ // Sanitize name for use as directory name in projects/<name>/
140
+ const safeName = (name || 'project').replace(/[^a-zA-Z0-9._-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 60) || 'project';
138
141
  return {
139
- name,
142
+ name: safeName,
140
143
  description: description || '',
141
144
  localPath: (localPath || '').replace(/\\/g, '/'),
142
- repoHost: repoHost || 'ado',
145
+ repoHost: repoHost || 'github',
143
146
  repositoryId: repositoryId || '',
144
147
  adoOrg: org || '',
145
148
  adoProject: project || '',
@@ -149,10 +152,6 @@ function buildProjectEntry({ name, description, localPath, repoHost, repositoryI
149
152
  };
150
153
  }
151
154
 
152
- function ensureProjectStateFiles() {
153
- // Project state is stored centrally at ~/.minions/projects/<name>/
154
- // No files created inside user repos.
155
- }
156
155
 
157
156
  // ─── Commands ────────────────────────────────────────────────────────────────
158
157
 
@@ -187,7 +186,7 @@ async function addProject(targetDir) {
187
186
 
188
187
  const name = await ask('Project name', detected.name || path.basename(target));
189
188
  const description = await ask('Description (what this repo contains/does)', detected.description || '');
190
- const repoHost = await ask('Repo host (ado/github)', detected.repoHost || 'ado');
189
+ const repoHost = await ask('Repo host (github/ado)', detected.repoHost || 'github');
191
190
  const org = await ask('Organization', detected.org || '');
192
191
  const project = await ask('Project', detected.project || '');
193
192
  const repoName = await ask('Repo name', detected.repoName || name);
@@ -198,7 +197,6 @@ async function addProject(targetDir) {
198
197
 
199
198
  config.projects.push(buildProjectEntry({ name, description, localPath: target, repoHost, repositoryId, org, project, repoName, mainBranch }));
200
199
  saveConfig(config);
201
- ensureProjectStateFiles(target);
202
200
 
203
201
  console.log(`\n Linked "${name}" (${target})`);
204
202
  console.log(` Total projects: ${config.projects.length}`);
@@ -259,7 +257,9 @@ function findGitRepos(rootDir, maxDepth = 3) {
259
257
  // Skip common non-project dirs
260
258
  const base = path.basename(dir);
261
259
  if (['node_modules', '.git', '.hg', 'AppData', '$Recycle.Bin', 'Windows', 'Program Files',
262
- 'Program Files (x86)', '.cache', '.npm', '.yarn', '.nuget', 'worktrees'].includes(base)) return;
260
+ 'Program Files (x86)', '.cache', '.npm', '.yarn', '.nuget', 'worktrees', '.minions'].includes(base)) return;
261
+ // Skip minions home directory itself
262
+ if (path.resolve(dir) === path.resolve(MINIONS_HOME)) return;
263
263
 
264
264
  const gitDir = path.join(dir, '.git');
265
265
  if (fs.existsSync(gitDir)) {
@@ -377,14 +377,22 @@ async function scanAndAdd({ root, depth } = {}) {
377
377
 
378
378
  console.log(`\n Adding ${toAdd.length} project(s)...\n`);
379
379
 
380
+ const existingNames = new Set((config.projects || []).map(p => p.name));
380
381
  for (const repo of toAdd) {
382
+ // Deduplicate names — append -2, -3 etc. if name already taken
383
+ let name = repo.name;
384
+ if (existingNames.has(name)) {
385
+ let i = 2;
386
+ while (existingNames.has(name + '-' + i)) i++;
387
+ name = name + '-' + i;
388
+ }
389
+ existingNames.add(name);
381
390
  config.projects.push(buildProjectEntry({
382
- name: repo.name, description: repo.description, localPath: repo.path,
391
+ name, description: repo.description, localPath: repo.path,
383
392
  repoHost: repo.host, org: repo.org, project: repo.project,
384
393
  repoName: repo.repoName, mainBranch: repo.mainBranch,
385
394
  }));
386
- ensureProjectStateFiles(repo.path);
387
- console.log(` + ${repo.name} (${repo.path})`);
395
+ console.log(` + ${name} (${repo.path})`);
388
396
  }
389
397
 
390
398
  saveConfig(config);
@@ -416,19 +424,36 @@ async function initMinions({ skipScan = false, scanRoot, scanDepth } = {}) {
416
424
  saveConfig(config);
417
425
  console.log(`\n Minions initialized at ${MINIONS_HOME}`);
418
426
  console.log(` Config, agents, and engine defaults created.\n`);
427
+
428
+ // Preflight checks (skip if called from bin/minions.js which runs its own)
429
+ if (!skipScan) {
430
+ let preflightOk = true;
431
+ try { execSync('git --version', { encoding: 'utf8', timeout: 5000, stdio: 'pipe' }); console.log(' ✓ Git found'); }
432
+ catch { console.log(' ✗ Git not found — agents need git for worktrees and PRs'); preflightOk = false; }
433
+ try {
434
+ const isWin = process.platform === 'win32';
435
+ const cmd = isWin ? 'where claude 2>NUL' : 'which claude 2>/dev/null';
436
+ execSync(cmd, { encoding: 'utf8', timeout: 5000, stdio: 'pipe' });
437
+ console.log(' ✓ Claude Code CLI found');
438
+ } catch { console.log(' ✗ Claude Code CLI not found — install: npm i -g @anthropic-ai/claude-code (or native installer)'); preflightOk = false; }
439
+ const nodeVer = parseInt(process.versions.node);
440
+ if (nodeVer >= 18) { console.log(' ✓ Node.js ' + process.versions.node); }
441
+ else { console.log(' ✗ Node.js ' + process.versions.node + ' — version 18+ required'); preflightOk = false; }
442
+ if (!preflightOk) console.log('\n Some prerequisites missing — agents may fail until resolved.\n');
443
+ else console.log('');
444
+ }
419
445
  if (removedPlaceholders > 0) {
420
446
  console.log(` Removed ${removedPlaceholders} placeholder project entr${removedPlaceholders === 1 ? 'y' : 'ies'} from config.\n`);
421
447
  }
422
448
 
423
449
  if (skipScan) {
424
450
  console.log(' Skipping repo scan (--skip-scan). Run "node minions.js scan" later to link projects.\n');
451
+ rl.close();
425
452
  } else {
426
- // Auto-chain into scan
453
+ // Auto-chain into scan (scanAndAdd closes rl)
427
454
  console.log(' Now let\'s find your repos...\n');
428
455
  await scanAndAdd({ root: scanRoot, depth: scanDepth });
429
456
  }
430
-
431
- rl.close();
432
457
  }
433
458
 
434
459
  function nukeMinions() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.202",
3
+ "version": "0.1.204",
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"