@yemi33/minions 0.1.364 → 0.1.366
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 +6 -0
- package/dashboard/js/render-agents.js +5 -5
- package/dashboard/js/render-inbox.js +4 -4
- package/dashboard/js/render-pinned.js +5 -5
- package/dashboard/js/render-plans.js +2 -1
- package/dashboard/js/render-prs.js +6 -5
- package/dashboard/js/render-schedules.js +1 -0
- package/dashboard/js/render-work-items.js +1 -1
- package/dashboard/js/utils.js +8 -1
- package/dashboard.js +15 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,12 +4,12 @@ function renderAgents(agents) {
|
|
|
4
4
|
agentData = agents;
|
|
5
5
|
const grid = document.getElementById('agents-grid');
|
|
6
6
|
grid.innerHTML = agents.map(a => `
|
|
7
|
-
<div class="agent-card ${statusColor(a.status)}" onclick="openAgentDetail('${a.id}')">
|
|
7
|
+
<div class="agent-card ${statusColor(a.status)}" onclick="openAgentDetail('${escHtml(a.id)}')">
|
|
8
8
|
<div class="agent-card-header">
|
|
9
|
-
<span class="agent-name"><span class="agent-emoji">${a.emoji}</span>${a.name}</span>
|
|
10
|
-
<span class="status-badge ${a.status}">${a.status}</span>
|
|
9
|
+
<span class="agent-name"><span class="agent-emoji">${escHtml(a.emoji)}</span>${escHtml(a.name)}</span>
|
|
10
|
+
<span class="status-badge ${escHtml(a.status)}">${escHtml(a.status)}</span>
|
|
11
11
|
</div>
|
|
12
|
-
<div class="agent-role">${a.role}</div>
|
|
12
|
+
<div class="agent-role">${escHtml(a.role)}</div>
|
|
13
13
|
<div class="agent-action" title="${escHtml(a.lastAction)}">${escHtml(a.lastAction)}</div>
|
|
14
14
|
${a._warning ? `<div style="margin-top:4px;padding:4px 8px;background:rgba(210,153,34,0.15);border:1px solid rgba(210,153,34,0.3);border-radius:4px;font-size:10px;color:var(--yellow)">⚠ ${escHtml(a._warning)}</div>` : ''}
|
|
15
15
|
${a._permissionMode && a._permissionMode !== 'bypassPermissions' && !a._warning ? `<div style="margin-top:4px;font-size:9px;color:var(--muted)">Permission mode: ${escHtml(a._permissionMode)}</div>` : ''}
|
|
@@ -25,7 +25,7 @@ async function openAgentDetail(id) {
|
|
|
25
25
|
currentTab = (agent.status === 'working') ? 'live' : 'thought-process';
|
|
26
26
|
|
|
27
27
|
document.getElementById('detail-agent-name').innerHTML =
|
|
28
|
-
'<span style="font-size:22px">' + agent.emoji + '</span> ' + agent.name + ' — ' + agent.role;
|
|
28
|
+
'<span style="font-size:22px">' + escHtml(agent.emoji) + '</span> ' + escHtml(agent.name) + ' — ' + escHtml(agent.role);
|
|
29
29
|
|
|
30
30
|
const badgeClass = agent.status;
|
|
31
31
|
document.getElementById('detail-status-line').innerHTML =
|
|
@@ -24,13 +24,13 @@ function renderInbox(inbox) {
|
|
|
24
24
|
const idx = inboxStart + i;
|
|
25
25
|
return `<div class="inbox-item" data-file="notes/inbox/${escHtml(item.name)}">
|
|
26
26
|
<div class="inbox-name" onclick="openModal(${idx})" style="cursor:pointer">
|
|
27
|
-
<span>${escHtml(item.name)}</span><span>${item.age}</span>
|
|
27
|
+
<span>${escHtml(item.name)}</span><span>${escHtml(item.age || '')}</span>
|
|
28
28
|
</div>
|
|
29
29
|
<div class="inbox-preview" onclick="openModal(${idx})" style="cursor:pointer">${escHtml(item.content.slice(0,200))}</div>
|
|
30
30
|
<div style="display:flex;gap:6px;margin-top:6px;align-items:center">
|
|
31
|
-
<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" onclick="event.stopPropagation();promoteToKB(
|
|
32
|
-
<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" onclick="event.stopPropagation();openInboxInExplorer(
|
|
33
|
-
<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red)" onclick="event.stopPropagation();deleteInboxItem(
|
|
31
|
+
<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" data-inbox-name="${escHtml(item.name)}" onclick="event.stopPropagation();promoteToKB(this.dataset.inboxName)">Add to Knowledge Base</button>
|
|
32
|
+
<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" data-inbox-name="${escHtml(item.name)}" onclick="event.stopPropagation();openInboxInExplorer(this.dataset.inboxName)">Open in Explorer</button>
|
|
33
|
+
<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red)" data-inbox-name="${escHtml(item.name)}" onclick="event.stopPropagation();deleteInboxItem(this.dataset.inboxName)">Delete</button>
|
|
34
34
|
</div>
|
|
35
35
|
</div>`;
|
|
36
36
|
}).join('');
|
|
@@ -14,7 +14,7 @@ function renderPinned(entries) {
|
|
|
14
14
|
';border-radius:4px">' +
|
|
15
15
|
'<div style="display:flex;justify-content:space-between;align-items:center">' +
|
|
16
16
|
'<strong style="font-size:var(--text-md)">' + escHtml(e.title) + '</strong>' +
|
|
17
|
-
'<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--red);border-color:var(--red)"
|
|
17
|
+
'<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--red);border-color:var(--red)" data-pin-title="' + escHtml(e.title) + '" onclick="removePinnedNote(this.dataset.pinTitle)">Unpin</button>' +
|
|
18
18
|
'</div>' +
|
|
19
19
|
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">' + renderMd(e.content.slice(0, 200)) + '</div>' +
|
|
20
20
|
'</div>'
|
|
@@ -28,13 +28,13 @@ function openPinNoteModal() {
|
|
|
28
28
|
'<label style="color:var(--text);font-size:var(--text-md)">Title<input id="pin-title" style="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)" placeholder="e.g. API freeze until Friday"></label>' +
|
|
29
29
|
'<label style="color:var(--text);font-size:var(--text-md)">Content<textarea id="pin-content" rows="4" style="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);resize:vertical;font-family:inherit" placeholder="Context all agents should see..."></textarea></label>' +
|
|
30
30
|
'<label style="color:var(--text);font-size:var(--text-md)">Level<select id="pin-level" style="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)"><option value="info">Info</option><option value="warning">Warning</option><option value="critical">Critical</option></select></label>' +
|
|
31
|
-
'<div style="display:flex;justify-content:flex-end;gap:8px"><button onclick="closeModal()" class="pr-pager-btn">Cancel</button><button onclick="submitPinnedNote()" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer">Pin</button></div>' +
|
|
31
|
+
'<div style="display:flex;justify-content:flex-end;gap:8px"><button onclick="closeModal()" class="pr-pager-btn">Cancel</button><button onclick="submitPinnedNote(event)" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer">Pin</button></div>' +
|
|
32
32
|
'</div>';
|
|
33
33
|
document.getElementById('modal').classList.add('open');
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
async function submitPinnedNote() {
|
|
37
|
-
var btn = event?.target; if (btn) { btn.disabled = true; btn.textContent = 'Pinning...'; }
|
|
36
|
+
async function submitPinnedNote(e) {
|
|
37
|
+
var btn = (e || window.event)?.target; if (btn) { btn.disabled = true; btn.textContent = 'Pinning...'; }
|
|
38
38
|
const title = document.getElementById('pin-title').value;
|
|
39
39
|
const content = document.getElementById('pin-content').value;
|
|
40
40
|
const level = document.getElementById('pin-level').value;
|
|
@@ -50,7 +50,7 @@ async function submitPinnedNote() {
|
|
|
50
50
|
async function removePinnedNote(title) {
|
|
51
51
|
if (!confirm('Unpin "' + title + '"?')) return;
|
|
52
52
|
markDeleted('pin:' + title);
|
|
53
|
-
const btn = event?.target; if (btn) { const card = btn.closest('.pinned-card') || btn.parentElement?.parentElement; if (card) card.remove(); }
|
|
53
|
+
const btn = (window.event)?.target; if (btn) { const card = btn.closest('.pinned-card') || btn.parentElement?.parentElement; if (card) card.remove(); }
|
|
54
54
|
try {
|
|
55
55
|
const res = await fetch('/api/pinned/remove', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title }) });
|
|
56
56
|
if (!res.ok) { alert('Unpin failed'); refresh(); }
|
|
@@ -255,7 +255,7 @@ function renderPlans(plans) {
|
|
|
255
255
|
'<div><div class="plan-card-title">' + escHtml(p.summary || p.file) + versionBadge + '</div>' +
|
|
256
256
|
'<div class="plan-card-meta">' +
|
|
257
257
|
'<span style="font-weight:600;color:' + (statusColors[effectiveStatus] || 'var(--muted)') + '">' + label + '</span>' +
|
|
258
|
-
'<span>' + escHtml(p.project) + '</span>' +
|
|
258
|
+
(p.project ? '<span>' + escHtml(p.project) + '</span>' : '') +
|
|
259
259
|
'<span>' + p.itemCount + ' items</span>' +
|
|
260
260
|
(p.updatedAt ? '<span title="Last updated: ' + p.updatedAt + '">Updated ' + timeAgo(p.updatedAt) + '</span>' : '') +
|
|
261
261
|
(p.completedAt ? '<span>' + p.completedAt.slice(0, 10) + '</span>' : '') +
|
|
@@ -370,6 +370,7 @@ async function planSubmitRevise(file) {
|
|
|
370
370
|
try {
|
|
371
371
|
const res = await fetch('/api/plans/revise', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file, feedback }) });
|
|
372
372
|
const data = await res.json();
|
|
373
|
+
if (!res.ok) { showToast('cmd-toast', 'Revision failed: ' + (data.error || 'unknown'), false); return; }
|
|
373
374
|
showToast('cmd-toast', 'Revision requested — agent will update the plan (' + data.workItemId + ')', true);
|
|
374
375
|
planHideRevise(file);
|
|
375
376
|
refreshPlans();
|
|
@@ -20,7 +20,7 @@ function prRow(pr) {
|
|
|
20
20
|
const prId = pr.id || '—';
|
|
21
21
|
return '<tr>' +
|
|
22
22
|
'<td><span class="pr-id">' + escHtml(String(prId)) + '</span></td>' +
|
|
23
|
-
'<td><a class="pr-title" href="' + escHtml(url) + '" target="_blank">' + escHtml(pr.title || 'Untitled') + '</a></td>' +
|
|
23
|
+
'<td><a class="pr-title" href="' + escHtml(safeUrl(url)) + '" target="_blank" rel="noopener">' + escHtml(pr.title || 'Untitled') + '</a></td>' +
|
|
24
24
|
'<td><span class="pr-agent">' + escHtml(pr.agent || '—') + '</span></td>' +
|
|
25
25
|
'<td><span class="pr-branch">' + escHtml(pr.branch || '—') + '</span></td>' +
|
|
26
26
|
'<td><span class="pr-badge ' + reviewClass + '">' + escHtml(reviewLabel) + '</span></td>' +
|
|
@@ -33,7 +33,7 @@ function prRow(pr) {
|
|
|
33
33
|
|
|
34
34
|
function prTableHtml(rows) {
|
|
35
35
|
return '<div class="pr-table-wrap"><table class="pr-table"><thead><tr>' +
|
|
36
|
-
'<th>PR</th><th>Title</th><th>Agent</th><th>Branch</th><th>Review</th><th>Signed Off By</th><th>Build</th><th>Status</th><th>Created</th
|
|
36
|
+
'<th>PR</th><th>Title</th><th>Agent</th><th>Branch</th><th>Review</th><th>Signed Off By</th><th>Build</th><th>Status</th><th>Created</th>' +
|
|
37
37
|
'</tr></thead><tbody>' + rows + '</tbody></table></div>';
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -96,9 +96,10 @@ function openModal(i) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
function openAddPrModal() {
|
|
99
|
-
const projOpts = (typeof cmdProjects !== 'undefined' ? cmdProjects : []).map(p =>
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
const projOpts = (typeof cmdProjects !== 'undefined' ? cmdProjects : []).map(p => {
|
|
100
|
+
const name = typeof p === 'object' ? p.name : p;
|
|
101
|
+
return '<option value="' + escHtml(name) + '">' + escHtml(name) + '</option>';
|
|
102
|
+
}).join('');
|
|
102
103
|
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';
|
|
103
104
|
|
|
104
105
|
document.getElementById('modal-title').textContent = 'Link Pull Request';
|
|
@@ -484,6 +484,7 @@ function openEditScheduleModal(id) {
|
|
|
484
484
|
document.getElementById('modal-body').innerHTML = _scheduleFormHtml(sched, true);
|
|
485
485
|
window._editScheduleId = id;
|
|
486
486
|
document.getElementById('modal').classList.add('open');
|
|
487
|
+
_updateCronPreview();
|
|
487
488
|
}
|
|
488
489
|
|
|
489
490
|
async function submitSchedule(isEdit) {
|
|
@@ -84,7 +84,7 @@ function renderWorkItems(items) {
|
|
|
84
84
|
allWorkItems = items;
|
|
85
85
|
const el = document.getElementById('work-items-content');
|
|
86
86
|
const countEl = document.getElementById('wi-count');
|
|
87
|
-
countEl.textContent = items.length;
|
|
87
|
+
if (countEl) countEl.textContent = items.length;
|
|
88
88
|
if (!items.length) {
|
|
89
89
|
el.innerHTML = '<p class="empty">No work items. Add tasks via Command Center above.</p>';
|
|
90
90
|
return;
|
package/dashboard/js/utils.js
CHANGED
|
@@ -12,6 +12,13 @@ function escHtml(s) {
|
|
|
12
12
|
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,''');
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
function safeUrl(url) {
|
|
16
|
+
const s = String(url || '').trim();
|
|
17
|
+
if (/^https?:\/\//i.test(s)) return s;
|
|
18
|
+
if (s === '#' || s === '') return '#';
|
|
19
|
+
return '#'; // block javascript:, data:, etc.
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
function normalizePlanFile(file) {
|
|
16
23
|
return String(file || '').replace(/\\/g, '/').split('/').pop();
|
|
17
24
|
}
|
|
@@ -31,7 +38,7 @@ function timeAgo(isoStr) {
|
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
function statusColor(s) {
|
|
34
|
-
return s === 'working' ? 'working' : s === 'done' ? 'done' : '';
|
|
41
|
+
return s === 'working' ? 'working' : s === 'done' ? 'done' : s === 'error' ? 'error' : '';
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
function llmCopyBtn() {
|
package/dashboard.js
CHANGED
|
@@ -959,15 +959,18 @@ const server = http.createServer(async (req, res) => {
|
|
|
959
959
|
}
|
|
960
960
|
if (!wiPath) return jsonReply(res, 404, { error: 'source not found' });
|
|
961
961
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
962
|
+
let item = null;
|
|
963
|
+
let found = false;
|
|
964
|
+
mutateJsonFileLocked(wiPath, (items) => {
|
|
965
|
+
if (!Array.isArray(items)) return items;
|
|
966
|
+
const idx = items.findIndex(i => i.id === id);
|
|
967
|
+
if (idx === -1) return items;
|
|
968
|
+
item = items[idx];
|
|
969
|
+
items.splice(idx, 1);
|
|
970
|
+
found = true;
|
|
971
|
+
return items;
|
|
972
|
+
}, { defaultValue: [] });
|
|
973
|
+
if (!found) return jsonReply(res, 404, { error: 'item not found' });
|
|
971
974
|
|
|
972
975
|
// Clean dispatch entries + kill running agent
|
|
973
976
|
const dispatchRemoved = cleanDispatchEntries(d =>
|
|
@@ -1080,6 +1083,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
1080
1083
|
if (body.agents) item.agents = body.agents;
|
|
1081
1084
|
if (body.references) item.references = body.references;
|
|
1082
1085
|
if (body.acceptanceCriteria) item.acceptanceCriteria = body.acceptanceCriteria;
|
|
1086
|
+
if (body.skipPr) item.skipPr = true;
|
|
1083
1087
|
items.push(item);
|
|
1084
1088
|
safeWrite(wiPath, items);
|
|
1085
1089
|
return jsonReply(res, 200, { ok: true, id });
|
|
@@ -3297,6 +3301,8 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
3297
3301
|
config.claude = { ...shared.DEFAULT_CLAUDE };
|
|
3298
3302
|
config.agents = { ...shared.DEFAULT_AGENTS };
|
|
3299
3303
|
safeWrite(path.join(MINIONS_DIR, 'config.json'), config);
|
|
3304
|
+
reloadConfig();
|
|
3305
|
+
invalidateStatusCache();
|
|
3300
3306
|
return jsonReply(res, 200, { ok: true });
|
|
3301
3307
|
} catch (e) { return jsonReply(res, 500, { error: e.message }); }
|
|
3302
3308
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.366",
|
|
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"
|