@yemi33/minions 0.1.1986 → 0.1.1988
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/qa.js +11 -35
- package/dashboard/js/refresh.js +16 -9
- package/dashboard/js/render-managed.js +7 -0
- package/dashboard/js/render-other.js +34 -4
- package/dashboard/layout.html +1 -1
- package/dashboard/pages/engine.html +2 -2
- package/dashboard/pages/qa.html +2 -14
- package/package.json +1 -1
package/dashboard/js/qa.js
CHANGED
|
@@ -1,41 +1,19 @@
|
|
|
1
1
|
// dashboard/js/qa.js — QA tab wiring (W-mpd5ewhj000oc5c5).
|
|
2
2
|
//
|
|
3
|
-
// The QA tab
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// the same poll loop in refresh.js — no extra fetches, no extra SSE streams).
|
|
3
|
+
// The QA tab hosts validation runbooks (human-driven and agent-driven) against
|
|
4
|
+
// running managed instances. It does NOT mirror the live-process inventory —
|
|
5
|
+
// that lives on /engine (Managed Processes + Keep-Processes panels). Runbook
|
|
6
|
+
// rows in the next WI will link to their targets by name rather than duplicate
|
|
7
|
+
// the inventory tables (W-mpdad3mq000m53bb).
|
|
9
8
|
//
|
|
10
|
-
//
|
|
11
|
-
// user
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// disabled "+ New runbook" button is the only UX hook for the next phase.
|
|
9
|
+
// The only wiring this file owns is the switchPage SSE-close hook: if the
|
|
10
|
+
// user has the managed-log modal (defined in render-managed.js) open on the
|
|
11
|
+
// engine page and navigates away, we close the EventSource so it doesn't
|
|
12
|
+
// keep streaming behind the new page. The hook is harmless when the QA page
|
|
13
|
+
// never opens the modal itself, and matches the broader page-navigation
|
|
14
|
+
// contract for SSE cleanup.
|
|
17
15
|
|
|
18
16
|
(function () {
|
|
19
|
-
function _registerQaMounts() {
|
|
20
|
-
if (typeof mountManagedProcessesPanel === 'function') {
|
|
21
|
-
mountManagedProcessesPanel({
|
|
22
|
-
contentId: 'qa-managed-processes-content',
|
|
23
|
-
countId: 'qa-managed-processes-count',
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
if (typeof mountKeepProcessesPanel === 'function') {
|
|
27
|
-
mountKeepProcessesPanel({
|
|
28
|
-
contentId: 'qa-keep-processes-content',
|
|
29
|
-
countId: 'qa-keep-processes-count',
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// The page fragment is in the DOM at script-load time (all .page divs are
|
|
35
|
-
// assembled into layout.html at build), so registering immediately is safe.
|
|
36
|
-
// The mount API is no-op when the QA fragment is missing (defensive).
|
|
37
|
-
_registerQaMounts();
|
|
38
|
-
|
|
39
17
|
// Close any open managed-log SSE stream when the user navigates away from a
|
|
40
18
|
// page that triggered it — the modal otherwise floats over the new page and
|
|
41
19
|
// the EventSource keeps streaming. Hooks into the existing switchPage()
|
|
@@ -48,6 +26,4 @@
|
|
|
48
26
|
};
|
|
49
27
|
window.switchPage.__qaWrapped = true;
|
|
50
28
|
}
|
|
51
|
-
|
|
52
|
-
window.MinionsQA = { _registerQaMounts };
|
|
53
29
|
})();
|
package/dashboard/js/refresh.js
CHANGED
|
@@ -103,16 +103,23 @@ function _processStatusUpdate(data) {
|
|
|
103
103
|
prunePrdRequeueState(window._lastWorkItems);
|
|
104
104
|
if (_changed('engineLog', data.engineLog)) renderEngineLog(data.engineLog || []);
|
|
105
105
|
if (_changed('metrics', data.metrics)) renderMetrics(data.metrics || {});
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// managed-processes panel — same mount-point pattern, ETag-gated so
|
|
113
|
-
// unchanged ticks return 304 with no body (P-6e2a8b13).
|
|
106
|
+
// managed-processes panel — ETag-gated so unchanged ticks return 304 with
|
|
107
|
+
// no body (P-6e2a8b13). Sequenced BEFORE the keep-processes call below via
|
|
108
|
+
// .then() so the keep renderer reads a populated managed-PID cache for
|
|
109
|
+
// dedup (W-mpdad3mq000m53bb). _processStatusUpdate isn't async, so we
|
|
110
|
+
// chain on the returned Promise instead of awaiting.
|
|
111
|
+
let _managedRender = Promise.resolve();
|
|
114
112
|
if (typeof renderManagedProcesses === 'function') {
|
|
115
|
-
try { renderManagedProcesses(); } catch {}
|
|
113
|
+
try { _managedRender = Promise.resolve(renderManagedProcesses()); } catch {}
|
|
114
|
+
}
|
|
115
|
+
// keep_processes panel renders on every page where its mount is in the DOM.
|
|
116
|
+
// Cheap call (one fetch); the renderer iterates all registered mounts, skips
|
|
117
|
+
// when none are present, and suppresses any PID already tracked as a managed
|
|
118
|
+
// process via MinionsManagedProcesses.getLastItems().
|
|
119
|
+
if (typeof renderKeepProcesses === 'function') {
|
|
120
|
+
_managedRender
|
|
121
|
+
.catch(function () { /* keep render even if managed fetch failed — getLastItems() returns the last good cache (or []) */ })
|
|
122
|
+
.then(function () { try { renderKeepProcesses(); } catch {} });
|
|
116
123
|
}
|
|
117
124
|
if (_changed('workItems', data.workItems)) renderWorkItems(data.workItems || []);
|
|
118
125
|
if (_changed('skills', data.skills)) renderSkills(data.skills || []);
|
|
@@ -45,6 +45,12 @@ function unmountManagedProcessesPanel(contentId) {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
// Read-only accessor for the last successfully-fetched managed-process items.
|
|
49
|
+
// Used by render-other.js renderKeepProcesses() to suppress PIDs that are
|
|
50
|
+
// already tracked as managed processes (W-mpdad3mq000m53bb dedup). Returns
|
|
51
|
+
// the live cache reference — callers must not mutate it.
|
|
52
|
+
function getLastItems() { return _managedProcessesLastItems || []; }
|
|
53
|
+
|
|
48
54
|
function _fmtAgo(ms) {
|
|
49
55
|
if (!ms || ms < 0) return '0s';
|
|
50
56
|
const s = Math.floor(ms / 1000);
|
|
@@ -302,4 +308,5 @@ window.MinionsManagedProcesses = {
|
|
|
302
308
|
closeManagedLog,
|
|
303
309
|
mountManagedProcessesPanel,
|
|
304
310
|
unmountManagedProcessesPanel,
|
|
311
|
+
getLastItems,
|
|
305
312
|
};
|
|
@@ -529,15 +529,45 @@ async function renderKeepProcesses() {
|
|
|
529
529
|
} catch (e) {
|
|
530
530
|
fetchErr = e;
|
|
531
531
|
}
|
|
532
|
+
// Dedup against managed-processes: agents that declare a process via
|
|
533
|
+
// managed-spawn.json AND leave it running via keep_processes show up in
|
|
534
|
+
// both panels. Managed is canonical (engine owns the lifecycle), so we
|
|
535
|
+
// suppress any PID already tracked there from the keep-processes table
|
|
536
|
+
// (W-mpdad3mq000m53bb).
|
|
537
|
+
const managed = (window.MinionsManagedProcesses && typeof window.MinionsManagedProcesses.getLastItems === 'function')
|
|
538
|
+
? window.MinionsManagedProcesses.getLastItems()
|
|
539
|
+
: [];
|
|
540
|
+
const managedPidSet = new Set(
|
|
541
|
+
(Array.isArray(managed) ? managed : [])
|
|
542
|
+
.map(m => Number(m && m.pid))
|
|
543
|
+
.filter(n => Number.isFinite(n))
|
|
544
|
+
);
|
|
545
|
+
let rawCount = 0;
|
|
546
|
+
let filtered = items;
|
|
547
|
+
if (!fetchErr && items) {
|
|
548
|
+
rawCount = items.length;
|
|
549
|
+
filtered = [];
|
|
550
|
+
for (const it of items) {
|
|
551
|
+
if (!it.valid) { filtered.push(it); continue; }
|
|
552
|
+
// Shallow clone so we don't mutate the fetched array — caller may
|
|
553
|
+
// re-render the same payload on a 304 tick.
|
|
554
|
+
const pids = Array.isArray(it.pids) ? it.pids.filter(p => !managedPidSet.has(Number(p && p.pid))) : [];
|
|
555
|
+
if (!pids.length) continue;
|
|
556
|
+
filtered.push({ ...it, pids });
|
|
557
|
+
}
|
|
558
|
+
}
|
|
532
559
|
if (fetchErr) {
|
|
533
560
|
countText = '?';
|
|
534
561
|
html = '<span style="color:var(--red)">Failed to load: ' + escHtml(fetchErr.message) + '</span>';
|
|
535
|
-
} else if (!
|
|
562
|
+
} else if (!filtered.length) {
|
|
536
563
|
countText = '0';
|
|
537
|
-
|
|
564
|
+
const baseEmpty = '<p class="empty">No agents have left processes running. Set <code>meta.keep_processes: true</code> on a work item to enable.</p>';
|
|
565
|
+
html = (rawCount > 0)
|
|
566
|
+
? baseEmpty.replace('</p>', ' <span style="color:var(--muted)">(all PIDs are tracked as managed processes above)</span></p>')
|
|
567
|
+
: baseEmpty;
|
|
538
568
|
} else {
|
|
539
|
-
countText = String(
|
|
540
|
-
html =
|
|
569
|
+
countText = String(filtered.length);
|
|
570
|
+
html = filtered.map(function (it) {
|
|
541
571
|
if (!it.valid) {
|
|
542
572
|
return '<div style="border:1px solid var(--border);border-radius:4px;padding:8px;margin-bottom:8px;background:var(--surface2)">' +
|
|
543
573
|
'<div style="color:var(--red);font-weight:600">' + escHtml(it.agentId) + ' INVALID</div>' +
|
package/dashboard/layout.html
CHANGED
|
@@ -69,13 +69,13 @@
|
|
|
69
69
|
<a class="sidebar-link" data-page="work" href="/work">Work Items <span class="sidebar-count" id="sidebar-wi"></span></a>
|
|
70
70
|
<a class="sidebar-link" data-page="plans" href="/plans">Plans & PRD</a>
|
|
71
71
|
<a class="sidebar-link" data-page="prs" href="/prs">Pull Requests <span class="sidebar-count" id="sidebar-pr"></span></a>
|
|
72
|
+
<a class="sidebar-link" data-page="qa" href="/qa" title="QA — live processes + validation runbooks (managed-spawn + keep-processes)">QA</a>
|
|
72
73
|
<a class="sidebar-link" data-page="inbox" href="/inbox">Notes & KB</a>
|
|
73
74
|
<a class="sidebar-link" data-page="tools" href="/tools">Skills & MCP</a>
|
|
74
75
|
<a class="sidebar-link" data-page="schedule" href="/schedule" title="Cron-based recurring tasks (single task per schedule)">Schedules</a>
|
|
75
76
|
<a class="sidebar-link" data-page="watches" href="/watches" title="Persistent watches that monitor PRs, work items, and branches">Watches</a>
|
|
76
77
|
<a class="sidebar-link" data-page="pipelines" href="/pipelines" title="Multi-stage workflows — chain tasks, meetings, plans with dependencies">Pipelines</a>
|
|
77
78
|
<a class="sidebar-link" data-page="meetings" href="/meetings">Meetings</a>
|
|
78
|
-
<a class="sidebar-link" data-page="qa" href="/qa" title="QA — live processes + validation runbooks (managed-spawn + keep-processes)">QA</a>
|
|
79
79
|
<a class="sidebar-link" data-page="engine" href="/engine">Engine</a>
|
|
80
80
|
</nav>
|
|
81
81
|
<div class="page-content" id="page-content"><!-- __PAGES__ --></div>
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
</section>
|
|
22
22
|
<section id="keep-processes-section">
|
|
23
23
|
<h2>Keep-Processes <span class="count" id="keep-processes-count">0</span>
|
|
24
|
-
<span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">processes left running by agents
|
|
24
|
+
<span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">processes left running by agents</span>
|
|
25
25
|
</h2>
|
|
26
26
|
<div id="keep-processes-content"><p class="empty">No agents have left processes running. Set <code>meta.keep_processes: true</code> on a work item to enable.</p></div>
|
|
27
27
|
</section>
|
|
28
28
|
<section id="managed-processes-section">
|
|
29
29
|
<h2>Managed Processes <span class="count" id="managed-processes-count">0</span>
|
|
30
|
-
<span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">engine-managed long-running services
|
|
30
|
+
<span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">engine-managed long-running services</span>
|
|
31
31
|
</h2>
|
|
32
32
|
<div id="managed-processes-content"><p class="empty">No managed processes. Agents declare them via <code>agents/<id>/managed-spawn.json</code>.</p></div>
|
|
33
33
|
</section>
|
package/dashboard/pages/qa.html
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
<section>
|
|
2
|
-
<h2>
|
|
3
|
-
<p class="empty" style="margin:4px 0 12px 0">
|
|
4
|
-
</section>
|
|
5
|
-
<section id="qa-managed-processes-section">
|
|
6
|
-
<h2>Managed Processes <span class="count" id="qa-managed-processes-count">0</span>
|
|
7
|
-
<span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">engine-managed long-running services (P-6e2a8b13 — managed-spawn primitive)</span>
|
|
8
|
-
</h2>
|
|
9
|
-
<div id="qa-managed-processes-content"><p class="empty">No managed processes. Agents declare them via <code>agents/<id>/managed-spawn.json</code>.</p></div>
|
|
10
|
-
</section>
|
|
11
|
-
<section id="qa-keep-processes-section">
|
|
12
|
-
<h2>Keep-Processes <span class="count" id="qa-keep-processes-count">0</span>
|
|
13
|
-
<span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">processes left running by agents (W-mp68q6ke0010de68 — opt-in keep_processes flag)</span>
|
|
14
|
-
</h2>
|
|
15
|
-
<div id="qa-keep-processes-content"><p class="empty">No agents have left processes running. Set <code>meta.keep_processes: true</code> on a work item to enable.</p></div>
|
|
2
|
+
<h2>QA</h2>
|
|
3
|
+
<p class="empty" style="margin:4px 0 12px 0">Canonical home for human-driven and agent-driven validation against running managed instances. Runbook dispatch lands in a follow-up WI.</p>
|
|
16
4
|
</section>
|
|
17
5
|
<section id="qa-runbooks-section">
|
|
18
6
|
<h2>Validation Runbooks <span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">human or agent-driven smoke / E2E flows against the live instances above</span></h2>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1988",
|
|
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"
|