@yemi33/minions 0.1.564 → 0.1.566

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,12 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.564 (2026-04-08)
3
+ ## 0.1.566 (2026-04-08)
4
+
5
+ ### Other
6
+ - refactor: use safeJson/safeWrite for spawn-agent cache, remove unused checkedAt
7
+
8
+ ## 0.1.565 (2026-04-08)
4
9
 
5
10
  ### Fixes
6
11
  - worktree audit followups — delete ordering, path traversal guard
7
12
  - worktree lifecycle — fail on dep merge, fallback rm, cleanup on plan delete
8
13
  - auto-reset CC session on resume failure, add error logging
9
14
 
15
+ ### Other
16
+ - perf: cache claude binary path across spawns in spawn-agent.js
17
+
10
18
  ## 0.1.561 (2026-04-08)
11
19
 
12
20
  ### Fixes
@@ -8,7 +8,7 @@
8
8
 
9
9
  const fs = require('fs');
10
10
  const path = require('path');
11
- const { exec, runFile, cleanChildEnv, killGracefully, killImmediate, ts } = require('./shared');
11
+ const { exec, runFile, cleanChildEnv, killGracefully, killImmediate, ts, safeJson, safeWrite } = require('./shared');
12
12
 
13
13
  const [,, promptFile, sysPromptFile, ...extraArgs] = process.argv;
14
14
 
@@ -25,9 +25,19 @@ const env = cleanChildEnv();
25
25
  // Resolve claude binary — supports both npm install (cli.js) and native installer (binary on PATH)
26
26
  let claudeBin;
27
27
  let claudeIsNative = false; // true = native binary, false = node cli.js
28
+ const capsCachePath = path.join(__dirname, 'claude-caps.json');
29
+ let _sysPromptFileSupported = null;
30
+
31
+ // Fast path: use cached binary path if it still exists on disk
32
+ const caps = safeJson(capsCachePath);
33
+ if (caps?.claudeBin && fs.existsSync(caps.claudeBin)) {
34
+ claudeBin = caps.claudeBin;
35
+ claudeIsNative = !!caps.claudeIsNative;
36
+ _sysPromptFileSupported = caps.sysPromptFile ?? null;
37
+ }
28
38
 
29
39
  // Strategy 1: Check if `claude` is on PATH (native installer or npm global bin)
30
- try {
40
+ if (!claudeBin) try {
31
41
  const isWin = process.platform === 'win32';
32
42
  const cmd = isWin ? 'where claude 2>NUL' : 'which claude 2>/dev/null';
33
43
  const which = exec(cmd, { encoding: 'utf8', env, timeout: 10000 }).trim().split('\n')[0].trim();
@@ -79,11 +89,11 @@ if (!claudeBin) {
79
89
  } catch { /* optional */ }
80
90
  }
81
91
 
82
- // Debug log
92
+ // Debug log (async — not on critical path)
83
93
  const tmpDir = path.join(__dirname, 'tmp');
84
94
  if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
85
95
  const debugPath = path.join(tmpDir, 'spawn-debug.log');
86
- fs.writeFileSync(debugPath, `spawn-agent.js at ${ts()}\nclaudeBin=${claudeBin || 'not found'}\nnative=${claudeIsNative}\nprompt=${promptFile}\nsysPrompt=${sysPromptFile}\nextraArgs=${extraArgs.join(' ')}\n`);
96
+ fs.writeFile(debugPath, `spawn-agent.js at ${ts()}\nclaudeBin=${claudeBin || 'not found'}\nnative=${claudeIsNative}\nprompt=${promptFile}\nsysPrompt=${sysPromptFile}\nextraArgs=${extraArgs.join(' ')}\n`, () => {});
87
97
 
88
98
  // When resuming a session, skip system prompt (it's baked into the session)
89
99
  const isResume = extraArgs.includes('--resume');
@@ -104,14 +114,8 @@ if (!claudeBin) {
104
114
  process.exit(78); // 78 = configuration error (distinct from runtime failures)
105
115
  }
106
116
 
107
- // Check if --system-prompt-file is supported (cached to avoid spawning claude --help every call)
117
+ // Check if --system-prompt-file is supported (cached alongside binary path above)
108
118
  let actualArgs = cliArgs;
109
- const capsCachePath = path.join(__dirname, 'claude-caps.json');
110
- let _sysPromptFileSupported = null;
111
- try {
112
- const caps = JSON.parse(fs.readFileSync(capsCachePath, 'utf8'));
113
- if (caps.claudeBin === claudeBin) _sysPromptFileSupported = caps.sysPromptFile;
114
- } catch {}
115
119
  if (_sysPromptFileSupported === null) {
116
120
  try {
117
121
  const { spawnSync } = require('child_process');
@@ -119,8 +123,9 @@ if (_sysPromptFileSupported === null) {
119
123
  ? spawnSync(claudeBin, ['--help'], { encoding: 'utf8', timeout: 10000, windowsHide: true })
120
124
  : spawnSync(process.execPath, [claudeBin, '--help'], { encoding: 'utf8', timeout: 10000, windowsHide: true });
121
125
  _sysPromptFileSupported = (testResult.stdout || '').includes('system-prompt-file');
122
- try { fs.writeFileSync(capsCachePath, JSON.stringify({ claudeBin, sysPromptFile: _sysPromptFileSupported, checkedAt: ts() })); } catch { /* optional */ }
123
126
  } catch { _sysPromptFileSupported = true; /* assume supported */ }
127
+ // Save binary path + capability flag together
128
+ try { safeWrite(capsCachePath, { claudeBin, claudeIsNative, sysPromptFile: _sysPromptFileSupported }); } catch {}
124
129
  }
125
130
  if (!isResume) try {
126
131
  if (!_sysPromptFileSupported) {
@@ -147,7 +152,7 @@ const proc = claudeIsNative
147
152
  ? runFile(claudeBin, actualArgs, { stdio: ['pipe', 'pipe', 'pipe'], env })
148
153
  : runFile(process.execPath, [claudeBin, ...actualArgs], { stdio: ['pipe', 'pipe', 'pipe'], env });
149
154
 
150
- fs.appendFileSync(debugPath, `PID=${proc.pid || 'none'}\nargs=${actualArgs.join(' ').slice(0, 500)}\n`);
155
+ fs.appendFile(debugPath, `PID=${proc.pid || 'none'}\nargs=${actualArgs.join(' ').slice(0, 500)}\n`, () => {});
151
156
 
152
157
  // Write PID file for parent engine to verify spawn
153
158
  const pidFile = promptFile.replace(/prompt-/, 'pid-').replace(/\.md$/, '.pid');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.564",
3
+ "version": "0.1.566",
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"