@yemi33/minions 0.1.2166 → 0.1.2168

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.
@@ -37,11 +37,12 @@
37
37
  "symbols": ["parseStructuredCompletion", "parseCompletionFieldSummary"],
38
38
  "removalSites": [
39
39
  { "file": "engine/lifecycle.js", "line": 4675, "symbol": "parseStructuredCompletion", "reason": "Gated fallback at engine/lifecycle.js:4675-4700 — removed in the same follow-up PR that drops the parser definitions." },
40
- { "file": "engine/lifecycle.js", "line": 4676, "symbol": "parseCompletionFieldSummary", "reason": "Gated fallback at engine/lifecycle.js:4675-4700 — removed in the same follow-up PR that drops the parser definitions." }
40
+ { "file": "engine/lifecycle.js", "line": 4676, "symbol": "parseCompletionFieldSummary", "reason": "Gated fallback at engine/lifecycle.js:4675-4700 — removed in the same follow-up PR that drops the parser definitions." },
41
+ { "file": "engine/timeout.js", "line": 646, "symbol": "parseStructuredCompletion", "reason": "Gated fallback inside detectNonTerminalResultSummary on the timeout/process-exit path. Already removed on yemi33/master in P-a7b2c1d9 (commit eb544aa80dbd64c87b78ad08a17ca3560e627094, merged 2026-06-10); tracked here so the static call-site audit still passes on opg-microsoft/minions where the P-a7b2c1d9 backport is pending. Stale entry once the opg sync lands and can be dropped together with the parser definitions." }
41
42
  ],
42
43
  "allowedCallers": [],
43
44
  "schemaRef": "docs/deprecated-process.md (see 'Static call-site audit fields')",
44
- "notes": "Do NOT set removedAt until telemetry confirms zero usage across the sweepWindowDays from sweepStartDate. The follow-up code-removal PR (dropping parseStructuredCompletion at engine/lifecycle.js:3410, parseCompletionFieldSummary at :3608, and the gated fallback at :4675-4700) is dispatched separately once the window is observed clean. The symbols/removalSites/allowedCallers triple is enforced by test/unit/deprecated-call-site-audit.test.js — see docs/deprecated-process.md for the schema."
45
+ "notes": "Do NOT set removedAt until telemetry confirms zero usage across the sweepWindowDays from sweepStartDate. The follow-up code-removal PR (dropping parseStructuredCompletion at engine/lifecycle.js:3410, parseCompletionFieldSummary at :3608, the gated fallback at :4675-4700, and the opg-only timeout.js:646 caller after the P-a7b2c1d9 backport lands) is dispatched separately once the window is observed clean. The symbols/removalSites/allowedCallers triple is enforced by test/unit/deprecated-call-site-audit.test.js — see docs/deprecated-process.md for the schema."
45
46
  },
46
47
  {
47
48
  "id": "config-claude-binary-override",
package/engine/github.js CHANGED
@@ -154,6 +154,7 @@ function _isNonActionableComment(c, config = {}) {
154
154
  const ignoredAuthors = new Set((config.engine?.ignoredCommentAuthors || []).map(a => String(a).toLowerCase()));
155
155
  const login = String(c?.user?.login || '').toLowerCase();
156
156
  if (ignoredAuthors.has(login)) return true;
157
+ if (_isGitHubBotComment(c)) return true;
157
158
  if (_isAgentComment(c)) return true;
158
159
  // P-f23classifier (F2): body-only preview/CI-report check is now host-
159
160
  // agnostic. The legacy `_isCiReportCommentBody` body match (Coverage /
@@ -167,6 +168,18 @@ function _isNonActionableComment(c, config = {}) {
167
168
  return false;
168
169
  }
169
170
 
171
+ function _commentKey(c) {
172
+ if (!c || c.id == null) return '';
173
+ const type = c._type ? String(c._type) : '';
174
+ return type ? `${type}:${c.id}` : String(c.id);
175
+ }
176
+
177
+ function _entryCommentKey(entry) {
178
+ if (!entry || entry.commentId == null) return '';
179
+ const type = entry._type ? String(entry._type) : '';
180
+ return type ? `${type}:${entry.commentId}` : String(entry.commentId);
181
+ }
182
+
170
183
  // W-mp3bp0ha000997ab-b — Structural classifier for Minions-authored PR comments.
171
184
  //
172
185
  // Replaces the body-shape classifier chain (PR #2431's _isAgentSelfReviewDeclinedComment,
@@ -1141,6 +1154,8 @@ async function pollPrHumanComments(config) {
1141
1154
  const allCommentEntries = [];
1142
1155
  const newComments = [];
1143
1156
  const seenInNewComments = new Set();
1157
+ const nonActionableCommentKeys = new Set();
1158
+ const nonActionableCommentIds = new Set();
1144
1159
 
1145
1160
  for (const c of allComments) {
1146
1161
  const date = c.created_at || c.updated_at || '';
@@ -1152,7 +1167,12 @@ async function pollPrHumanComments(config) {
1152
1167
  // with this PR.
1153
1168
  const isNonActionable = _isNonActionableComment(c, config);
1154
1169
  if (dateMs) allCommentDates.push(date);
1155
- if (isNonActionable) continue;
1170
+ if (isNonActionable) {
1171
+ const key = _commentKey(c);
1172
+ if (key) nonActionableCommentKeys.add(key);
1173
+ if (c.id != null) nonActionableCommentIds.add(String(c.id));
1174
+ continue;
1175
+ }
1156
1176
  const entry = {
1157
1177
  commentId: c.id,
1158
1178
  author: c.user?.login || 'Human',
@@ -1167,6 +1187,7 @@ async function pollPrHumanComments(config) {
1167
1187
  // same-head guard can dedup via a single comparable key.
1168
1188
  _type: c._type,
1169
1189
  };
1190
+ entry.commentKey = _entryCommentKey(entry);
1170
1191
  allCommentEntries.push(entry);
1171
1192
 
1172
1193
  if (dateMs && dateMs > cutoffMs) {
@@ -1181,25 +1202,58 @@ async function pollPrHumanComments(config) {
1181
1202
  }
1182
1203
  }
1183
1204
 
1205
+ // Sort all actionable comments chronologically before any state repair so
1206
+ // stale bot/agent keys can be replaced with the newest actionable human key
1207
+ // even when the cutoff already advanced past the human comments.
1208
+ allCommentEntries.sort((a, b) => a.date.localeCompare(b.date));
1209
+ newComments.sort((a, b) => a.date.localeCompare(b.date));
1210
+ const latestActionableComment = allCommentEntries[allCommentEntries.length - 1] || null;
1211
+ const currentFeedback = pr.humanFeedback || {};
1212
+ const currentCommentKey = String(currentFeedback.lastProcessedCommentKey || '');
1213
+ const currentCommentId = String(currentFeedback.lastProcessedCommentId || '');
1214
+ const currentCauseIsNonActionable = !!(
1215
+ (currentCommentKey && nonActionableCommentKeys.has(currentCommentKey))
1216
+ || (!currentCommentKey && currentCommentId && nonActionableCommentIds.has(currentCommentId))
1217
+ );
1218
+
1219
+ const repairNonActionableCause = (nextFeedback) => {
1220
+ if (!currentCauseIsNonActionable) return false;
1221
+ if (latestActionableComment) {
1222
+ nextFeedback.lastProcessedCommentId = String(latestActionableComment.commentId);
1223
+ nextFeedback.lastProcessedCommentKey = latestActionableComment.commentKey || _entryCommentKey(latestActionableComment);
1224
+ nextFeedback.pendingFix = true;
1225
+ } else {
1226
+ nextFeedback.pendingFix = false;
1227
+ delete nextFeedback.lastProcessedCommentId;
1228
+ delete nextFeedback.lastProcessedCommentKey;
1229
+ delete nextFeedback.feedbackContent;
1230
+ }
1231
+ return true;
1232
+ };
1233
+
1184
1234
  // Update cutoff even if only non-actionable comments are new.
1185
1235
  const allNewDates = allCommentDates.filter(date => (new Date(date).getTime() || 0) > cutoffMs);
1186
1236
  if (allNewDates.length > 0 && newComments.length === 0) {
1187
- pr.humanFeedback = { ...(pr.humanFeedback || {}), lastProcessedCommentDate: allNewDates.sort().pop() };
1237
+ pr.humanFeedback = { ...currentFeedback, lastProcessedCommentDate: allNewDates.sort().pop() };
1238
+ repairNonActionableCause(pr.humanFeedback);
1188
1239
  if (editsSeenChanged) pr.humanFeedback.editsSeen = editsSeen;
1189
1240
  return true; // non-actionable comments only — persist cutoff without triggering fix
1190
1241
  }
1191
1242
  if (newComments.length === 0) {
1243
+ if (currentCauseIsNonActionable) {
1244
+ pr.humanFeedback = { ...currentFeedback };
1245
+ repairNonActionableCause(pr.humanFeedback);
1246
+ if (editsSeenChanged) pr.humanFeedback.editsSeen = editsSeen;
1247
+ return true;
1248
+ }
1192
1249
  // F6: persist pruned/updated editsSeen map even when no dispatch is queued.
1193
1250
  if (editsSeenChanged) {
1194
- pr.humanFeedback = { ...(pr.humanFeedback || {}), editsSeen };
1251
+ pr.humanFeedback = { ...currentFeedback, editsSeen };
1195
1252
  return true;
1196
1253
  }
1197
1254
  return false;
1198
1255
  }
1199
1256
 
1200
- // Sort all comments chronologically and build full context for the fix agent
1201
- allCommentEntries.sort((a, b) => a.date.localeCompare(b.date));
1202
- newComments.sort((a, b) => a.date.localeCompare(b.date));
1203
1257
  const latestDate = allNewDates.sort().pop() || newComments[newComments.length - 1].date;
1204
1258
 
1205
1259
  // Provide ALL comments as context — the agent needs full thread context to fix properly.
@@ -1230,7 +1284,7 @@ async function pollPrHumanComments(config) {
1230
1284
  // form. Falls back to the bare id when `_type` is absent (defensive;
1231
1285
  // every entry above sets it, but the pollPrHumanComments path in
1232
1286
  // engine/ado.js writes the legacy format too).
1233
- lastProcessedCommentKey: `${newComments[newComments.length - 1]._type || ''}:${newComments[newComments.length - 1].commentId}`,
1287
+ lastProcessedCommentKey: newComments[newComments.length - 1].commentKey || _entryCommentKey(newComments[newComments.length - 1]),
1234
1288
  pendingFix: true,
1235
1289
  feedbackContent,
1236
1290
  editsSeen,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2166",
3
+ "version": "0.1.2168",
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"