@yemi33/minions 0.1.384 → 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 CHANGED
@@ -1,8 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.384 (2026-04-06)
3
+ ## 0.1.385 (2026-04-06)
4
4
 
5
5
  ### Features
6
+ - npm update check — show when newer version is available
6
7
  - show engine version and stale-code warning in dashboard
7
8
 
8
9
  ## 0.1.383 (2026-04-06)
@@ -215,19 +215,24 @@ function renderVersionBanner(version) {
215
215
  if (!el) return;
216
216
  if (!version) { el.style.display = 'none'; return; }
217
217
 
218
- // Show version in footer area
219
- const label = version.running ? 'v' + version.running : '';
218
+ const v = version.running || version.disk || '?';
220
219
  const commitLabel = version.runningCommit ? ' (' + version.runningCommit + ')' : '';
221
- el.textContent = label + commitLabel;
222
- el.title = 'Engine: v' + (version.running || '?') + ' ' + (version.runningCommit || '') +
223
- '\nDisk: v' + (version.disk || '?') + ' ' + (version.diskCommit || '');
224
220
 
225
221
  if (version.stale) {
222
+ // Engine running old code — needs restart
226
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';
227
- el.textContent = '\u26A0 Engine running v' + (version.running || '?') + ' (' + (version.runningCommit || '?') + ') — disk has v' + (version.disk || '?') + ' (' + (version.diskCommit || '?') + '). Restart to apply.';
224
+ el.textContent = '\u26A0 Engine running v' + (version.running || '?') + ' — disk has v' + (version.disk || '?') + '. Restart to apply.';
228
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';
229
231
  } else {
232
+ // Up to date
230
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)' : '');
231
236
  }
232
237
  }
233
238
 
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();
@@ -261,6 +302,8 @@ function getStatus() {
261
302
  diskCommit,
262
303
  stale: !!(engine.codeVersion && diskVersion && engine.codeVersion !== diskVersion) ||
263
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),
264
307
  };
265
308
  })(),
266
309
  timestamp: new Date().toISOString(),
@@ -3367,6 +3410,20 @@ What would you like to discuss or change? When you're happy, say "approve" and I
3367
3410
 
3368
3411
  const ROUTES = [
3369
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
+ }},
3370
3427
  { method: 'GET', path: '/api/routes', desc: 'List all available API endpoints', handler: (req, res) => {
3371
3428
  const list = ROUTES.map(r => ({
3372
3429
  method: r.method,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.384",
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"