@yemi33/minions 0.1.383 → 0.1.385
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 -0
- package/dashboard/js/refresh.js +1 -0
- package/dashboard/js/render-dispatch.js +27 -1
- package/dashboard/layout.html +1 -0
- package/dashboard.js +72 -0
- package/engine/cli.js +6 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dashboard/js/refresh.js
CHANGED
|
@@ -57,6 +57,7 @@ function _processStatusUpdate(data) {
|
|
|
57
57
|
renderPrs(data.pullRequests || []);
|
|
58
58
|
renderArchiveButtons(data.archivedPrds || []);
|
|
59
59
|
renderEngineStatus(data.engine);
|
|
60
|
+
renderVersionBanner(data.version);
|
|
60
61
|
renderDispatch(data.dispatch);
|
|
61
62
|
window._lastDispatch = data.dispatch;
|
|
62
63
|
window._lastWorkItems = data.workItems || [];
|
|
@@ -210,4 +210,30 @@ async function showErrorDetails(agentId, reason, task) {
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
function renderVersionBanner(version) {
|
|
214
|
+
const el = document.getElementById('version-banner');
|
|
215
|
+
if (!el) return;
|
|
216
|
+
if (!version) { el.style.display = 'none'; return; }
|
|
217
|
+
|
|
218
|
+
const v = version.running || version.disk || '?';
|
|
219
|
+
const commitLabel = version.runningCommit ? ' (' + version.runningCommit + ')' : '';
|
|
220
|
+
|
|
221
|
+
if (version.stale) {
|
|
222
|
+
// Engine running old code — needs restart
|
|
223
|
+
el.style.cssText = 'font-size:9px;padding:2px 8px;background:rgba(210,153,34,0.15);border:1px solid rgba(210,153,34,0.3);border-radius:4px;color:var(--yellow);cursor:help';
|
|
224
|
+
el.textContent = '\u26A0 Engine running v' + (version.running || '?') + ' — disk has v' + (version.disk || '?') + '. Restart to apply.';
|
|
225
|
+
el.title = 'The engine process is running older code than what is on disk. Run: minions restart';
|
|
226
|
+
} else if (version.updateAvailable) {
|
|
227
|
+
// New version on npm
|
|
228
|
+
el.style.cssText = 'font-size:9px;padding:2px 8px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:4px;color:var(--green);cursor:help';
|
|
229
|
+
el.textContent = 'v' + v + commitLabel + ' — v' + version.latest + ' available. Run: npm update -g @yemi33/minions';
|
|
230
|
+
el.title = 'A newer version is available on npm';
|
|
231
|
+
} else {
|
|
232
|
+
// Up to date
|
|
233
|
+
el.style.cssText = 'font-size:9px;color:var(--muted)';
|
|
234
|
+
el.textContent = 'v' + v + commitLabel;
|
|
235
|
+
el.title = 'Minions v' + v + (version.latest ? ' (latest)' : '');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
window.MinionsDispatch = { renderEngineStatus, renderEngineAlert, renderVersionBanner, renderDispatch, renderEngineLog, shortTime, showErrorDetails };
|
package/dashboard/layout.html
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
</header>
|
|
21
21
|
<div class="engine-alert" id="engine-alert"></div>
|
|
22
|
+
<div id="version-banner" style="font-size:9px;color:var(--muted);padding:0 16px"></div>
|
|
22
23
|
|
|
23
24
|
<!-- Command Center Drawer -->
|
|
24
25
|
<div id="cc-drawer" style="display:none;position:fixed;top:0;right:0;bottom:0;width:420px;background:var(--surface);border-left:1px solid var(--border);z-index:350;flex-direction:column;overscroll-behavior:contain">
|
package/dashboard.js
CHANGED
|
@@ -161,6 +161,47 @@ function getVerifyGuides() {
|
|
|
161
161
|
function getArchivedPrds() { return []; }
|
|
162
162
|
function getEngineState() { return queries.getControl(); }
|
|
163
163
|
|
|
164
|
+
// ── npm update check (cached for 4 hours) ──────────────────────────────────
|
|
165
|
+
let _npmVersionCache = null;
|
|
166
|
+
let _npmVersionCacheTs = 0;
|
|
167
|
+
const NPM_CHECK_INTERVAL = 4 * 60 * 60 * 1000; // 4 hours
|
|
168
|
+
const PKG_NAME = '@yemi33/minions';
|
|
169
|
+
|
|
170
|
+
async function checkNpmVersion() {
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
if (_npmVersionCache && (now - _npmVersionCacheTs) < NPM_CHECK_INTERVAL) return _npmVersionCache;
|
|
173
|
+
try {
|
|
174
|
+
const https = require('https');
|
|
175
|
+
const data = await new Promise((resolve, reject) => {
|
|
176
|
+
const req = https.get(`https://registry.npmjs.org/${PKG_NAME}/latest`, { timeout: 5000 }, (res) => {
|
|
177
|
+
let body = '';
|
|
178
|
+
res.on('data', c => body += c);
|
|
179
|
+
res.on('end', () => { try { resolve(JSON.parse(body)); } catch { reject(new Error('bad json')); } });
|
|
180
|
+
});
|
|
181
|
+
req.on('error', reject);
|
|
182
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
|
183
|
+
});
|
|
184
|
+
_npmVersionCache = { latest: data.version || null, checkedAt: new Date().toISOString() };
|
|
185
|
+
_npmVersionCacheTs = now;
|
|
186
|
+
} catch {
|
|
187
|
+
_npmVersionCache = _npmVersionCache || { latest: null, checkedAt: null, error: 'check failed' };
|
|
188
|
+
}
|
|
189
|
+
return _npmVersionCache;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function _compareVersions(a, b) {
|
|
193
|
+
const pa = (a || '').split('.').map(Number);
|
|
194
|
+
const pb = (b || '').split('.').map(Number);
|
|
195
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
196
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return 1;
|
|
197
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return -1;
|
|
198
|
+
}
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Kick off first npm check on startup (non-blocking)
|
|
203
|
+
checkNpmVersion().catch(() => {});
|
|
204
|
+
|
|
164
205
|
function getMcpServers() {
|
|
165
206
|
try {
|
|
166
207
|
const home = os.homedir();
|
|
@@ -248,6 +289,23 @@ function getStatus() {
|
|
|
248
289
|
},
|
|
249
290
|
initialized: !!(CONFIG.agents && Object.keys(CONFIG.agents).length > 0),
|
|
250
291
|
installId: safeRead(path.join(MINIONS_DIR, '.install-id')).trim() || null,
|
|
292
|
+
version: (() => {
|
|
293
|
+
const engine = getEngineState();
|
|
294
|
+
let diskVersion = null;
|
|
295
|
+
try { diskVersion = require('./package.json').version; } catch {}
|
|
296
|
+
let diskCommit = null;
|
|
297
|
+
try { diskCommit = require('child_process').execSync('git rev-parse --short HEAD', { cwd: MINIONS_DIR, encoding: 'utf8', timeout: 5000, windowsHide: true }).trim(); } catch {}
|
|
298
|
+
return {
|
|
299
|
+
running: engine.codeVersion || null,
|
|
300
|
+
runningCommit: engine.codeCommit || null,
|
|
301
|
+
disk: diskVersion,
|
|
302
|
+
diskCommit,
|
|
303
|
+
stale: !!(engine.codeVersion && diskVersion && engine.codeVersion !== diskVersion) ||
|
|
304
|
+
!!(engine.codeCommit && diskCommit && engine.codeCommit !== diskCommit),
|
|
305
|
+
latest: _npmVersionCache?.latest || null,
|
|
306
|
+
updateAvailable: !!(diskVersion && _npmVersionCache?.latest && _npmVersionCache.latest !== diskVersion && _compareVersions(_npmVersionCache.latest, diskVersion) > 0),
|
|
307
|
+
};
|
|
308
|
+
})(),
|
|
251
309
|
timestamp: new Date().toISOString(),
|
|
252
310
|
};
|
|
253
311
|
_statusCacheTs = now;
|
|
@@ -3352,6 +3410,20 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
3352
3410
|
|
|
3353
3411
|
const ROUTES = [
|
|
3354
3412
|
// Routes endpoint (self-describing API)
|
|
3413
|
+
{ method: 'GET', path: '/api/version', desc: 'Current + latest version info with update check', handler: async (req, res) => {
|
|
3414
|
+
const npm = await checkNpmVersion();
|
|
3415
|
+
let diskVersion = null;
|
|
3416
|
+
try { diskVersion = require('./package.json').version; } catch {}
|
|
3417
|
+
const engine = getEngineState();
|
|
3418
|
+
return jsonReply(res, 200, {
|
|
3419
|
+
current: diskVersion,
|
|
3420
|
+
running: engine.codeVersion || null,
|
|
3421
|
+
latest: npm.latest,
|
|
3422
|
+
updateAvailable: !!(diskVersion && npm.latest && _compareVersions(npm.latest, diskVersion) > 0),
|
|
3423
|
+
stale: !!(engine.codeVersion && diskVersion && engine.codeVersion !== diskVersion),
|
|
3424
|
+
checkedAt: npm.checkedAt,
|
|
3425
|
+
});
|
|
3426
|
+
}},
|
|
3355
3427
|
{ method: 'GET', path: '/api/routes', desc: 'List all available API endpoints', handler: (req, res) => {
|
|
3356
3428
|
const list = ROUTES.map(r => ({
|
|
3357
3429
|
method: r.method,
|
package/engine/cli.js
CHANGED
|
@@ -84,7 +84,12 @@ const commands = {
|
|
|
84
84
|
console.log(`Engine was running (PID ${control.pid}) but process is dead — restarting.`);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
// Record version + git commit so dashboard can detect stale engine code
|
|
88
|
+
let codeVersion = null;
|
|
89
|
+
try { codeVersion = require('../package.json').version; } catch {}
|
|
90
|
+
let codeCommit = null;
|
|
91
|
+
try { codeCommit = require('child_process').execSync('git rev-parse --short HEAD', { cwd: path.resolve(__dirname, '..'), encoding: 'utf8', timeout: 5000, windowsHide: true }).trim(); } catch {}
|
|
92
|
+
safeWrite(CONTROL_PATH, { state: 'running', pid: process.pid, started_at: e.ts(), codeVersion, codeCommit });
|
|
88
93
|
e.log('info', 'Engine started');
|
|
89
94
|
console.log(`Engine started (PID: ${process.pid})`);
|
|
90
95
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.385",
|
|
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"
|