@yemi33/minions 0.1.1697 → 0.1.1698
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 -2
- package/bin/minions.js +11 -6
- package/dashboard.js +37 -1
- package/engine/copilot-models.json +1 -1
- package/engine.js +28 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.1698 (2026-05-04)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
- fix update restart and Copilot steering (#2025)
|
|
7
|
+
|
|
8
|
+
## 0.1.1696 (2026-05-04)
|
|
4
9
|
|
|
5
10
|
### Features
|
|
6
|
-
- guard engine shutdown ownership (#2021)
|
|
7
11
|
- preserve doc-chat final payload (#2019)
|
|
8
12
|
|
|
9
13
|
## 0.1.1695 (2026-05-04)
|
package/bin/minions.js
CHANGED
|
@@ -203,6 +203,7 @@ function resolveMinionsHome(forInit = false) {
|
|
|
203
203
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
204
204
|
let force = rest.includes('--force');
|
|
205
205
|
const skipScan = rest.includes('--skip-scan');
|
|
206
|
+
const skipStart = rest.includes('--skip-start') || rest.includes('--no-start');
|
|
206
207
|
const MINIONS_HOME = resolveMinionsHome(cmd === 'init');
|
|
207
208
|
|
|
208
209
|
function isSubpath(parent, child) {
|
|
@@ -339,7 +340,12 @@ function init() {
|
|
|
339
340
|
printPreflight(results, { label: 'Preflight checks' });
|
|
340
341
|
} catch {}
|
|
341
342
|
|
|
342
|
-
|
|
343
|
+
if (isUpgrade && skipStart) {
|
|
344
|
+
console.log(`\n Upgrade complete (${pkgVersion}). Restart skipped by caller.\n`);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Auto-start on fresh install; direct force-upgrade restarts automatically.
|
|
343
349
|
if (isUpgrade) {
|
|
344
350
|
try { execSync(`node "${path.join(MINIONS_HOME, 'engine.js')}" stop`, { stdio: 'ignore', cwd: MINIONS_HOME }); } catch {}
|
|
345
351
|
}
|
|
@@ -436,7 +442,7 @@ function showVersion() {
|
|
|
436
442
|
if (installed) {
|
|
437
443
|
console.log(` Installed version: ${installed}`);
|
|
438
444
|
if (installed !== pkg) {
|
|
439
|
-
console.log('\n Update available! Run: minions
|
|
445
|
+
console.log('\n Update available! Run: minions update');
|
|
440
446
|
} else {
|
|
441
447
|
console.log(' Up to date.');
|
|
442
448
|
}
|
|
@@ -449,7 +455,7 @@ function showVersion() {
|
|
|
449
455
|
const latest = execSync('npm view @yemi33/minions version', { encoding: 'utf8', timeout: 5000, windowsHide: true }).trim();
|
|
450
456
|
if (latest && latest !== pkg) {
|
|
451
457
|
console.log(`\n Latest on npm: ${latest}`);
|
|
452
|
-
console.log(' To update:
|
|
458
|
+
console.log(' To update: minions update');
|
|
453
459
|
}
|
|
454
460
|
} catch {} // offline or npm not available — skip silently
|
|
455
461
|
|
|
@@ -489,7 +495,7 @@ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
|
489
495
|
|
|
490
496
|
Setup:
|
|
491
497
|
minions init Bootstrap ~/.minions/ (first time)
|
|
492
|
-
minions update Update to latest version (npm update +
|
|
498
|
+
minions update Update to latest version (npm update + one restart)
|
|
493
499
|
minions version Show installed vs package version
|
|
494
500
|
minions doctor Check prerequisites and runtime health
|
|
495
501
|
minions add <project-dir> Link a project (interactive)
|
|
@@ -538,7 +544,7 @@ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
|
538
544
|
console.error(' npm update failed:', e.message);
|
|
539
545
|
process.exit(1);
|
|
540
546
|
}
|
|
541
|
-
execSync('minions init --force', { stdio: 'inherit', timeout: 120000 });
|
|
547
|
+
execSync('minions init --force --skip-start', { stdio: 'inherit', timeout: 120000 });
|
|
542
548
|
}
|
|
543
549
|
// Restart engine + dashboard so they pick up the new code
|
|
544
550
|
console.log('\n Restarting engine and dashboard...\n');
|
|
@@ -761,4 +767,3 @@ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
|
761
767
|
console.log(' Run "minions help" for usage.\n');
|
|
762
768
|
process.exit(1);
|
|
763
769
|
}
|
|
764
|
-
|
package/dashboard.js
CHANGED
|
@@ -226,6 +226,40 @@ function _agentSessionIsDraining(agentId) {
|
|
|
226
226
|
return terminalIdx >= 0 && terminalIdx > lastSteer;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
function _dispatchBranch(item) {
|
|
230
|
+
const branch = item?.meta?.branch || item?.branch || item?.meta?.item?.branch || item?.meta?.item?.featureBranch;
|
|
231
|
+
return branch ? String(branch).replace(/^refs\/heads\//, '') : null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function _hasCachedResumeSession(agentId, activeDispatch, maxAgeMs = 2 * 60 * 60 * 1000) {
|
|
235
|
+
const sessionFile = safeJson(path.join(AGENTS_DIR, agentId, 'session.json'));
|
|
236
|
+
if (!sessionFile?.sessionId || !sessionFile.savedAt) return false;
|
|
237
|
+
const savedAtMs = new Date(sessionFile.savedAt).getTime();
|
|
238
|
+
if (!Number.isFinite(savedAtMs) || Date.now() - savedAtMs >= maxAgeMs) return false;
|
|
239
|
+
const dispatchBranch = _dispatchBranch(activeDispatch);
|
|
240
|
+
const sessionBranch = sessionFile.branch ? String(sessionFile.branch).replace(/^refs\/heads\//, '') : null;
|
|
241
|
+
return !!dispatchBranch && !!sessionBranch && dispatchBranch === sessionBranch;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function _steeringDeliveryState(agentId) {
|
|
245
|
+
const activeDispatch = (getDispatchQueue().active || []).find(d => d.agent === agentId);
|
|
246
|
+
if (!activeDispatch) return { deliveryStatus: 'queued', pendingDelivery: true };
|
|
247
|
+
|
|
248
|
+
const runtimeName = shared.resolveAgentCli(CONFIG.agents?.[agentId], CONFIG.engine);
|
|
249
|
+
try {
|
|
250
|
+
const runtime = require('./engine/runtimes').resolveRuntime(runtimeName);
|
|
251
|
+
if (runtime?.capabilities?.midRunSessionId === false && !_hasCachedResumeSession(agentId, activeDispatch)) {
|
|
252
|
+
return {
|
|
253
|
+
deliveryStatus: 'pending_checkpoint',
|
|
254
|
+
pendingDelivery: true,
|
|
255
|
+
detail: 'Runtime has not emitted a resumable session yet; delivery is pending until the next resumable checkpoint.',
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
} catch { /* unknown runtime: checkSteering will surface retry state */ }
|
|
259
|
+
|
|
260
|
+
return { deliveryStatus: 'queued', pendingDelivery: false };
|
|
261
|
+
}
|
|
262
|
+
|
|
229
263
|
const PLANS_DIR = path.join(MINIONS_DIR, 'plans');
|
|
230
264
|
const TEAMS_INBOX_PATH = path.join(ENGINE_DIR, 'teams-inbox.json');
|
|
231
265
|
|
|
@@ -6219,6 +6253,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6219
6253
|
}
|
|
6220
6254
|
|
|
6221
6255
|
const entry = steering.writeSteeringMessage(agentId, text);
|
|
6256
|
+
const delivery = _steeringDeliveryState(agentId);
|
|
6222
6257
|
|
|
6223
6258
|
// Also append to live-output.log so it shows in the chat view
|
|
6224
6259
|
const liveLogPath = path.join(agentDir, 'live-output.log');
|
|
@@ -6226,7 +6261,8 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6226
6261
|
|
|
6227
6262
|
return jsonReply(res, 200, {
|
|
6228
6263
|
ok: true,
|
|
6229
|
-
message: 'Steering message queued',
|
|
6264
|
+
message: delivery.pendingDelivery ? 'Steering message pending delivery' : 'Steering message queued',
|
|
6265
|
+
...delivery,
|
|
6230
6266
|
file: entry?.file || null,
|
|
6231
6267
|
inboxCount: steering.listUnreadSteeringMessages(agentId).length,
|
|
6232
6268
|
});
|
package/engine.js
CHANGED
|
@@ -1129,14 +1129,35 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1129
1129
|
const procInfo = activeProcesses.get(id);
|
|
1130
1130
|
ackPendingSteeringFiles(agentId, procInfo, stdout);
|
|
1131
1131
|
|
|
1132
|
+
if (procInfo?._deferredSteeringFiles?.length && procInfo.sessionId) {
|
|
1133
|
+
const deferredPaths = new Set(procInfo._deferredSteeringFiles);
|
|
1134
|
+
const pendingDeferred = steering.listUnreadSteeringMessages(agentId)
|
|
1135
|
+
.filter(entry => deferredPaths.has(entry.path) && entry.message.trim());
|
|
1136
|
+
if (pendingDeferred.length > 0) {
|
|
1137
|
+
log('info', `Steering: delivering ${pendingDeferred.length} deferred message(s) for ${agentId} at resumable checkpoint`);
|
|
1138
|
+
procInfo._steeringMessage = pendingDeferred.map(entry => entry.message.trim()).join('\n\n');
|
|
1139
|
+
procInfo._steeringSessionId = procInfo.sessionId;
|
|
1140
|
+
procInfo._steeringEntry = pendingDeferred;
|
|
1141
|
+
procInfo._steeringDeferredCheckpoint = true;
|
|
1142
|
+
delete procInfo._deferredSteeringFiles;
|
|
1143
|
+
} else {
|
|
1144
|
+
delete procInfo._deferredSteeringFiles;
|
|
1145
|
+
}
|
|
1146
|
+
} else if (procInfo?._deferredSteeringFiles?.length) {
|
|
1147
|
+
log('warn', `Steering: ${agentId} exited before a resumable sessionId was available — message remains pending`);
|
|
1148
|
+
try { fs.appendFileSync(liveOutputPath, `\n[steering-pending] Agent exited before a resumable session was available. Your message remains unread and will be retried on the next dispatch.\n`); } catch {}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1132
1151
|
// Check if this was a steering kill — re-spawn with resume
|
|
1133
1152
|
if (procInfo?._steeringMessage) {
|
|
1134
1153
|
const steerMsg = procInfo._steeringMessage;
|
|
1135
1154
|
const steerSessionId = procInfo._steeringSessionId;
|
|
1136
1155
|
const steerEntry = procInfo._steeringEntry;
|
|
1156
|
+
const steeringDeferredCheckpoint = procInfo._steeringDeferredCheckpoint === true;
|
|
1137
1157
|
delete procInfo._steeringMessage;
|
|
1138
1158
|
delete procInfo._steeringSessionId;
|
|
1139
1159
|
delete procInfo._steeringEntry;
|
|
1160
|
+
delete procInfo._steeringDeferredCheckpoint;
|
|
1140
1161
|
|
|
1141
1162
|
// Guard: can't resume without a session
|
|
1142
1163
|
if (!steerSessionId) {
|
|
@@ -1247,9 +1268,13 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1247
1268
|
),
|
|
1248
1269
|
});
|
|
1249
1270
|
|
|
1250
|
-
//
|
|
1251
|
-
|
|
1252
|
-
|
|
1271
|
+
// Live steering kills discard partial old output. Deferred checkpoint
|
|
1272
|
+
// steering keeps the completed turn output so completion parsing still
|
|
1273
|
+
// sees the original work if the follow-up only acknowledges steering.
|
|
1274
|
+
if (!steeringDeferredCheckpoint) {
|
|
1275
|
+
stdout = '';
|
|
1276
|
+
stderr = '';
|
|
1277
|
+
}
|
|
1253
1278
|
sessionCaptureState.sessionLineBuffer = '';
|
|
1254
1279
|
// Re-wire stdout/stderr handlers (same as original)
|
|
1255
1280
|
resumeProc.stdout.on('data', (data) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1698",
|
|
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"
|