@yemi33/minions 0.1.2362 → 0.1.2363
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 +7 -1
- package/engine/lifecycle.js +14 -1
- package/engine/queries.js +14 -1
- package/engine/shared.js +17 -0
- package/engine.js +2 -1
- package/package.json +1 -1
package/dashboard.js
CHANGED
|
@@ -14113,8 +14113,14 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
14113
14113
|
path.join(MINIONS_DIR, 'pull-requests.json'),
|
|
14114
14114
|
];
|
|
14115
14115
|
let found = false;
|
|
14116
|
+
// Issue #803: tombstone EVERY scope that has a copy of this PR id, not
|
|
14117
|
+
// just the first one found. When enrollPrFromCanonicalId (issue #802)
|
|
14118
|
+
// has left a stray cross-scope duplicate (e.g. a legit per-project row
|
|
14119
|
+
// plus a stray central-scope copy), stopping at the first match leaves
|
|
14120
|
+
// the other scope's copy fully untouched — queries.js#getPullRequests
|
|
14121
|
+
// then de-dupes by picking that untouched duplicate as the "winner"
|
|
14122
|
+
// and silently resurrects the "deleted" PR on the next read.
|
|
14116
14123
|
for (const prPath of prPaths) {
|
|
14117
|
-
if (found) break;
|
|
14118
14124
|
// Issue #384: use a tombstone (userDeleted:true) instead of splice so
|
|
14119
14125
|
// the next poller cycle cannot re-add the PR. The entry stays in the
|
|
14120
14126
|
// file but is filtered from API responses and skipped by pollers.
|
package/engine/lifecycle.js
CHANGED
|
@@ -1378,7 +1378,20 @@ async function enrollPrFromCanonicalId(canonicalPrId, project, opts = {}) {
|
|
|
1378
1378
|
// pr-links stays consistent (#779 pattern).
|
|
1379
1379
|
if (opts.itemId && Array.isArray(existing.prdItems) && !existing.prdItems.includes(opts.itemId)) {
|
|
1380
1380
|
try {
|
|
1381
|
-
|
|
1381
|
+
// W-mrduef3q000m2172 — derive targetPath from the scope the store
|
|
1382
|
+
// actually returned `existing` under (existing._scope), NOT from the
|
|
1383
|
+
// current call's `project` argument. When the two differ (e.g. the
|
|
1384
|
+
// record lives under 'central' but this enrollment call was made
|
|
1385
|
+
// with a specific project), re-deriving from `project` sends the
|
|
1386
|
+
// upsert to the WRONG scope's file/array. upsertPullRequestRecord's
|
|
1387
|
+
// tombstone guard then finds no matching record in that (wrong)
|
|
1388
|
+
// scope and falls through to insert-as-new, silently clearing any
|
|
1389
|
+
// userDeleted tombstone on the real record. See issue writeup for
|
|
1390
|
+
// the confirmed repro.
|
|
1391
|
+
const store = require('./pull-requests-store');
|
|
1392
|
+
const targetPath = existing._scope
|
|
1393
|
+
? store._filePathForScope(existing._scope)
|
|
1394
|
+
: (project ? shared.projectPrPath(project) : path.join(MINIONS_DIR, 'pull-requests.json'));
|
|
1382
1395
|
shared.upsertPullRequestRecord(targetPath, {
|
|
1383
1396
|
id: normalizedCanonicalId,
|
|
1384
1397
|
prNumber,
|
package/engine/queries.js
CHANGED
|
@@ -995,12 +995,25 @@ function getPullRequests(config) {
|
|
|
995
995
|
// Then merge non-conflicting fields from the loser into the winner so we
|
|
996
996
|
// never lose prdItems, sourcePlan, itemType, minionsReview, or
|
|
997
997
|
// _automationFixCauses if only the loser carried them.
|
|
998
|
+
// Issue #803 — defense in depth: if a canonical PR id has a tombstoned
|
|
999
|
+
// (userDeleted:true) copy in ANY scope, treat the whole id as deleted, not
|
|
1000
|
+
// just that one record. Without this, a delete that (for whatever reason)
|
|
1001
|
+
// only tombstones one scope's copy would still have its untouched
|
|
1002
|
+
// cross-scope duplicate survive grouping below and get picked as the
|
|
1003
|
+
// dedupe "winner", silently resurrecting a PR the user just deleted.
|
|
1004
|
+
const tombstonedIds = new Set();
|
|
1005
|
+
for (const pr of sqlPrs) {
|
|
1006
|
+
if (pr && pr.id && pr.userDeleted === true) tombstonedIds.add(pr.id);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
998
1009
|
const groups = [];
|
|
999
1010
|
const groupsById = new Map();
|
|
1000
1011
|
for (const pr of sqlPrs) {
|
|
1001
1012
|
if (!pr || !pr.id) continue;
|
|
1002
|
-
// Issue #384: skip tombstoned records (user explicitly deleted)
|
|
1013
|
+
// Issue #384/#803: skip tombstoned records (user explicitly deleted), and
|
|
1014
|
+
// skip ANY record sharing an id that has a tombstoned copy elsewhere.
|
|
1003
1015
|
if (pr.userDeleted === true) continue;
|
|
1016
|
+
if (tombstonedIds.has(pr.id)) continue;
|
|
1004
1017
|
if (!groupsById.has(pr.id)) {
|
|
1005
1018
|
const g = [];
|
|
1006
1019
|
groupsById.set(pr.id, g);
|
package/engine/shared.js
CHANGED
|
@@ -7930,6 +7930,23 @@ function upsertPullRequestRecord(prPath, entry, { project = null, itemId = null,
|
|
|
7930
7930
|
delete target.userDeletedAt;
|
|
7931
7931
|
resurrected = true;
|
|
7932
7932
|
}
|
|
7933
|
+
// W-mrduef3q000m2172 — defense-in-depth: `prs` here is scoped to a single
|
|
7934
|
+
// scope's array (mutatePullRequests routes by prPath). If a caller
|
|
7935
|
+
// resolved the wrong scope for an already-tombstoned canonical id (the
|
|
7936
|
+
// record actually lives in a DIFFERENT scope's file), the above check
|
|
7937
|
+
// never sees it and would otherwise fall through to insert-as-new,
|
|
7938
|
+
// silently clearing the tombstone. Check globally before inserting.
|
|
7939
|
+
if (!target) {
|
|
7940
|
+
try {
|
|
7941
|
+
const store = require('./pull-requests-store');
|
|
7942
|
+
const globalMatch = (store.readAllPullRequests() || [])
|
|
7943
|
+
.find(pr => pr && pr.id === canonicalId && pr.userDeleted === true);
|
|
7944
|
+
if (globalMatch) {
|
|
7945
|
+
skipped = true;
|
|
7946
|
+
return prs;
|
|
7947
|
+
}
|
|
7948
|
+
} catch { /* best-effort global tombstone check — fall through on failure */ }
|
|
7949
|
+
}
|
|
7933
7950
|
// P-e9f0a2b4 — When findPrRecord returns null but multiple records share the
|
|
7934
7951
|
// same prNumber (e.g. cross-scope contamination or a project-config change
|
|
7935
7952
|
// that shifted canonical IDs), collapse the duplicates before inserting.
|
package/engine.js
CHANGED
|
@@ -28,13 +28,14 @@ require('./engine/stdio-timestamps').installIfNotInstalled();
|
|
|
28
28
|
|
|
29
29
|
const fs = require('fs');
|
|
30
30
|
const path = require('path');
|
|
31
|
+
const os = require('os');
|
|
31
32
|
const crypto = require('crypto');
|
|
32
33
|
const shared = require('./engine/shared');
|
|
33
34
|
const { exec, execAsync, execSilent, runFile, ts, ENGINE_DEFAULTS,
|
|
34
35
|
WI_STATUS, DONE_STATUSES, WORK_TYPE, PLAN_STATUS, PRD_ITEM_STATUS, PRD_MATERIALIZABLE, PR_STATUS, REVIEW_STATUS, DISPATCH_RESULT, AGENT_STATUS,
|
|
35
36
|
FAILURE_CLASS, resolvePollFlag } = shared;
|
|
36
37
|
const { resolveRuntime } = require('./engine/runtimes');
|
|
37
|
-
const { assertStaleHeadOk } = require('./engine/spawn-agent');
|
|
38
|
+
const { assertStaleHeadOk, preApproveWorkspaceMcps, computeAddDirs } = require('./engine/spawn-agent');
|
|
38
39
|
const adoGitAuth = require('./engine/ado-git-auth');
|
|
39
40
|
const queries = require('./engine/queries');
|
|
40
41
|
const dispatchEvents = require('./engine/dispatch-events');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2363",
|
|
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"
|