@yemi33/minions 0.1.2180 → 0.1.2181
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/refresh.js +41 -61
- package/dashboard-build.js +44 -8
- package/engine/features.js +0 -18
- package/engine/queries.js +12 -4
- package/engine/shared.js +16 -25
- package/package.json +1 -1
package/dashboard/js/refresh.js
CHANGED
|
@@ -1167,21 +1167,16 @@ document.addEventListener('visibilitychange', function() {
|
|
|
1167
1167
|
// Ring buffer capturing the last 50 /api/status poll cycles so a user
|
|
1168
1168
|
// reporting "the dashboard didn't auto-update when X changed" can paste
|
|
1169
1169
|
// `window._refreshDiagnostics()` from devtools or click the "diag" footer
|
|
1170
|
-
// chip to surface a table.
|
|
1171
|
-
//
|
|
1172
|
-
//
|
|
1173
|
-
//
|
|
1174
|
-
//
|
|
1170
|
+
// chip to surface a table. The capture is cheap (in-memory ring buffer,
|
|
1171
|
+
// no network, no DOM writes) and always on (P-c1d4e8b6 deleted the
|
|
1172
|
+
// per-flag gate that had shipped default ON since v0.1.2034) so the next
|
|
1173
|
+
// staleness complaint can be diagnosed immediately from
|
|
1174
|
+
// window._refreshDiagnostics without a settings flip.
|
|
1175
1175
|
const _DIAG_RING_SIZE = 50;
|
|
1176
1176
|
const _refreshDiagBuf = [];
|
|
1177
1177
|
let _prevRefreshTs = 0;
|
|
1178
1178
|
let _diagHiddenSinceMs = 0; // ts when tab last went hidden; 0 when visible
|
|
1179
1179
|
let _lastVisibilityChangeAt = 0;
|
|
1180
|
-
function _isRefreshDiagOn() {
|
|
1181
|
-
try {
|
|
1182
|
-
return !!(window.MinionsFeatures && window.MinionsFeatures.isOn('dashboard-refresh-diagnostics'));
|
|
1183
|
-
} catch { return false; }
|
|
1184
|
-
}
|
|
1185
1180
|
function _pushDiagEntry(entry) {
|
|
1186
1181
|
_refreshDiagBuf.push(entry);
|
|
1187
1182
|
if (_refreshDiagBuf.length > _DIAG_RING_SIZE) _refreshDiagBuf.shift();
|
|
@@ -1191,7 +1186,6 @@ function _pushDiagEntry(entry) {
|
|
|
1191
1186
|
window._refreshDiagnostics = function() { return _refreshDiagBuf.slice(); };
|
|
1192
1187
|
window._refreshDiagnosticsClear = function() { _refreshDiagBuf.length = 0; };
|
|
1193
1188
|
document.addEventListener('visibilitychange', function() {
|
|
1194
|
-
if (!_isRefreshDiagOn()) return;
|
|
1195
1189
|
const now = Date.now();
|
|
1196
1190
|
const vs = document.visibilityState;
|
|
1197
1191
|
let hiddenForMs = null;
|
|
@@ -1220,11 +1214,10 @@ async function refresh(opts) {
|
|
|
1220
1214
|
// console-spam and adds load to whatever's wedged).
|
|
1221
1215
|
if (_nextPollAllowedAt && Date.now() < _nextPollAllowedAt) return;
|
|
1222
1216
|
_refreshInFlight = true;
|
|
1223
|
-
const
|
|
1224
|
-
const
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
const _diagEntry = _diagOn ? {
|
|
1217
|
+
const _t0 = Date.now();
|
|
1218
|
+
const _gap = _prevRefreshTs ? _t0 - _prevRefreshTs : null;
|
|
1219
|
+
_prevRefreshTs = _t0;
|
|
1220
|
+
const _diagEntry = {
|
|
1228
1221
|
ts: _t0,
|
|
1229
1222
|
kind: 'refresh',
|
|
1230
1223
|
gap_since_prev_ms: _gap,
|
|
@@ -1239,7 +1232,7 @@ async function refresh(opts) {
|
|
|
1239
1232
|
changed: null,
|
|
1240
1233
|
render_duration_ms: null,
|
|
1241
1234
|
error_message: null,
|
|
1242
|
-
}
|
|
1235
|
+
};
|
|
1243
1236
|
try {
|
|
1244
1237
|
const headers = {};
|
|
1245
1238
|
if (_lastStatusEtag) headers['If-None-Match'] = _lastStatusEtag;
|
|
@@ -1253,16 +1246,14 @@ async function refresh(opts) {
|
|
|
1253
1246
|
if (res.status === 304 && _lastStatusData) {
|
|
1254
1247
|
// Cache hit — reuse last payload, skip parsing entirely.
|
|
1255
1248
|
data = _lastStatusData;
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
if (etag304) _diagEntry.etag_received = etag304;
|
|
1265
|
-
}
|
|
1249
|
+
_diagEntry.response_status = '304';
|
|
1250
|
+
_diagEntry.bytes_received = 0;
|
|
1251
|
+
// D2: capture etag on 304 so the diag table can show whether the
|
|
1252
|
+
// server's ETag advanced even when we're reusing the cached body.
|
|
1253
|
+
// Without this the "etag↓" column is blank on every 304 row and the
|
|
1254
|
+
// operator can't tell server-side advancement from a pinned cache.
|
|
1255
|
+
const etag304 = res.headers && (res.headers.get ? res.headers.get('etag') : null);
|
|
1256
|
+
if (etag304) _diagEntry.etag_received = etag304;
|
|
1266
1257
|
} else {
|
|
1267
1258
|
data = await res.json();
|
|
1268
1259
|
const etag = res.headers && (res.headers.get ? res.headers.get('etag') : null);
|
|
@@ -1270,12 +1261,10 @@ async function refresh(opts) {
|
|
|
1270
1261
|
_lastStatusEtag = etag;
|
|
1271
1262
|
_lastStatusData = data;
|
|
1272
1263
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
_diagEntry.bytes_received = cl != null && cl !== '' ? Number(cl) : null;
|
|
1278
|
-
}
|
|
1264
|
+
_diagEntry.response_status = String(res.status);
|
|
1265
|
+
_diagEntry.etag_received = etag || null;
|
|
1266
|
+
const cl = res.headers && (res.headers.get ? res.headers.get('content-length') : null);
|
|
1267
|
+
_diagEntry.bytes_received = cl != null && cl !== '' ? Number(cl) : null;
|
|
1279
1268
|
}
|
|
1280
1269
|
// Auto-reload policy (2026-05-29):
|
|
1281
1270
|
// - dashboardStartedAt change → reload (covers `minions restart`)
|
|
@@ -1302,31 +1291,26 @@ async function refresh(opts) {
|
|
|
1302
1291
|
_consecutiveStatusFails = 0;
|
|
1303
1292
|
_nextPollAllowedAt = 0;
|
|
1304
1293
|
if (_unreachableSince) _markDashboardReachable();
|
|
1305
|
-
const _renderStart =
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
_diagChanges = {};
|
|
1309
|
-
_lastChangedFlags = _diagChanges;
|
|
1310
|
-
}
|
|
1294
|
+
const _renderStart = Date.now();
|
|
1295
|
+
const _diagChanges = {};
|
|
1296
|
+
_lastChangedFlags = _diagChanges;
|
|
1311
1297
|
try {
|
|
1312
1298
|
_processStatusUpdate(data, opts);
|
|
1313
1299
|
} finally {
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
: null;
|
|
1325
|
-
}
|
|
1300
|
+
_lastChangedFlags = null;
|
|
1301
|
+
_diagEntry.render_duration_ms = Date.now() - _renderStart;
|
|
1302
|
+
_diagEntry.changed = _diagChanges;
|
|
1303
|
+
_diagEntry.workItems_changed = !!(_diagChanges && _diagChanges.workItems);
|
|
1304
|
+
// Post-slim, data.workItems is undefined; read from the dedicated
|
|
1305
|
+
// endpoint cache.
|
|
1306
|
+
_diagEntry.workItems_count = (window._lastWorkItems || []).length;
|
|
1307
|
+
_diagEntry.statusCacheVersion = (data.version && data.version.statusCacheVersion) != null
|
|
1308
|
+
? data.version.statusCacheVersion
|
|
1309
|
+
: null;
|
|
1326
1310
|
}
|
|
1327
1311
|
} catch(e) {
|
|
1328
1312
|
console.error('refresh error', e);
|
|
1329
|
-
if (
|
|
1313
|
+
if (!_diagEntry.response_status) {
|
|
1330
1314
|
_diagEntry.response_status = (e && e.name === 'AbortError') ? 'abort' : 'error';
|
|
1331
1315
|
_diagEntry.error_message = String((e && e.message) || e);
|
|
1332
1316
|
}
|
|
@@ -1346,7 +1330,7 @@ async function refresh(opts) {
|
|
|
1346
1330
|
}
|
|
1347
1331
|
finally {
|
|
1348
1332
|
_refreshInFlight = false;
|
|
1349
|
-
|
|
1333
|
+
_pushDiagEntry(_diagEntry);
|
|
1350
1334
|
}
|
|
1351
1335
|
}
|
|
1352
1336
|
|
|
@@ -1394,15 +1378,11 @@ switchPage(currentPage);
|
|
|
1394
1378
|
window.MinionsRefresh = { refresh };
|
|
1395
1379
|
|
|
1396
1380
|
// ── Refresh-diagnostic footer chip + modal (W-mphejzx100081972) ───────────
|
|
1397
|
-
//
|
|
1398
|
-
//
|
|
1399
|
-
//
|
|
1400
|
-
//
|
|
1401
|
-
// touched (and no listeners installed beyond the visibilitychange handler
|
|
1402
|
-
// above, which itself short-circuits when the flag is off) when the flag is
|
|
1403
|
-
// disabled — production behaviour stays untouched.
|
|
1381
|
+
// Always installed (P-c1d4e8b6 deleted the per-flag gate that previously
|
|
1382
|
+
// guarded this). The chip floats bottom-left and opens a simple table view
|
|
1383
|
+
// of the ring buffer plus a "send to engine" button that POSTs the
|
|
1384
|
+
// snapshot to /api/diagnostics/refresh.
|
|
1404
1385
|
(function installRefreshDiagChip() {
|
|
1405
|
-
if (!_isRefreshDiagOn()) return;
|
|
1406
1386
|
try {
|
|
1407
1387
|
const chip = document.createElement('button');
|
|
1408
1388
|
chip.id = 'refresh-diag-chip';
|
package/dashboard-build.js
CHANGED
|
@@ -74,19 +74,51 @@ const SLIM_JS_ORDER = [
|
|
|
74
74
|
'command-send', 'status', 'members', 'modals-tiles', 'history', 'pinned',
|
|
75
75
|
];
|
|
76
76
|
|
|
77
|
+
// Cache for the assembled slim source fragments (layout/css/body/js). Keyed on
|
|
78
|
+
// the input file mtimes so dev edits still take effect on the next request
|
|
79
|
+
// without a server restart, while production serves repeated requests without
|
|
80
|
+
// re-reading the ~14 fragment files each time. Phase 3 perf audit (P-a7b8c9d0)
|
|
81
|
+
// measured `buildSlimHtml()` at ~7.7 ms/req pre-cache; post-cache it's ~14
|
|
82
|
+
// cheap fs.statSync() calls + one string substitution per request (~sub-ms).
|
|
83
|
+
let _slimPartsCache = null;
|
|
84
|
+
|
|
85
|
+
function _slimSourcePaths(slimDir) {
|
|
86
|
+
return [
|
|
87
|
+
path.join(slimDir, 'layout.html'),
|
|
88
|
+
path.join(slimDir, 'styles.css'),
|
|
89
|
+
path.join(slimDir, 'body.html'),
|
|
90
|
+
...SLIM_JS_ORDER.map(f => path.join(slimDir, 'js', f + '.js')),
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _statMtimeOrZero(p) {
|
|
95
|
+
try { return fs.statSync(p).mtimeMs; } catch { return 0; }
|
|
96
|
+
}
|
|
97
|
+
|
|
77
98
|
function buildSlimHtml(opts) {
|
|
78
99
|
const slimDir = path.join(MINIONS_DIR, 'dashboard', 'slim');
|
|
79
100
|
const layoutPath = path.join(slimDir, 'layout.html');
|
|
80
101
|
if (!fs.existsSync(layoutPath)) {
|
|
81
102
|
throw new Error(`Slim layout not found: ${layoutPath}. The dashboard/slim/ directory must exist.`);
|
|
82
103
|
}
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
const paths = _slimSourcePaths(slimDir);
|
|
105
|
+
const mtimes = paths.map(_statMtimeOrZero);
|
|
106
|
+
if (!_slimPartsCache
|
|
107
|
+
|| _slimPartsCache.mtimes.length !== mtimes.length
|
|
108
|
+
|| _slimPartsCache.mtimes.some((m, i) => m !== mtimes[i])) {
|
|
109
|
+
const [lp, cp, bp, ...jsPaths] = paths;
|
|
110
|
+
_slimPartsCache = {
|
|
111
|
+
mtimes,
|
|
112
|
+
layout: safeRead(lp),
|
|
113
|
+
css: safeRead(cp),
|
|
114
|
+
body: safeRead(bp),
|
|
115
|
+
// Join with a newline so a fragment that loses its trailing newline
|
|
116
|
+
// can't glue two statements together (e.g. `}var foo`). Parts share one
|
|
117
|
+
// IIFE scope, so order is load-bearing — see SLIM_JS_ORDER.
|
|
118
|
+
js: jsPaths.map(p => safeRead(p)).join('\n'),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const { layout, css, body, js } = _slimPartsCache;
|
|
90
122
|
|
|
91
123
|
// Feature-flag bootstrap (window.MINIONS_FEATURES) injected at the top of the
|
|
92
124
|
// slim IIFE. serveSlimUx passes the live flags as JSON via opts.featuresJson;
|
|
@@ -103,4 +135,8 @@ function buildSlimHtml(opts) {
|
|
|
103
135
|
.replace('/* __JS__ */', () => js);
|
|
104
136
|
}
|
|
105
137
|
|
|
106
|
-
|
|
138
|
+
// exported for testing — lets tests reset the module-scope cache so they can
|
|
139
|
+
// observe a cold first call without depending on test execution order.
|
|
140
|
+
function _resetSlimPartsCacheForTest() { _slimPartsCache = null; }
|
|
141
|
+
|
|
142
|
+
module.exports = { buildDashboardHtml, buildSlimHtml, SLIM_JS_ORDER, _resetSlimPartsCacheForTest };
|
package/engine/features.js
CHANGED
|
@@ -78,24 +78,6 @@ const FEATURES = {
|
|
|
78
78
|
addedIn: '0.1.1916',
|
|
79
79
|
requiredCcRuntime: 'copilot',
|
|
80
80
|
},
|
|
81
|
-
// dashboard-refresh-diagnostics — W-mphejzx100081972. Enables the in-browser
|
|
82
|
-
// /api/status poll telemetry ring buffer in dashboard/js/refresh.js: per-cycle
|
|
83
|
-
// ETag/status/bytes/render-duration capture, visibility-transition tracking,
|
|
84
|
-
// a small "diag" footer chip that opens a table modal, and a "send to engine"
|
|
85
|
-
// button that POSTs the buffer to /api/diagnostics/refresh for offline triage.
|
|
86
|
-
// Default ON (W-mphlr4lv0008c24f) — the diagnostic capture is cheap (in-memory
|
|
87
|
-
// ring buffer, no network, no DOM writes) and is gated by _isRefreshDiagOn()
|
|
88
|
-
// at the top of refresh() so the disabled path remains byte-identical to the
|
|
89
|
-
// pre-flag steady state. Having it always-on means the next staleness
|
|
90
|
-
// complaint can be diagnosed immediately from window._refreshDiagnostics
|
|
91
|
-
// without needing a settings flip first.
|
|
92
|
-
// Disable via config.features['dashboard-refresh-diagnostics']: false or
|
|
93
|
-
// env MINIONS_FEATURE_DASHBOARD_REFRESH_DIAGNOSTICS=0.
|
|
94
|
-
'dashboard-refresh-diagnostics': {
|
|
95
|
-
description: 'Capture the last 50 dashboard /api/status poll cycles (timing, ETag, status code, render duration, per-renderer change flags) in a browser-side ring buffer accessible via window._refreshDiagnostics, a footer "diag" chip, and POST /api/diagnostics/refresh.',
|
|
96
|
-
default: true,
|
|
97
|
-
addedIn: '0.1.2034',
|
|
98
|
-
},
|
|
99
81
|
};
|
|
100
82
|
|
|
101
83
|
const ENV_TRUTHY = new Set(['1', 'true', 'on', 'yes']);
|
package/engine/queries.js
CHANGED
|
@@ -1516,6 +1516,14 @@ function getKnowledgeBaseEntriesSnapshot() {
|
|
|
1516
1516
|
}
|
|
1517
1517
|
|
|
1518
1518
|
async function _scanKnowledgeBase() {
|
|
1519
|
+
// V8 sliced-string + regex-capture footgun (P-b8c9d0e1, Phase 2 audit):
|
|
1520
|
+
// `String.prototype.slice` and `match()` capture groups both produce
|
|
1521
|
+
// sliced strings that retain the entire `content` (100-400 KB per file)
|
|
1522
|
+
// alive in heap as long as any short derivative is referenced. The
|
|
1523
|
+
// Phase 2 heap snapshot measured ~6.5 MB retained per process across
|
|
1524
|
+
// ~30 large KB entries. `_flat()` materialises a fresh flat string via
|
|
1525
|
+
// Buffer round-trip so the cached entry no longer pins the parent file.
|
|
1526
|
+
const _flat = (s) => Buffer.from(String(s || ''), 'utf8').toString('utf8');
|
|
1519
1527
|
const entries = [];
|
|
1520
1528
|
for (const cat of KB_CATEGORIES) {
|
|
1521
1529
|
const catDir = path.join(KNOWLEDGE_DIR, cat);
|
|
@@ -1527,19 +1535,19 @@ async function _scanKnowledgeBase() {
|
|
|
1527
1535
|
fsp.stat(filePath).catch(() => null),
|
|
1528
1536
|
]);
|
|
1529
1537
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
1530
|
-
const title = titleMatch ? titleMatch[1].trim() : f.replace(/\.md$/, '');
|
|
1538
|
+
const title = _flat(titleMatch ? titleMatch[1].trim() : f.replace(/\.md$/, ''));
|
|
1531
1539
|
const agentMatch = f.match(/^\d{4}-\d{2}-\d{2}-(\w+)-/);
|
|
1532
1540
|
const dateMatch = f.match(/^(\d{4}-\d{2}-\d{2})/) || content.match(/^date:\s*(\d{4}-\d{2}-\d{2})$/m);
|
|
1533
1541
|
const sourceMatch = content.match(/^source:\s*(.+)/m);
|
|
1534
1542
|
const sortTs = (stat && stat.mtimeMs) || 0;
|
|
1535
|
-
const displayDate = dateMatch ? dateMatch[1] : (sortTs ? new Date(sortTs).toISOString().slice(0, 10) : '');
|
|
1543
|
+
const displayDate = dateMatch ? _flat(dateMatch[1]) : (sortTs ? new Date(sortTs).toISOString().slice(0, 10) : '');
|
|
1536
1544
|
return {
|
|
1537
1545
|
cat, file: f, title,
|
|
1538
1546
|
agent: agentMatch ? agentMatch[1] : '',
|
|
1539
1547
|
date: displayDate,
|
|
1540
1548
|
sortTs,
|
|
1541
|
-
source: sourceMatch ? sourceMatch[1].trim() : '',
|
|
1542
|
-
preview: content.slice(0, 200),
|
|
1549
|
+
source: _flat(sourceMatch ? sourceMatch[1].trim() : ''),
|
|
1550
|
+
preview: _flat(content.slice(0, 200)),
|
|
1543
1551
|
size: content.length,
|
|
1544
1552
|
};
|
|
1545
1553
|
}));
|
package/engine/shared.js
CHANGED
|
@@ -3018,10 +3018,6 @@ function resolvePollFlag(engineCfg, granularKey, legacyMacroKey) {
|
|
|
3018
3018
|
// (CLI chooses)" option (which submits an empty string) clears the override
|
|
3019
3019
|
// instead of pinning the runtime to nothing.
|
|
3020
3020
|
|
|
3021
|
-
function _isMeaningful(v) {
|
|
3022
|
-
return v !== undefined && v !== null && v !== '';
|
|
3023
|
-
}
|
|
3024
|
-
|
|
3025
3021
|
/**
|
|
3026
3022
|
* Resolve the CLI runtime for a per-agent spawn. Priority:
|
|
3027
3023
|
* 1. `agent.cli` — per-agent override
|
|
@@ -3031,8 +3027,8 @@ function _isMeaningful(v) {
|
|
|
3031
3027
|
* Does NOT fall through to `engine.ccCli`. CC and agents are independent paths.
|
|
3032
3028
|
*/
|
|
3033
3029
|
function resolveAgentCli(agent, engine) {
|
|
3034
|
-
if (agent &&
|
|
3035
|
-
if (engine &&
|
|
3030
|
+
if (agent && agent.cli !== undefined && agent.cli !== null && agent.cli !== '') return String(agent.cli);
|
|
3031
|
+
if (engine && engine.defaultCli !== undefined && engine.defaultCli !== null && engine.defaultCli !== '') return String(engine.defaultCli);
|
|
3036
3032
|
return ENGINE_DEFAULTS.defaultCli;
|
|
3037
3033
|
}
|
|
3038
3034
|
|
|
@@ -3046,8 +3042,8 @@ function resolveAgentCli(agent, engine) {
|
|
|
3046
3042
|
* it's a fleet-wide singleton.
|
|
3047
3043
|
*/
|
|
3048
3044
|
function resolveCcCli(engine) {
|
|
3049
|
-
if (engine &&
|
|
3050
|
-
if (engine &&
|
|
3045
|
+
if (engine && engine.ccCli !== undefined && engine.ccCli !== null && engine.ccCli !== '') return String(engine.ccCli);
|
|
3046
|
+
if (engine && engine.defaultCli !== undefined && engine.defaultCli !== null && engine.defaultCli !== '') return String(engine.defaultCli);
|
|
3051
3047
|
return ENGINE_DEFAULTS.defaultCli;
|
|
3052
3048
|
}
|
|
3053
3049
|
|
|
@@ -3068,7 +3064,8 @@ function resolveCcCli(engine) {
|
|
|
3068
3064
|
* 4. ENGINE_DEFAULTS.ccUseWorkerPool — final fallback
|
|
3069
3065
|
*
|
|
3070
3066
|
* Strict boolean check on the override so a literal `false` opts out even on
|
|
3071
|
-
* Copilot, matching
|
|
3067
|
+
* Copilot, matching the "treat empty/null/undefined as unset" semantics used
|
|
3068
|
+
* throughout the resolve* helpers for boolean flags.
|
|
3072
3069
|
*/
|
|
3073
3070
|
function resolveCcUseWorkerPool(engine) {
|
|
3074
3071
|
// Guard 1 (W-mphlriic00095f69): pool transport is ACP-only. If CC runtime
|
|
@@ -3093,8 +3090,8 @@ function resolveCcUseWorkerPool(engine) {
|
|
|
3093
3090
|
* to the user's `~/.copilot/settings.json` model).
|
|
3094
3091
|
*/
|
|
3095
3092
|
function resolveAgentModel(agent, engine) {
|
|
3096
|
-
if (agent &&
|
|
3097
|
-
if (engine &&
|
|
3093
|
+
if (agent && agent.model !== undefined && agent.model !== null && agent.model !== '') return String(agent.model);
|
|
3094
|
+
if (engine && engine.defaultModel !== undefined && engine.defaultModel !== null && engine.defaultModel !== '') return String(engine.defaultModel);
|
|
3098
3095
|
return undefined;
|
|
3099
3096
|
}
|
|
3100
3097
|
|
|
@@ -3105,8 +3102,8 @@ function resolveAgentModel(agent, engine) {
|
|
|
3105
3102
|
* 3. `undefined` — let the runtime adapter pick
|
|
3106
3103
|
*/
|
|
3107
3104
|
function resolveCcModel(engine) {
|
|
3108
|
-
if (engine &&
|
|
3109
|
-
if (engine &&
|
|
3105
|
+
if (engine && engine.ccModel !== undefined && engine.ccModel !== null && engine.ccModel !== '') return String(engine.ccModel);
|
|
3106
|
+
if (engine && engine.defaultModel !== undefined && engine.defaultModel !== null && engine.defaultModel !== '') return String(engine.defaultModel);
|
|
3110
3107
|
return undefined;
|
|
3111
3108
|
}
|
|
3112
3109
|
|
|
@@ -3233,14 +3230,12 @@ let _legacyCcModelMigrationLogged = false;
|
|
|
3233
3230
|
function applyLegacyCcModelMigration(config, { logger = log } = {}) {
|
|
3234
3231
|
if (!config || !config.engine || typeof config.engine !== 'object') return false;
|
|
3235
3232
|
const e = config.engine;
|
|
3236
|
-
if (
|
|
3237
|
-
if (!
|
|
3233
|
+
if (e.defaultModel !== undefined && e.defaultModel !== null && e.defaultModel !== '') return false;
|
|
3234
|
+
if (!(e.ccModel !== undefined && e.ccModel !== null && e.ccModel !== '')) return false;
|
|
3238
3235
|
e.defaultModel = e.ccModel;
|
|
3239
3236
|
if (!_legacyCcModelMigrationLogged) {
|
|
3240
3237
|
_legacyCcModelMigrationLogged = true;
|
|
3241
|
-
|
|
3242
|
-
logger('warn', 'ccModel is now a CC-specific override; set defaultModel to apply fleet-wide');
|
|
3243
|
-
} catch { /* logger may not be wired during tests — best-effort */ }
|
|
3238
|
+
logger('warn', 'ccModel is now a CC-specific override; set defaultModel to apply fleet-wide');
|
|
3244
3239
|
}
|
|
3245
3240
|
return true;
|
|
3246
3241
|
}
|
|
@@ -3332,7 +3327,7 @@ function runtimeConfigWarnings(config, registeredRuntimes) {
|
|
|
3332
3327
|
// 1. Unknown CLI values across the fleet.
|
|
3333
3328
|
const seen = new Set();
|
|
3334
3329
|
const checkCli = (label, value) => {
|
|
3335
|
-
if (!
|
|
3330
|
+
if (!(value !== undefined && value !== null && value !== '')) return;
|
|
3336
3331
|
const key = `${label}:${value}`;
|
|
3337
3332
|
if (seen.has(key)) return;
|
|
3338
3333
|
seen.add(key);
|
|
@@ -3376,7 +3371,7 @@ function runtimeConfigWarnings(config, registeredRuntimes) {
|
|
|
3376
3371
|
const ccCli = resolveCcCli(engine);
|
|
3377
3372
|
let ccRuntime = null;
|
|
3378
3373
|
try { ccRuntime = require('./runtimes').resolveRuntime(ccCli); } catch { /* unknown runtime — skip */ }
|
|
3379
|
-
if (ccRuntime?.capabilities?.bareMode === true && !
|
|
3374
|
+
if (ccRuntime?.capabilities?.bareMode === true && !(engine.ccSystemPrompt !== undefined && engine.ccSystemPrompt !== null && engine.ccSystemPrompt !== '')) {
|
|
3380
3375
|
warnings.push({
|
|
3381
3376
|
id: 'bare-mode-misconfig',
|
|
3382
3377
|
message: `engine.claudeBareMode is true but CC runs on ${ccCli} (which honours --bare) with no engine.ccSystemPrompt — CLAUDE.md auto-discovery is suppressed and CC will lose project context.`,
|
|
@@ -5102,11 +5097,7 @@ function sanitizeBranch(name) {
|
|
|
5102
5097
|
// of side-effecting child_process imports at module load.
|
|
5103
5098
|
|
|
5104
5099
|
function getOperatorLogin(config) {
|
|
5105
|
-
|
|
5106
|
-
return require('./operator-identity').resolveOperatorLogin(config || {});
|
|
5107
|
-
} catch {
|
|
5108
|
-
return null;
|
|
5109
|
-
}
|
|
5100
|
+
return require('./operator-identity').resolveOperatorLogin(config || {});
|
|
5110
5101
|
}
|
|
5111
5102
|
|
|
5112
5103
|
function deriveWorkItemBranchName(item, config) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2181",
|
|
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"
|