@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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.36 (2026-03-28)
4
+
5
+ ### Dashboard
6
+ - dashboard.js
7
+
8
+ ## 0.1.35 (2026-03-28)
9
+
10
+ ### Dashboard
11
+ - dashboard/js/render-work-items.js
12
+
3
13
  ## 0.1.34 (2026-03-28)
4
14
 
5
15
  ### Dashboard
@@ -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
- const HTML_RAW = buildDashboardHtml();
96
- const HTML = HTML_RAW.replace('Minions Mission Control', `Minions Mission Control — ${projectNames}`);
97
- const HTML_GZ = zlib.gzipSync(HTML);
98
- const HTML_ETAG = '"' + require('crypto').createHash('md5').update(HTML).digest('hex') + '"';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
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"