From 0b1b5da5044ee32d39d89f8c25e1400b7e069753 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 11:56:22 +0000 Subject: [PATCH 1/5] Bump typescript from 5.9.3 to 6.0.2 Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.3 to 6.0.2. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.9.3...v6.0.2) --- updated-dependencies: - dependency-name: typescript dependency-version: 6.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d85c177..7053547 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,6 @@ "eslint": "^10.0.0", "eslint-plugin-github": "^6.0.0", "prettier": "^3.0.0", - "typescript": "^5.0.0" + "typescript": "^6.0.2" } } From abab6e564a1bee0f2437f4e36f2efedcc1898a34 Mon Sep 17 00:00:00 2001 From: tcely Date: Mon, 30 Mar 2026 08:40:58 -0400 Subject: [PATCH 2/5] Specify types for typescript 6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7053547..c9ab2ca 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "ci": "bun run format && bun run lint && bun run check:types && bun run test", "build": "bun build --compile --outfile bin/no-response-bin ./src/main.ts", - "check:types": "bun x --package=typescript -- tsc --noEmit --moduleResolution bundler --module es2022 --target es2022 --lib es2022,dom src/main.ts", + "check:types": "bun x --package=typescript -- tsc --noEmit --moduleResolution bundler --module es2022 --target es2022 --lib es2022,dom --types node src/main.ts", "format:write": "bun x -- prettier --write **/*.ts **/*.yaml **/*.yml", "format": "bun x -- prettier --check **/*.ts **/*.yaml **/*.yml", "lint": "bun x -- eslint src/**/*.ts", From bc293b986c0e496fcdecf09271884deaaf7c62d3 Mon Sep 17 00:00:00 2001 From: tcely Date: Mon, 30 Mar 2026 09:00:12 -0400 Subject: [PATCH 3/5] chore(deps): update lock --- bun.lock | 6 ++++-- package.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bun.lock b/bun.lock index 710db23..12fa444 100644 --- a/bun.lock +++ b/bun.lock @@ -15,7 +15,7 @@ "eslint": "^10.0.0", "eslint-plugin-github": "^6.0.0", "prettier": "^3.0.0", - "typescript": "^5.0.0", + "typescript": "^6.0.0", }, }, }, @@ -530,7 +530,7 @@ "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], "typescript-eslint": ["typescript-eslint@8.57.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.57.0", "@typescript-eslint/parser": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA=="], @@ -594,6 +594,8 @@ "eslint-plugin-eslint-comments/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + "eslint-plugin-github/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "eslint-plugin-import/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], diff --git a/package.json b/package.json index c9ab2ca..0196a2d 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,6 @@ "eslint": "^10.0.0", "eslint-plugin-github": "^6.0.0", "prettier": "^3.0.0", - "typescript": "^6.0.2" + "typescript": "^6.0.0" } } From 1601f11e22c3b581d9b35dcfe3cee2fe2bade03d Mon Sep 17 00:00:00 2001 From: tcely Date: Mon, 30 Mar 2026 09:47:06 -0400 Subject: [PATCH 4/5] fix(types): ensure Date for closed issues --- src/gh-api-helpers.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/gh-api-helpers.ts b/src/gh-api-helpers.ts index 17a2217..7f5d0c1 100644 --- a/src/gh-api-helpers.ts +++ b/src/gh-api-helpers.ts @@ -45,18 +45,32 @@ export function toDate(dateStr?: string | null): Date | undefined { * Maps a raw GitHub API response to a clean IssueDetails object. */ export function mapRestIssue(raw: any, repo: Repository): IssueDetails { - return { + const closedAt = toDate(raw.closed_at) + const date_closedAt = closedAt ?? new Date() + + const openIssue = { number: raw.number, repo, - state: raw.state, + state: 'open' as 'open', user: { login: raw.user?.login || 'unknown' }, labels: (raw.labels || []).map((l: any) => ({ name: 'string' === typeof l ? l : l.name!, repo, color: ('string' === typeof l ? '' : l.color) || 'ffffff' })), - closed_by: raw.closed_by ? { login: raw.closed_by.login } : undefined, - closed_at: toDate(raw.closed_at) + closed_by: undefined, + closed_at: undefined + } + + if ('closed' === raw.state) { + return { + ...openIssue, + state: 'closed' as 'closed', + closed_by: raw.closed_by ? { login: raw.closed_by.login } : undefined, + closed_at: date_closedAt + } + } else { + return openIssue } } From fece21bd55e79f733b8fb88c1511e9cb0d802b78 Mon Sep 17 00:00:00 2001 From: tcely Date: Mon, 30 Mar 2026 10:33:45 -0400 Subject: [PATCH 5/5] fix(types): narrow to closed issue --- src/issue-cache.ts | 11 ++++++----- src/no-response.ts | 14 +++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/issue-cache.ts b/src/issue-cache.ts index 63a335a..17bff1c 100644 --- a/src/issue-cache.ts +++ b/src/issue-cache.ts @@ -3,7 +3,7 @@ import { GitHubApiClient } from './gh-api-client' import { findLastClosedEvent } from './logic-helpers' import { RepoMetadataCache } from './repo-metadata-cache' -import { Issue, IssueDetails, Label, Repository, TimelineEvent } from './types' +import { ClosedIssueDetails, Issue, IssueDetails, Label, Repository, TimelineEvent } from './types' export class IssueCache { // Key format: "repoNodeId:issueNumber" @@ -101,19 +101,20 @@ export class IssueCache { return { details, timeline: undefined } } + const closedIssue: ClosedIssueDetails = details const timeline = await this.client.fetchTimeline(details) const lastClosed = findLastClosedEvent(timeline) if (lastClosed === undefined) { - if (missingClosedAt) details.closed_at = new Date(0) - if (missingCloser) details.closed_by = { login: 'unknown' } + if (missingClosedAt) closedIssue.closed_at = new Date(0) + if (missingCloser) closedIssue.closed_by = { login: 'unknown' } return { details, timeline } } // Patch what we can from timeline - if (missingCloser || suspiciousCloser) details.closed_by = { login: lastClosed.actor.login } + if (missingCloser || suspiciousCloser) closedIssue.closed_by = { login: lastClosed.actor.login } // Optional: timeline "closed" created_at can be used if REST closed_at is missing - if (missingClosedAt) details.closed_at = lastClosed.created_at + if (missingClosedAt) closedIssue.closed_at = lastClosed.created_at await this.set(details) return { details, timeline } diff --git a/src/no-response.ts b/src/no-response.ts index 7078918..93605ff 100644 --- a/src/no-response.ts +++ b/src/no-response.ts @@ -15,7 +15,7 @@ import { isTargetLabeledEvent } from './logic-helpers' import { RepoMetadataCache } from './repo-metadata-cache' -import { Repository, Label, Issue, IssueDetails } from './types' +import { ClosedIssueDetails, Repository, Label, Issue, IssueDetails } from './types' export default class NoResponse { private gracePeriodMs = 1000 * 60 * 15 // minutes @@ -179,7 +179,7 @@ export default class NoResponse { * CASE 1: Closed by someone else (Bot/Maintainer). * Reopen immediately on author response. */ - if (!isAuthorClosed && 'closed' === issueDetails.state) { + if (!isAuthorClosed && 'closed' === details.state) { core.info( `Author responded to closed issue ${this.repository.owner}/${this.repository.name}#${issueDetails.number}. Reopening.` ) @@ -191,8 +191,9 @@ export default class NoResponse { * CASE 2: Closed by the author themselves. * Reopen only if the comment happened after the grace period. */ - if (isAuthorClosed) { - const closedAt = details.closed_at.getTime() + if (isAuthorClosed && 'closed' === details.state) { + const closedIssue: ClosedIssueDetails = details + const closedAt = closedIssue.closed_at.getTime() const createdAt = toDate(payload.comment.created_at) const commentedAt = createdAt ? createdAt.getTime() : Date.now() @@ -262,10 +263,13 @@ export default class NoResponse { const reopenable: IssueDetails[] = [] for (const raw of results) { const issueDetails = await this.issueCache.fetch(this.repository, raw.number) + if ('closed' !== issueDetails.state) continue const { details, timeline } = await this.issueCache.ensureClosureDetails(issueDetails) + if ('closed' !== details.state) continue + const closedIssue: ClosedIssueDetails = details const closedAt = - (checkClosedByAuthor(details) ? this.gracePeriodMs : 0) + details.closed_at.getTime() + (checkClosedByAuthor(details) ? this.gracePeriodMs : 0) + closedIssue.closed_at.getTime() const events = timeline ?? (await this.client.fetchTimeline(details)) const authorResponded = events.some( (e) =>