@yemi33/minions 0.1.2444 → 0.1.2445
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/engine/dispatch.js +30 -15
- package/engine/shared.js +82 -0
- package/package.json +1 -1
package/engine/dispatch.js
CHANGED
|
@@ -36,8 +36,10 @@ const MINIONS_DIR = shared.MINIONS_DIR;
|
|
|
36
36
|
// against context-only PRs because casting a review vote, posting a
|
|
37
37
|
// comment, asking a question, or running a read-only explore never mutates the
|
|
38
38
|
// PR's source branch. Auto-discovery (engine.js#discoverFromPrs) is still
|
|
39
|
-
// gated on `contextOnly` separately
|
|
40
|
-
//
|
|
39
|
+
// gated on `contextOnly` separately. Mutating types are not universally barred
|
|
40
|
+
// from a context-only PR either — they survive when the work item carries
|
|
41
|
+
// explicit human/API provenance (see getStalePrDispatchReason's context-only
|
|
42
|
+
// gate and shared.isExplicitlyRequestedPrDispatch).
|
|
41
43
|
const NON_MUTATING_DISPATCH_TYPES = new Set([
|
|
42
44
|
WORK_TYPE.REVIEW,
|
|
43
45
|
WORK_TYPE.ASK,
|
|
@@ -594,18 +596,29 @@ function getStalePrDispatchReason(entry, config) {
|
|
|
594
596
|
const prLabel = entry.meta.pr?.id || entry.meta.pr?.url || entry.id;
|
|
595
597
|
if (!tracked) return `PR ${prLabel} is no longer tracked`;
|
|
596
598
|
if (tracked.status !== PR_STATUS.ACTIVE) return `PR ${tracked.id || prLabel} is ${tracked.status || 'missing status'}`;
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
//
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
599
|
+
// Context-only gate (W-mq5v612m001g1545 + #3126, corrected by
|
|
600
|
+
// W-ms5sr82s00ze0af8-c). `contextOnly` suppresses AUTOMATIC PR discovery and
|
|
601
|
+
// auto-management only — it must not cancel PR-targeted work a human or API
|
|
602
|
+
// caller explicitly created. A dispatch survives a context-only PR when
|
|
603
|
+
// either leg holds:
|
|
604
|
+
// 1. It is a work-item dispatch of a non-mutating type (review/ask/explore)
|
|
605
|
+
// — casting a vote, commenting, or reading never pushes to the PR's
|
|
606
|
+
// source branch, so intent doesn't need to be established.
|
|
607
|
+
// 2. `shared.isExplicitlyRequestedPrDispatch(entry, wi)` — the dispatch
|
|
608
|
+
// came from an explicit work item (`meta.source === 'work-item'`) whose
|
|
609
|
+
// structured provenance (`_originAgent` / `_originWi` from the
|
|
610
|
+
// `X-Minions-Agent` / `X-Minions-Origin-Wi` headers, or an explicit
|
|
611
|
+
// `createdBy` root such as `dashboard`) proves a human or API caller
|
|
612
|
+
// asked for it. This is what un-breaks operator-authored `fix` work
|
|
613
|
+
// items, which fail leg 1 purely because `fix` is a mutating type.
|
|
614
|
+
// Auto-discovered dispatches (`source: 'pr'`, `'pr-human-feedback'`) satisfy
|
|
615
|
+
// neither leg and are still pruned exactly as before. The work item is only
|
|
616
|
+
// resolved when both cheap checks have already failed.
|
|
617
|
+
if (shared.isContextOnlyPrRecord(tracked)) {
|
|
618
|
+
const allowed = entry.meta?.source === 'work-item'
|
|
619
|
+
&& (NON_MUTATING_DISPATCH_TYPES.has(entry.type)
|
|
620
|
+
|| shared.isExplicitlyRequestedPrDispatch(entry, _resolveWorkItemForPrunedEntry(entry)));
|
|
621
|
+
if (!allowed) return `PR ${tracked.id || prLabel} is context-only`;
|
|
609
622
|
}
|
|
610
623
|
|
|
611
624
|
const queuedBranch = entry.meta.branch || entry.meta.pr?.branch || '';
|
|
@@ -655,7 +668,9 @@ function cancelSourceWorkItemForPrunedDispatch(entry, reason) {
|
|
|
655
668
|
|
|
656
669
|
/**
|
|
657
670
|
* W-mr9jo2n2000667ad (bug B) — best-effort resolution of the work item behind
|
|
658
|
-
* a pending dispatch entry, used
|
|
671
|
+
* a pending dispatch entry, used by the scope-overlap gate below and by the
|
|
672
|
+
* context-only provenance gate in getStalePrDispatchReason (which needs the
|
|
673
|
+
* persisted `_originAgent` / `createdBy` fields, not just the queued snapshot).
|
|
659
674
|
*/
|
|
660
675
|
function _resolveWorkItemForPrunedEntry(entry) {
|
|
661
676
|
const itemId = entry?.meta?.item?.id;
|
package/engine/shared.js
CHANGED
|
@@ -7697,6 +7697,85 @@ function isAutoManagedPrRecord(pr) {
|
|
|
7697
7697
|
return !!pr && typeof pr === 'object' && !isContextOnlyPrRecord(pr);
|
|
7698
7698
|
}
|
|
7699
7699
|
|
|
7700
|
+
/**
|
|
7701
|
+
* Work-item `createdBy` roots that represent an EXPLICIT request: a human
|
|
7702
|
+
* operator acting through the dashboard, an external caller on
|
|
7703
|
+
* `POST /api/work-items`, or an operator-authored automation definition
|
|
7704
|
+
* (watch rule, schedule, pipeline, QA session). All of these are work a
|
|
7705
|
+
* person deliberately declared.
|
|
7706
|
+
*
|
|
7707
|
+
* Deliberately NOT listed: engine-derived origins (`engine:*`,
|
|
7708
|
+
* `decomposition`, `lifecycle:*`, `harness:iterate`). Those are the engine
|
|
7709
|
+
* auto-managing a PR on its own initiative, which is exactly what a
|
|
7710
|
+
* `contextOnly` PR is flagged to suppress.
|
|
7711
|
+
*
|
|
7712
|
+
* Fails CLOSED — an unlisted `createdBy` is treated as non-explicit, so a new
|
|
7713
|
+
* engine-automatic creator can never accidentally inherit explicit status. A
|
|
7714
|
+
* new human/API-facing creator must register its root here.
|
|
7715
|
+
*/
|
|
7716
|
+
const EXPLICIT_WORK_ITEM_ORIGIN_ROOTS = new Set([
|
|
7717
|
+
'dashboard', // dashboard UI + POST /api/work-items, incl. CC/agent API callers
|
|
7718
|
+
// (dashboard.js hard-codes createdBy:'dashboard'; also
|
|
7719
|
+
// dashboard:execute, dashboard:revision, dashboard:promotion:…)
|
|
7720
|
+
'human', // engine/meeting.js
|
|
7721
|
+
'operator',
|
|
7722
|
+
'watch', // operator-authored watch rule (watch:<watchId>)
|
|
7723
|
+
'scheduler', // operator-authored schedule (scheduler, scheduler:harness)
|
|
7724
|
+
'pipeline', // operator-authored pipeline definition (pipeline:<pipelineId>)
|
|
7725
|
+
'qa-dispatch', // operator-started QA session
|
|
7726
|
+
'qa-session',
|
|
7727
|
+
]);
|
|
7728
|
+
|
|
7729
|
+
/**
|
|
7730
|
+
* Normalize a work item's `createdBy` to its namespace root so the allowlist
|
|
7731
|
+
* above stays short. Creators namespace themselves as `<root>:<detail>`
|
|
7732
|
+
* (`dashboard:execute`, `pipeline:<id>`, `watch:<id>`, `scheduler:harness`);
|
|
7733
|
+
* `qa-session-<phase>` (engine/qa-sessions.js) uses a hyphen instead.
|
|
7734
|
+
*/
|
|
7735
|
+
function workItemOriginRoot(createdBy) {
|
|
7736
|
+
const raw = typeof createdBy === 'string' ? createdBy.trim().toLowerCase() : '';
|
|
7737
|
+
if (!raw) return '';
|
|
7738
|
+
const root = raw.split(':')[0];
|
|
7739
|
+
return root.startsWith('qa-session-') ? 'qa-session' : root;
|
|
7740
|
+
}
|
|
7741
|
+
|
|
7742
|
+
/**
|
|
7743
|
+
* W-ms5sr82s00ze0af8-c — provenance gate for PR-targeted dispatches against a
|
|
7744
|
+
* `contextOnly` PR.
|
|
7745
|
+
*
|
|
7746
|
+
* `contextOnly` suppresses AUTOMATIC PR discovery and auto-management; it must
|
|
7747
|
+
* never cancel PR-targeted work a human or API caller explicitly created (the
|
|
7748
|
+
* defect that cancelled the operator-authored `fix` work items for opg PRs
|
|
7749
|
+
* #1066 / #1067 with `_lastDispatchResult: 'pruned-stale-pr-dispatch'`).
|
|
7750
|
+
*
|
|
7751
|
+
* Explicit provenance is read from structured fields only — never from title
|
|
7752
|
+
* or description text:
|
|
7753
|
+
* 1. `entry.meta.source === 'work-item'` is mandatory. Auto-discovery
|
|
7754
|
+
* (`source: 'pr'`, `'pr-human-feedback'`) never qualifies, whatever work
|
|
7755
|
+
* item it happens to resolve to.
|
|
7756
|
+
* 2. The backing work item must carry either the `_originAgent` /
|
|
7757
|
+
* `_originWi` audit fields persisted by `POST /api/work-items` from the
|
|
7758
|
+
* `X-Minions-Agent` / `X-Minions-Origin-Wi` headers, or a `createdBy`
|
|
7759
|
+
* whose root is in EXPLICIT_WORK_ITEM_ORIGIN_ROOTS.
|
|
7760
|
+
*
|
|
7761
|
+
* @param {object} entry - pending dispatch entry
|
|
7762
|
+
* @param {object} [workItem] - the resolved source work item; falls back to
|
|
7763
|
+
* the `entry.meta.item` snapshot the dispatch was queued with.
|
|
7764
|
+
* @returns {boolean}
|
|
7765
|
+
*/
|
|
7766
|
+
function isExplicitlyRequestedPrDispatch(entry, workItem = null) {
|
|
7767
|
+
if (!entry || typeof entry !== 'object') return false;
|
|
7768
|
+
if (entry.meta?.source !== 'work-item') return false;
|
|
7769
|
+
const item = (workItem && typeof workItem === 'object')
|
|
7770
|
+
? workItem
|
|
7771
|
+
: (entry.meta?.item && typeof entry.meta.item === 'object' ? entry.meta.item : null);
|
|
7772
|
+
if (!item) return false;
|
|
7773
|
+
const originAgent = typeof item._originAgent === 'string' ? item._originAgent.trim() : '';
|
|
7774
|
+
const originWi = typeof item._originWi === 'string' ? item._originWi.trim() : '';
|
|
7775
|
+
if (originAgent || originWi) return true;
|
|
7776
|
+
return EXPLICIT_WORK_ITEM_ORIGIN_ROOTS.has(workItemOriginRoot(item.createdBy));
|
|
7777
|
+
}
|
|
7778
|
+
|
|
7700
7779
|
function mergePrLinkItems(links, prId, itemIds) {
|
|
7701
7780
|
if (!prId) return;
|
|
7702
7781
|
const merged = new Set([...(links[prId] || []), ...normalizePrLinkItems(itemIds)]);
|
|
@@ -9568,6 +9647,9 @@ module.exports = {
|
|
|
9568
9647
|
upsertPullRequestRecord,
|
|
9569
9648
|
collapseDuplicatePrRecords, // P-e9f0a2b4 — one-time repair helper
|
|
9570
9649
|
isAutoManagedPrRecord, // W-mq5s5ttx000j7ab8-a — exported for engine + watch-plugin gate consolidation
|
|
9650
|
+
isExplicitlyRequestedPrDispatch, // W-ms5sr82s00ze0af8-c — provenance gate shared by both stale-PR-dispatch pruners
|
|
9651
|
+
workItemOriginRoot, // exported for testing
|
|
9652
|
+
EXPLICIT_WORK_ITEM_ORIGIN_ROOTS,
|
|
9571
9653
|
autoEnrollPrFromWorkItem,
|
|
9572
9654
|
autoEnrollPrFromFixWorkItem,
|
|
9573
9655
|
deriveUrlForPrRef, // exported for testing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2445",
|
|
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"
|