@yemi33/minions 0.1.576 → 0.1.577
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 +2 -1
- package/dashboard.js +4 -4
- package/engine/llm.js +111 -47
- package/engine.js +44 -32
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
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,79 @@ 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
|
+
|
|
46
71
|
// ── Core LLM Call ───────────────────────────────────────────────────────────
|
|
47
72
|
|
|
48
|
-
function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, effort = null } = {}) {
|
|
73
|
+
function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, effort = null, direct = false } = {}) {
|
|
49
74
|
return new Promise((resolve) => {
|
|
75
|
+
const _startMs = Date.now();
|
|
76
|
+
const fs = require('fs');
|
|
50
77
|
const id = uid();
|
|
51
78
|
const tmpDir = path.join(ENGINE_DIR, 'tmp');
|
|
52
|
-
if (!
|
|
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);
|
|
79
|
+
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
const
|
|
81
|
+
let proc;
|
|
82
|
+
const cleanupFiles = [];
|
|
83
|
+
const resolved = direct ? _resolveClaudeBin() : null;
|
|
84
|
+
|
|
85
|
+
if (resolved) {
|
|
86
|
+
// Direct spawn: skip spawn-agent.js — fewer file syscalls, no extra process
|
|
87
|
+
let sysTmpPath = null;
|
|
88
|
+
if (!sessionId && sysPromptText) {
|
|
89
|
+
sysTmpPath = path.join(tmpDir, `direct-sys-${id}.md`);
|
|
90
|
+
fs.writeFileSync(sysTmpPath, sysPromptText);
|
|
91
|
+
cleanupFiles.push(sysTmpPath);
|
|
92
|
+
}
|
|
93
|
+
const cliArgs = _buildCliArgs({ model, maxTurns, allowedTools, effort, sessionId, sysPromptFile: sysTmpPath });
|
|
94
|
+
proc = resolved.native
|
|
95
|
+
? runFile(resolved.bin, cliArgs, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() })
|
|
96
|
+
: runFile(process.execPath, [resolved.bin, ...cliArgs], { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
|
|
97
|
+
try { proc.stdin.write(promptText); proc.stdin.end(); } catch { /* broken pipe */ }
|
|
98
|
+
} else {
|
|
99
|
+
// Indirect: use spawn-agent.js (for agent dispatches or if binary not cached)
|
|
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
|
+
proc = runFile(process.execPath, args, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
|
|
118
|
+
}
|
|
72
119
|
|
|
73
120
|
let stdout = '';
|
|
74
121
|
let stderr = '';
|
|
@@ -79,8 +126,7 @@ function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', m
|
|
|
79
126
|
|
|
80
127
|
proc.on('close', (code) => {
|
|
81
128
|
clearTimeout(timer);
|
|
82
|
-
safeUnlink(
|
|
83
|
-
safeUnlink(sysPath);
|
|
129
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
84
130
|
const parsed = parseStreamJsonOutput(stdout);
|
|
85
131
|
const durationMs = Date.now() - _startMs;
|
|
86
132
|
const usage = parsed.usage ? { ...parsed.usage, durationMs } : { durationMs };
|
|
@@ -89,8 +135,7 @@ function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', m
|
|
|
89
135
|
|
|
90
136
|
proc.on('error', (err) => {
|
|
91
137
|
clearTimeout(timer);
|
|
92
|
-
safeUnlink(
|
|
93
|
-
safeUnlink(sysPath);
|
|
138
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
94
139
|
resolve({ text: '', usage: null, sessionId: null, code: 1, stderr: err.message, raw: '' });
|
|
95
140
|
});
|
|
96
141
|
});
|
|
@@ -118,30 +163,51 @@ function isResumeSessionStillValid(result) {
|
|
|
118
163
|
* Returns the same result object as callLLM when the process completes.
|
|
119
164
|
* onChunk(text) is called for each assistant text block as it arrives.
|
|
120
165
|
*/
|
|
121
|
-
function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, onChunk = () => {}, onToolUse = null, effort = null } = {}) {
|
|
166
|
+
function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label = 'llm', model = 'sonnet', maxTurns = 1, allowedTools = '', sessionId = null, onChunk = () => {}, onToolUse = null, effort = null, direct = false } = {}) {
|
|
122
167
|
let _abort = null;
|
|
123
168
|
const promise = new Promise((resolve) => {
|
|
169
|
+
const _startMs = Date.now();
|
|
170
|
+
const fs = require('fs');
|
|
124
171
|
const id = uid();
|
|
125
172
|
const tmpDir = path.join(ENGINE_DIR, 'tmp');
|
|
126
|
-
if (!
|
|
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);
|
|
173
|
+
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
|
|
142
174
|
|
|
143
|
-
|
|
144
|
-
const
|
|
175
|
+
let proc;
|
|
176
|
+
const cleanupFiles = [];
|
|
177
|
+
const resolved = direct ? _resolveClaudeBin() : null;
|
|
178
|
+
|
|
179
|
+
if (resolved) {
|
|
180
|
+
let sysTmpPath = null;
|
|
181
|
+
if (!sessionId && sysPromptText) {
|
|
182
|
+
sysTmpPath = path.join(tmpDir, `direct-sys-${id}.md`);
|
|
183
|
+
fs.writeFileSync(sysTmpPath, sysPromptText);
|
|
184
|
+
cleanupFiles.push(sysTmpPath);
|
|
185
|
+
}
|
|
186
|
+
const cliArgs = _buildCliArgs({ model, maxTurns, allowedTools, effort, sessionId, sysPromptFile: sysTmpPath });
|
|
187
|
+
proc = resolved.native
|
|
188
|
+
? runFile(resolved.bin, cliArgs, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() })
|
|
189
|
+
: runFile(process.execPath, [resolved.bin, ...cliArgs], { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
|
|
190
|
+
try { proc.stdin.write(promptText); proc.stdin.end(); } catch { /* broken pipe */ }
|
|
191
|
+
} else {
|
|
192
|
+
const promptPath = path.join(tmpDir, `${label}-prompt-${id}.md`);
|
|
193
|
+
const sysPath = path.join(tmpDir, `${label}-sys-${id}.md`);
|
|
194
|
+
safeWrite(promptPath, promptText);
|
|
195
|
+
safeWrite(sysPath, sysPromptText || '');
|
|
196
|
+
cleanupFiles.push(promptPath, sysPath);
|
|
197
|
+
|
|
198
|
+
const spawnScript = path.join(ENGINE_DIR, 'spawn-agent.js');
|
|
199
|
+
const args = [
|
|
200
|
+
spawnScript, promptPath, sysPath,
|
|
201
|
+
'--output-format', 'stream-json', '--max-turns', String(maxTurns), '--model', model,
|
|
202
|
+
'--verbose',
|
|
203
|
+
];
|
|
204
|
+
if (allowedTools) args.push('--allowedTools', allowedTools);
|
|
205
|
+
if (effort) args.push('--effort', effort);
|
|
206
|
+
args.push('--permission-mode', 'bypassPermissions');
|
|
207
|
+
if (sessionId) args.push('--resume', sessionId);
|
|
208
|
+
|
|
209
|
+
proc = runFile(process.execPath, args, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
|
|
210
|
+
}
|
|
145
211
|
|
|
146
212
|
_abort = () => { shared.killImmediate(proc); };
|
|
147
213
|
|
|
@@ -181,8 +247,7 @@ function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label =
|
|
|
181
247
|
|
|
182
248
|
proc.on('close', (code) => {
|
|
183
249
|
clearTimeout(timer);
|
|
184
|
-
safeUnlink(
|
|
185
|
-
safeUnlink(sysPath);
|
|
250
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
186
251
|
const parsed = parseStreamJsonOutput(stdout);
|
|
187
252
|
const durationMs = Date.now() - _startMs;
|
|
188
253
|
const usage = parsed.usage ? { ...parsed.usage, durationMs } : { durationMs };
|
|
@@ -191,8 +256,7 @@ function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label =
|
|
|
191
256
|
|
|
192
257
|
proc.on('error', (err) => {
|
|
193
258
|
clearTimeout(timer);
|
|
194
|
-
safeUnlink(
|
|
195
|
-
safeUnlink(sysPath);
|
|
259
|
+
for (const f of cleanupFiles) safeUnlink(f);
|
|
196
260
|
resolve({ text: '', usage: null, sessionId: null, code: 1, stderr: err.message, raw: '' });
|
|
197
261
|
});
|
|
198
262
|
});
|
package/engine.js
CHANGED
|
@@ -278,6 +278,21 @@ 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
|
+
|
|
281
296
|
if (branchName) {
|
|
282
297
|
const wtSuffix = id ? id.split('-').pop() : shared.uid();
|
|
283
298
|
const projectSlug = (project.name || 'default').replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
@@ -413,21 +428,37 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
413
428
|
try {
|
|
414
429
|
const depBranches = resolveDependencyBranches(depIds, meta?.item?.sourcePlan, project, config);
|
|
415
430
|
let depMergeFailed = false;
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
431
|
+
// Fetch all dependency branches in parallel (git fetches are independent)
|
|
432
|
+
const fetchable = depBranches.filter(d => !_failedRefCache.has(d.branch));
|
|
433
|
+
const unfetchable = depBranches.filter(d => _failedRefCache.has(d.branch));
|
|
434
|
+
for (const { branch: depBranch } of unfetchable) {
|
|
435
|
+
log('warn', `Skipping dependency ${depBranch} — already failed to fetch this tick`);
|
|
436
|
+
depMergeFailed = true;
|
|
437
|
+
}
|
|
438
|
+
const fetchResults = await Promise.allSettled(
|
|
439
|
+
fetchable.map(({ branch: depBranch }) =>
|
|
440
|
+
execAsync(`git fetch origin "${depBranch}"`, { ..._gitOpts, cwd: rootDir }).then(() => depBranch)
|
|
441
|
+
)
|
|
442
|
+
);
|
|
443
|
+
for (const r of fetchResults) {
|
|
444
|
+
if (r.status === 'rejected') {
|
|
445
|
+
const failedBranch = fetchable.find(d => r.reason?.message?.includes(d.branch))?.branch || 'unknown';
|
|
446
|
+
_failedRefCache.add(failedBranch);
|
|
447
|
+
log('warn', `Failed to fetch dependency ${failedBranch}: ${r.reason?.message}`);
|
|
420
448
|
depMergeFailed = true;
|
|
421
|
-
continue;
|
|
422
449
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
450
|
+
}
|
|
451
|
+
// Merge fetched branches sequentially (merges modify the worktree)
|
|
452
|
+
if (!depMergeFailed) {
|
|
453
|
+
for (const { branch: depBranch, prId } of fetchable) {
|
|
454
|
+
try {
|
|
455
|
+
await execAsync(`git merge "origin/${depBranch}" --no-edit`, { ..._gitOpts, cwd: worktreePath });
|
|
456
|
+
log('info', `Merged dependency branch ${depBranch} (${prId}) into worktree ${branchName}`);
|
|
457
|
+
} catch (mergeErr) {
|
|
458
|
+
log('warn', `Failed to merge dependency ${depBranch} into ${branchName}: ${mergeErr.message}`);
|
|
459
|
+
depMergeFailed = true;
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
431
462
|
}
|
|
432
463
|
}
|
|
433
464
|
if (depMergeFailed) {
|
|
@@ -441,30 +472,11 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
441
472
|
}
|
|
442
473
|
}
|
|
443
474
|
|
|
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
475
|
// Safety check: warn if a write-capable task is running in the main repo without a worktree
|
|
449
476
|
if (cwd === rootDir && ['implement', 'implement:large', 'fix', 'test', 'verify', 'plan-to-prd'].includes(type)) {
|
|
450
477
|
log('warn', `Agent ${agentId} running ${type} task in main repo (no worktree) for ${id} — changes may land on master directly`);
|
|
451
478
|
}
|
|
452
479
|
|
|
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
480
|
// Build claude CLI args
|
|
469
481
|
const args = [
|
|
470
482
|
'--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.577",
|
|
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"
|