@yemi33/minions 0.1.460 → 0.1.462
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 +3 -1
- package/dashboard/js/render-plans.js +9 -1
- package/dashboard/js/render-work-items.js +3 -1
- package/dashboard.js +26 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.462 (2026-04-07)
|
|
4
4
|
|
|
5
5
|
### Fixes
|
|
6
|
+
- show 'shared branch' label in work item PR column when no PR yet
|
|
7
|
+
- plan card click opens modal immediately with loading state
|
|
6
8
|
- remove non-functional Discuss & Revise button from plan cards
|
|
7
9
|
- steering no longer causes pending/active flip
|
|
8
10
|
|
|
@@ -476,6 +476,12 @@ async function planView(file) {
|
|
|
476
476
|
_stopPlanPoll();
|
|
477
477
|
try {
|
|
478
478
|
const normalizedFile = normalizePlanFile(file);
|
|
479
|
+
|
|
480
|
+
// Show modal immediately with loading state
|
|
481
|
+
document.getElementById('modal-title').textContent = normalizedFile;
|
|
482
|
+
document.getElementById('modal-body').innerHTML = '<p style="color:var(--muted)">Loading...</p>';
|
|
483
|
+
document.getElementById('modal').classList.add('open');
|
|
484
|
+
|
|
479
485
|
const planRes = await fetch('/api/plans/' + encodeURIComponent(normalizedFile));
|
|
480
486
|
const lastMod = planRes.headers.get('Last-Modified');
|
|
481
487
|
const resolvedPath = planRes.headers.get('X-Resolved-Path');
|
|
@@ -487,7 +493,6 @@ async function planView(file) {
|
|
|
487
493
|
_modalFilePath = resolvedPath || ((normalizedFile.endsWith('.json') ? 'prd/' : 'plans/') + normalizedFile); showModalQa();
|
|
488
494
|
const card = findCardForFile(_modalFilePath);
|
|
489
495
|
if (card) clearNotifBadge(card);
|
|
490
|
-
document.getElementById('modal').classList.add('open');
|
|
491
496
|
|
|
492
497
|
// Live-poll while modal is open
|
|
493
498
|
_planPollFile = normalizedFile;
|
|
@@ -625,6 +630,9 @@ async function planDiscuss(file) {
|
|
|
625
630
|
|
|
626
631
|
async function planOpenInDocChat(file) {
|
|
627
632
|
try {
|
|
633
|
+
document.getElementById('modal-title').textContent = file;
|
|
634
|
+
document.getElementById('modal-body').innerHTML = '<p style="color:var(--muted)">Loading...</p>';
|
|
635
|
+
document.getElementById('modal').classList.add('open');
|
|
628
636
|
const normalizedFile = normalizePlanFile(file);
|
|
629
637
|
const planRes = await fetch('/api/plans/' + encodeURIComponent(normalizedFile));
|
|
630
638
|
const resolvedPath = planRes.headers.get('X-Resolved-Path');
|
|
@@ -37,7 +37,9 @@ function wiRow(item) {
|
|
|
37
37
|
const priBadge = (p) => '<span class="prd-item-priority ' + (p || '') + '">' + escHtml(p || 'medium') + '</span>';
|
|
38
38
|
const prLink = item._pr
|
|
39
39
|
? '<a class="pr-title" href="' + escHtml(item._prUrl || '#') + '" target="_blank" style="font-size:10px">' + escHtml(item._pr) + '</a>'
|
|
40
|
-
: '
|
|
40
|
+
: (item.branchStrategy === 'shared-branch' && item.status === 'done')
|
|
41
|
+
? '<span style="font-size:9px;color:var(--muted)" title="Part of shared branch — aggregate PR created at verify stage">shared branch</span>'
|
|
42
|
+
: '<span style="color:var(--muted)">—</span>';
|
|
41
43
|
return '<tr style="cursor:pointer" onclick="openWorkItemDetail(\'' + escHtml(item.id) + '\')">' +
|
|
42
44
|
'<td><span class="pr-id">' + escHtml(item.id || '') + '</span></td>' +
|
|
43
45
|
'<td style="max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escHtml((item.title || '').slice(0, 200)) + '">' + escHtml(item.title || '') + '</td>' +
|
package/dashboard.js
CHANGED
|
@@ -844,6 +844,9 @@ function cleanDispatchEntries(matchFn) {
|
|
|
844
844
|
const engineDir = path.join(MINIONS_DIR, 'engine');
|
|
845
845
|
try {
|
|
846
846
|
let removed = 0;
|
|
847
|
+
// Collect PIDs and file paths inside the lock, execute kills outside
|
|
848
|
+
const pidsToKill = [];
|
|
849
|
+
const filesToDelete = [];
|
|
847
850
|
mutateJsonFileLocked(dispatchPath, (dispatch) => {
|
|
848
851
|
dispatch.pending = Array.isArray(dispatch.pending) ? dispatch.pending : [];
|
|
849
852
|
dispatch.active = Array.isArray(dispatch.active) ? dispatch.active : [];
|
|
@@ -853,17 +856,16 @@ function cleanDispatchEntries(matchFn) {
|
|
|
853
856
|
if (queue === 'active') {
|
|
854
857
|
for (const d of dispatch[queue]) {
|
|
855
858
|
if (!matchFn(d)) continue;
|
|
856
|
-
//
|
|
859
|
+
// Collect PID and cleanup paths — actual I/O happens after lock release
|
|
857
860
|
const pidFile = path.join(engineDir, `pid-${d.id}.pid`);
|
|
858
861
|
try {
|
|
859
862
|
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim());
|
|
860
|
-
if (pid)
|
|
861
|
-
} catch { /*
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
try { fs.unlinkSync(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md.tmp`)); } catch { /* cleanup */ }
|
|
863
|
+
if (pid) pidsToKill.push(pid);
|
|
864
|
+
} catch { /* PID file may not exist */ }
|
|
865
|
+
filesToDelete.push(pidFile);
|
|
866
|
+
filesToDelete.push(path.join(engineDir, 'tmp', `prompt-${d.id}.md`));
|
|
867
|
+
filesToDelete.push(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md`));
|
|
868
|
+
filesToDelete.push(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md.tmp`));
|
|
867
869
|
}
|
|
868
870
|
}
|
|
869
871
|
dispatch[queue] = dispatch[queue].filter(d => !matchFn(d));
|
|
@@ -871,6 +873,22 @@ function cleanDispatchEntries(matchFn) {
|
|
|
871
873
|
}
|
|
872
874
|
return dispatch;
|
|
873
875
|
}, { defaultValue: { pending: [], active: [], completed: [] } });
|
|
876
|
+
// Kill processes outside the lock — these can take hundreds of ms on Windows
|
|
877
|
+
for (const pid of pidsToKill) {
|
|
878
|
+
try {
|
|
879
|
+
const safePid = shared.validatePid(pid);
|
|
880
|
+
if (process.platform === 'win32') {
|
|
881
|
+
const { execFileSync } = require('child_process');
|
|
882
|
+
execFileSync('taskkill', ['/PID', String(safePid), '/T'], { stdio: 'pipe', timeout: 5000, windowsHide: true });
|
|
883
|
+
} else {
|
|
884
|
+
process.kill(safePid, 'SIGTERM');
|
|
885
|
+
}
|
|
886
|
+
} catch { /* process may already be dead */ }
|
|
887
|
+
}
|
|
888
|
+
// Clean up files outside the lock
|
|
889
|
+
for (const fp of filesToDelete) {
|
|
890
|
+
try { fs.unlinkSync(fp); } catch { /* file may not exist */ }
|
|
891
|
+
}
|
|
874
892
|
return removed;
|
|
875
893
|
} catch { return 0; }
|
|
876
894
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.462",
|
|
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"
|