@yemi33/minions 0.1.200 → 0.1.202
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 +6 -1
- package/engine/spawn-agent.js +50 -58
- package/minions.js +9 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/engine/spawn-agent.js
CHANGED
|
@@ -22,64 +22,55 @@ const sysPrompt = fs.readFileSync(sysPromptFile, 'utf8');
|
|
|
22
22
|
|
|
23
23
|
const env = cleanChildEnv();
|
|
24
24
|
|
|
25
|
-
// Resolve claude binary —
|
|
25
|
+
// Resolve claude binary — supports both npm install (cli.js) and native installer (binary on PATH)
|
|
26
26
|
let claudeBin;
|
|
27
|
+
let claudeIsNative = false; // true = native binary, false = node cli.js
|
|
27
28
|
|
|
28
|
-
// Strategy 1:
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
path.join(path.dirname(process.execPath), 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
|
|
44
|
-
// Local node_modules (if minions is in a project)
|
|
45
|
-
path.join(__dirname, '..', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
|
|
46
|
-
].filter(Boolean);
|
|
47
|
-
for (const p of searchPaths) {
|
|
48
|
-
try { if (fs.existsSync(p)) { claudeBin = p; break; } } catch {}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Strategy 2: Use `which` (Unix) or `where` (Windows) to find the claude wrapper, then resolve cli.js
|
|
52
|
-
if (!claudeBin) {
|
|
53
|
-
try {
|
|
54
|
-
const isWin = process.platform === 'win32';
|
|
55
|
-
const cmd = isWin ? 'where claude 2>NUL' : 'which claude 2>/dev/null';
|
|
56
|
-
const which = exec(cmd, { encoding: 'utf8', env, timeout: 10000 }).trim().split('\n')[0].trim();
|
|
57
|
-
if (which) {
|
|
58
|
-
const whichNative = isWin ? which : which.replace(/^\/([a-zA-Z])\//, (_, d) => d.toUpperCase() + ':/').replace(/\//g, path.sep);
|
|
59
|
-
// The wrapper script or symlink — resolve to cli.js
|
|
60
|
-
try {
|
|
61
|
-
const resolved = fs.realpathSync(whichNative);
|
|
62
|
-
if (resolved.endsWith('cli.js')) {
|
|
63
|
-
claudeBin = resolved;
|
|
64
|
-
} else {
|
|
65
|
-
// Read wrapper script to extract cli.js path
|
|
66
|
-
const wrapper = fs.readFileSync(resolved, 'utf8');
|
|
67
|
-
const m = wrapper.match(/node_modules[\\/]@anthropic-ai[\\/]claude-code[\\/]cli\.js/);
|
|
68
|
-
if (m) claudeBin = path.join(path.dirname(resolved), 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js');
|
|
69
|
-
}
|
|
70
|
-
} catch {
|
|
71
|
-
// Try reading the wrapper directly (may be a batch file on Windows)
|
|
72
|
-
try {
|
|
73
|
-
const wrapper = fs.readFileSync(whichNative, 'utf8');
|
|
74
|
-
const m = wrapper.match(/node_modules[\\/]@anthropic-ai[\\/]claude-code[\\/]cli\.js/);
|
|
75
|
-
if (m) claudeBin = path.join(path.dirname(whichNative), 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js');
|
|
76
|
-
} catch {}
|
|
29
|
+
// Strategy 1: Check if `claude` is on PATH (native installer or npm global bin)
|
|
30
|
+
try {
|
|
31
|
+
const isWin = process.platform === 'win32';
|
|
32
|
+
const cmd = isWin ? 'where claude 2>NUL' : 'which claude 2>/dev/null';
|
|
33
|
+
const which = exec(cmd, { encoding: 'utf8', env, timeout: 10000 }).trim().split('\n')[0].trim();
|
|
34
|
+
if (which) {
|
|
35
|
+
const whichNative = isWin ? which : which.replace(/^\/([a-zA-Z])\//, (_, d) => d.toUpperCase() + ':/').replace(/\//g, path.sep);
|
|
36
|
+
// Check if it's a node wrapper (npm install) or native binary
|
|
37
|
+
try {
|
|
38
|
+
const content = fs.readFileSync(whichNative, 'utf8');
|
|
39
|
+
// npm wrapper scripts reference cli.js — extract the path
|
|
40
|
+
const m = content.match(/node_modules[\\/]@anthropic-ai[\\/]claude-code[\\/]cli\.js/);
|
|
41
|
+
if (m) {
|
|
42
|
+
const candidate = path.join(path.dirname(whichNative), 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js');
|
|
43
|
+
if (fs.existsSync(candidate)) { claudeBin = candidate; }
|
|
77
44
|
}
|
|
45
|
+
} catch {
|
|
46
|
+
// Can't read as text — it's a compiled binary
|
|
78
47
|
}
|
|
79
|
-
|
|
48
|
+
if (!claudeBin) {
|
|
49
|
+
// Native binary or wrapper without cli.js reference — use directly
|
|
50
|
+
claudeBin = whichNative;
|
|
51
|
+
claudeIsNative = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} catch { /* optional */ }
|
|
55
|
+
|
|
56
|
+
// Strategy 2: Known node_modules locations (npm global installs)
|
|
57
|
+
if (!claudeBin) {
|
|
58
|
+
const searchPaths = [
|
|
59
|
+
process.env.npm_config_prefix ? path.join(process.env.npm_config_prefix, 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js') : '',
|
|
60
|
+
process.env.APPDATA ? path.join(process.env.APPDATA, 'npm', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js') : '',
|
|
61
|
+
'/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js',
|
|
62
|
+
'/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js',
|
|
63
|
+
'/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js',
|
|
64
|
+
path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
|
|
65
|
+
path.join(path.dirname(process.execPath), 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
|
|
66
|
+
path.join(__dirname, '..', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
|
|
67
|
+
].filter(Boolean);
|
|
68
|
+
for (const p of searchPaths) {
|
|
69
|
+
try { if (fs.existsSync(p)) { claudeBin = p; break; } } catch {}
|
|
70
|
+
}
|
|
80
71
|
}
|
|
81
72
|
|
|
82
|
-
// Strategy 3: npm root -g
|
|
73
|
+
// Strategy 3: npm root -g
|
|
83
74
|
if (!claudeBin) {
|
|
84
75
|
try {
|
|
85
76
|
const globalRoot = exec('npm root -g', { encoding: 'utf8', env, timeout: 10000 }).trim();
|
|
@@ -92,7 +83,7 @@ if (!claudeBin) {
|
|
|
92
83
|
const tmpDir = path.join(__dirname, 'tmp');
|
|
93
84
|
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
|
|
94
85
|
const debugPath = path.join(tmpDir, 'spawn-debug.log');
|
|
95
|
-
fs.writeFileSync(debugPath, `spawn-agent.js at ${new Date().toISOString()}\nclaudeBin=${claudeBin || 'not found'}\nprompt=${promptFile}\nsysPrompt=${sysPromptFile}\nextraArgs=${extraArgs.join(' ')}\n`);
|
|
86
|
+
fs.writeFileSync(debugPath, `spawn-agent.js at ${new Date().toISOString()}\nclaudeBin=${claudeBin || 'not found'}\nnative=${claudeIsNative}\nprompt=${promptFile}\nsysPrompt=${sysPromptFile}\nextraArgs=${extraArgs.join(' ')}\n`);
|
|
96
87
|
|
|
97
88
|
// When resuming a session, skip system prompt (it's baked into the session)
|
|
98
89
|
const isResume = extraArgs.includes('--resume');
|
|
@@ -124,7 +115,9 @@ try {
|
|
|
124
115
|
if (_sysPromptFileSupported === null) {
|
|
125
116
|
try {
|
|
126
117
|
const { spawnSync } = require('child_process');
|
|
127
|
-
const testResult =
|
|
118
|
+
const testResult = claudeIsNative
|
|
119
|
+
? spawnSync(claudeBin, ['--help'], { encoding: 'utf8', timeout: 10000, windowsHide: true })
|
|
120
|
+
: spawnSync(process.execPath, [claudeBin, '--help'], { encoding: 'utf8', timeout: 10000, windowsHide: true });
|
|
128
121
|
_sysPromptFileSupported = (testResult.stdout || '').includes('system-prompt-file');
|
|
129
122
|
try { fs.writeFileSync(capsCachePath, JSON.stringify({ claudeBin, sysPromptFile: _sysPromptFileSupported, checkedAt: new Date().toISOString() })); } catch { /* optional */ }
|
|
130
123
|
} catch { _sysPromptFileSupported = true; /* assume supported */ }
|
|
@@ -150,10 +143,9 @@ if (!isResume) try {
|
|
|
150
143
|
// If help check fails, try file approach anyway
|
|
151
144
|
}
|
|
152
145
|
|
|
153
|
-
const proc =
|
|
154
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
155
|
-
env
|
|
156
|
-
});
|
|
146
|
+
const proc = claudeIsNative
|
|
147
|
+
? runFile(claudeBin, actualArgs, { stdio: ['pipe', 'pipe', 'pipe'], env })
|
|
148
|
+
: runFile(process.execPath, [claudeBin, ...actualArgs], { stdio: ['pipe', 'pipe', 'pipe'], env });
|
|
157
149
|
|
|
158
150
|
fs.appendFileSync(debugPath, `PID=${proc.pid || 'none'}\nargs=${actualArgs.join(' ').slice(0, 500)}\n`);
|
|
159
151
|
|
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 {}
|
|
@@ -141,20 +146,12 @@ function buildProjectEntry({ name, description, localPath, repoHost, repositoryI
|
|
|
141
146
|
repoName: repoName || name,
|
|
142
147
|
mainBranch: mainBranch || 'main',
|
|
143
148
|
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
149
|
};
|
|
149
150
|
}
|
|
150
151
|
|
|
151
|
-
function ensureProjectStateFiles(
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
}
|
|
152
|
+
function ensureProjectStateFiles() {
|
|
153
|
+
// Project state is stored centrally at ~/.minions/projects/<name>/
|
|
154
|
+
// No files created inside user repos.
|
|
158
155
|
}
|
|
159
156
|
|
|
160
157
|
// ─── Commands ────────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.202",
|
|
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"
|