@yemi33/minions 0.1.1750 → 0.1.1752
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 +8 -0
- package/dashboard/js/render-other.js +4 -3
- package/dashboard/js/render-prd.js +11 -0
- package/dashboard.js +47 -8
- package/engine/copilot-models.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -85,17 +85,18 @@ function renderMcpServers(servers) {
|
|
|
85
85
|
const countEl = document.getElementById('mcp-count');
|
|
86
86
|
countEl.textContent = servers.length;
|
|
87
87
|
if (!servers.length) {
|
|
88
|
-
el.innerHTML = '<p class="empty">No MCP servers found. Add them to <code>~/.claude.json</code> and they\'ll appear here automatically.</p>';
|
|
88
|
+
el.innerHTML = '<p class="empty">No MCP servers found. Add them to <code>~/.claude.json</code> or <code>~/.copilot/mcp-config.json</code> and they\'ll appear here automatically.</p>';
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
el.innerHTML = '<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px">' +
|
|
92
92
|
servers.map(s =>
|
|
93
|
-
'<div style="font-size:11px;padding:5px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;color:var(--text)" title="' + escHtml(s.args || s.command) + '">' +
|
|
93
|
+
'<div style="font-size:11px;padding:5px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;color:var(--text)" title="' + escHtml([s.source, s.args || s.command].filter(Boolean).join(': ')) + '">' +
|
|
94
94
|
escHtml(s.name) +
|
|
95
|
+
(s.source ? ' <span style="color:var(--muted)">(' + escHtml(s.source) + ')</span>' : '') +
|
|
95
96
|
'</div>'
|
|
96
97
|
).join('') +
|
|
97
98
|
'</div>' +
|
|
98
|
-
'<p style="font-size:10px;color:var(--muted);margin:0">Synced from <code style="color:var(--blue)">~/.claude.json</code>
|
|
99
|
+
'<p style="font-size:10px;color:var(--muted);margin:0">Synced from <code style="color:var(--blue)">~/.claude.json</code> and <code style="color:var(--blue)">~/.copilot/mcp-config.json</code>.</p>';
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
function renderMetrics(metrics) {
|
|
@@ -406,12 +406,22 @@ function renderPrdProgress(prog) {
|
|
|
406
406
|
const agentDisplay = agentInfo ? (agentInfo.emoji || '') + ' ' + escHtml(agentInfo.name || agentId) : (agentId ? escHtml(agentId) : '');
|
|
407
407
|
const deps = (i.depends_on || []).join(', ');
|
|
408
408
|
const wipAnim = i.status === 'in-progress' ? 'animation:prdWipPulse 2s infinite;' : '';
|
|
409
|
+
const wiForCard = wi[i.id];
|
|
410
|
+
const wiIdBadge = wiForCard ? '<span style="font-size:8px;color:var(--muted);background:var(--surface);padding:1px 4px;border-radius:3px;border:1px solid var(--border)" title="Work item: ' + escHtml(wiForCard.id) + '">' + escHtml(wiForCard.id) + '</span>' : '';
|
|
411
|
+
const isDoneCard = i.status === 'done' || (wiForCard && wiForCard.status === 'done');
|
|
412
|
+
const reopenBtnGraph = isDoneCard
|
|
413
|
+
? '<span onclick="event.stopPropagation();prdItemReopen(\'' + src + '\',\'' + iid + '\')" style="font-size:8px;color:var(--blue);cursor:pointer;padding:1px 4px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="Re-open: set to updated so engine re-dispatches on existing branch">re-open</span>'
|
|
414
|
+
: '';
|
|
415
|
+
const cardTitle = i.description ? escHtml(i.name + ' — ' + i.description) : escHtml(i.name || '');
|
|
409
416
|
html += '<div onclick="prdItemEdit(\'' + src + '\',\'' + iid + '\')" ' +
|
|
417
|
+
'title="' + cardTitle + '" ' +
|
|
410
418
|
'style="background:var(--surface2);border:1px solid var(--border);border-left:3px solid ' + borderColor + ';' + wipAnim +
|
|
411
419
|
'border-radius:4px;padding:6px 8px;margin-bottom:6px;cursor:pointer;font-size:11px">' +
|
|
412
420
|
'<div style="display:flex;align-items:center;gap:4px;margin-bottom:2px">' +
|
|
413
421
|
statusBadge(i.status, i.id) +
|
|
414
422
|
'<span style="font-weight:600;color:var(--text)">' + escHtml(i.id) + '</span>' +
|
|
423
|
+
wiIdBadge +
|
|
424
|
+
'<span onclick="event.stopPropagation();prdItemRemove(\'' + src + '\',\'' + iid + '\')" style="margin-left:auto;color:var(--red);cursor:pointer;font-size:10px;padding:0 4px;line-height:1" title="Remove item">x</span>' +
|
|
415
425
|
'</div>' +
|
|
416
426
|
'<div style="color:var(--text);font-size:11px;line-height:1.3;margin-bottom:3px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical">' + escHtml(i.name) + '</div>' +
|
|
417
427
|
'<div style="display:flex;gap:4px;flex-wrap:wrap;align-items:center">' +
|
|
@@ -436,6 +446,7 @@ function renderPrdProgress(prog) {
|
|
|
436
446
|
if (!canRetry) return '';
|
|
437
447
|
return '<span onclick="event.stopPropagation();prdItemRequeue(\'' + escHtml(rqId) + '\',\'' + escHtml(w ? (w._source || '') : '') + '\',\'' + escHtml(i.source || '') + '\')" style="font-size:8px;color:var(--green);cursor:pointer;padding:1px 4px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">retry</span>';
|
|
438
448
|
})() +
|
|
449
|
+
reopenBtnGraph +
|
|
439
450
|
(deps ? '<span style="font-size:8px;color:var(--muted)" title="Depends on: ' + escHtml(deps) + '">deps: ' + escHtml(deps) + '</span>' : '') +
|
|
440
451
|
(function() {
|
|
441
452
|
var w = wi[i.id];
|
package/dashboard.js
CHANGED
|
@@ -721,17 +721,24 @@ function getDiskVersion() {
|
|
|
721
721
|
return _diskVersionCache;
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
+
function readMcpServersFromConfig(configPath, source) {
|
|
725
|
+
const data = safeJsonObj(configPath);
|
|
726
|
+
const servers = data.mcpServers || {};
|
|
727
|
+
return Object.entries(servers).map(([name, cfg]) => ({
|
|
728
|
+
name,
|
|
729
|
+
source,
|
|
730
|
+
command: cfg.command || cfg.url || '',
|
|
731
|
+
args: (cfg.args || []).slice(-1)[0] || '',
|
|
732
|
+
}));
|
|
733
|
+
}
|
|
734
|
+
|
|
724
735
|
function getMcpServers() {
|
|
725
736
|
try {
|
|
726
737
|
const home = os.homedir();
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
name,
|
|
732
|
-
command: cfg.command || '',
|
|
733
|
-
args: (cfg.args || []).slice(-1)[0] || '',
|
|
734
|
-
}));
|
|
738
|
+
return [
|
|
739
|
+
...readMcpServersFromConfig(path.join(home, '.claude.json'), 'Claude'),
|
|
740
|
+
...readMcpServersFromConfig(path.join(home, '.copilot', 'mcp-config.json'), 'Copilot'),
|
|
741
|
+
];
|
|
735
742
|
} catch { return []; }
|
|
736
743
|
}
|
|
737
744
|
|
|
@@ -7389,6 +7396,33 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
7389
7396
|
}
|
|
7390
7397
|
});
|
|
7391
7398
|
|
|
7399
|
+
// Crash handlers — install before listen() so a rogue Promise rejection or
|
|
7400
|
+
// thrown error in any request handler is logged via shared.log instead of
|
|
7401
|
+
// silently killing the dashboard with no audit trail.
|
|
7402
|
+
//
|
|
7403
|
+
// Mirrors the pattern in engine/cli.js, but tuned for a long-running HTTP
|
|
7404
|
+
// server: unhandledRejection is logged-and-recovered (transient bugs in
|
|
7405
|
+
// individual requests should not take down the whole process), while
|
|
7406
|
+
// uncaughtException sets process.exitCode = 1 and lets pending writes flush
|
|
7407
|
+
// (per Node docs, the process state is undefined after an uncaught exception,
|
|
7408
|
+
// so the safe move is to log, mark exit-non-zero, and let the runtime tear
|
|
7409
|
+
// down naturally rather than calling process.exit() synchronously).
|
|
7410
|
+
function _installCrashHandlers() {
|
|
7411
|
+
process.on('unhandledRejection', (reason) => {
|
|
7412
|
+
const msg = reason instanceof Error ? reason.stack || reason.message : String(reason);
|
|
7413
|
+
console.error(`[dashboard] Unhandled promise rejection: ${msg}`);
|
|
7414
|
+
try { shared.log('error', `dashboard unhandledRejection: ${msg}`); } catch { /* best effort */ }
|
|
7415
|
+
});
|
|
7416
|
+
|
|
7417
|
+
process.on('uncaughtException', (err) => {
|
|
7418
|
+
const msg = err instanceof Error ? err.stack || err.message : String(err);
|
|
7419
|
+
console.error(`[dashboard] Uncaught exception: ${msg}`);
|
|
7420
|
+
try { shared.log('error', `dashboard uncaughtException: ${msg}`); } catch { /* best effort */ }
|
|
7421
|
+
try { shared.flushLogs(); } catch { /* best effort */ }
|
|
7422
|
+
process.exitCode = 1;
|
|
7423
|
+
});
|
|
7424
|
+
}
|
|
7425
|
+
|
|
7392
7426
|
// Exported for testing — pure helpers with no hidden side effects.
|
|
7393
7427
|
// Production entry points use the closures directly; tests import via require('./dashboard').
|
|
7394
7428
|
module.exports = {
|
|
@@ -7418,12 +7452,17 @@ module.exports = {
|
|
|
7418
7452
|
_formatCcApiRoutesIndex,
|
|
7419
7453
|
_formatCcCliCommandsIndex,
|
|
7420
7454
|
_resetPreambleCache,
|
|
7455
|
+
_installCrashHandlers,
|
|
7421
7456
|
};
|
|
7422
7457
|
|
|
7423
7458
|
// Start the HTTP server only when run directly (node dashboard.js).
|
|
7424
7459
|
// When required as a module (e.g. by unit tests), skip the listen/watchdog/signal
|
|
7425
7460
|
// handlers so tests can import exported helpers without binding to port 7331.
|
|
7426
7461
|
if (require.main === module) {
|
|
7462
|
+
// Install crash handlers FIRST so any error during bootstrap (HTML assembly,
|
|
7463
|
+
// engine reads, port binding) is captured rather than dying silently.
|
|
7464
|
+
_installCrashHandlers();
|
|
7465
|
+
|
|
7427
7466
|
server.listen(PORT, '127.0.0.1', () => {
|
|
7428
7467
|
console.log(`\n Minions Mission Control`);
|
|
7429
7468
|
console.log(` -----------------------------------`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1752",
|
|
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"
|