@link-assistant/hive-mind 1.72.5 → 1.72.6
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
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.72.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 57f15ec: Detect same-account human feedback in auto-restart comment monitoring only when the AI tool is idle, while still filtering hive-mind tool-generated comments by marker and tracked ID.
|
|
8
|
+
|
|
3
9
|
## 1.72.5
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -76,7 +76,7 @@ const formatRunLine = run => {
|
|
|
76
76
|
// search scope for checkForExistingComment() stays in lock-step with the
|
|
77
77
|
// markers actually embedded in tool-posted comments.
|
|
78
78
|
const toolComments = await import('./tool-comments.lib.mjs');
|
|
79
|
-
const { SESSION_ENDING_MARKERS } = toolComments;
|
|
79
|
+
const { SESSION_ENDING_MARKERS, isToolGeneratedComment, isToolTrackedCommentId } = toolComments;
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
82
|
* Issue #1323: Check if a comment with specific content already exists on the PR
|
|
@@ -168,14 +168,25 @@ export const checkForExistingComment = async (owner, repo, prNumber, commentSign
|
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
170
|
* Check for new comments from non-bot users since last commit
|
|
171
|
+
*
|
|
172
|
+
* Same-account comments are only considered feedback when
|
|
173
|
+
* `trustAuthenticatedUserComments` is true. Keep the default false for callers
|
|
174
|
+
* that may run while an AI tool is still active: those tools can post through
|
|
175
|
+
* the authenticated GitHub account.
|
|
176
|
+
*
|
|
177
|
+
* @param {Function} commandRunner - Tagged-template command runner, injectable for tests
|
|
178
|
+
* @param {Object} options - Comment classification options
|
|
179
|
+
* @param {boolean} options.trustAuthenticatedUserComments - True only when the caller knows the AI tool is not running
|
|
171
180
|
* @returns {Promise<{hasNewComments: boolean, comments: Array}>}
|
|
172
181
|
*/
|
|
173
|
-
export const checkForNonBotComments = async (owner, repo, prNumber, issueNumber, lastCheckTime, verbose = false) => {
|
|
182
|
+
export const checkForNonBotComments = async (owner, repo, prNumber, issueNumber, lastCheckTime, verbose = false, commandRunner = $, options = {}) => {
|
|
174
183
|
try {
|
|
184
|
+
const { trustAuthenticatedUserComments = false } = options;
|
|
185
|
+
|
|
175
186
|
// Get current GitHub user to identify which comments are from the bot/hive-mind
|
|
176
187
|
let currentUser = null;
|
|
177
188
|
try {
|
|
178
|
-
const userResult = await
|
|
189
|
+
const userResult = await commandRunner`gh api user --jq .login`;
|
|
179
190
|
if (userResult.code === 0) {
|
|
180
191
|
currentUser = userResult.stdout.toString().trim();
|
|
181
192
|
}
|
|
@@ -183,7 +194,12 @@ export const checkForNonBotComments = async (owner, repo, prNumber, issueNumber,
|
|
|
183
194
|
// If we can't get the current user, continue without filtering
|
|
184
195
|
}
|
|
185
196
|
|
|
186
|
-
// Common bot usernames and patterns to filter out
|
|
197
|
+
// Common bot usernames and patterns to filter out.
|
|
198
|
+
// Issue #1821: In same-account operation, humans and AI tools can both
|
|
199
|
+
// post through the authenticated account. The safe default treats that
|
|
200
|
+
// account as tool-owned; auto-restart-until-mergeable opts in to trusting
|
|
201
|
+
// same-account comments only while no AI tool execution is active, and
|
|
202
|
+
// still filters tool-generated comments by tracked IDs and marker strings.
|
|
187
203
|
// Note: Patterns use word boundaries or end-of-string to avoid false positives
|
|
188
204
|
// (e.g., "claudeuser" should NOT match as a bot)
|
|
189
205
|
const botPatterns = [
|
|
@@ -201,21 +217,21 @@ export const checkForNonBotComments = async (owner, repo, prNumber, issueNumber,
|
|
|
201
217
|
|
|
202
218
|
const isBot = login => {
|
|
203
219
|
if (!login) return false;
|
|
204
|
-
// Check if it's the current user (the bot running hive-mind)
|
|
205
|
-
if (currentUser && login === currentUser) return true;
|
|
206
220
|
// Check against known bot patterns
|
|
207
221
|
return botPatterns.some(pattern => pattern.test(login));
|
|
208
222
|
};
|
|
209
223
|
|
|
224
|
+
const isToolComment = comment => isToolTrackedCommentId(comment.id) || isToolGeneratedComment(comment.body);
|
|
225
|
+
|
|
210
226
|
// Fetch PR conversation comments
|
|
211
|
-
const prCommentsResult = await
|
|
227
|
+
const prCommentsResult = await commandRunner`gh api repos/${owner}/${repo}/issues/${prNumber}/comments --paginate`;
|
|
212
228
|
let prComments = [];
|
|
213
229
|
if (prCommentsResult.code === 0 && prCommentsResult.stdout) {
|
|
214
230
|
prComments = JSON.parse(prCommentsResult.stdout.toString() || '[]');
|
|
215
231
|
}
|
|
216
232
|
|
|
217
233
|
// Fetch PR review comments (inline code comments)
|
|
218
|
-
const prReviewCommentsResult = await
|
|
234
|
+
const prReviewCommentsResult = await commandRunner`gh api repos/${owner}/${repo}/pulls/${prNumber}/comments --paginate`;
|
|
219
235
|
let prReviewComments = [];
|
|
220
236
|
if (prReviewCommentsResult.code === 0 && prReviewCommentsResult.stdout) {
|
|
221
237
|
prReviewComments = JSON.parse(prReviewCommentsResult.stdout.toString() || '[]');
|
|
@@ -224,7 +240,7 @@ export const checkForNonBotComments = async (owner, repo, prNumber, issueNumber,
|
|
|
224
240
|
// Fetch issue comments if we have an issue number
|
|
225
241
|
let issueComments = [];
|
|
226
242
|
if (issueNumber && issueNumber !== prNumber) {
|
|
227
|
-
const issueCommentsResult = await
|
|
243
|
+
const issueCommentsResult = await commandRunner`gh api repos/${owner}/${repo}/issues/${issueNumber}/comments --paginate`;
|
|
228
244
|
if (issueCommentsResult.code === 0 && issueCommentsResult.stdout) {
|
|
229
245
|
issueComments = JSON.parse(issueCommentsResult.stdout.toString() || '[]');
|
|
230
246
|
}
|
|
@@ -233,14 +249,28 @@ export const checkForNonBotComments = async (owner, repo, prNumber, issueNumber,
|
|
|
233
249
|
// Combine all comments
|
|
234
250
|
const allComments = [...prComments, ...prReviewComments, ...issueComments];
|
|
235
251
|
|
|
236
|
-
// Filter for new comments from non-bot users
|
|
252
|
+
// Filter for new comments from non-bot users. Automated hive-mind/tool
|
|
253
|
+
// comments are excluded by marker/ID, including comments posted by the
|
|
254
|
+
// authenticated user during the current or a previous process.
|
|
237
255
|
const newNonBotComments = allComments.filter(comment => {
|
|
238
256
|
const commentTime = new Date(comment.created_at);
|
|
239
257
|
const isAfterLastCheck = commentTime > lastCheckTime;
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
258
|
+
const login = comment.user?.login;
|
|
259
|
+
const isFromAuthenticatedUser = Boolean(currentUser && login === currentUser);
|
|
260
|
+
const isFromTool = isToolComment(comment);
|
|
261
|
+
const isFromAuthenticatedUserToolContext = isFromAuthenticatedUser && !trustAuthenticatedUserComments;
|
|
262
|
+
const isFromBot = isBot(login) || isFromAuthenticatedUserToolContext;
|
|
263
|
+
const isFromNonBot = !isFromBot && !isFromTool;
|
|
264
|
+
|
|
265
|
+
if (verbose && isAfterLastCheck && isFromTool) {
|
|
266
|
+
console.log(`[VERBOSE] Skipping tool-generated comment from ${login} at ${comment.created_at}`);
|
|
267
|
+
} else if (verbose && isAfterLastCheck && isFromAuthenticatedUserToolContext) {
|
|
268
|
+
console.log(`[VERBOSE] Skipping authenticated-user comment from ${login} at ${comment.created_at} because same-account feedback is not trusted in this context`);
|
|
269
|
+
} else if (verbose && isAfterLastCheck && isFromBot) {
|
|
270
|
+
console.log(`[VERBOSE] Skipping bot comment from ${login} at ${comment.created_at}`);
|
|
271
|
+
} else if (verbose && isAfterLastCheck && isFromNonBot) {
|
|
272
|
+
const sameAccountSuffix = currentUser && login === currentUser ? ' (authenticated user)' : '';
|
|
273
|
+
console.log(`[VERBOSE] New non-bot comment from ${login}${sameAccountSuffix} at ${comment.created_at}`);
|
|
244
274
|
}
|
|
245
275
|
|
|
246
276
|
return isAfterLastCheck && isFromNonBot;
|
|
@@ -206,8 +206,12 @@ export const watchUntilMergeable = async params => {
|
|
|
206
206
|
// Keep the counter as-is (it reached the safety valve or wasn't needed).
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
// Check for new comments from non-bot users
|
|
210
|
-
|
|
209
|
+
// Check for new comments from non-bot users. At this point the AI tool
|
|
210
|
+
// is not executing, so same-account non-tool comments can be trusted as
|
|
211
|
+
// human feedback while known tool comments remain filtered by markers/IDs.
|
|
212
|
+
const { hasNewComments, comments } = await checkForNonBotComments(owner, repo, prNumber, issueNumber, lastCheckTime, argv.verbose, $, {
|
|
213
|
+
trustAuthenticatedUserComments: true,
|
|
214
|
+
});
|
|
211
215
|
|
|
212
216
|
// Check for uncommitted changes using shared utility
|
|
213
217
|
const hasUncommittedChanges = await checkForUncommittedChanges(tempDir, argv);
|