From 5f20d923b703b9378b557c0976a20df911f50985 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:31:28 +0000 Subject: [PATCH 1/7] Initial plan From 861b09e9643640205308f59eed20a0afaae8ace5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:35:24 +0000 Subject: [PATCH 2/7] Initial plan for periodic notification refresh Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --- src/@types/vscode.proposed.chatParticipantAdditions.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/@types/vscode.proposed.chatParticipantAdditions.d.ts b/src/@types/vscode.proposed.chatParticipantAdditions.d.ts index 71520fa1ec..aa7001a3d2 100644 --- a/src/@types/vscode.proposed.chatParticipantAdditions.d.ts +++ b/src/@types/vscode.proposed.chatParticipantAdditions.d.ts @@ -105,6 +105,7 @@ declare module 'vscode' { isComplete?: boolean; toolSpecificData?: ChatTerminalToolInvocationData; fromSubAgent?: boolean; + presentation?: 'hidden' | 'hiddenAfterComplete' | undefined; constructor(toolName: string, toolCallId: string, isError?: boolean); } From 52b10157f9ae757916cad3956321f83f3eef34cc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:38:53 +0000 Subject: [PATCH 3/7] Add periodic notification refresh setting Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --- package.json | 6 ++++ package.nls.json | 1 + src/common/settingKeys.ts | 1 + src/notifications/notificationsManager.ts | 36 +++++++++++++++-------- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 121adffe67..46d74bf1e5 100644 --- a/package.json +++ b/package.json @@ -297,6 +297,12 @@ "default": "off", "description": "%githubPullRequests.notifications.description%" }, + "githubPullRequests.notificationsRefreshInterval": { + "type": "number", + "default": 600, + "minimum": 60, + "description": "%githubPullRequests.notificationsRefreshInterval.description%" + }, "githubPullRequests.fileListLayout": { "type": "string", "enum": [ diff --git a/package.nls.json b/package.nls.json index 73c02b7684..4f05c33e21 100644 --- a/package.nls.json +++ b/package.nls.json @@ -35,6 +35,7 @@ "githubPullRequests.queries.createdByMe": "Created By Me", "githubPullRequests.defaultMergeMethod.description": "The method to use when merging pull requests.", "githubPullRequests.notifications.description": "If GitHub notifications should be shown to the user.", + "githubPullRequests.notificationsRefreshInterval.description": "The interval in seconds at which to refresh GitHub notifications. Default is 600 seconds (10 minutes). Minimum is 60 seconds.", "githubPullRequests.fileListLayout.description": "The layout to use when displaying changed files list.", "githubPullRequests.hideViewedFiles.description": "Hide files that have been marked as viewed in the pull request changes tree.", "githubPullRequests.defaultDeletionMethod.selectLocalBranch.description": "When true, the option to delete the local branch will be selected by default when deleting a branch from a pull request.", diff --git a/src/common/settingKeys.ts b/src/common/settingKeys.ts index 1376c4c7bc..a98e7e87c2 100644 --- a/src/common/settingKeys.ts +++ b/src/common/settingKeys.ts @@ -62,6 +62,7 @@ export const EXPERIMENTAL_CHAT = 'experimental.chat'; export const EXPERIMENTAL_USE_QUICK_CHAT = 'experimental.useQuickChat'; export const EXPERIMENTAL_NOTIFICATIONS_PAGE_SIZE = 'experimental.notificationsViewPageSize'; export const EXPERIMENTAL_NOTIFICATIONS_SCORE = 'experimental.notificationsScore'; +export const NOTIFICATIONS_REFRESH_INTERVAL = 'notificationsRefreshInterval'; export const WEBVIEW_REFRESH_INTERVAL = 'webviewRefreshInterval'; // git diff --git a/src/notifications/notificationsManager.ts b/src/notifications/notificationsManager.ts index 86fdfcaeab..3b4b1521bc 100644 --- a/src/notifications/notificationsManager.ts +++ b/src/notifications/notificationsManager.ts @@ -9,7 +9,7 @@ import { NotificationsProvider } from './notificationsProvider'; import { commands, contexts } from '../common/executeCommands'; import { Disposable } from '../common/lifecycle'; import Logger from '../common/logger'; -import { NOTIFICATION_SETTING, NotificationVariants, PR_SETTINGS_NAMESPACE } from '../common/settingKeys'; +import { NOTIFICATION_SETTING, NOTIFICATIONS_REFRESH_INTERVAL, NotificationVariants, PR_SETTINGS_NAMESPACE } from '../common/settingKeys'; import { EventType, TimelineEvent } from '../common/timelineEvent'; import { toNotificationUri } from '../common/uri'; import { CredentialStore } from '../github/credentials'; @@ -70,6 +70,13 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP this._startPolling(); } } + if (e.affectsConfiguration(`${PR_SETTINGS_NAMESPACE}.${NOTIFICATIONS_REFRESH_INTERVAL}`)) { + if (this.isPRNotificationsOn() && this._pollingHandler) { + // Restart polling with new interval + this._stopPolling(); + this._startPolling(); + } + } })); this._register(PullRequestOverviewPanel.onVisible(e => { this.markPrNotificationsAsRead(e); @@ -412,6 +419,10 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP return (vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get(NOTIFICATION_SETTING) === 'pullRequests'); } + private _getRefreshInterval(): number { + return vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get(NOTIFICATIONS_REFRESH_INTERVAL, 600); + } + private async _pollForNewNotifications() { this._pageCount = 1; this._dateTime = new Date(); @@ -423,16 +434,7 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP return; } - // Adapt polling interval if it has changed. - if (response.pollInterval !== this._pollingDuration) { - this._pollingDuration = response.pollInterval; - if (this._pollingHandler && this.isPRNotificationsOn()) { - Logger.appendLine('Notifications: Clearing interval', NotificationsManager.ID); - clearInterval(this._pollingHandler); - Logger.appendLine(`Notifications: Starting new polling interval with ${this._pollingDuration}`, NotificationsManager.ID); - this._startPolling(); - } - } + // Note: We ignore the pollInterval from GitHub's response and use the user-configured interval instead if (response.lastModified !== this._pollingLastModified) { this._pollingLastModified = response.lastModified; this._onDidChangeTreeData.fire(); @@ -440,16 +442,26 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP // this._onDidChangeNotifications.fire(oldPRNodesToUpdate); } + private _stopPolling() { + if (this._pollingHandler) { + Logger.appendLine('Notifications: Clearing interval', NotificationsManager.ID); + clearInterval(this._pollingHandler); + this._pollingHandler = null; + } + } + private _startPolling() { if (!this.isPRNotificationsOn()) { return; } + const refreshInterval = this._getRefreshInterval(); + Logger.appendLine(`Notifications: Starting polling with interval ${refreshInterval} seconds`, NotificationsManager.ID); this._pollForNewNotifications(); this._pollingHandler = setInterval( function (notificationProvider: NotificationsManager) { notificationProvider._pollForNewNotifications(); }, - this._pollingDuration * 1000, + refreshInterval * 1000, this ); this._register({ dispose: () => clearInterval(this._pollingHandler!) }); From 5c56351025d05a98567eb7d3a35f85546ee80d70 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:42:49 +0000 Subject: [PATCH 4/7] Remove unused _pollingDuration field and fix reference Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --- src/notifications/notificationsManager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/notifications/notificationsManager.ts b/src/notifications/notificationsManager.ts index 3b4b1521bc..f9f73b8100 100644 --- a/src/notifications/notificationsManager.ts +++ b/src/notifications/notificationsManager.ts @@ -47,7 +47,6 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP private _fetchNotifications: boolean = false; private _notifications = new Map(); - private _pollingDuration: number = 60; // Default polling duration private _pollingHandler: NodeJS.Timeout | null; private _pollingLastModified: string; @@ -202,7 +201,7 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP } public async getNotifications(): Promise { - let pollInterval = this._pollingDuration; + let pollInterval = this._getRefreshInterval(); let lastModified = this._pollingLastModified; if (this._fetchNotifications) { // Get raw notifications From 24ed0c1bd5f986bb9e04aa8d89b3c16f37204ec8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:45:14 +0000 Subject: [PATCH 5/7] Fix disposable leak and handle restart when polling is not active Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --- src/notifications/notificationsManager.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/notifications/notificationsManager.ts b/src/notifications/notificationsManager.ts index f9f73b8100..95939c1813 100644 --- a/src/notifications/notificationsManager.ts +++ b/src/notifications/notificationsManager.ts @@ -48,6 +48,7 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP private _notifications = new Map(); private _pollingHandler: NodeJS.Timeout | null; + private _pollingDisposable: vscode.Disposable | null; private _pollingLastModified: string; private _sortingMethod: NotificationsSortMethod = NotificationsSortMethod.Timestamp; @@ -70,7 +71,7 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP } } if (e.affectsConfiguration(`${PR_SETTINGS_NAMESPACE}.${NOTIFICATIONS_REFRESH_INTERVAL}`)) { - if (this.isPRNotificationsOn() && this._pollingHandler) { + if (this.isPRNotificationsOn()) { // Restart polling with new interval this._stopPolling(); this._startPolling(); @@ -447,6 +448,10 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP clearInterval(this._pollingHandler); this._pollingHandler = null; } + if (this._pollingDisposable) { + this._pollingDisposable.dispose(); + this._pollingDisposable = null; + } } private _startPolling() { @@ -463,7 +468,7 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP refreshInterval * 1000, this ); - this._register({ dispose: () => clearInterval(this._pollingHandler!) }); + this._pollingDisposable = this._register({ dispose: () => clearInterval(this._pollingHandler!) }); } private _findNotificationKeyForIssueModel(issueModel: IssueModel | PullRequestModel | { owner: string; repo: string; number: number }): string | undefined { From 3a2c363e5198845b1c307ec8fb7abc1e3370e8b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:47:14 +0000 Subject: [PATCH 6/7] Improve polling lifecycle management to prevent resource leaks Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --- src/notifications/notificationsManager.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/notifications/notificationsManager.ts b/src/notifications/notificationsManager.ts index 95939c1813..c16d26d6fd 100644 --- a/src/notifications/notificationsManager.ts +++ b/src/notifications/notificationsManager.ts @@ -72,8 +72,7 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP } if (e.affectsConfiguration(`${PR_SETTINGS_NAMESPACE}.${NOTIFICATIONS_REFRESH_INTERVAL}`)) { if (this.isPRNotificationsOn()) { - // Restart polling with new interval - this._stopPolling(); + // Restart polling with new interval (stopPolling is called inside startPolling) this._startPolling(); } } @@ -443,21 +442,24 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP } private _stopPolling() { + if (this._pollingDisposable) { + this._pollingDisposable.dispose(); + this._pollingDisposable = null; + } if (this._pollingHandler) { Logger.appendLine('Notifications: Clearing interval', NotificationsManager.ID); clearInterval(this._pollingHandler); this._pollingHandler = null; } - if (this._pollingDisposable) { - this._pollingDisposable.dispose(); - this._pollingDisposable = null; - } } private _startPolling() { if (!this.isPRNotificationsOn()) { return; } + // Stop any existing polling to prevent resource leaks + this._stopPolling(); + const refreshInterval = this._getRefreshInterval(); Logger.appendLine(`Notifications: Starting polling with interval ${refreshInterval} seconds`, NotificationsManager.ID); this._pollForNewNotifications(); From a00adb1326b3c8af4f9e98d3e77821187e809cd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:52:12 +0000 Subject: [PATCH 7/7] Improve code safety and comments based on code review Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --- src/notifications/notificationsManager.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/notifications/notificationsManager.ts b/src/notifications/notificationsManager.ts index c16d26d6fd..2269782d63 100644 --- a/src/notifications/notificationsManager.ts +++ b/src/notifications/notificationsManager.ts @@ -433,7 +433,8 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP return; } - // Note: We ignore the pollInterval from GitHub's response and use the user-configured interval instead + // Use the user-configured interval instead of GitHub's poll interval to respect user preferences. + // This allows users to control notification refresh frequency for managing notification volume and API rate limits. if (response.lastModified !== this._pollingLastModified) { this._pollingLastModified = response.lastModified; this._onDidChangeTreeData.fire(); @@ -470,7 +471,13 @@ export class NotificationsManager extends Disposable implements vscode.TreeDataP refreshInterval * 1000, this ); - this._pollingDisposable = this._register({ dispose: () => clearInterval(this._pollingHandler!) }); + this._pollingDisposable = this._register({ + dispose: () => { + if (this._pollingHandler) { + clearInterval(this._pollingHandler); + } + } + }); } private _findNotificationKeyForIssueModel(issueModel: IssueModel | PullRequestModel | { owner: string; repo: string; number: number }): string | undefined {