@yemi33/minions 0.1.901 → 0.1.903
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-kb.js +39 -11
- package/dashboard.js +37 -8
- package/package.json +1 -1
- package/playbooks/fix.md +2 -0
- package/playbooks/implement.md +2 -0
- package/playbooks/work-item.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -144,21 +144,49 @@ async function kbSweep() {
|
|
|
144
144
|
btn.style.color = 'var(--blue)';
|
|
145
145
|
try {
|
|
146
146
|
showToast('cmd-toast', 'KB sweep started', true);
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
150
|
-
btn.textContent = 'done';
|
|
151
|
-
btn.style.color = 'var(--green)';
|
|
152
|
-
refreshKnowledgeBase();
|
|
153
|
-
} else {
|
|
147
|
+
const triggerRes = await fetch('/api/knowledge/sweep', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pinnedKeys: getPinnedItems().filter(function(k) { return k.startsWith('knowledge/'); }) }) });
|
|
148
|
+
const triggerData = await triggerRes.json();
|
|
149
|
+
if (!triggerData.ok) {
|
|
154
150
|
btn.style.color = 'var(--red)';
|
|
155
151
|
btn.textContent = 'failed';
|
|
156
|
-
showToast('cmd-toast', 'Sweep failed: ' + (
|
|
152
|
+
showToast('cmd-toast', 'Sweep failed: ' + (triggerData.error || 'unknown'), false);
|
|
153
|
+
setTimeout(function() { btn.textContent = origText; btn.style.color = 'var(--muted)'; btn.disabled = false; }, 60000);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Poll status until sweep completes (every 3s, up to 10 min)
|
|
157
|
+
var maxPolls = 200;
|
|
158
|
+
var pollCount = 0;
|
|
159
|
+
while (pollCount < maxPolls) {
|
|
160
|
+
await new Promise(function(r) { setTimeout(r, 3000); });
|
|
161
|
+
pollCount++;
|
|
162
|
+
try {
|
|
163
|
+
var statusRes = await fetch('/api/knowledge/sweep/status');
|
|
164
|
+
var statusData = await statusRes.json();
|
|
165
|
+
if (!statusData.inFlight) {
|
|
166
|
+
var result = statusData.lastResult;
|
|
167
|
+
if (result && result.ok) {
|
|
168
|
+
btn.textContent = 'done';
|
|
169
|
+
btn.style.color = 'var(--green)';
|
|
170
|
+
showToast('cmd-toast', 'KB sweep complete: ' + (result.summary || 'done'), true);
|
|
171
|
+
refreshKnowledgeBase();
|
|
172
|
+
} else {
|
|
173
|
+
btn.style.color = 'var(--red)';
|
|
174
|
+
btn.textContent = 'failed';
|
|
175
|
+
showToast('cmd-toast', 'Sweep failed: ' + ((result && result.error) || 'unknown'), false);
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
} catch { /* poll error — retry */ }
|
|
180
|
+
}
|
|
181
|
+
if (pollCount >= maxPolls) {
|
|
182
|
+
btn.textContent = 'timeout';
|
|
183
|
+
btn.style.color = 'var(--red)';
|
|
184
|
+
showToast('cmd-toast', 'Sweep polling timed out — check status later', false);
|
|
157
185
|
}
|
|
158
186
|
// Show notification on sidebar if user is on a different page
|
|
159
187
|
var kbLink = document.querySelector('.sidebar-link[data-page="inbox"]');
|
|
160
188
|
var activePage = document.querySelector('.sidebar-link.active')?.getAttribute('data-page');
|
|
161
|
-
if (kbLink && activePage !== 'inbox') showNotifBadge(kbLink,
|
|
189
|
+
if (kbLink && activePage !== 'inbox') showNotifBadge(kbLink, 'done');
|
|
162
190
|
} catch (e) {
|
|
163
191
|
btn.style.color = 'var(--red)';
|
|
164
192
|
btn.textContent = 'failed';
|
|
@@ -167,8 +195,8 @@ async function kbSweep() {
|
|
|
167
195
|
var activePage2 = document.querySelector('.sidebar-link.active')?.getAttribute('data-page');
|
|
168
196
|
if (kbLink2 && activePage2 !== 'inbox') showNotifBadge(kbLink2);
|
|
169
197
|
}
|
|
170
|
-
|
|
171
|
-
setTimeout(()
|
|
198
|
+
var isError = btn.textContent === 'failed' || btn.textContent === 'timeout';
|
|
199
|
+
setTimeout(function() { btn.textContent = origText; btn.style.color = 'var(--muted)'; btn.disabled = false; }, isError ? 60000 : 3000);
|
|
172
200
|
}
|
|
173
201
|
|
|
174
202
|
function openCreateKbModal() {
|
package/dashboard.js
CHANGED
|
@@ -1942,16 +1942,28 @@ const server = http.createServer(async (req, res) => {
|
|
|
1942
1942
|
console.log('[kb-sweep] Auto-releasing stale guard (>5min)');
|
|
1943
1943
|
global._kbSweepInFlight = false;
|
|
1944
1944
|
}
|
|
1945
|
-
if (global._kbSweepInFlight)
|
|
1945
|
+
if (global._kbSweepInFlight) {
|
|
1946
|
+
return jsonReply(res, 200, { ok: true, alreadyRunning: true, startedAt: global._kbSweepStartedAt });
|
|
1947
|
+
}
|
|
1946
1948
|
// Generation token prevents stale finally blocks from clearing the flag for a new sweep
|
|
1947
1949
|
const sweepToken = Date.now() + Math.random();
|
|
1948
1950
|
global._kbSweepToken = sweepToken;
|
|
1949
1951
|
global._kbSweepInFlight = true;
|
|
1950
1952
|
global._kbSweepStartedAt = Date.now();
|
|
1953
|
+
const body = await readBody(req).catch(() => ({}));
|
|
1954
|
+
// Run sweep in background — return immediately so agents/UI don't time out
|
|
1955
|
+
_runKbSweepBackground(body, sweepToken);
|
|
1956
|
+
return jsonReply(res, 202, { ok: true, started: true });
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
async function _runKbSweepBackground(body, sweepToken) {
|
|
1951
1960
|
try {
|
|
1952
|
-
const body = await readBody(req).catch(() => ({}));
|
|
1953
1961
|
const entries = getKnowledgeBaseEntries();
|
|
1954
|
-
if (entries.length < 2)
|
|
1962
|
+
if (entries.length < 2) {
|
|
1963
|
+
global._kbSweepLastResult = { ok: true, summary: 'nothing to sweep (< 2 entries)' };
|
|
1964
|
+
global._kbSweepLastCompletedAt = Date.now();
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1955
1967
|
|
|
1956
1968
|
// Build a manifest of all KB entries with their content (skip pinned — user wants to keep them)
|
|
1957
1969
|
const pinnedKeys = new Set(body.pinnedKeys || []);
|
|
@@ -2012,10 +2024,12 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
|
|
|
2012
2024
|
let removed = 0, reclassified = 0, merged = 0;
|
|
2013
2025
|
const kbDir = path.join(MINIONS_DIR, 'knowledge');
|
|
2014
2026
|
|
|
2015
|
-
// If nothing to do, return
|
|
2027
|
+
// If nothing to do, store result and return
|
|
2016
2028
|
const totalActions = (plan.remove || []).length + (plan.duplicates || []).reduce((n, d) => n + (d.remove || []).length, 0) + (plan.reclassify || []).length;
|
|
2017
2029
|
if (totalActions === 0) {
|
|
2018
|
-
|
|
2030
|
+
global._kbSweepLastResult = { ok: true, summary: 'KB is clean — nothing to sweep', plan };
|
|
2031
|
+
global._kbSweepLastCompletedAt = Date.now();
|
|
2032
|
+
return;
|
|
2019
2033
|
}
|
|
2020
2034
|
|
|
2021
2035
|
// Archive dir for swept files (never delete, always preserve)
|
|
@@ -2086,8 +2100,22 @@ If nothing to do: { "duplicates": [], "reclassify": [], "remove": [] }`;
|
|
|
2086
2100
|
|
|
2087
2101
|
const summary = `${merged} duplicates merged, ${removed} stale removed, ${reclassified} reclassified${pruned ? ', ' + pruned + ' old swept files pruned' : ''}`;
|
|
2088
2102
|
safeWrite(path.join(ENGINE_DIR, 'kb-swept.json'), JSON.stringify({ timestamp: new Date().toISOString(), summary }));
|
|
2089
|
-
|
|
2090
|
-
|
|
2103
|
+
global._kbSweepLastResult = { ok: true, summary, plan };
|
|
2104
|
+
global._kbSweepLastCompletedAt = Date.now();
|
|
2105
|
+
} catch (e) {
|
|
2106
|
+
console.error('[kb-sweep] background error:', e.message);
|
|
2107
|
+
global._kbSweepLastResult = { ok: false, error: e.message };
|
|
2108
|
+
global._kbSweepLastCompletedAt = Date.now();
|
|
2109
|
+
} finally { if (global._kbSweepToken === sweepToken) global._kbSweepInFlight = false; }
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
function handleKnowledgeSweepStatus(req, res) {
|
|
2113
|
+
return jsonReply(res, 200, {
|
|
2114
|
+
inFlight: !!global._kbSweepInFlight,
|
|
2115
|
+
startedAt: global._kbSweepStartedAt || null,
|
|
2116
|
+
lastResult: global._kbSweepLastResult || null,
|
|
2117
|
+
lastCompletedAt: global._kbSweepLastCompletedAt || null
|
|
2118
|
+
});
|
|
2091
2119
|
}
|
|
2092
2120
|
|
|
2093
2121
|
async function handlePlansList(req, res) {
|
|
@@ -4131,7 +4159,8 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
4131
4159
|
invalidateStatusCache();
|
|
4132
4160
|
return jsonReply(res, 200, { ok: true, path: filePath });
|
|
4133
4161
|
}},
|
|
4134
|
-
{ method: 'POST', path: '/api/knowledge/sweep', desc: '
|
|
4162
|
+
{ method: 'POST', path: '/api/knowledge/sweep', desc: 'Trigger async KB sweep (returns 202)', handler: handleKnowledgeSweep },
|
|
4163
|
+
{ method: 'GET', path: '/api/knowledge/sweep/status', desc: 'Poll KB sweep status', handler: handleKnowledgeSweepStatus },
|
|
4135
4164
|
{ method: 'GET', path: /^\/api\/knowledge\/([^/]+)\/([^?]+)/, desc: 'Read a specific knowledge base entry', handler: handleKnowledgeRead },
|
|
4136
4165
|
|
|
4137
4166
|
// Doc chat
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.903",
|
|
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"
|
package/playbooks/fix.md
CHANGED
|
@@ -76,6 +76,8 @@ After pushing, respond to each review comment/thread:
|
|
|
76
76
|
|
|
77
77
|
Your task is complete once you have: (1) confirmed build and tests pass, (2) pushed the fix, (3) commented on the PR, and (4) resolved addressed review threads. Do NOT continue exploring unrelated code or making additional improvements. Stop immediately.
|
|
78
78
|
|
|
79
|
+
**NEVER run `gh pr merge` or any merge command on this PR.** The engine handles merging after review approval. Self-merging bypasses the review cycle and is prohibited.
|
|
80
|
+
|
|
79
81
|
## Completion
|
|
80
82
|
|
|
81
83
|
After finishing, output a structured completion block so the engine can parse your results:
|
package/playbooks/implement.md
CHANGED
|
@@ -82,3 +82,5 @@ Include build/test status and run instructions in the PR description. If the pro
|
|
|
82
82
|
## When to Stop
|
|
83
83
|
|
|
84
84
|
Your task is complete once you have: (1) confirmed build and tests pass, (2) pushed your branch, and (3) created the PR. Your final message MUST include the PR URL so the engine can track it. Stop immediately after.
|
|
85
|
+
|
|
86
|
+
**NEVER run `gh pr merge` or any merge command on your own PR.** The engine reviews and merges PRs through a separate review cycle. Self-merging bypasses code review entirely and is prohibited regardless of circumstances.
|
package/playbooks/work-item.md
CHANGED
|
@@ -58,3 +58,5 @@ If you encounter merge conflicts during push or PR creation:
|
|
|
58
58
|
## When to Stop
|
|
59
59
|
|
|
60
60
|
Your task is complete once you have: (1) confirmed build and tests pass, (2) pushed your branch, and (3) created the PR. Do NOT continue beyond the task description. Stop immediately.
|
|
61
|
+
|
|
62
|
+
**NEVER run `gh pr merge` or any merge command on your own PR.** The engine reviews and merges PRs through a separate review cycle. Self-merging bypasses code review entirely and is prohibited regardless of circumstances.
|