@yemi33/minions 0.1.201 → 0.1.203
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 +10 -0
- package/minions.js +47 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/minions.js
CHANGED
|
@@ -54,7 +54,12 @@ function autoDiscover(targetDir) {
|
|
|
54
54
|
|
|
55
55
|
// 1. Detect main branch from git
|
|
56
56
|
try {
|
|
57
|
-
|
|
57
|
+
let head = '';
|
|
58
|
+
try {
|
|
59
|
+
head = execSync('git symbolic-ref refs/remotes/origin/HEAD', { cwd: targetDir, encoding: 'utf8', timeout: 5000 }).trim();
|
|
60
|
+
} catch {
|
|
61
|
+
head = execSync('git symbolic-ref HEAD', { cwd: targetDir, encoding: 'utf8', timeout: 5000 }).trim();
|
|
62
|
+
}
|
|
58
63
|
const branch = head.replace('refs/remotes/origin/', '').replace('refs/heads/', '');
|
|
59
64
|
if (branch) { result.mainBranch = branch; result._found.push('main branch'); }
|
|
60
65
|
} catch {}
|
|
@@ -124,38 +129,29 @@ function buildPrUrlBase({ repoHost, org, project, repoName }) {
|
|
|
124
129
|
if (repoHost === 'github') {
|
|
125
130
|
return org && repoName ? `https://github.com/${org}/${repoName}/pull/` : '';
|
|
126
131
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
if (repoHost === 'ado' && org && project && repoName) {
|
|
133
|
+
return `https://dev.azure.com/${org}/${project}/_git/${repoName}/pullrequest/`;
|
|
134
|
+
}
|
|
135
|
+
return '';
|
|
130
136
|
}
|
|
131
137
|
|
|
132
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';
|
|
133
141
|
return {
|
|
134
|
-
name,
|
|
142
|
+
name: safeName,
|
|
135
143
|
description: description || '',
|
|
136
144
|
localPath: (localPath || '').replace(/\\/g, '/'),
|
|
137
|
-
repoHost: repoHost || '
|
|
145
|
+
repoHost: repoHost || 'github',
|
|
138
146
|
repositoryId: repositoryId || '',
|
|
139
147
|
adoOrg: org || '',
|
|
140
148
|
adoProject: project || '',
|
|
141
149
|
repoName: repoName || name,
|
|
142
150
|
mainBranch: mainBranch || 'main',
|
|
143
151
|
prUrlBase: buildPrUrlBase({ repoHost, org, project, repoName }),
|
|
144
|
-
workSources: {
|
|
145
|
-
pullRequests: { enabled: true, path: '.minions/pull-requests.json', cooldownMinutes: 30 },
|
|
146
|
-
workItems: { enabled: true, path: '.minions/work-items.json', cooldownMinutes: 0 },
|
|
147
|
-
}
|
|
148
152
|
};
|
|
149
153
|
}
|
|
150
154
|
|
|
151
|
-
function ensureProjectStateFiles(projectPath) {
|
|
152
|
-
const minionsDir = path.join(projectPath, '.minions');
|
|
153
|
-
if (!fs.existsSync(minionsDir)) fs.mkdirSync(minionsDir, { recursive: true });
|
|
154
|
-
for (const f of ['pull-requests.json', 'work-items.json']) {
|
|
155
|
-
const fp = path.join(minionsDir, f);
|
|
156
|
-
if (!fs.existsSync(fp)) fs.writeFileSync(fp, '[]');
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
155
|
|
|
160
156
|
// ─── Commands ────────────────────────────────────────────────────────────────
|
|
161
157
|
|
|
@@ -190,7 +186,7 @@ async function addProject(targetDir) {
|
|
|
190
186
|
|
|
191
187
|
const name = await ask('Project name', detected.name || path.basename(target));
|
|
192
188
|
const description = await ask('Description (what this repo contains/does)', detected.description || '');
|
|
193
|
-
const repoHost = await ask('Repo host (ado
|
|
189
|
+
const repoHost = await ask('Repo host (github/ado)', detected.repoHost || 'github');
|
|
194
190
|
const org = await ask('Organization', detected.org || '');
|
|
195
191
|
const project = await ask('Project', detected.project || '');
|
|
196
192
|
const repoName = await ask('Repo name', detected.repoName || name);
|
|
@@ -201,7 +197,6 @@ async function addProject(targetDir) {
|
|
|
201
197
|
|
|
202
198
|
config.projects.push(buildProjectEntry({ name, description, localPath: target, repoHost, repositoryId, org, project, repoName, mainBranch }));
|
|
203
199
|
saveConfig(config);
|
|
204
|
-
ensureProjectStateFiles(target);
|
|
205
200
|
|
|
206
201
|
console.log(`\n Linked "${name}" (${target})`);
|
|
207
202
|
console.log(` Total projects: ${config.projects.length}`);
|
|
@@ -262,7 +257,9 @@ function findGitRepos(rootDir, maxDepth = 3) {
|
|
|
262
257
|
// Skip common non-project dirs
|
|
263
258
|
const base = path.basename(dir);
|
|
264
259
|
if (['node_modules', '.git', '.hg', 'AppData', '$Recycle.Bin', 'Windows', 'Program Files',
|
|
265
|
-
'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;
|
|
266
263
|
|
|
267
264
|
const gitDir = path.join(dir, '.git');
|
|
268
265
|
if (fs.existsSync(gitDir)) {
|
|
@@ -380,14 +377,22 @@ async function scanAndAdd({ root, depth } = {}) {
|
|
|
380
377
|
|
|
381
378
|
console.log(`\n Adding ${toAdd.length} project(s)...\n`);
|
|
382
379
|
|
|
380
|
+
const existingNames = new Set((config.projects || []).map(p => p.name));
|
|
383
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);
|
|
384
390
|
config.projects.push(buildProjectEntry({
|
|
385
|
-
name
|
|
391
|
+
name, description: repo.description, localPath: repo.path,
|
|
386
392
|
repoHost: repo.host, org: repo.org, project: repo.project,
|
|
387
393
|
repoName: repo.repoName, mainBranch: repo.mainBranch,
|
|
388
394
|
}));
|
|
389
|
-
|
|
390
|
-
console.log(` + ${repo.name} (${repo.path})`);
|
|
395
|
+
console.log(` + ${name} (${repo.path})`);
|
|
391
396
|
}
|
|
392
397
|
|
|
393
398
|
saveConfig(config);
|
|
@@ -419,19 +424,34 @@ async function initMinions({ skipScan = false, scanRoot, scanDepth } = {}) {
|
|
|
419
424
|
saveConfig(config);
|
|
420
425
|
console.log(`\n Minions initialized at ${MINIONS_HOME}`);
|
|
421
426
|
console.log(` Config, agents, and engine defaults created.\n`);
|
|
427
|
+
|
|
428
|
+
// Preflight checks
|
|
429
|
+
let preflightOk = true;
|
|
430
|
+
try { execSync('git --version', { encoding: 'utf8', timeout: 5000, stdio: 'pipe' }); console.log(' ✓ Git found'); }
|
|
431
|
+
catch { console.log(' ✗ Git not found — agents need git for worktrees and PRs'); preflightOk = false; }
|
|
432
|
+
try {
|
|
433
|
+
const isWin = process.platform === 'win32';
|
|
434
|
+
const cmd = isWin ? 'where claude 2>NUL' : 'which claude 2>/dev/null';
|
|
435
|
+
execSync(cmd, { encoding: 'utf8', timeout: 5000, stdio: 'pipe' });
|
|
436
|
+
console.log(' ✓ Claude Code CLI found');
|
|
437
|
+
} catch { console.log(' ✗ Claude Code CLI not found — install: npm i -g @anthropic-ai/claude-code (or native installer)'); preflightOk = false; }
|
|
438
|
+
const nodeVer = parseInt(process.versions.node);
|
|
439
|
+
if (nodeVer >= 18) { console.log(' ✓ Node.js ' + process.versions.node); }
|
|
440
|
+
else { console.log(' ✗ Node.js ' + process.versions.node + ' — version 18+ required'); preflightOk = false; }
|
|
441
|
+
if (!preflightOk) console.log('\n Some prerequisites missing — agents may fail until resolved.\n');
|
|
442
|
+
else console.log('');
|
|
422
443
|
if (removedPlaceholders > 0) {
|
|
423
444
|
console.log(` Removed ${removedPlaceholders} placeholder project entr${removedPlaceholders === 1 ? 'y' : 'ies'} from config.\n`);
|
|
424
445
|
}
|
|
425
446
|
|
|
426
447
|
if (skipScan) {
|
|
427
448
|
console.log(' Skipping repo scan (--skip-scan). Run "node minions.js scan" later to link projects.\n');
|
|
449
|
+
rl.close();
|
|
428
450
|
} else {
|
|
429
|
-
// Auto-chain into scan
|
|
451
|
+
// Auto-chain into scan (scanAndAdd closes rl)
|
|
430
452
|
console.log(' Now let\'s find your repos...\n');
|
|
431
453
|
await scanAndAdd({ root: scanRoot, depth: scanDepth });
|
|
432
454
|
}
|
|
433
|
-
|
|
434
|
-
rl.close();
|
|
435
455
|
}
|
|
436
456
|
|
|
437
457
|
function nukeMinions() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.203",
|
|
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"
|