@yemi33/minions 0.1.33 → 0.1.35

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,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.35 (2026-03-28)
4
+
5
+ ### Dashboard
6
+ - dashboard/js/render-work-items.js
7
+
8
+ ## 0.1.34 (2026-03-28)
9
+
10
+ ### Dashboard
11
+ - dashboard/js/render-work-items.js
12
+ - dashboard/pages/work.html
13
+
3
14
  ## 0.1.33 (2026-03-28)
4
15
 
5
16
  ### 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>' +
@@ -273,6 +273,120 @@ async function submitFeedback(id, source) {
273
273
  } catch (e) { alert('Error: ' + e.message); }
274
274
  }
275
275
 
276
+ function openCreateWorkItemModal() {
277
+ const typeOpts = ['implement', 'fix', 'explore', 'test', 'review', 'ask', 'plan'].map(t =>
278
+ '<option value="' + t + '"' + (t === 'implement' ? ' selected' : '') + '>' + t + '</option>'
279
+ ).join('');
280
+ const priOpts = ['high', 'medium', 'low'].map(p =>
281
+ '<option value="' + p + '"' + (p === 'medium' ? ' selected' : '') + '>' + p + '</option>'
282
+ ).join('');
283
+ const agentOpts = (typeof cmdAgents !== 'undefined' ? cmdAgents : []).map(a =>
284
+ '<option value="' + escHtml(a.id) + '">' + escHtml(a.name) + '</option>'
285
+ ).join('');
286
+ const projOpts = (typeof cmdProjects !== 'undefined' ? cmdProjects : []).map(p =>
287
+ '<option value="' + escHtml(p) + '">' + escHtml(p) + '</option>'
288
+ ).join('');
289
+ const inputStyle = 'display:block;width:100%;margin-top:4px;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:var(--text-md);font-family:inherit';
290
+
291
+ document.getElementById('modal-title').textContent = 'Create Work Item';
292
+ document.getElementById('modal-body').innerHTML =
293
+ '<div style="display:flex;flex-direction:column;gap:10px">' +
294
+ '<label style="color:var(--text);font-size:var(--text-md)">Title <input id="wi-new-title" style="' + inputStyle + '" placeholder="What needs to be done?"></label>' +
295
+ '<label style="color:var(--text);font-size:var(--text-md)">Description <textarea id="wi-new-desc" rows="3" style="' + inputStyle + ';resize:vertical" placeholder="Detailed description..."></textarea></label>' +
296
+ '<div style="display:flex;gap:8px">' +
297
+ '<label style="flex:1;color:var(--text);font-size:var(--text-md)">Type <select id="wi-new-type" style="' + inputStyle + '">' + typeOpts + '</select></label>' +
298
+ '<label style="flex:1;color:var(--text);font-size:var(--text-md)">Priority <select id="wi-new-priority" style="' + inputStyle + '">' + priOpts + '</select></label>' +
299
+ '</div>' +
300
+ '<div style="display:flex;gap:8px">' +
301
+ '<label style="flex:1;color:var(--text);font-size:var(--text-md)">Agent <select id="wi-new-agent" style="' + inputStyle + '"><option value="">Auto</option>' + agentOpts + '</select></label>' +
302
+ '<label style="flex:1;color:var(--text);font-size:var(--text-md)">Project <select id="wi-new-project" style="' + inputStyle + '"><option value="">Central</option>' + projOpts + '</select></label>' +
303
+ '</div>' +
304
+ '<label style="color:var(--text);font-size:var(--text-md)">Acceptance Criteria <textarea id="wi-new-ac" rows="2" style="' + inputStyle + ';resize:vertical" placeholder="One criterion per line (optional)"></textarea></label>' +
305
+ '<label style="color:var(--text);font-size:var(--text-md)">References <textarea id="wi-new-refs" rows="2" style="' + inputStyle + ';resize:vertical" placeholder="url | title | type — one per line (optional)"></textarea></label>' +
306
+ '<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:4px">' +
307
+ '<button onclick="closeModal()" class="pr-pager-btn">Cancel</button>' +
308
+ '<button onclick="_submitCreateWorkItem()" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer">Create</button>' +
309
+ '</div>' +
310
+ '</div>';
311
+ document.getElementById('modal').classList.add('open');
312
+ setTimeout(() => document.getElementById('wi-new-title')?.focus(), 100);
313
+ }
314
+
315
+ async function _submitCreateWorkItem() {
316
+ const title = document.getElementById('wi-new-title')?.value?.trim();
317
+ if (!title) { alert('Title is required'); return; }
318
+ const desc = document.getElementById('wi-new-desc')?.value || '';
319
+ const type = document.getElementById('wi-new-type')?.value || 'implement';
320
+ const priority = document.getElementById('wi-new-priority')?.value || 'medium';
321
+ const agent = document.getElementById('wi-new-agent')?.value || '';
322
+ const project = document.getElementById('wi-new-project')?.value || '';
323
+ const acRaw = document.getElementById('wi-new-ac')?.value || '';
324
+ const acceptanceCriteria = acRaw.split('\n').map(l => l.trim()).filter(Boolean);
325
+ const refsRaw = document.getElementById('wi-new-refs')?.value || '';
326
+ const references = refsRaw.split('\n').filter(l => l.trim()).map(l => {
327
+ const parts = l.split('|').map(s => s.trim());
328
+ return { url: parts[0], title: parts[1] || parts[0], type: parts[2] || 'link' };
329
+ });
330
+
331
+ try {
332
+ const body = { title, description: desc, type, priority };
333
+ if (agent) body.agents = [agent];
334
+ if (project) body.project = project;
335
+ if (acceptanceCriteria.length) body.acceptanceCriteria = acceptanceCriteria;
336
+ if (references.length && references[0].url) body.references = references;
337
+
338
+ const res = await fetch('/api/work-items', {
339
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
340
+ body: JSON.stringify(body)
341
+ });
342
+ const data = await res.json();
343
+ if (res.ok) {
344
+ try { closeModal(); } catch {}
345
+ wakeEngine();
346
+ refresh();
347
+ try { showToast('cmd-toast', 'Work item ' + (data.id || '') + ' created', true); } catch {}
348
+ } else {
349
+ alert('Failed: ' + (data.error || 'unknown'));
350
+ }
351
+ } catch (e) { alert('Error: ' + e.message); }
352
+ }
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
+
276
390
  function openAllWorkItems() {
277
391
  document.getElementById('modal-title').textContent = 'All Work Items (' + allWorkItems.length + ')';
278
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>' +
@@ -1,5 +1,8 @@
1
1
  <section id="work-items-section" style="overflow:visible">
2
- <h2>Work Items <span class="count" id="wi-count">0</span> <button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;margin-left:8px" onclick="toggleWorkItemArchive()">See Archive</button></h2>
3
- <div id="work-items-content"><p class="empty">No work items. Add tasks via Command Center above.</p></div>
2
+ <h2>Work Items <span class="count" id="wi-count">0</span>
3
+ <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:8px" onclick="openCreateWorkItemModal()">+ New</button>
4
+ <button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;margin-left:4px" onclick="toggleWorkItemArchive()">See Archive</button>
5
+ </h2>
6
+ <div id="work-items-content"><p class="empty">No work items yet.</p></div>
4
7
  <div id="work-items-archive" style="display:none;margin-top:12px"></div>
5
8
  </section>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
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"