@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 CHANGED
@@ -1,6 +1,11 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.200 (2026-04-02)
3
+ ## 0.1.202 (2026-04-02)
4
+
5
+ ### Other
6
+ - minions.js
7
+
8
+ ## 0.1.201 (2026-04-02)
4
9
 
5
10
  ### Engine
6
11
  - engine/ado.js
@@ -22,64 +22,55 @@ const sysPrompt = fs.readFileSync(sysPromptFile, 'utf8');
22
22
 
23
23
  const env = cleanChildEnv();
24
24
 
25
- // Resolve claude binary — find the actual JS entry point
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: Known global install locations
29
- const homeDir = process.env.USERPROFILE || process.env.HOME || '';
30
- const searchPaths = [
31
- // npm global (npm_config_prefix)
32
- process.env.npm_config_prefix ? path.join(process.env.npm_config_prefix, 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js') : '',
33
- // Windows: %APPDATA%\npm
34
- process.env.APPDATA ? path.join(process.env.APPDATA, 'npm', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js') : '',
35
- // Unix global
36
- '/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js',
37
- '/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js',
38
- // Homebrew (macOS)
39
- '/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js',
40
- // nvm (current node version)
41
- path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'),
42
- // fnm / volta sibling to the node binary
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
- } catch { /* optional */ }
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 to find global node_modules
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 = spawnSync(process.execPath, [claudeBin, '--help'], { encoding: 'utf8', timeout: 10000, windowsHide: true });
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 = runFile(process.execPath, [claudeBin, ...actualArgs], {
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
- const head = execSync('git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || git symbolic-ref HEAD', { cwd: targetDir, encoding: 'utf8', timeout: 5000 }).trim();
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(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
- }
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.200",
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"