@yemi33/minions 0.1.576 → 0.1.578
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 +7 -1
- package/dashboard.js +4 -4
- package/engine/llm.js +83 -51
- package/engine.js +46 -32
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.578 (2026-04-08)
|
|
4
4
|
|
|
5
5
|
### Other
|
|
6
|
+
- refactor: extract _spawnProcess helper, fix dep fetch error tracking, cleanup file leak
|
|
7
|
+
|
|
8
|
+
## 0.1.577 (2026-04-08)
|
|
9
|
+
|
|
10
|
+
### Other
|
|
11
|
+
- perf: parallelize worktree/prompt, direct CLI spawn, parallel dep fetch
|
|
6
12
|
- chore: remove orphaned comment, fix PID write test assertion
|
|
7
13
|
|
|
8
14
|
## 0.1.575 (2026-04-08)
|
package/dashboard.js
CHANGED
|
@@ -788,7 +788,7 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
|
|
|
788
788
|
// Attempt 1: resume existing session — skip preamble (session already has context)
|
|
789
789
|
if (sessionId && maxTurns > 1) {
|
|
790
790
|
result = await llm.callLLM(buildPrompt({ includePreamble: false }), '', {
|
|
791
|
-
timeout, label, model, maxTurns, allowedTools, sessionId, effort: ccEffort,
|
|
791
|
+
timeout, label, model, maxTurns, allowedTools, sessionId, effort: ccEffort, direct: true,
|
|
792
792
|
});
|
|
793
793
|
llm.trackEngineUsage(label, result.usage);
|
|
794
794
|
|
|
@@ -823,7 +823,7 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
|
|
|
823
823
|
// Attempt 2: fresh session (include preamble for full context)
|
|
824
824
|
const freshPrompt = buildPrompt();
|
|
825
825
|
result = await llm.callLLM(freshPrompt, CC_STATIC_SYSTEM_PROMPT, {
|
|
826
|
-
timeout, label, model, maxTurns, allowedTools, effort: ccEffort,
|
|
826
|
+
timeout, label, model, maxTurns, allowedTools, effort: ccEffort, direct: true,
|
|
827
827
|
});
|
|
828
828
|
llm.trackEngineUsage(label, result.usage);
|
|
829
829
|
|
|
@@ -837,7 +837,7 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
|
|
|
837
837
|
console.log(`[${label}] Fresh call also failed (code=${result.code}, empty=${!result.text}), retrying once more...`);
|
|
838
838
|
await new Promise(r => setTimeout(r, 2000));
|
|
839
839
|
result = await llm.callLLM(freshPrompt, CC_STATIC_SYSTEM_PROMPT, {
|
|
840
|
-
timeout, label, model, maxTurns, allowedTools, effort: ccEffort,
|
|
840
|
+
timeout, label, model, maxTurns, allowedTools, effort: ccEffort, direct: true,
|
|
841
841
|
});
|
|
842
842
|
llm.trackEngineUsage(label, result.usage);
|
|
843
843
|
|
|
@@ -3350,7 +3350,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
3350
3350
|
const llmPromise = callLLMStreaming(prompt, CC_STATIC_SYSTEM_PROMPT, {
|
|
3351
3351
|
timeout: 900000, label: 'command-center', model: streamModel, maxTurns: 50,
|
|
3352
3352
|
allowedTools: 'Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch',
|
|
3353
|
-
sessionId, effort: streamEffort,
|
|
3353
|
+
sessionId, effort: streamEffort, direct: true,
|
|
3354
3354
|
onChunk: (text) => {
|
|
3355
3355
|
try { res.write('data: ' + JSON.stringify({ type: 'chunk', text }) + '\n\n'); } catch {}
|
|
3356
3356
|
},
|
package/engine/llm.js
CHANGED
|
@@ -43,32 +43,87 @@ function trackEngineUsage(category, usage) {
|
|
|
43
43
|
} catch (e) { console.error('metrics update:', e.message); }
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// ── Claude Binary Resolution (cached by spawn-agent.js) ─────────────────────
|
|
47
|
+
|
|
48
|
+
let _claudeBinCache = null;
|
|
49
|
+
function _resolveClaudeBin() {
|
|
50
|
+
if (_claudeBinCache) return _claudeBinCache;
|
|
51
|
+
const caps = shared.safeJson(path.join(ENGINE_DIR, 'claude-caps.json'));
|
|
52
|
+
if (caps?.claudeBin && require('fs').existsSync(caps.claudeBin)) {
|
|
53
|
+
_claudeBinCache = { bin: caps.claudeBin, native: !!caps.claudeIsNative };
|
|
54
|
+
return _claudeBinCache;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Spawn Helpers ───────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
function _buildCliArgs({ model, maxTurns, allowedTools, effort, sessionId, sysPromptFile }) {
|
|
62
|
+
const args = ['-p', '--output-format', 'stream-json', '--max-turns', String(maxTurns), '--model', model, '--verbose'];
|
|
63
|
+
if (sysPromptFile) args.push('--system-prompt-file', sysPromptFile);
|
|
64
|
+
if (allowedTools) args.push('--allowedTools', allowedTools);
|
|
65
|
+
if (effort) args.push('--effort', effort);
|
|
66
|
+
args.push('--permission-mode', 'bypassPermissions');
|
|
67
|
+
if (sessionId) args.push('--resume', sessionId);
|
|
68
|
+
return args;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Spawn a claude CLI process. Returns { proc, cleanupFiles } or null if binary not cached.
|
|
73
|
+
* When direct=true, spawns claude CLI directly (fewer syscalls). Otherwise uses spawn-agent.js.
|
|
74
|
+
*/
|
|
75
|
+
function _spawnProcess(promptText, sysPromptText, { direct, label, model, maxTurns, allowedTools, effort, sessionId }) {
|
|
76
|
+
const fs = require('fs');
|
|
77
|
+
const id = uid();
|
|
78
|
+
const tmpDir = path.join(ENGINE_DIR, 'tmp');
|
|
79
|
+
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
|
|
80
|
+
|
|
81
|
+
const cleanupFiles = [];
|
|
82
|
+
const resolved = direct ? _resolveClaudeBin() : null;
|
|
83
|
+
|
|
84
|
+
if (resolved) {
|
|
85
|
+
let sysTmpPath = null;
|
|
86
|
+
if (!sessionId && sysPromptText) {
|
|
87
|
+
sysTmpPath = path.join(tmpDir, `direct-sys-${id}.md`);
|
|
88
|
+
fs.writeFileSync(sysTmpPath, sysPromptText);
|
|
89
|
+
cleanupFiles.push(sysTmpPath);
|
|
90
|
+
}
|
|
91
|
+
const cliArgs = _buildCliArgs({ model, maxTurns, allowedTools, effort, sessionId, sysPromptFile: sysTmpPath });
|
|
92
|
+
const proc = resolved.native
|
|
93
|
+
? runFile(resolved.bin, cliArgs, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() })
|
|
94
|
+
: runFile(process.execPath, [resolved.bin, ...cliArgs], { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
|
|
95
|
+
try { proc.stdin.write(promptText); proc.stdin.end(); } catch { /* broken pipe */ }
|
|
96
|
+
return { proc, cleanupFiles };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Indirect: use spawn-agent.js
|
|
100
|
+
const promptPath = path.join(tmpDir, `${label}-prompt-${id}.md`);
|
|
101
|
+
const sysPath = path.join(tmpDir, `${label}-sys-${id}.md`);
|
|
102
|
+
safeWrite(promptPath, promptText);
|
|
103
|
+
safeWrite(sysPath, sysPromptText || '');
|
|
104
|
+
cleanupFiles.push(promptPath, sysPath);
|
|
105
|
+
|
|
106
|
+
const spawnScript = path.join(ENGINE_DIR, 'spawn-agent.js');
|
|
107
|
+
const args = [
|
|
108
|
+
spawnScript, promptPath, sysPath,
|
|
109
|
+
'--output-format', 'stream-json', '--max-turns', String(maxTurns), '--model', model,
|
|
110
|
+
'--verbose',
|
|
111
|
+
];
|
|
112
|
+
if (allowedTools) args.push('--allowedTools', allowedTools);
|
|
113
|
+
if (effort) args.push('--effort', effort);
|
|
114
|
+
args.push('--permission-mode', 'bypassPermissions');
|
|
115
|
+
if (sessionId) args.push('--resume', sessionId);
|
|
116
|
+
|
|
117
|
+
const proc = runFile(process.execPath, args, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
|
|
118
|
+
return { proc, cleanupFiles };
|
|
119
|
+
}
|
|
120
|
+
|
|
46
121
|
// ── Core LLM Call ───────────────────────────────────────────────────────────
|
|
47
122
|
|
|
48
|
-
function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, effort = null } = {}) {
|
|
123
|
+
function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, effort = null, direct = false } = {}) {
|
|
49
124
|
return new Promise((resolve) => {
|
|
50
|
-
const id = uid();
|
|
51
|
-
const tmpDir = path.join(ENGINE_DIR, 'tmp');
|
|
52
|
-
if (!require('fs').existsSync(tmpDir)) require('fs').mkdirSync(tmpDir, { recursive: true });
|
|
53
|
-
const promptPath = path.join(tmpDir, `${label}-prompt-${id}.md`);
|
|
54
|
-
const sysPath = path.join(tmpDir, `${label}-sys-${id}.md`);
|
|
55
|
-
safeWrite(promptPath, promptText);
|
|
56
|
-
safeWrite(sysPath, sysPromptText || '');
|
|
57
|
-
|
|
58
|
-
const spawnScript = path.join(ENGINE_DIR, 'spawn-agent.js');
|
|
59
|
-
const args = [
|
|
60
|
-
spawnScript, promptPath, sysPath,
|
|
61
|
-
'--output-format', 'stream-json', '--max-turns', String(maxTurns), '--model', model,
|
|
62
|
-
'--verbose',
|
|
63
|
-
];
|
|
64
|
-
if (allowedTools) args.push('--allowedTools', allowedTools);
|
|
65
|
-
if (effort) args.push('--effort', effort);
|
|
66
|
-
args.push('--permission-mode', 'bypassPermissions');
|
|
67
|
-
|
|
68
|
-
if (sessionId) args.push('--resume', sessionId);
|
|
69
|
-
|
|
70
125
|
const _startMs = Date.now();
|
|
71
|
-
const proc =
|
|
126
|
+
const { proc, cleanupFiles } = _spawnProcess(promptText, sysPromptText, { direct, label, model, maxTurns, allowedTools, effort, sessionId });
|
|
72
127
|
|
|
73
128
|
let stdout = '';
|
|
74
129
|
let stderr = '';
|
|
@@ -79,8 +134,7 @@ function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', m
|
|
|
79
134
|
|
|
80
135
|
proc.on('close', (code) => {
|
|
81
136
|
clearTimeout(timer);
|
|
82
|
-
safeUnlink(
|
|
83
|
-
safeUnlink(sysPath);
|
|
137
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
84
138
|
const parsed = parseStreamJsonOutput(stdout);
|
|
85
139
|
const durationMs = Date.now() - _startMs;
|
|
86
140
|
const usage = parsed.usage ? { ...parsed.usage, durationMs } : { durationMs };
|
|
@@ -89,8 +143,7 @@ function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', m
|
|
|
89
143
|
|
|
90
144
|
proc.on('error', (err) => {
|
|
91
145
|
clearTimeout(timer);
|
|
92
|
-
safeUnlink(
|
|
93
|
-
safeUnlink(sysPath);
|
|
146
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
94
147
|
resolve({ text: '', usage: null, sessionId: null, code: 1, stderr: err.message, raw: '' });
|
|
95
148
|
});
|
|
96
149
|
});
|
|
@@ -118,30 +171,11 @@ function isResumeSessionStillValid(result) {
|
|
|
118
171
|
* Returns the same result object as callLLM when the process completes.
|
|
119
172
|
* onChunk(text) is called for each assistant text block as it arrives.
|
|
120
173
|
*/
|
|
121
|
-
function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, onChunk = () => {}, onToolUse = null, effort = null } = {}) {
|
|
174
|
+
function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, onChunk = () => {}, onToolUse = null, effort = null, direct = false } = {}) {
|
|
122
175
|
let _abort = null;
|
|
123
176
|
const promise = new Promise((resolve) => {
|
|
124
|
-
const id = uid();
|
|
125
|
-
const tmpDir = path.join(ENGINE_DIR, 'tmp');
|
|
126
|
-
if (!require('fs').existsSync(tmpDir)) require('fs').mkdirSync(tmpDir, { recursive: true });
|
|
127
|
-
const promptPath = path.join(tmpDir, `${label}-prompt-${id}.md`);
|
|
128
|
-
const sysPath = path.join(tmpDir, `${label}-sys-${id}.md`);
|
|
129
|
-
safeWrite(promptPath, promptText);
|
|
130
|
-
safeWrite(sysPath, sysPromptText || '');
|
|
131
|
-
|
|
132
|
-
const spawnScript = path.join(ENGINE_DIR, 'spawn-agent.js');
|
|
133
|
-
const args = [
|
|
134
|
-
spawnScript, promptPath, sysPath,
|
|
135
|
-
'--output-format', 'stream-json', '--max-turns', String(maxTurns), '--model', model,
|
|
136
|
-
'--verbose',
|
|
137
|
-
];
|
|
138
|
-
if (allowedTools) args.push('--allowedTools', allowedTools);
|
|
139
|
-
if (effort) args.push('--effort', effort);
|
|
140
|
-
args.push('--permission-mode', 'bypassPermissions');
|
|
141
|
-
if (sessionId) args.push('--resume', sessionId);
|
|
142
|
-
|
|
143
177
|
const _startMs = Date.now();
|
|
144
|
-
const proc =
|
|
178
|
+
const { proc, cleanupFiles } = _spawnProcess(promptText, sysPromptText, { direct, label, model, maxTurns, allowedTools, effort, sessionId });
|
|
145
179
|
|
|
146
180
|
_abort = () => { shared.killImmediate(proc); };
|
|
147
181
|
|
|
@@ -181,8 +215,7 @@ function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label =
|
|
|
181
215
|
|
|
182
216
|
proc.on('close', (code) => {
|
|
183
217
|
clearTimeout(timer);
|
|
184
|
-
safeUnlink(
|
|
185
|
-
safeUnlink(sysPath);
|
|
218
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
186
219
|
const parsed = parseStreamJsonOutput(stdout);
|
|
187
220
|
const durationMs = Date.now() - _startMs;
|
|
188
221
|
const usage = parsed.usage ? { ...parsed.usage, durationMs } : { durationMs };
|
|
@@ -191,8 +224,7 @@ function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label =
|
|
|
191
224
|
|
|
192
225
|
proc.on('error', (err) => {
|
|
193
226
|
clearTimeout(timer);
|
|
194
|
-
safeUnlink(
|
|
195
|
-
safeUnlink(sysPath);
|
|
227
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
196
228
|
resolve({ text: '', usage: null, sessionId: null, code: 1, stderr: err.message, raw: '' });
|
|
197
229
|
});
|
|
198
230
|
});
|
package/engine.js
CHANGED
|
@@ -278,6 +278,22 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
278
278
|
const _gitOpts = { stdio: 'pipe', timeout: 30000, windowsHide: true, env: shared.gitEnv() };
|
|
279
279
|
const _worktreeGitOpts = { ..._gitOpts, timeout: worktreeCreateTimeout };
|
|
280
280
|
|
|
281
|
+
// Build prompt before worktree setup — prompt doesn't depend on worktree path
|
|
282
|
+
// and this avoids blocking 200ms of file reads behind 20-60s of git operations
|
|
283
|
+
const systemPrompt = buildSystemPrompt(agentId, config, project);
|
|
284
|
+
const agentContext = buildAgentContext(agentId, config, project);
|
|
285
|
+
const fullTaskPrompt = agentContext
|
|
286
|
+
? `## Agent Context\n\n${agentContext}\n---\n\n## Your Task\n\n${taskPrompt}`
|
|
287
|
+
: taskPrompt;
|
|
288
|
+
const tmpDir = path.join(ENGINE_DIR, 'tmp');
|
|
289
|
+
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
|
|
290
|
+
const safeId = id.replace(/[:\\/*?"<>|]/g, '-');
|
|
291
|
+
const promptPath = path.join(tmpDir, `prompt-${safeId}.md`);
|
|
292
|
+
safeWrite(promptPath, fullTaskPrompt);
|
|
293
|
+
const sysPromptPath = path.join(tmpDir, `sysprompt-${safeId}.md`);
|
|
294
|
+
safeWrite(sysPromptPath, systemPrompt);
|
|
295
|
+
const _cleanupPromptFiles = () => { safeUnlink(promptPath); safeUnlink(sysPromptPath); };
|
|
296
|
+
|
|
281
297
|
if (branchName) {
|
|
282
298
|
const wtSuffix = id ? id.split('-').pop() : shared.uid();
|
|
283
299
|
const projectSlug = (project.name || 'default').replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
@@ -413,24 +429,41 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
413
429
|
try {
|
|
414
430
|
const depBranches = resolveDependencyBranches(depIds, meta?.item?.sourcePlan, project, config);
|
|
415
431
|
let depMergeFailed = false;
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
432
|
+
// Fetch all dependency branches in parallel (git fetches are independent)
|
|
433
|
+
const fetchable = depBranches.filter(d => !_failedRefCache.has(d.branch));
|
|
434
|
+
const unfetchable = depBranches.filter(d => _failedRefCache.has(d.branch));
|
|
435
|
+
for (const { branch: depBranch } of unfetchable) {
|
|
436
|
+
log('warn', `Skipping dependency ${depBranch} — already failed to fetch this tick`);
|
|
437
|
+
depMergeFailed = true;
|
|
438
|
+
}
|
|
439
|
+
const fetchResults = await Promise.allSettled(
|
|
440
|
+
fetchable.map(({ branch: depBranch }) =>
|
|
441
|
+
execAsync(`git fetch origin "${depBranch}"`, { ..._gitOpts, cwd: rootDir }).then(() => depBranch)
|
|
442
|
+
)
|
|
443
|
+
);
|
|
444
|
+
for (let i = 0; i < fetchResults.length; i++) {
|
|
445
|
+
if (fetchResults[i].status === 'rejected') {
|
|
446
|
+
const failedBranch = fetchable[i].branch;
|
|
447
|
+
_failedRefCache.add(failedBranch);
|
|
448
|
+
log('warn', `Failed to fetch dependency ${failedBranch}: ${fetchResults[i].reason?.message}`);
|
|
420
449
|
depMergeFailed = true;
|
|
421
|
-
continue;
|
|
422
450
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
451
|
+
}
|
|
452
|
+
// Merge fetched branches sequentially (merges modify the worktree)
|
|
453
|
+
if (!depMergeFailed) {
|
|
454
|
+
for (const { branch: depBranch, prId } of fetchable) {
|
|
455
|
+
try {
|
|
456
|
+
await execAsync(`git merge "origin/${depBranch}" --no-edit`, { ..._gitOpts, cwd: worktreePath });
|
|
457
|
+
log('info', `Merged dependency branch ${depBranch} (${prId}) into worktree ${branchName}`);
|
|
458
|
+
} catch (mergeErr) {
|
|
459
|
+
log('warn', `Failed to merge dependency ${depBranch} into ${branchName}: ${mergeErr.message}`);
|
|
460
|
+
depMergeFailed = true;
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
431
463
|
}
|
|
432
464
|
}
|
|
433
465
|
if (depMergeFailed) {
|
|
466
|
+
_cleanupPromptFiles();
|
|
434
467
|
completeDispatch(id, DISPATCH_RESULT.ERROR, `Dependency merge failed — will retry next tick`);
|
|
435
468
|
return;
|
|
436
469
|
}
|
|
@@ -441,30 +474,11 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
441
474
|
}
|
|
442
475
|
}
|
|
443
476
|
|
|
444
|
-
// Build lean system prompt (identity + rules, ~2-4KB) and bulk context (history, notes, skills)
|
|
445
|
-
const systemPrompt = buildSystemPrompt(agentId, config, project);
|
|
446
|
-
const agentContext = buildAgentContext(agentId, config, project);
|
|
447
|
-
|
|
448
477
|
// Safety check: warn if a write-capable task is running in the main repo without a worktree
|
|
449
478
|
if (cwd === rootDir && ['implement', 'implement:large', 'fix', 'test', 'verify', 'plan-to-prd'].includes(type)) {
|
|
450
479
|
log('warn', `Agent ${agentId} running ${type} task in main repo (no worktree) for ${id} — changes may land on master directly`);
|
|
451
480
|
}
|
|
452
481
|
|
|
453
|
-
// Prepend bulk context to task prompt — keeps system prompt small and stable
|
|
454
|
-
const fullTaskPrompt = agentContext
|
|
455
|
-
? `## Agent Context\n\n${agentContext}\n---\n\n## Your Task\n\n${taskPrompt}`
|
|
456
|
-
: taskPrompt;
|
|
457
|
-
|
|
458
|
-
// Write prompt and system prompt to temp files (avoids shell escaping issues)
|
|
459
|
-
const tmpDir = path.join(ENGINE_DIR, 'tmp');
|
|
460
|
-
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
|
|
461
|
-
const safeId = id.replace(/[:\\/*?"<>|]/g, '-');
|
|
462
|
-
const promptPath = path.join(tmpDir, `prompt-${safeId}.md`);
|
|
463
|
-
safeWrite(promptPath, fullTaskPrompt);
|
|
464
|
-
|
|
465
|
-
const sysPromptPath = path.join(tmpDir, `sysprompt-${safeId}.md`);
|
|
466
|
-
safeWrite(sysPromptPath, systemPrompt);
|
|
467
|
-
|
|
468
482
|
// Build claude CLI args
|
|
469
483
|
const args = [
|
|
470
484
|
'--output-format', claudeConfig.outputFormat || 'stream-json',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.578",
|
|
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"
|