Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116#!/usr/bin/env bun
const repo = "anomalyco/opencode"const days = 60const msg = `To stay organized issues are automatically closed after ${days} days of no activity. If the issue is still relevant please open a new one.`
const token = process.env.GITHUB_TOKENif (!token) { console.error("GITHUB_TOKEN environment variable is required") process.exit(1)}
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000)const agentLogin = "opencode-agent[bot]"const teamMembers = new Set( (await Bun.file(new URL("../../.github/TEAM_MEMBERS", import.meta.url)).text()) .split("\n") .map((line) => line.trim().toLowerCase()) .filter(Boolean),)const teamAssociations = new Set(["OWNER", "MEMBER"])
type Issue = { number: number updated_at: string author_association: string user: { login: string } | null}
const headers = { Authorization: `Bearer ${token}`, "Content-Type": "application/json", Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28",}
function shouldSkip(i: Issue) { const login = i.user?.login.toLowerCase() return login === agentLogin || (login ? teamMembers.has(login) : false) || teamAssociations.has(i.author_association)}
async function close(num: number) { const base = `https://api.github.com/repos/${repo}/issues/${num}`
const comment = await fetch(`${base}/comments`, { method: "POST", headers, body: JSON.stringify({ body: msg }), }) if (!comment.ok) throw new Error(`Failed to comment #${num}: ${comment.status} ${comment.statusText}`)
const patch = await fetch(base, { method: "PATCH", headers, body: JSON.stringify({ state: "closed", state_reason: "not_planned" }), }) if (!patch.ok) throw new Error(`Failed to close #${num}: ${patch.status} ${patch.statusText}`)
console.log(`Closed https://github.com/${repo}/issues/${num}`)}
async function main() { let page = 1 let closed = 0
while (true) { const res = await fetch( `https://api.github.com/repos/${repo}/issues?state=open&sort=updated&direction=asc&per_page=100&page=${page}`, { headers }, ) if (!res.ok) throw new Error(res.statusText)
const all = (await res.json()) as Issue[] if (all.length === 0) break console.log(`Fetched page ${page} ${all.length} issues`)
const stale: number[] = [] for (const i of all) { const updated = new Date(i.updated_at) if (updated < cutoff) { if (shouldSkip(i)) { console.log(`Skipping stale issue #${i.number}; author ${i.user?.login ?? "unknown"} is exempt`) continue } stale.push(i.number) } else { console.log(`\nFound fresh issue #${i.number}, stopping`) if (stale.length > 0) { for (const num of stale) { await close(num) closed++ } } console.log(`Closed ${closed} issues total`) return } }
if (stale.length > 0) { for (const num of stale) { await close(num) closed++ } }
page++ }
console.log(`Closed ${closed} issues total`)}
main().catch((err) => { console.error("Error:", err) process.exit(1)})