@yemi33/minions 0.1.1800 → 0.1.1802
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 +44 -4
- package/engine/cli.js +3 -3
- package/engine/copilot-models.json +1 -1
- package/engine/dispatch.js +45 -1
- package/package.json +1 -1
package/dashboard.js
CHANGED
|
@@ -1929,16 +1929,52 @@ function fencedUntrustedBlock(label, content) {
|
|
|
1929
1929
|
return `### ${label}\n${fence}text\n${value}\n${fence}`;
|
|
1930
1930
|
}
|
|
1931
1931
|
|
|
1932
|
+
function _messageExplicitlyRequestsMonitoring(message) {
|
|
1933
|
+
const text = String(message || '').toLowerCase();
|
|
1934
|
+
if (!text.trim()) return false;
|
|
1935
|
+
if (/\b(?:do\s+not|don't|dont|never|without|no\s+need\s+to)\s+(?:monitor(?:ing)?|watch(?:ing)?|poll(?:ing)?|check(?:ing)?|notify(?:ing)?|ping(?:ing)?|keep(?:ing)?\s+an\s+eye)\b/.test(text)) {
|
|
1936
|
+
return false;
|
|
1937
|
+
}
|
|
1938
|
+
return [
|
|
1939
|
+
/\bmonitor(?:ing)?\b/,
|
|
1940
|
+
/\bwatch(?:ing)?\b/,
|
|
1941
|
+
/\bkeep(?:ing)?\s+an\s+eye\s+on\b/,
|
|
1942
|
+
/\bcheck(?:ing)?\s+(?:it|this|that|[^.?!\n]+)\s+periodically\b/,
|
|
1943
|
+
/\bperiodically\s+check\b/,
|
|
1944
|
+
/\bcheck(?:ing)?\s+[^.?!\n]+\bevery\s+\d+\s*(?:s|sec|seconds?|m|min|minutes?|h|hr|hours?)\b/,
|
|
1945
|
+
/\bevery\s+\d+\s*(?:s|sec|seconds?|m|min|minutes?|h|hr|hours?)\b[^.?!\n]+\b(?:check|poll|monitor|watch)\b/,
|
|
1946
|
+
/\bping\s+(?:me\s+)?(?:on|when|after)\b/,
|
|
1947
|
+
/\bping\s+on\s+completion\b/,
|
|
1948
|
+
/\bnotify\s+(?:me\s+)?(?:on|when|after)\b/,
|
|
1949
|
+
/\blet\s+me\s+know\s+(?:when|once|if)\b/,
|
|
1950
|
+
/\bpoll(?:ing)?\b/,
|
|
1951
|
+
].some(pattern => pattern.test(text));
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
function _isDispatchLikeCCAction(action) {
|
|
1955
|
+
const type = String(action?.type || '').trim().toLowerCase();
|
|
1956
|
+
return type === 'dispatch' || ['fix', 'explore', 'review', 'test'].includes(type);
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
function _filterImplicitPostDispatchActions(actions, humanMessage) {
|
|
1960
|
+
if (!Array.isArray(actions) || actions.length === 0) return [];
|
|
1961
|
+
if (_messageExplicitlyRequestsMonitoring(humanMessage)) return actions;
|
|
1962
|
+
const dispatchIdx = actions.findIndex(_isDispatchLikeCCAction);
|
|
1963
|
+
if (dispatchIdx < 0) return actions;
|
|
1964
|
+
return actions.slice(0, dispatchIdx + 1);
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1932
1967
|
// ── /loop → create-watch safety net ──────────────────────────────────────────
|
|
1933
1968
|
// CC sometimes invokes the /loop skill instead of emitting a create-watch action.
|
|
1934
1969
|
// This pure function detects /loop invocation in CC response text and synthesizes
|
|
1935
1970
|
// a create-watch action as a fallback. Returns null if no conversion needed.
|
|
1936
1971
|
|
|
1937
|
-
function _detectLoopInvocation(text, actions, toolUses) {
|
|
1972
|
+
function _detectLoopInvocation(text, actions, toolUses, humanMessage) {
|
|
1938
1973
|
const observedToolUses = Array.isArray(toolUses) ? toolUses : [];
|
|
1939
1974
|
if (!text && observedToolUses.length === 0) return null;
|
|
1940
1975
|
// If a create-watch action was already emitted, no fallback needed
|
|
1941
1976
|
if (actions && actions.some(a => a.type === 'create-watch')) return null;
|
|
1977
|
+
if (humanMessage !== undefined && !_messageExplicitlyRequestsMonitoring(humanMessage)) return null;
|
|
1942
1978
|
|
|
1943
1979
|
function _extractTargetFromValue(value, keyHint) {
|
|
1944
1980
|
if (value == null) return null;
|
|
@@ -6509,12 +6545,13 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6509
6545
|
const parsed = parseCCActions(result.text);
|
|
6510
6546
|
const toolUses = Array.isArray(result.toolUses) ? result.toolUses : _extractToolUsesFromRaw(result.raw);
|
|
6511
6547
|
// Safety net: detect /loop invocation and convert to create-watch
|
|
6512
|
-
const _loopWatch = _detectLoopInvocation(parsed.text, parsed.actions, toolUses);
|
|
6548
|
+
const _loopWatch = _detectLoopInvocation(parsed.text, parsed.actions, toolUses, body.message);
|
|
6513
6549
|
if (_loopWatch) {
|
|
6514
6550
|
parsed.actions.push(_loopWatch);
|
|
6515
6551
|
console.warn('[CC] /loop invocation detected — converted to create-watch');
|
|
6516
6552
|
try { shared.log('warn', '/loop invocation detected in CC response — auto-converted to create-watch'); } catch {}
|
|
6517
6553
|
}
|
|
6554
|
+
parsed.actions = _filterImplicitPostDispatchActions(parsed.actions, body.message);
|
|
6518
6555
|
if (parsed.actions.length > 0) {
|
|
6519
6556
|
parsed.actionResults = await executeCCActions(parsed.actions);
|
|
6520
6557
|
}
|
|
@@ -6834,14 +6871,15 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6834
6871
|
}
|
|
6835
6872
|
|
|
6836
6873
|
// Send final result with actions — execute server-side first
|
|
6837
|
-
|
|
6874
|
+
let { text: displayText, actions, _actionParseError } = parseCCActions(result.text);
|
|
6838
6875
|
// Safety net: detect /loop invocation and convert to create-watch
|
|
6839
|
-
const _loopWatch = _detectLoopInvocation(displayText, actions, toolUses);
|
|
6876
|
+
const _loopWatch = _detectLoopInvocation(displayText, actions, toolUses, body.message);
|
|
6840
6877
|
if (_loopWatch) {
|
|
6841
6878
|
actions.push(_loopWatch);
|
|
6842
6879
|
console.warn('[CC] /loop invocation detected — converted to create-watch');
|
|
6843
6880
|
try { shared.log('warn', '/loop invocation detected in CC response — auto-converted to create-watch'); } catch {}
|
|
6844
6881
|
}
|
|
6882
|
+
actions = _filterImplicitPostDispatchActions(actions, body.message);
|
|
6845
6883
|
let actionResults;
|
|
6846
6884
|
if (actions.length > 0) {
|
|
6847
6885
|
actionResults = await executeCCActions(actions);
|
|
@@ -8471,6 +8509,8 @@ module.exports = {
|
|
|
8471
8509
|
_resolveSkillReadPath,
|
|
8472
8510
|
DOC_CHAT_DOCUMENT_DELIMITER,
|
|
8473
8511
|
_ccValidateAction,
|
|
8512
|
+
_messageExplicitlyRequestsMonitoring,
|
|
8513
|
+
_filterImplicitPostDispatchActions,
|
|
8474
8514
|
_findDuplicateWorkItemCreate: findDuplicateWorkItemCreate,
|
|
8475
8515
|
_createWorkItemWithDedup: createWorkItemWithDedup,
|
|
8476
8516
|
_resolveWorkItemsCreateTarget: resolveWorkItemsCreateTarget,
|
package/engine/cli.js
CHANGED
|
@@ -1079,14 +1079,14 @@ const commands = {
|
|
|
1079
1079
|
return;
|
|
1080
1080
|
}
|
|
1081
1081
|
const dispatch = getDispatch();
|
|
1082
|
-
const
|
|
1083
|
-
if (!
|
|
1082
|
+
const item = (dispatch.active || []).find(d => d.id === id);
|
|
1083
|
+
if (!item) {
|
|
1084
1084
|
console.log(` Dispatch "${id}" not found in active queue.`);
|
|
1085
1085
|
const pending = (dispatch.pending || []).some(d => d.id === id);
|
|
1086
1086
|
if (pending) console.log(' (It is in pending — it hasn\'t started yet.)');
|
|
1087
1087
|
return;
|
|
1088
1088
|
}
|
|
1089
|
-
engine().completeDispatch(id, '
|
|
1089
|
+
engine().completeDispatch(id, DISPATCH_RESULT.SUCCESS, '', '', { processWorkItemSuccess: true });
|
|
1090
1090
|
console.log(` Marked ${id} as completed.`);
|
|
1091
1091
|
},
|
|
1092
1092
|
|
package/engine/dispatch.js
CHANGED
|
@@ -322,12 +322,45 @@ function writeFailedAgentReport(item, reason, resultSummary, failureClass) {
|
|
|
322
322
|
shared.writeToInbox(agentId, `agent-failure-${item.id}`, content, null, metadata);
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
function markCompletedSourceWorkItem(item) {
|
|
326
|
+
const meta = item?.meta;
|
|
327
|
+
const itemId = meta?.item?.id;
|
|
328
|
+
if (!itemId) return false;
|
|
329
|
+
const wiPath = lifecycle().resolveWorkItemPath(meta);
|
|
330
|
+
if (!wiPath) return false;
|
|
331
|
+
let found = false;
|
|
332
|
+
let terminal = false;
|
|
333
|
+
mutateWorkItems(wiPath, items => {
|
|
334
|
+
if (!Array.isArray(items)) return items;
|
|
335
|
+
const wi = items.find(i => i.id === itemId);
|
|
336
|
+
if (!wi) return items;
|
|
337
|
+
found = true;
|
|
338
|
+
if (wi.status === WI_STATUS.DONE) {
|
|
339
|
+
terminal = true;
|
|
340
|
+
return items;
|
|
341
|
+
}
|
|
342
|
+
wi.status = WI_STATUS.DONE;
|
|
343
|
+
delete wi.failReason;
|
|
344
|
+
delete wi.failedAt;
|
|
345
|
+
delete wi._retryCount;
|
|
346
|
+
if (!wi.completedAt) wi.completedAt = ts();
|
|
347
|
+
if (item.agent && !wi.dispatched_to) wi.dispatched_to = item.agent;
|
|
348
|
+
terminal = true;
|
|
349
|
+
return items;
|
|
350
|
+
});
|
|
351
|
+
if (!found) {
|
|
352
|
+
throw new Error(`source work item ${itemId} not found`);
|
|
353
|
+
}
|
|
354
|
+
return terminal;
|
|
355
|
+
}
|
|
356
|
+
|
|
325
357
|
// ─── Complete Dispatch ───────────────────────────────────────────────────────
|
|
326
358
|
|
|
327
359
|
function completeDispatch(id, result = DISPATCH_RESULT.SUCCESS, reason = '', resultSummary = '', opts = {}) {
|
|
328
|
-
const { processWorkItemFailure = true, failureClass } = opts;
|
|
360
|
+
const { processWorkItemFailure = true, processWorkItemSuccess = false, failureClass } = opts;
|
|
329
361
|
const agentRetryable = normalizeRetryableDecision(opts.agentRetryable ?? opts.retryable);
|
|
330
362
|
let item = null;
|
|
363
|
+
let completedSourceWorkItem = false;
|
|
331
364
|
|
|
332
365
|
mutateDispatch((dispatch) => {
|
|
333
366
|
// Check active list first
|
|
@@ -356,6 +389,10 @@ function completeDispatch(id, result = DISPATCH_RESULT.SUCCESS, reason = '', res
|
|
|
356
389
|
item.meta.completionReportPath = opts.structuredCompletion._path;
|
|
357
390
|
}
|
|
358
391
|
}
|
|
392
|
+
if (processWorkItemSuccess && result === DISPATCH_RESULT.SUCCESS && item.meta?.item?.id) {
|
|
393
|
+
if (item.agent) item.meta._agentId = item.agent;
|
|
394
|
+
completedSourceWorkItem = markCompletedSourceWorkItem(item);
|
|
395
|
+
}
|
|
359
396
|
// Drop prompt (and sidecar file, if any) — completed entries don't need
|
|
360
397
|
// replayable content and it would accumulate forever (#1167).
|
|
361
398
|
try { deleteDispatchPromptSidecar(item); } catch { /* best-effort */ }
|
|
@@ -469,6 +506,13 @@ function completeDispatch(id, result = DISPATCH_RESULT.SUCCESS, reason = '', res
|
|
|
469
506
|
}
|
|
470
507
|
}
|
|
471
508
|
|
|
509
|
+
if (completedSourceWorkItem) {
|
|
510
|
+
try {
|
|
511
|
+
lifecycle().syncPrdItemStatus(item.meta.item.id, WI_STATUS.DONE, item.meta.item?.sourcePlan);
|
|
512
|
+
log('info', `Work item ${item.meta.item.id} → ${WI_STATUS.DONE}`);
|
|
513
|
+
} catch (e) { log('warn', 'manual completion PRD sync: ' + e.message); }
|
|
514
|
+
}
|
|
515
|
+
|
|
472
516
|
// Restore pendingFix on failed human-feedback fix so engine re-dispatches on next tick
|
|
473
517
|
if (result === DISPATCH_RESULT.ERROR && item.meta?.source === 'pr-human-feedback') {
|
|
474
518
|
const prId = item.meta.pr?.id;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1802",
|
|
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"
|