@oss-autopilot/core 0.42.3 → 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.
@@ -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(() => void 0) : Promise.resolve(void 0);
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 dismissedUrls = new Set(Object.keys(stateManager2.getState().config.dismissedIssues ?? {}));
13711
- const nonDismissedPRs = activePRs.filter((pr) => !dismissedUrls.has(pr.url));
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);
@@ -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 PR URLs from actionable issues (#416)
331
- const dismissedUrls = new Set(Object.keys(stateManager.getState().config.dismissedIssues ?? {}));
332
- const nonDismissedPRs = activePRs.filter((pr) => !dismissedUrls.has(pr.url));
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);
@@ -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(() => undefined)
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "0.42.3",
3
+ "version": "0.42.4",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {