@oss-autopilot/core 0.42.2 → 0.42.4
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/dist/cli.bundle.cjs +54 -16
- package/dist/commands/daily.js +35 -9
- package/dist/commands/dismiss.d.ts +0 -2
- package/dist/commands/dismiss.js +0 -2
- package/dist/core/pr-monitor.js +17 -1
- package/dist/core/review-analysis.js +2 -1
- package/dist/core/state.d.ts +7 -7
- package/dist/core/state.js +7 -7
- package/dist/core/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli.bundle.cjs
CHANGED
|
@@ -4387,10 +4387,10 @@ var init_state = __esm({
|
|
|
4387
4387
|
}
|
|
4388
4388
|
// === Dismiss / Undismiss Issues ===
|
|
4389
4389
|
/**
|
|
4390
|
-
* Dismiss an issue by URL. Dismissed
|
|
4390
|
+
* Dismiss an issue or PR by URL. Dismissed URLs are excluded from `new_response` notifications
|
|
4391
4391
|
* until new activity occurs after the dismiss timestamp.
|
|
4392
|
-
* @param url - The full GitHub issue URL.
|
|
4393
|
-
* @param timestamp - ISO timestamp of when the issue was dismissed.
|
|
4392
|
+
* @param url - The full GitHub issue or PR URL.
|
|
4393
|
+
* @param timestamp - ISO timestamp of when the issue/PR was dismissed.
|
|
4394
4394
|
* @returns true if newly dismissed, false if already dismissed.
|
|
4395
4395
|
*/
|
|
4396
4396
|
dismissIssue(url, timestamp) {
|
|
@@ -4404,8 +4404,8 @@ var init_state = __esm({
|
|
|
4404
4404
|
return true;
|
|
4405
4405
|
}
|
|
4406
4406
|
/**
|
|
4407
|
-
* Undismiss an issue by URL.
|
|
4408
|
-
* @param url - The full GitHub issue URL.
|
|
4407
|
+
* Undismiss an issue or PR by URL.
|
|
4408
|
+
* @param url - The full GitHub issue or PR URL.
|
|
4409
4409
|
* @returns true if found and removed, false if not dismissed.
|
|
4410
4410
|
*/
|
|
4411
4411
|
undismissIssue(url) {
|
|
@@ -4416,8 +4416,8 @@ var init_state = __esm({
|
|
|
4416
4416
|
return true;
|
|
4417
4417
|
}
|
|
4418
4418
|
/**
|
|
4419
|
-
* Get the timestamp when an issue was dismissed.
|
|
4420
|
-
* @param url - The full GitHub issue URL.
|
|
4419
|
+
* Get the timestamp when an issue or PR was dismissed.
|
|
4420
|
+
* @param url - The full GitHub issue or PR URL.
|
|
4421
4421
|
* @returns The ISO dismiss timestamp, or undefined if not dismissed.
|
|
4422
4422
|
*/
|
|
4423
4423
|
getIssueDismissedAt(url) {
|
|
@@ -11213,7 +11213,24 @@ var init_pr_monitor = __esm({
|
|
|
11213
11213
|
);
|
|
11214
11214
|
const ciPromise = this.getCIStatus(owner, repo, ghPR.head.sha);
|
|
11215
11215
|
const needCommitDate = hasUnrespondedComment || reviewDecision === "changes_requested";
|
|
11216
|
-
const commitDatePromise = needCommitDate ? this.octokit.repos.getCommit({ owner, repo, ref: ghPR.head.sha }).then((res) => res.data.commit.author?.date).catch(() =>
|
|
11216
|
+
const commitDatePromise = needCommitDate ? this.octokit.repos.getCommit({ owner, repo, ref: ghPR.head.sha }).then((res) => res.data.commit.author?.date).catch((err) => {
|
|
11217
|
+
const status2 = getHttpStatusCode(err);
|
|
11218
|
+
if (status2 === 429) throw err;
|
|
11219
|
+
if (status2 === 403) {
|
|
11220
|
+
const msg = errorMessage(err).toLowerCase();
|
|
11221
|
+
if (msg.includes("rate limit") || msg.includes("abuse detection")) throw err;
|
|
11222
|
+
warn(
|
|
11223
|
+
"pr-monitor",
|
|
11224
|
+
`403 fetching commit date for ${owner}/${repo}@${ghPR.head.sha.slice(0, 7)}: ${errorMessage(err)}`
|
|
11225
|
+
);
|
|
11226
|
+
return void 0;
|
|
11227
|
+
}
|
|
11228
|
+
warn(
|
|
11229
|
+
"pr-monitor",
|
|
11230
|
+
`Failed to fetch commit date for ${owner}/${repo}@${ghPR.head.sha.slice(0, 7)}: ${errorMessage(err)}`
|
|
11231
|
+
);
|
|
11232
|
+
return void 0;
|
|
11233
|
+
}) : Promise.resolve(void 0);
|
|
11217
11234
|
const [{ status: ciStatus, failingCheckNames, failingCheckConclusions }, latestCommitDate] = await Promise.all([
|
|
11218
11235
|
ciPromise,
|
|
11219
11236
|
commitDatePromise
|
|
@@ -13685,11 +13702,12 @@ function generateDigestOutput(digest, activePRs, shelvedPRs, commentedIssues, fa
|
|
|
13685
13702
|
const dismissTime = new Date(dismissedAt).getTime();
|
|
13686
13703
|
if (isNaN(responseTime) || isNaN(dismissTime)) {
|
|
13687
13704
|
console.error(`[DAILY] Invalid timestamp in dismiss check for ${issue.url}, including issue`);
|
|
13688
|
-
stateManager2.undismissIssue(issue.url);
|
|
13689
|
-
hasAutoUndismissed = true;
|
|
13690
13705
|
return true;
|
|
13691
13706
|
}
|
|
13692
13707
|
if (responseTime > dismissTime) {
|
|
13708
|
+
console.error(
|
|
13709
|
+
`[DAILY] Auto-undismissing issue ${issue.url}: new response at ${issue.lastResponseAt} after dismiss at ${dismissedAt}`
|
|
13710
|
+
);
|
|
13693
13711
|
stateManager2.undismissIssue(issue.url);
|
|
13694
13712
|
hasAutoUndismissed = true;
|
|
13695
13713
|
return true;
|
|
@@ -13697,9 +13715,6 @@ function generateDigestOutput(digest, activePRs, shelvedPRs, commentedIssues, fa
|
|
|
13697
13715
|
}
|
|
13698
13716
|
return false;
|
|
13699
13717
|
});
|
|
13700
|
-
if (hasAutoUndismissed) {
|
|
13701
|
-
stateManager2.save();
|
|
13702
|
-
}
|
|
13703
13718
|
const issueResponses = filteredCommentedIssues.filter(
|
|
13704
13719
|
(i) => i.status === "new_response"
|
|
13705
13720
|
);
|
|
@@ -13707,8 +13722,32 @@ function generateDigestOutput(digest, activePRs, shelvedPRs, commentedIssues, fa
|
|
|
13707
13722
|
const snoozedUrls = new Set(
|
|
13708
13723
|
Object.keys(stateManager2.getState().config.snoozedPRs ?? {}).filter((url) => stateManager2.isSnoozed(url))
|
|
13709
13724
|
);
|
|
13710
|
-
const
|
|
13711
|
-
|
|
13725
|
+
const nonDismissedPRs = activePRs.filter((pr) => {
|
|
13726
|
+
const dismissedAt = stateManager2.getIssueDismissedAt(pr.url);
|
|
13727
|
+
if (!dismissedAt) return true;
|
|
13728
|
+
const activityTime = new Date(pr.updatedAt).getTime();
|
|
13729
|
+
const dismissTime = new Date(dismissedAt).getTime();
|
|
13730
|
+
if (isNaN(activityTime) || isNaN(dismissTime)) {
|
|
13731
|
+
console.error(`[DAILY] Invalid timestamp in PR dismiss check for ${pr.url}, including PR`);
|
|
13732
|
+
return true;
|
|
13733
|
+
}
|
|
13734
|
+
if (activityTime > dismissTime) {
|
|
13735
|
+
console.error(
|
|
13736
|
+
`[DAILY] Auto-undismissing PR ${pr.url}: new activity at ${pr.updatedAt} after dismiss at ${dismissedAt}`
|
|
13737
|
+
);
|
|
13738
|
+
stateManager2.undismissIssue(pr.url);
|
|
13739
|
+
hasAutoUndismissed = true;
|
|
13740
|
+
return true;
|
|
13741
|
+
}
|
|
13742
|
+
return false;
|
|
13743
|
+
});
|
|
13744
|
+
if (hasAutoUndismissed) {
|
|
13745
|
+
try {
|
|
13746
|
+
stateManager2.save();
|
|
13747
|
+
} catch (error) {
|
|
13748
|
+
console.error("[DAILY] Failed to persist auto-undismissed state:", errorMessage(error));
|
|
13749
|
+
}
|
|
13750
|
+
}
|
|
13712
13751
|
const actionableIssues = collectActionableIssues(nonDismissedPRs, snoozedUrls);
|
|
13713
13752
|
digest.summary.totalNeedingAttention = actionableIssues.length;
|
|
13714
13753
|
const briefSummary = formatBriefSummary(digest, actionableIssues.length, issueResponses.length);
|
|
@@ -17199,7 +17238,6 @@ var init_shelve = __esm({
|
|
|
17199
17238
|
// src/commands/dismiss.ts
|
|
17200
17239
|
var dismiss_exports = {};
|
|
17201
17240
|
__export(dismiss_exports, {
|
|
17202
|
-
ISSUE_OR_PR_URL_PATTERN: () => ISSUE_OR_PR_URL_PATTERN,
|
|
17203
17241
|
runDismiss: () => runDismiss,
|
|
17204
17242
|
runUndismiss: () => runUndismiss
|
|
17205
17243
|
});
|
package/dist/commands/daily.js
CHANGED
|
@@ -305,14 +305,14 @@ function generateDigestOutput(digest, activePRs, shelvedPRs, commentedIssues, fa
|
|
|
305
305
|
const responseTime = new Date(issue.lastResponseAt).getTime();
|
|
306
306
|
const dismissTime = new Date(dismissedAt).getTime();
|
|
307
307
|
if (isNaN(responseTime) || isNaN(dismissTime)) {
|
|
308
|
-
// Invalid timestamp — fail open (include issue to be safe)
|
|
308
|
+
// Invalid timestamp — fail open (include issue to be safe) without
|
|
309
|
+
// permanently removing dismiss record (may be a transient data issue)
|
|
309
310
|
console.error(`[DAILY] Invalid timestamp in dismiss check for ${issue.url}, including issue`);
|
|
310
|
-
stateManager.undismissIssue(issue.url);
|
|
311
|
-
hasAutoUndismissed = true;
|
|
312
311
|
return true;
|
|
313
312
|
}
|
|
314
313
|
if (responseTime > dismissTime) {
|
|
315
314
|
// New activity after dismiss — auto-undismiss and resurface
|
|
315
|
+
console.error(`[DAILY] Auto-undismissing issue ${issue.url}: new response at ${issue.lastResponseAt} after dismiss at ${dismissedAt}`);
|
|
316
316
|
stateManager.undismissIssue(issue.url);
|
|
317
317
|
hasAutoUndismissed = true;
|
|
318
318
|
return true;
|
|
@@ -321,15 +321,41 @@ function generateDigestOutput(digest, activePRs, shelvedPRs, commentedIssues, fa
|
|
|
321
321
|
// Still dismissed (last response is at or before dismiss timestamp)
|
|
322
322
|
return false;
|
|
323
323
|
});
|
|
324
|
-
if (hasAutoUndismissed) {
|
|
325
|
-
stateManager.save();
|
|
326
|
-
}
|
|
327
324
|
const issueResponses = filteredCommentedIssues.filter((i) => i.status === 'new_response');
|
|
328
325
|
const summary = formatSummary(digest, capacity, issueResponses);
|
|
329
326
|
const snoozedUrls = new Set(Object.keys(stateManager.getState().config.snoozedPRs ?? {}).filter((url) => stateManager.isSnoozed(url)));
|
|
330
|
-
// Filter dismissed
|
|
331
|
-
const
|
|
332
|
-
|
|
327
|
+
// Filter dismissed PRs: suppress if dismissed after last activity, auto-undismiss if new activity (#416, #468)
|
|
328
|
+
const nonDismissedPRs = activePRs.filter((pr) => {
|
|
329
|
+
const dismissedAt = stateManager.getIssueDismissedAt(pr.url);
|
|
330
|
+
if (!dismissedAt)
|
|
331
|
+
return true; // Not dismissed — include
|
|
332
|
+
const activityTime = new Date(pr.updatedAt).getTime();
|
|
333
|
+
const dismissTime = new Date(dismissedAt).getTime();
|
|
334
|
+
if (isNaN(activityTime) || isNaN(dismissTime)) {
|
|
335
|
+
// Invalid timestamp — fail open (include PR to be safe) without
|
|
336
|
+
// permanently removing dismiss record (may be a transient data issue)
|
|
337
|
+
console.error(`[DAILY] Invalid timestamp in PR dismiss check for ${pr.url}, including PR`);
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
if (activityTime > dismissTime) {
|
|
341
|
+
// New activity after dismiss — auto-undismiss and resurface
|
|
342
|
+
console.error(`[DAILY] Auto-undismissing PR ${pr.url}: new activity at ${pr.updatedAt} after dismiss at ${dismissedAt}`);
|
|
343
|
+
stateManager.undismissIssue(pr.url);
|
|
344
|
+
hasAutoUndismissed = true;
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
// Still dismissed (last activity is at or before dismiss timestamp)
|
|
348
|
+
return false;
|
|
349
|
+
});
|
|
350
|
+
// Persist auto-undismiss state changes (issue + PR combined into one save)
|
|
351
|
+
if (hasAutoUndismissed) {
|
|
352
|
+
try {
|
|
353
|
+
stateManager.save();
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
console.error('[DAILY] Failed to persist auto-undismissed state:', errorMessage(error));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
333
359
|
const actionableIssues = collectActionableIssues(nonDismissedPRs, snoozedUrls);
|
|
334
360
|
digest.summary.totalNeedingAttention = actionableIssues.length;
|
|
335
361
|
const briefSummary = formatBriefSummary(digest, actionableIssues.length, issueResponses.length);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Manages dismissing issue and PR notifications without posting a comment.
|
|
4
4
|
* Dismissed URLs resurface automatically when new responses arrive after the dismiss timestamp.
|
|
5
5
|
*/
|
|
6
|
-
import { ISSUE_OR_PR_URL_PATTERN } from './validation.js';
|
|
7
6
|
export interface DismissOutput {
|
|
8
7
|
dismissed: boolean;
|
|
9
8
|
url: string;
|
|
@@ -12,7 +11,6 @@ export interface UndismissOutput {
|
|
|
12
11
|
undismissed: boolean;
|
|
13
12
|
url: string;
|
|
14
13
|
}
|
|
15
|
-
export { ISSUE_OR_PR_URL_PATTERN };
|
|
16
14
|
export declare function runDismiss(options: {
|
|
17
15
|
url: string;
|
|
18
16
|
}): Promise<DismissOutput>;
|
package/dist/commands/dismiss.js
CHANGED
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { getStateManager } from '../core/index.js';
|
|
7
7
|
import { ISSUE_OR_PR_URL_PATTERN, validateGitHubUrl, validateUrl } from './validation.js';
|
|
8
|
-
// Re-export for tests
|
|
9
|
-
export { ISSUE_OR_PR_URL_PATTERN };
|
|
10
8
|
export async function runDismiss(options) {
|
|
11
9
|
validateUrl(options.url);
|
|
12
10
|
validateGitHubUrl(options.url, ISSUE_OR_PR_URL_PATTERN, 'issue or PR');
|
package/dist/core/pr-monitor.js
CHANGED
|
@@ -204,7 +204,23 @@ export class PRMonitor {
|
|
|
204
204
|
? this.octokit.repos
|
|
205
205
|
.getCommit({ owner, repo, ref: ghPR.head.sha })
|
|
206
206
|
.then((res) => res.data.commit.author?.date)
|
|
207
|
-
.catch(() =>
|
|
207
|
+
.catch((err) => {
|
|
208
|
+
// Rate limit errors must propagate — silently swallowing them produces
|
|
209
|
+
// misleading status (e.g. needs_changes when changes were addressed) (#469).
|
|
210
|
+
const status = getHttpStatusCode(err);
|
|
211
|
+
if (status === 429)
|
|
212
|
+
throw err;
|
|
213
|
+
if (status === 403) {
|
|
214
|
+
const msg = errorMessage(err).toLowerCase();
|
|
215
|
+
if (msg.includes('rate limit') || msg.includes('abuse detection'))
|
|
216
|
+
throw err;
|
|
217
|
+
// Non-rate-limit 403 (DMCA, private repo, SSO) — degrade gracefully
|
|
218
|
+
warn('pr-monitor', `403 fetching commit date for ${owner}/${repo}@${ghPR.head.sha.slice(0, 7)}: ${errorMessage(err)}`);
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
warn('pr-monitor', `Failed to fetch commit date for ${owner}/${repo}@${ghPR.head.sha.slice(0, 7)}: ${errorMessage(err)}`);
|
|
222
|
+
return undefined;
|
|
223
|
+
})
|
|
208
224
|
: Promise.resolve(undefined);
|
|
209
225
|
const [{ status: ciStatus, failingCheckNames, failingCheckConclusions }, latestCommitDate] = await Promise.all([
|
|
210
226
|
ciPromise,
|
|
@@ -108,7 +108,8 @@ export function checkUnrespondedComments(comments, reviews, reviewComments, user
|
|
|
108
108
|
if (!body && review.state !== 'COMMENTED' && review.state !== 'CHANGES_REQUESTED')
|
|
109
109
|
continue;
|
|
110
110
|
const author = review.user?.login || 'unknown';
|
|
111
|
-
// For inline-only COMMENTED reviews, skip pure self-replies (#199)
|
|
111
|
+
// For inline-only COMMENTED reviews, skip pure self-replies (#199).
|
|
112
|
+
// CHANGES_REQUESTED reviews are always actionable regardless of self-replies.
|
|
112
113
|
if (!body && review.state === 'COMMENTED' && review.id != null) {
|
|
113
114
|
if (isAllSelfReplies(review.id, reviewComments)) {
|
|
114
115
|
continue;
|
package/dist/core/state.d.ts
CHANGED
|
@@ -206,22 +206,22 @@ export declare class StateManager {
|
|
|
206
206
|
*/
|
|
207
207
|
isPRShelved(url: string): boolean;
|
|
208
208
|
/**
|
|
209
|
-
* Dismiss an issue by URL. Dismissed
|
|
209
|
+
* Dismiss an issue or PR by URL. Dismissed URLs are excluded from `new_response` notifications
|
|
210
210
|
* until new activity occurs after the dismiss timestamp.
|
|
211
|
-
* @param url - The full GitHub issue URL.
|
|
212
|
-
* @param timestamp - ISO timestamp of when the issue was dismissed.
|
|
211
|
+
* @param url - The full GitHub issue or PR URL.
|
|
212
|
+
* @param timestamp - ISO timestamp of when the issue/PR was dismissed.
|
|
213
213
|
* @returns true if newly dismissed, false if already dismissed.
|
|
214
214
|
*/
|
|
215
215
|
dismissIssue(url: string, timestamp: string): boolean;
|
|
216
216
|
/**
|
|
217
|
-
* Undismiss an issue by URL.
|
|
218
|
-
* @param url - The full GitHub issue URL.
|
|
217
|
+
* Undismiss an issue or PR by URL.
|
|
218
|
+
* @param url - The full GitHub issue or PR URL.
|
|
219
219
|
* @returns true if found and removed, false if not dismissed.
|
|
220
220
|
*/
|
|
221
221
|
undismissIssue(url: string): boolean;
|
|
222
222
|
/**
|
|
223
|
-
* Get the timestamp when an issue was dismissed.
|
|
224
|
-
* @param url - The full GitHub issue URL.
|
|
223
|
+
* Get the timestamp when an issue or PR was dismissed.
|
|
224
|
+
* @param url - The full GitHub issue or PR URL.
|
|
225
225
|
* @returns The ISO dismiss timestamp, or undefined if not dismissed.
|
|
226
226
|
*/
|
|
227
227
|
getIssueDismissedAt(url: string): string | undefined;
|
package/dist/core/state.js
CHANGED
|
@@ -721,10 +721,10 @@ export class StateManager {
|
|
|
721
721
|
}
|
|
722
722
|
// === Dismiss / Undismiss Issues ===
|
|
723
723
|
/**
|
|
724
|
-
* Dismiss an issue by URL. Dismissed
|
|
724
|
+
* Dismiss an issue or PR by URL. Dismissed URLs are excluded from `new_response` notifications
|
|
725
725
|
* until new activity occurs after the dismiss timestamp.
|
|
726
|
-
* @param url - The full GitHub issue URL.
|
|
727
|
-
* @param timestamp - ISO timestamp of when the issue was dismissed.
|
|
726
|
+
* @param url - The full GitHub issue or PR URL.
|
|
727
|
+
* @param timestamp - ISO timestamp of when the issue/PR was dismissed.
|
|
728
728
|
* @returns true if newly dismissed, false if already dismissed.
|
|
729
729
|
*/
|
|
730
730
|
dismissIssue(url, timestamp) {
|
|
@@ -738,8 +738,8 @@ export class StateManager {
|
|
|
738
738
|
return true;
|
|
739
739
|
}
|
|
740
740
|
/**
|
|
741
|
-
* Undismiss an issue by URL.
|
|
742
|
-
* @param url - The full GitHub issue URL.
|
|
741
|
+
* Undismiss an issue or PR by URL.
|
|
742
|
+
* @param url - The full GitHub issue or PR URL.
|
|
743
743
|
* @returns true if found and removed, false if not dismissed.
|
|
744
744
|
*/
|
|
745
745
|
undismissIssue(url) {
|
|
@@ -750,8 +750,8 @@ export class StateManager {
|
|
|
750
750
|
return true;
|
|
751
751
|
}
|
|
752
752
|
/**
|
|
753
|
-
* Get the timestamp when an issue was dismissed.
|
|
754
|
-
* @param url - The full GitHub issue URL.
|
|
753
|
+
* Get the timestamp when an issue or PR was dismissed.
|
|
754
|
+
* @param url - The full GitHub issue or PR URL.
|
|
755
755
|
* @returns The ISO dismiss timestamp, or undefined if not dismissed.
|
|
756
756
|
*/
|
|
757
757
|
getIssueDismissedAt(url) {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -451,7 +451,7 @@ export interface AgentConfig {
|
|
|
451
451
|
aiPolicyBlocklist?: string[];
|
|
452
452
|
/** PR URLs manually shelved by the user. Shelved PRs are excluded from capacity and actionable issues. Auto-unshelved when maintainers engage. */
|
|
453
453
|
shelvedPRUrls?: string[];
|
|
454
|
-
/** Issue URLs dismissed by the user, mapped to ISO timestamp of when dismissed. Issues with new responses after the dismiss timestamp resurface automatically. */
|
|
454
|
+
/** Issue/PR URLs dismissed by the user, mapped to ISO timestamp of when dismissed. Issues with new responses after the dismiss timestamp resurface automatically. Named dismissedIssues for state backward compatibility (#416). */
|
|
455
455
|
dismissedIssues?: Record<string, string>;
|
|
456
456
|
/** PR URLs with snoozed CI failures, mapped to snooze metadata. Snoozed PRs are excluded from actionable CI failure list until expiry. */
|
|
457
457
|
snoozedPRs?: Record<string, SnoozeInfo>;
|