@yemi33/minions 0.1.34 → 0.1.36
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 +10 -0
- package/dashboard/js/render-work-items.js +37 -1
- package/dashboard.js +32 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,7 +14,7 @@ function wiRow(item) {
|
|
|
14
14
|
const prLink = item._pr
|
|
15
15
|
? '<a class="pr-title" href="' + escHtml(item._prUrl || '#') + '" target="_blank" style="font-size:10px">' + escHtml(item._pr) + '</a>'
|
|
16
16
|
: '<span style="color:var(--muted)">—</span>';
|
|
17
|
-
return '<tr>' +
|
|
17
|
+
return '<tr style="cursor:pointer" onclick="openWorkItemDetail(\'' + escHtml(item.id) + '\')">' +
|
|
18
18
|
'<td><span class="pr-id">' + escHtml(item.id || '') + '</span></td>' +
|
|
19
19
|
'<td style="max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escHtml(item.description || item.title || '') + '">' + escHtml(item.title || '') + '</td>' +
|
|
20
20
|
'<td><span style="font-size:10px;color:var(--muted)">' + escHtml(item._source || '') + '</span>' +
|
|
@@ -351,6 +351,42 @@ async function _submitCreateWorkItem() {
|
|
|
351
351
|
} catch (e) { alert('Error: ' + e.message); }
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
+
function openWorkItemDetail(id) {
|
|
355
|
+
const item = allWorkItems.find(i => i.id === id);
|
|
356
|
+
if (!item) return;
|
|
357
|
+
|
|
358
|
+
const field = (label, value) => value ? '<div style="margin-bottom:8px"><span style="color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:0.5px">' + label + '</span><div style="margin-top:2px">' + value + '</div></div>' : '';
|
|
359
|
+
const badge = (cls, text) => '<span class="pr-badge ' + cls + '">' + escHtml(text) + '</span>';
|
|
360
|
+
const statusCls = item.status === 'failed' ? 'rejected' : item.status === 'dispatched' ? 'building' : item.status === 'done' ? 'approved' : 'active';
|
|
361
|
+
|
|
362
|
+
let html = '<div style="display:flex;flex-direction:column;gap:4px;font-size:13px">';
|
|
363
|
+
html += '<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px">' +
|
|
364
|
+
badge(statusCls, item.status || 'pending') + ' ' +
|
|
365
|
+
'<span class="dispatch-type ' + (item.type || 'implement') + '">' + escHtml(item.type || 'implement') + '</span>' +
|
|
366
|
+
'<span class="prd-item-priority ' + (item.priority || '') + '">' + escHtml(item.priority || 'medium') + '</span>' +
|
|
367
|
+
'</div>';
|
|
368
|
+
html += field('Description', '<div style="white-space:pre-wrap;font-size:12px">' + escHtml(item.description || item.title || '—') + '</div>');
|
|
369
|
+
html += field('Agent', escHtml(item.dispatched_to || item.agent || 'Auto'));
|
|
370
|
+
html += field('Source', escHtml(item._source || 'central'));
|
|
371
|
+
if (item.created) html += field('Created', escHtml(new Date(item.created).toLocaleString()));
|
|
372
|
+
if (item.dispatched_at) html += field('Dispatched', escHtml(new Date(item.dispatched_at).toLocaleString()) + ' to ' + escHtml(item.dispatched_to || '?'));
|
|
373
|
+
if (item.completedAt) html += field('Completed', escHtml(new Date(item.completedAt).toLocaleString()));
|
|
374
|
+
if (item.failReason) html += field('Failure Reason', '<span style="color:var(--red)">' + escHtml(item.failReason) + '</span>');
|
|
375
|
+
if (item._pendingReason) html += field('Pending Reason', escHtml(item._pendingReason.replace(/_/g, ' ')));
|
|
376
|
+
if (item.depends_on?.length) html += field('Depends On', item.depends_on.map(d => '<code>' + escHtml(d) + '</code>').join(', '));
|
|
377
|
+
if (item.acceptanceCriteria?.length) html += field('Acceptance Criteria', '<ul style="margin:0;padding-left:20px">' + item.acceptanceCriteria.map(c => '<li>' + escHtml(c) + '</li>').join('') + '</ul>');
|
|
378
|
+
if (item.references?.length) html += field('References', item.references.map(r => '<a href="' + escHtml(r.url) + '" target="_blank" style="color:var(--blue)">' + escHtml(r.title || r.url) + '</a>' + (r.type ? ' <span style="color:var(--muted);font-size:10px">(' + escHtml(r.type) + ')</span>' : '')).join('<br>'));
|
|
379
|
+
if (item._humanFeedback) html += field('Human Feedback', (item._humanFeedback.rating === 'up' ? '👍' : '👎') + (item._humanFeedback.comment ? ' — ' + escHtml(item._humanFeedback.comment) : ''));
|
|
380
|
+
if (item._pr) html += field('Pull Request', '<a href="' + escHtml(item._prUrl || '#') + '" target="_blank" style="color:var(--blue)">' + escHtml(item._pr) + '</a>');
|
|
381
|
+
html += '</div>';
|
|
382
|
+
|
|
383
|
+
document.getElementById('modal-title').textContent = item.title || item.id;
|
|
384
|
+
document.getElementById('modal-body').innerHTML = html;
|
|
385
|
+
document.getElementById('modal-body').style.fontFamily = "'Segoe UI', system-ui, sans-serif";
|
|
386
|
+
document.getElementById('modal-body').style.whiteSpace = 'normal';
|
|
387
|
+
document.getElementById('modal').classList.add('open');
|
|
388
|
+
}
|
|
389
|
+
|
|
354
390
|
function openAllWorkItems() {
|
|
355
391
|
document.getElementById('modal-title').textContent = 'All Work Items (' + allWorkItems.length + ')';
|
|
356
392
|
const html = '<div class="pr-table-wrap"><table class="pr-table"><thead><tr><th>ID</th><th>Title</th><th>Source</th><th>Type</th><th>Priority</th><th>Status</th><th>Agent</th><th>PR</th><th>Created</th><th></th><th></th></tr></thead><tbody>' +
|
package/dashboard.js
CHANGED
|
@@ -92,11 +92,39 @@ function buildDashboardHtml() {
|
|
|
92
92
|
.replace('/* __JS__ */', () => jsHtml);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
let HTML_RAW = buildDashboardHtml();
|
|
96
|
+
let HTML = HTML_RAW.replace('Minions Mission Control', `Minions Mission Control — ${projectNames}`);
|
|
97
|
+
let HTML_GZ = zlib.gzipSync(HTML);
|
|
98
|
+
let HTML_ETAG = '"' + require('crypto').createHash('md5').update(HTML).digest('hex') + '"';
|
|
99
99
|
|
|
100
|
+
// Hot-reload: watch dashboard/ directory for changes and rebuild
|
|
101
|
+
function rebuildDashboardHtml() {
|
|
102
|
+
try {
|
|
103
|
+
const newRaw = buildDashboardHtml();
|
|
104
|
+
if (newRaw === HTML_RAW) return; // no changes
|
|
105
|
+
HTML_RAW = newRaw;
|
|
106
|
+
HTML = HTML_RAW.replace('Minions Mission Control', `Minions Mission Control — ${projectNames}`);
|
|
107
|
+
HTML_GZ = zlib.gzipSync(HTML);
|
|
108
|
+
HTML_ETAG = '"' + require('crypto').createHash('md5').update(HTML).digest('hex') + '"';
|
|
109
|
+
console.log(' Dashboard hot-reloaded');
|
|
110
|
+
} catch (e) { console.error(' Hot-reload error:', e.message); }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const dashDir = path.join(MINIONS_DIR, 'dashboard');
|
|
114
|
+
if (fs.existsSync(dashDir)) {
|
|
115
|
+
let _reloadTimer = null;
|
|
116
|
+
const scheduleReload = () => {
|
|
117
|
+
if (_reloadTimer) clearTimeout(_reloadTimer);
|
|
118
|
+
_reloadTimer = setTimeout(rebuildDashboardHtml, 300); // debounce 300ms
|
|
119
|
+
};
|
|
120
|
+
// Watch top-level files (styles.css, layout.html)
|
|
121
|
+
try { fs.watch(dashDir, scheduleReload); } catch {}
|
|
122
|
+
// Watch subdirectories (pages/, js/)
|
|
123
|
+
for (const sub of ['pages', 'js']) {
|
|
124
|
+
const subDir = path.join(dashDir, sub);
|
|
125
|
+
if (fs.existsSync(subDir)) try { fs.watch(subDir, scheduleReload); } catch {}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
100
128
|
|
|
101
129
|
// -- Data Collectors (most moved to engine/queries.js) --
|
|
102
130
|
|
package/package.json
CHANGED