@yemi33/minions 0.1.2060 → 0.1.2061
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/dashboard/js/render-agents.js +39 -24
- package/package.json +1 -1
|
@@ -69,24 +69,18 @@ function renderAgents(agents) {
|
|
|
69
69
|
`).join('');
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// Emoji, name and role are all user-controlled fields; routing them through textContent
|
|
80
|
-
// guarantees no HTML interpretation even if the escape function were ever bypassed.
|
|
72
|
+
// Re-render the detail-panel header (name + emoji + runtime/model chips +
|
|
73
|
+
// status badge + lastAction + blocking-tool / resultSummary blocks) from a
|
|
74
|
+
// slim agentData record. Extracted so renderAgents can call it every poll
|
|
75
|
+
// tick to keep an open detail panel live without re-fetching the expensive
|
|
76
|
+
// /api/agent/<id> charter/history/output payload. SEC-03 Phase A rules
|
|
77
|
+
// still apply: emoji/name/role go through textContent.
|
|
78
|
+
function _renderAgentDetailHeader(agent) {
|
|
81
79
|
const nameEl = document.getElementById('detail-agent-name');
|
|
80
|
+
if (!nameEl) return;
|
|
82
81
|
const emojiSpan = document.createElement('span');
|
|
83
82
|
emojiSpan.style.fontSize = '22px';
|
|
84
83
|
emojiSpan.textContent = agent.emoji || '';
|
|
85
|
-
// Runtime tag \u2014 uses the inline-SVG logo from the same RUNTIME_TAGS map the
|
|
86
|
-
// card uses, so the visual is consistent. The container's user-controlled
|
|
87
|
-
// text fields stay on the textContent path; the SVG is a hardcoded literal
|
|
88
|
-
// from RUNTIME_TAGS keyed by the runtime string (server-controlled, finite
|
|
89
|
-
// set), so injecting via innerHTML on the icon-only span is safe.
|
|
90
84
|
const runtimeMeta = RUNTIME_TAGS[agent.runtime];
|
|
91
85
|
const runtimeSpan = document.createElement('span');
|
|
92
86
|
runtimeSpan.title = 'Runtime: ' + (runtimeMeta?.label || agent.runtime || 'unknown');
|
|
@@ -100,9 +94,6 @@ async function openAgentDetail(id) {
|
|
|
100
94
|
runtimeSpan.style.cssText += ';font-size:10px;font-weight:600;letter-spacing:0.4px;text-transform:uppercase;padding:2px 6px;border:1px solid var(--muted);border-radius:3px;color:var(--muted)';
|
|
101
95
|
runtimeSpan.textContent = agent.runtime || 'unknown';
|
|
102
96
|
}
|
|
103
|
-
// W-mpmwxk4y00053271 — mirror the model chip the card shows so the detail
|
|
104
|
-
// header stays in sync. textContent path keeps the model string from being
|
|
105
|
-
// interpreted as HTML.
|
|
106
97
|
const modelSpan = (agent.model && typeof agent.model === 'string')
|
|
107
98
|
? (() => {
|
|
108
99
|
const s = document.createElement('span');
|
|
@@ -121,12 +112,27 @@ async function openAgentDetail(id) {
|
|
|
121
112
|
nameEl.replaceChildren(...children);
|
|
122
113
|
|
|
123
114
|
const badgeClass = agent.status;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
115
|
+
const statusEl = document.getElementById('detail-status-line');
|
|
116
|
+
if (statusEl) {
|
|
117
|
+
// eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; status is an internal bounded enum and all user data is wrapped in escapeHtml()/renderMd() (fields: lastAction, blocking tool, resultSummary)
|
|
118
|
+
statusEl.innerHTML =
|
|
119
|
+
'<span class="status-badge ' + badgeClass + '">' + agent.status.toUpperCase() + '</span> ' +
|
|
120
|
+
'<span style="color:var(--muted)">' + escapeHtml(agent.lastAction) + '</span>' +
|
|
121
|
+
(agent._blockingToolCall ? '<div style="margin-top:4px;padding:4px 8px;background:rgba(130,160,210,0.13);border:1px solid rgba(130,160,210,0.3);border-radius:4px;font-size:11px;color:var(--muted)">⏳ Blocking tool call (' + escapeHtml(agent._blockingToolCall.tool) + ') — silent ' + Math.round(agent._blockingToolCall.silentMs/60000) + 'min, timeout in ' + Math.round(agent._blockingToolCall.remainingMs/60000) + 'min</div>' : '') +
|
|
122
|
+
(agent.resultSummary ? '<div style="margin-top:4px;font-size:11px;color:var(--text);line-height:1.4">' + renderMd(agent.resultSummary.slice(0, 300)) + '</div>' : '');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function openAgentDetail(id) {
|
|
127
|
+
const agent = agentData.find(a => a.id === id);
|
|
128
|
+
if (!agent) return;
|
|
129
|
+
currentAgentId = id;
|
|
130
|
+
currentTab = (agent.status === 'working') ? 'live' : 'thought-process';
|
|
131
|
+
|
|
132
|
+
// SEC-03 Phase A: Build the detail header via DOM + textContent instead of innerHTML.
|
|
133
|
+
// Emoji, name and role are all user-controlled fields; routing them through textContent
|
|
134
|
+
// guarantees no HTML interpretation even if the escape function were ever bypassed.
|
|
135
|
+
_renderAgentDetailHeader(agent);
|
|
130
136
|
|
|
131
137
|
// Show panel immediately with loading state — don't wait for API
|
|
132
138
|
document.getElementById('detail-content').innerHTML = '<div style="padding:24px;text-align:center;color:var(--muted)">Loading...</div>';
|
|
@@ -161,7 +167,12 @@ function _tickAgentRuntimes() {
|
|
|
161
167
|
el.textContent = 'Running: ' + (hr > 0 ? hr + 'h ' : '') + min + 'm ' + sec + 's';
|
|
162
168
|
});
|
|
163
169
|
}
|
|
164
|
-
// Start ticker after each render if working agents exist
|
|
170
|
+
// Start ticker after each render if working agents exist, and refresh the
|
|
171
|
+
// open agent-detail panel header so status / lastAction / blocking-tool /
|
|
172
|
+
// resultSummary track the latest /api/status slice without re-fetching the
|
|
173
|
+
// expensive /api/agent/<id> charter/history/output payload. The body tabs
|
|
174
|
+
// (thought-process, live, output, etc.) are loaded once on open via
|
|
175
|
+
// openAgentDetail's safeFetch — they stay as-is until the user reopens.
|
|
165
176
|
var _origRenderAgents = renderAgents;
|
|
166
177
|
renderAgents = function(agents) {
|
|
167
178
|
_origRenderAgents(agents);
|
|
@@ -170,6 +181,10 @@ renderAgents = function(agents) {
|
|
|
170
181
|
_tickAgentRuntimes();
|
|
171
182
|
_agentRuntimeTimer = setInterval(_tickAgentRuntimes, 1000);
|
|
172
183
|
}
|
|
184
|
+
if (currentAgentId) {
|
|
185
|
+
var open = agents.find(function(a) { return a.id === currentAgentId; });
|
|
186
|
+
if (open) _renderAgentDetailHeader(open);
|
|
187
|
+
}
|
|
173
188
|
};
|
|
174
189
|
|
|
175
190
|
window.MinionsAgents = { renderAgents, openAgentDetail };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2061",
|
|
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"
|