@yemi33/minions 0.1.2347 → 0.1.2348

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/dashboard.js CHANGED
@@ -9845,8 +9845,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
9845
9845
  const body = await readBody(req);
9846
9846
  const message = body && typeof body.message === 'string' ? body.message : '';
9847
9847
  if (!message.trim()) return jsonReply(res, 400, { error: 'message required' });
9848
- const watchId = body.watchId ? String(body.watchId) : '';
9849
- const label = watchId ? `watch-cc-triage:${watchId}` : 'watch-cc-triage';
9848
+ // W-mrb1a3950003d9ea flat, stable label (no per-watch-id interpolation).
9849
+ // Every other _engine category (kb-sweep, consolidation, command-center, …)
9850
+ // uses one flat label; a dynamic watchId suffix here used to mint a brand-new
9851
+ // permanent metrics.json._engine key per watch firing (20+ confirmed live).
9852
+ const label = 'watch-cc-triage';
9850
9853
 
9851
9854
  const model = CONFIG.engine?.ccModel || shared.ENGINE_DEFAULTS.ccModel;
9852
9855
  const maxTurns = CONFIG.engine?.ccMaxTurns || shared.ENGINE_DEFAULTS.ccMaxTurns;
@@ -172,6 +172,8 @@ function readMetrics() {
172
172
  try { db = getDb(); }
173
173
  catch { return _readJsonObjectFallback(); }
174
174
 
175
+ migrateWatchCcTriageKeysOnce();
176
+
175
177
  _resyncIfJsonDiverged(db);
176
178
 
177
179
  const rows = _readAllRows(db);
@@ -285,9 +287,73 @@ function _resetMetricsTableForTest() {
285
287
  _lastMirrorHash = null;
286
288
  }
287
289
 
290
+ // W-mrb1a3950003d9ea — one-time collapse of legacy `watch-cc-triage:<watchId>`
291
+ // per-watch _engine keys (minted before dashboard.js's handleCommandCenterTriage
292
+ // stopped interpolating watchId into the trackEngineUsage label) into a single
293
+ // flat `watch-cc-triage` bucket, matching every other _engine category. Sums
294
+ // calls/cost/tokens/duration/errorsByCode across all matching keys, then deletes
295
+ // the per-id keys. Idempotent — a no-op (no SQL/JSON write) once no key matches
296
+ // /^watch-cc-triage:/, so it's safe to call unconditionally on every process
297
+ // startup via migrateWatchCcTriageKeysOnce().
298
+ const WATCH_CC_TRIAGE_LEGACY_KEY_RE = /^watch-cc-triage:/;
299
+ const WATCH_CC_TRIAGE_FLAT_KEY = 'watch-cc-triage';
300
+
301
+ function migrateWatchCcTriageKeys() {
302
+ return applyMetricsMutation((metrics) => {
303
+ const engineMetrics = metrics._engine;
304
+ if (!engineMetrics || typeof engineMetrics !== 'object') return metrics;
305
+ const staleKeys = Object.keys(engineMetrics).filter((k) => WATCH_CC_TRIAGE_LEGACY_KEY_RE.test(k));
306
+ if (staleKeys.length === 0) return metrics;
307
+
308
+ if (!engineMetrics[WATCH_CC_TRIAGE_FLAT_KEY]) {
309
+ engineMetrics[WATCH_CC_TRIAGE_FLAT_KEY] = { calls: 0, costUsd: 0, inputTokens: 0, outputTokens: 0, cacheRead: 0, cacheCreation: 0 };
310
+ }
311
+ const flat = engineMetrics[WATCH_CC_TRIAGE_FLAT_KEY];
312
+ for (const key of staleKeys) {
313
+ const cat = engineMetrics[key] || {};
314
+ flat.calls = (flat.calls || 0) + (cat.calls || 0);
315
+ flat.costUsd = (flat.costUsd || 0) + (cat.costUsd || 0);
316
+ flat.inputTokens = (flat.inputTokens || 0) + (cat.inputTokens || 0);
317
+ flat.outputTokens = (flat.outputTokens || 0) + (cat.outputTokens || 0);
318
+ flat.cacheRead = (flat.cacheRead || 0) + (cat.cacheRead || 0);
319
+ flat.cacheCreation = (flat.cacheCreation || 0) + (cat.cacheCreation || 0);
320
+ if (cat.totalDurationMs) flat.totalDurationMs = (flat.totalDurationMs || 0) + cat.totalDurationMs;
321
+ if (cat.timedCalls) flat.timedCalls = (flat.timedCalls || 0) + cat.timedCalls;
322
+ if (cat.errorsByCode) {
323
+ if (!flat.errorsByCode) flat.errorsByCode = {};
324
+ for (const [code, count] of Object.entries(cat.errorsByCode)) {
325
+ flat.errorsByCode[code] = (flat.errorsByCode[code] || 0) + count;
326
+ }
327
+ }
328
+ delete engineMetrics[key];
329
+ }
330
+ return metrics;
331
+ });
332
+ }
333
+
334
+ let _watchCcTriageMigratedThisProcess = false;
335
+
336
+ // Startup-safe wrapper: runs migrateWatchCcTriageKeys() at most once per
337
+ // process (subsequent calls, e.g. on every readMetrics(), are a cheap
338
+ // no-op flag check). Failures (e.g. SQLite unavailable) are swallowed and
339
+ // retried on the next process start rather than surfaced to callers.
340
+ function migrateWatchCcTriageKeysOnce() {
341
+ if (_watchCcTriageMigratedThisProcess) return;
342
+ _watchCcTriageMigratedThisProcess = true;
343
+ try { migrateWatchCcTriageKeys(); }
344
+ catch { /* best-effort — next process start retries */ }
345
+ }
346
+
347
+ function _resetWatchCcTriageMigrationFlagForTest() {
348
+ _watchCcTriageMigratedThisProcess = false;
349
+ }
350
+
288
351
  module.exports = {
289
352
  readMetrics,
290
353
  applyMetricsMutation,
291
354
  _mirrorJsonFromSql,
292
355
  _resetMetricsTableForTest,
356
+ migrateWatchCcTriageKeys,
357
+ migrateWatchCcTriageKeysOnce,
358
+ _resetWatchCcTriageMigrationFlagForTest,
293
359
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2347",
3
+ "version": "0.1.2348",
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"