From 703c9478b96f6f4d6ff8072ad0b4c6d3eb6bfdac Mon Sep 17 00:00:00 2001
From: "kylin1020@outlook.com"
Date: Wed, 23 Sep 2026 13:02:57 +0800
Subject: [PATCH 1/2] chore: remove inherited issue/PR auto-close gate
The contributor gate workflows inherited from pi auto-closed every issue
and PR opened by non-collaborators. Remove the gate workflows, the
approved contributors list, and the auto-close wording in the issue
templates, CONTRIBUTING.md and the coding-agent README.
---
.github/APPROVED_CONTRIBUTORS | 385 ----------------------
.github/ISSUE_TEMPLATE/bug.yml | 2 -
.github/ISSUE_TEMPLATE/contribution.yml | 2 -
.github/ISSUE_TEMPLATE/package-report.yml | 2 -
.github/workflows/approve-contributor.yml | 223 -------------
.github/workflows/issue-gate.yml | 129 --------
.github/workflows/issue-triage-labels.yml | 142 --------
.github/workflows/pr-gate.yml | 128 -------
CONTRIBUTING.md | 21 +-
packages/coding-agent/README.md | 2 -
10 files changed, 1 insertion(+), 1035 deletions(-)
delete mode 100644 .github/APPROVED_CONTRIBUTORS
delete mode 100644 .github/workflows/approve-contributor.yml
delete mode 100644 .github/workflows/issue-gate.yml
delete mode 100644 .github/workflows/issue-triage-labels.yml
delete mode 100644 .github/workflows/pr-gate.yml
diff --git a/.github/APPROVED_CONTRIBUTORS b/.github/APPROVED_CONTRIBUTORS
deleted file mode 100644
index 37dc4fee..00000000
--- a/.github/APPROVED_CONTRIBUTORS
+++ /dev/null
@@ -1,385 +0,0 @@
-# GitHub handles approved to bypass contribution auto-close
-# Format:
-# capability:
-# issue future issues stay open
-# pr future issues and PRs stay open
-
-herrnel pr
-julien-c pr
-barapa pr
-alasano pr
-aadishv pr
-airtonix pr
-aliou pr
-aos pr
-austinm911 pr
-banteg pr
-ben-vargas pr
-butelo pr
-can1357 pr
-CarlosGtrz pr
-cau1k pr
-cmf pr
-crcatala pr
-Cursivez pr
-cv pr
-dannote pr
-default-anton pr
-dnouri pr
-DronNick pr
-enisdenjo pr
-ferologics pr
-fightbulc pr
-ghoulr pr
-gnattu pr
-HACKE-RC pr
-hewliyang pr
-hjanuschka pr
-iamd3vil pr
-jblwilliams pr
-joshp123 pr
-jsinge97 pr
-justram pr
-kaofelix pr
-kiliman pr
-kim0 pr
-lockmeister pr
-LukeFost pr
-lukele pr
-m-box-mr pr
-marckrenn pr
-markusylisiurunen pr
-mcinteerj pr
-melihmucuk pr
-mitsuhiko pr
-mrexodia pr
-nathyong pr
-nickseelert pr
-nicobailon pr
-ninlds pr
-ogulcancelik pr
-patrick-kidger pr
-paulbettner pr
-Perlence pr
-pjtf93 pr
-prateekmedia pr
-prathamdby pr
-ribelo pr
-richardgill pr
-robinwander pr
-ronyrus pr
-roshanasingh4 pr
-scutifer pr
-skuridin pr
-steipete pr
-svkozak pr
-tallshort pr
-theBucky pr
-thomasmhr pr
-tiagoefreitas pr
-timolins pr
-tmustier pr
-tudoroancea pr
-unexge pr
-vaayne pr
-VaclavSynacek pr
-vsabavat pr
-w-winter pr
-Whamp pr
-WismutHansen pr
-XesGaDeus pr
-yevhen pr
-badlogictest pr
-terrorobe pr
-zedrdave pr
-mrud pr
-toorusr pr
-andresaraujo pr
-lightningRalf pr
-williballenthin pr
-masonc15 pr
-4h9fbZ pr
-haoqixu pr
-Graffioh pr
-charles-cooper pr
-emanuelst pr
-juanibiapina pr
-liby pr
-pasky pr
-odysseus0 pr
-giuseppeg pr
-michaelpersonal pr
-academo pr
-PriNova pr
-semtexzv pr
-jasonish pr
-markusn pr
-SamFold pr
-Soleone pr
-virtuald pr
-NateSmyth pr
-7Sageer pr
-MatthieuBizien pr
-sumeet pr
-marchellodev pr
-vedang pr
-lucemia pr
-mcollina pr
-lajarre pr
-smithbm2316 pr
-drewburr pr
-gordonhwc pr
-deybhayden pr
-tintinweb pr
-asoules pr
-zhahaoyu pr
-in0vik pr
-jtac pr
-yzhg1983 pr
-smcllns pr
-dmmulroy pr
-zmberber pr
-andresvi94 pr
-sudosubin pr
-Mic92 pr
-pmateusz pr
-wirjo pr
-jay-aye-see-kay pr
-lucasmeijer pr
-Evizero pr
-
-ofa1 pr
-
-crisog issue
-
-mpazik pr
-
-vekexasia pr
-
-Michaelliv pr
-
-cmraible pr
-
-dljsjr pr
-
-drio pr
-
-jlaneve pr
-
-tantara pr
-
-Nutlope pr
-
-xl0 pr
-
-mdsjip pr
-
-Exrun94 pr
-
-marcbloech pr
-
-pidalf pr
-
-injaneity pr
-
-thirtythreeforty pr
-
-justinpbarnett pr
-
-cristinaponcela pr
-
-LooSik pr
-
-mchenco pr
-
-Phoen1xCode pr
-
-louis030195 pr
-
-technocidal pr
-
-pandada8 pr
-
-npupko issue
-
-chrisvariety pr
-
-maximilianzuern pr
-
-brianmichel pr
-
-abhinavmathur-atlan pr
-
-mattiacerutti pr
-
-josephyoung pr
-
-mbazso pr
-
-AJM10565 pr
-
-DanielThomas pr
-
-MichaelYochpaz pr
-
-stephanmck pr
-
-rolfvreijdenberger pr
-
-psoukie pr
-
-vastxie pr
-
-ItsumoSeito pr
-
-davidlifschitz pr
-
-vdxz pr
-
-dangooddd pr
-
-Mearman pr
-
-dodiego pr
-
-any-victor pr
-
-geraschenko pr
-
-skhoroshavin pr
-
-cyzlmh pr
-
-xz-dev pr
-
-rajp152k pr
-
-affanali2k3 pr
-
-ArcadiaLin pr
-
-anilgulecha pr
-
-DeviosLang pr
-
-HarrodRen pr
-
-aaronkyriesenbach pr
-
-farid-fari pr
-
-petrroll pr
-
-vibeinging pr
-
-DivineDominion pr
-
-ananthakumaran pr
-
-andrebreijao pr
-
-anh-chu pr
-
-rsaryev pr
-
-QuintinShaw pr
-
-R-Taneja pr
-
-zaycruz pr
-
-mteam88 pr
-
-christianbasch pr
-
-cpacker pr
-
-rgarcia pr
-
-renaudhartert-db pr
-
-HyeokjaeLee pr
-
-arajkumar pr
-
-brianstanley pr
-
-scruffymongrel pr
-
-SI-RUI-ZHANG pr
-
-sunnyyoung pr
-
-muyiyr pr
-
-hi-neason pr
-
-acmerfight pr
-
-tizmagik pr
-
-jingtao-wisdomgraph pr
-
-XRX193 pr
-
-autopeasant pr
-
-Snail-Turbo pr
-
-futile pr
-
-arasovic pr
-
-xXJSONDeruloXx pr
-
-Marvae pr
-
-skkdevcraft pr
-
-PierrunoYT pr
-
-zhichli pr
-
-wesleyzhangwq pr
-
-dgokeeffe pr
-
-vipentti pr
-
-midastruth pr
-
-Maximo-Guk pr
-
-bigoldcat123 pr
-
-johnatbasicas pr
-
-powerfooI pr
-
-yearth pr
-
-pablasso pr
-
-bilby91 pr
-
-giannisCKS pr
-
-Panoplos pr
-
-haoyongchun1125-maker pr
-
-gwokhou pr
-
-gaoyk19 pr
-
-cad0p pr
-
-Jaaneek pr
-
-CaiJichang212 pr
-
-Mallikarjun-0 pr
-
-wutongyuonce pr
-
-Terminator666666 pr
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index 0fd4964e..69c60e5f 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -7,8 +7,6 @@ body:
value: |
**Before you start:** Read [CONTRIBUTING.md](https://github.com/stepfun-ai/step-harness/blob/main/CONTRIBUTING.md).
- New issues from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/stepfun-ai/step-harness/blob/main/CONTRIBUTING.md) will not be reopened or receive a reply.
-
Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
**Important:** before reporting an issue in core, please validate first with `pi -ne` that this is not caused by an extension you loaded.
diff --git a/.github/ISSUE_TEMPLATE/contribution.yml b/.github/ISSUE_TEMPLATE/contribution.yml
index 94503b32..8f46e77a 100644
--- a/.github/ISSUE_TEMPLATE/contribution.yml
+++ b/.github/ISSUE_TEMPLATE/contribution.yml
@@ -7,8 +7,6 @@ body:
value: |
**Before you start:** Read [CONTRIBUTING.md](https://github.com/stepfun-ai/step-harness/blob/main/CONTRIBUTING.md).
- New issues from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/stepfun-ai/step-harness/blob/main/CONTRIBUTING.md) will not be reopened or receive a reply.
-
Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
- type: textarea
diff --git a/.github/ISSUE_TEMPLATE/package-report.yml b/.github/ISSUE_TEMPLATE/package-report.yml
index bf3d4c09..8a0308a5 100644
--- a/.github/ISSUE_TEMPLATE/package-report.yml
+++ b/.github/ISSUE_TEMPLATE/package-report.yml
@@ -7,8 +7,6 @@ body:
value: |
Use this form to report a Step package. For Step core bugs, use the bug report template instead.
- New issues from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/stepfun-ai/step-harness/blob/main/CONTRIBUTING.md) will not be reopened or receive a reply.
-
Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
- type: input
diff --git a/.github/workflows/approve-contributor.yml b/.github/workflows/approve-contributor.yml
deleted file mode 100644
index debe87a7..00000000
--- a/.github/workflows/approve-contributor.yml
+++ /dev/null
@@ -1,223 +0,0 @@
-name: Approve Contributor
-
-on:
- issue_comment:
- types: [created]
-
-jobs:
- approve:
- runs-on: ubuntu-latest
- permissions:
- contents: write
- issues: write
- pull-requests: write
- steps:
- - name: Checkout
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- ref: ${{ github.event.repository.default_branch }}
-
- - name: Update contributor approval
- id: update
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const fs = require('fs');
-
- const APPROVED_FILE = '.github/APPROVED_CONTRIBUTORS';
- const VALID_CAPABILITIES = new Set(['issue', 'pr']);
- const issueAuthor = context.payload.issue.user.login;
- const commenter = context.payload.comment.user.login;
- const commentBody = (context.payload.comment.body || '').trim();
-
- const approvalAtStartPattern = /^[\s.]*(?:@[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\s*,\s*|[.:]\s*|\s+))*(lgtmi|lgtm)(?=$|[\s]|[^\p{L}\p{N}_\s])/iu;
- const approvalAtEndPattern = /(?:^|[\s.])(lgtmi|lgtm)\s*(?:[^\p{L}\p{N}_\s])?\s*$/iu;
- const approvalMatch = commentBody.match(approvalAtStartPattern) ?? commentBody.match(approvalAtEndPattern);
-
- if (!approvalMatch) {
- console.log('Comment does not start or end with lgtm or lgtmi');
- core.setOutput('status', 'skipped');
- return;
- }
-
- const targetCapability = approvalMatch[1].toLowerCase() === 'lgtmi' ? 'issue' : 'pr';
-
- try {
- const { data: permissionLevel } = await github.rest.repos.getCollaboratorPermissionLevel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- username: commenter,
- });
-
- if (!['admin', 'maintain', 'write'].includes(permissionLevel.permission)) {
- console.log(`${commenter} does not have write access`);
- core.setOutput('status', 'skipped');
- return;
- }
- } catch {
- console.log(`${commenter} does not have collaborator access`);
- core.setOutput('status', 'skipped');
- return;
- }
-
- function parseMentionedUsers(body) {
- const users = [];
- const seenUsers = new Set();
- const mentionPattern = /(^|[^A-Za-z0-9_])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?)(?![A-Za-z0-9-]|\/)/g;
-
- for (const match of body.matchAll(mentionPattern)) {
- const username = match[2];
- const normalizedUser = username.toLowerCase();
- if (seenUsers.has(normalizedUser)) {
- continue;
- }
- seenUsers.add(normalizedUser);
- users.push(username);
- }
-
- return users;
- }
-
- function parseApprovedUsers(content) {
- const lines = content.split('\n');
- const entries = [];
- const users = new Map();
-
- for (const line of lines) {
- const trimmed = line.trim();
- if (!trimmed || trimmed.startsWith('#')) {
- entries.push({ type: 'other', line });
- continue;
- }
-
- const parts = trimmed.split(/\s+/);
- if (parts.length !== 2) {
- console.log(`Skipping malformed line: ${line}`);
- entries.push({ type: 'other', line });
- continue;
- }
-
- const [username, capability] = parts;
- const normalizedCapability = capability.toLowerCase();
- if (!VALID_CAPABILITIES.has(normalizedCapability)) {
- console.log(`Skipping line with invalid capability: ${line}`);
- entries.push({ type: 'other', line });
- continue;
- }
-
- const normalizedUser = username.toLowerCase();
- const entry = { type: 'user', username, normalizedUser, capability: normalizedCapability };
- entries.push(entry);
- users.set(normalizedUser, entry);
- }
-
- return { entries, users };
- }
-
- function stringifyApprovedUsers(entries) {
- const normalizedEntries = [...entries];
-
- while (normalizedEntries.length > 0) {
- const lastEntry = normalizedEntries[normalizedEntries.length - 1];
- if (lastEntry.type !== 'other' || lastEntry.line.trim() !== '') {
- break;
- }
- normalizedEntries.pop();
- }
-
- return `${normalizedEntries
- .map((entry) => (entry.type === 'user' ? `${entry.username} ${entry.capability}` : entry.line))
- .join('\n')}\n`;
- }
-
- const content = fs.readFileSync(APPROVED_FILE, 'utf8');
- const { entries, users } = parseApprovedUsers(content);
- const mentionedUsers = parseMentionedUsers(commentBody);
- const approvalTargets = mentionedUsers.length > 0 ? mentionedUsers : [issueAuthor];
- const changedTargets = [];
- const alreadyTargets = [];
-
- for (const username of approvalTargets) {
- const normalizedUser = username.toLowerCase();
- const existingEntry = users.get(normalizedUser);
- const existingCapability = existingEntry?.capability ?? null;
-
- if (existingCapability === 'pr' || existingCapability === targetCapability) {
- alreadyTargets.push(existingEntry?.username ?? username);
- console.log(`${username} is already approved for ${existingCapability}`);
- continue;
- }
-
- if (existingEntry) {
- existingEntry.capability = targetCapability;
- changedTargets.push(existingEntry.username);
- } else {
- const entry = { type: 'user', username, normalizedUser, capability: targetCapability };
- entries.push(entry);
- users.set(normalizedUser, entry);
- changedTargets.push(username);
- }
-
- console.log(`Set ${username} capability to ${targetCapability}`);
- }
-
- core.setOutput('capability', targetCapability);
- core.setOutput('changed_targets', JSON.stringify(changedTargets));
- core.setOutput('already_targets', JSON.stringify(alreadyTargets));
-
- if (changedTargets.length === 0) {
- core.setOutput('status', 'already');
- return;
- }
-
- fs.writeFileSync(APPROVED_FILE, stringifyApprovedUsers(entries));
- core.setOutput('status', 'changed');
-
- - name: Commit and push
- if: steps.update.outputs.status == 'changed'
- run: |
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
- git add .github/APPROVED_CONTRIBUTORS
- git diff --staged --quiet || git commit -m "chore: approve contributors from issue #${{ github.event.issue.number }}"
- git push
-
- - name: Comment on issue
- if: steps.update.outputs.status == 'changed' || steps.update.outputs.status == 'already'
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- CAPABILITY: ${{ steps.update.outputs.capability }}
- CHANGED_TARGETS: ${{ steps.update.outputs.changed_targets }}
- ALREADY_TARGETS: ${{ steps.update.outputs.already_targets }}
- with:
- script: |
- const capability = process.env.CAPABILITY;
- const changedTargets = JSON.parse(process.env.CHANGED_TARGETS || '[]');
- const alreadyTargets = JSON.parse(process.env.ALREADY_TARGETS || '[]');
- const defaultBranch = context.payload.repository.default_branch;
- const formatTargets = (targets) => targets.map((target) => `@${target}`).join(', ');
- const bodyLines = [];
-
- if (changedTargets.length > 0) {
- if (capability === 'issue') {
- bodyLines.push(`${formatTargets(changedTargets)} approved for issues. Future issues will not be auto-closed. PRs still require \`lgtm\` at the start of a maintainer reply (optionally after one or more \`@username\` mentions) or at the end.`);
- } else {
- bodyLines.push(`${formatTargets(changedTargets)} approved for issues and PRs. Future issues and PRs will not be auto-closed.`);
- }
- }
-
- if (alreadyTargets.length > 0) {
- const verb = alreadyTargets.length === 1 ? 'is' : 'are';
- bodyLines.push(`${formatTargets(alreadyTargets)} ${verb} already approved.`);
- }
-
- bodyLines.push('', `See [CONTRIBUTING.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${defaultBranch}/CONTRIBUTING.md).`);
- const body = bodyLines.join('\n');
-
- await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- body,
- });
-
diff --git a/.github/workflows/issue-gate.yml b/.github/workflows/issue-gate.yml
deleted file mode 100644
index 03372aca..00000000
--- a/.github/workflows/issue-gate.yml
+++ /dev/null
@@ -1,129 +0,0 @@
-name: Issue Gate
-
-on:
- issues:
- types: [opened]
-
-jobs:
- check-contributor:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- issues: write
- steps:
- - name: Check issue author
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const APPROVED_FILE = '.github/APPROVED_CONTRIBUTORS';
- const VALID_CAPABILITIES = new Set(['issue', 'pr']);
- const TRUSTED_BOT_AUTHORS = new Set(['dependabot[bot]', 'sentry[bot]', 'claude[bot]']);
- const issueAuthor = context.payload.issue.user.login;
- const defaultBranch = context.payload.repository.default_branch;
- const isBotAuthor = issueAuthor.endsWith('[bot]');
-
- if (TRUSTED_BOT_AUTHORS.has(issueAuthor)) {
- console.log(`Skipping trusted bot: ${issueAuthor}`);
- return;
- }
-
- async function getPermission(username) {
- try {
- const { data: permissionLevel } = await github.rest.repos.getCollaboratorPermissionLevel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- username,
- });
- return permissionLevel.permission;
- } catch {
- return null;
- }
- }
-
- async function getTextFile(path) {
- const { data: fileContent } = await github.rest.repos.getContent({
- owner: context.repo.owner,
- repo: context.repo.repo,
- path,
- ref: defaultBranch,
- });
-
- if (!('content' in fileContent) || typeof fileContent.content !== 'string') {
- throw new Error(`Expected file content for ${path}`);
- }
-
- return Buffer.from(fileContent.content, 'base64').toString('utf8');
- }
-
- function parseApprovedUsers(content) {
- const users = new Map();
-
- for (const rawLine of content.split('\n')) {
- const line = rawLine.trim();
- if (!line || line.startsWith('#')) continue;
-
- const parts = line.split(/\s+/);
- if (parts.length !== 2) {
- console.log(`Skipping malformed line: ${rawLine}`);
- continue;
- }
-
- const [username, capability] = parts;
- const normalizedCapability = capability.toLowerCase();
- if (!VALID_CAPABILITIES.has(normalizedCapability)) {
- console.log(`Skipping line with invalid capability: ${rawLine}`);
- continue;
- }
-
- users.set(username.toLowerCase(), normalizedCapability);
- }
-
- return users;
- }
-
- const permission = await getPermission(issueAuthor);
- if (!isBotAuthor && ['admin', 'maintain', 'write'].includes(permission)) {
- console.log(`${issueAuthor} is a collaborator with ${permission} access`);
- return;
- }
-
- const approvedContent = await getTextFile(APPROVED_FILE);
- const approvedUsers = parseApprovedUsers(approvedContent);
- const capability = approvedUsers.get(issueAuthor.toLowerCase());
-
- if (!isBotAuthor && (capability === 'issue' || capability === 'pr')) {
- console.log(`${issueAuthor} is approved for ${capability}`);
- return;
- }
-
- const message = [
- 'This issue was auto-closed. All issues from new contributors are auto-closed by default.',
- '',
- `Maintainers review auto-closed issues daily and reopen worthwhile ones. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${defaultBranch}/CONTRIBUTING.md) will not be reopened or receive a reply.`,
- '',
- 'If a maintainer replies `lgtmi` on one of your issues, your future issues will stay open. If a maintainer replies `lgtm`, your future issues and PRs will stay open. The command must be at the start of the reply (optionally after one or more `@username` mentions) or at the end.',
- '',
- `See [CONTRIBUTING.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${defaultBranch}/CONTRIBUTING.md).`,
- ].join('\n');
-
- await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- body: message,
- });
-
- await github.rest.issues.addLabels({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- labels: ['untriaged'],
- });
-
- await github.rest.issues.update({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- state: 'closed',
- state_reason: 'not_planned',
- });
diff --git a/.github/workflows/issue-triage-labels.yml b/.github/workflows/issue-triage-labels.yml
deleted file mode 100644
index 1a44253f..00000000
--- a/.github/workflows/issue-triage-labels.yml
+++ /dev/null
@@ -1,142 +0,0 @@
-name: Issue Triage Labels
-
-on:
- issues:
- types: [reopened, labeled]
-
-jobs:
- update-labels:
- runs-on: ubuntu-latest
- permissions:
- issues: write
- steps:
- - name: Update triage labels
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const UNTRIAGED_LABEL = 'untriaged';
- const NO_ACTION_LABEL = 'no-action';
- const LAST_READ_LABEL = 'last-read';
- const TO_DISCUSS_LABEL = 'to-discuss';
- const INPROGRESS_LABEL = 'inprogress';
-
- function issueHasLabel(issue, labelName) {
- return (issue.labels ?? []).some((label) => label.name === labelName);
- }
-
- async function removeLabelIfPresent(issueNumber, issue, labelName) {
- if (!issueHasLabel(issue, labelName)) {
- console.log(`Issue #${issueNumber} does not have ${labelName}`);
- return;
- }
-
- try {
- await github.rest.issues.removeLabel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: issueNumber,
- name: labelName,
- });
- console.log(`Removed ${labelName} from #${issueNumber}`);
- } catch (error) {
- if (error.status === 404) {
- console.log(`Label ${labelName} was already absent from #${issueNumber}`);
- return;
- }
- throw error;
- }
- }
-
- if (context.payload.action === 'reopened') {
- await removeLabelIfPresent(context.issue.number, context.payload.issue, UNTRIAGED_LABEL);
- await removeLabelIfPresent(context.issue.number, context.payload.issue, NO_ACTION_LABEL);
- return;
- }
-
- if (context.payload.action === 'labeled' && context.payload.label?.name === NO_ACTION_LABEL) {
- await removeLabelIfPresent(context.issue.number, context.payload.issue, UNTRIAGED_LABEL);
- return;
- }
-
- if (context.payload.action !== 'labeled' || context.payload.label?.name !== LAST_READ_LABEL) {
- console.log('Not a last-read label event');
- return;
- }
-
- const currentIssueNumber = context.issue.number;
- const lastReadIssues = await github.paginate(github.rest.issues.listForRepo, {
- owner: context.repo.owner,
- repo: context.repo.repo,
- state: 'all',
- labels: LAST_READ_LABEL,
- per_page: 100,
- });
-
- const previousIssueNumbers = lastReadIssues
- .filter((issue) => !issue.pull_request)
- .map((issue) => issue.number)
- .filter((issueNumber) => issueNumber !== currentIssueNumber);
-
- if (previousIssueNumbers.length === 0) {
- console.log('No previous last-read issue found');
- return;
- }
-
- const previousIssueNumber = Math.max(...previousIssueNumbers);
- if (currentIssueNumber <= previousIssueNumber) {
- console.log(
- `Last-read was added to old issue #${currentIssueNumber}; latest last-read is #${previousIssueNumber}`,
- );
- return;
- }
-
- const untriagedIssues = await github.paginate(github.rest.issues.listForRepo, {
- owner: context.repo.owner,
- repo: context.repo.repo,
- state: 'all',
- labels: UNTRIAGED_LABEL,
- per_page: 100,
- });
-
- const issuesToMark = untriagedIssues
- .filter((issue) => !issue.pull_request)
- .filter((issue) => issue.number >= previousIssueNumber && issue.number <= currentIssueNumber)
- .sort((a, b) => a.number - b.number);
-
- if (issuesToMark.length === 0) {
- console.log(`No untriaged issues found from #${previousIssueNumber} to #${currentIssueNumber}`);
- return;
- }
-
- for (const issue of issuesToMark) {
- if (issueHasLabel(issue, TO_DISCUSS_LABEL)) {
- console.log(`Skipped ${NO_ACTION_LABEL} for #${issue.number} because it has ${TO_DISCUSS_LABEL}`);
- } else {
- await github.rest.issues.addLabels({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: issue.number,
- labels: [NO_ACTION_LABEL],
- });
- console.log(`Added ${NO_ACTION_LABEL} to #${issue.number}`);
- }
-
- await github.rest.issues.update({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: issue.number,
- state: 'closed',
- state_reason: 'not_planned',
- });
- console.log(`Closed #${issue.number} as not planned`);
-
- await removeLabelIfPresent(issue.number, issue, INPROGRESS_LABEL);
-
- await github.rest.issues.removeLabel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: issue.number,
- name: UNTRIAGED_LABEL,
- });
- console.log(`Removed ${UNTRIAGED_LABEL} from #${issue.number}`);
- }
diff --git a/.github/workflows/pr-gate.yml b/.github/workflows/pr-gate.yml
deleted file mode 100644
index bc6f7eef..00000000
--- a/.github/workflows/pr-gate.yml
+++ /dev/null
@@ -1,128 +0,0 @@
-name: PR Gate
-
-on:
- pull_request_target:
- types: [opened]
-
-jobs:
- check-contributor:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- issues: write
- pull-requests: write
- steps:
- - name: Check if contributor is approved
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const APPROVED_FILE = '.github/APPROVED_CONTRIBUTORS';
- const VALID_CAPABILITIES = new Set(['issue', 'pr']);
- const TRUSTED_BOT_AUTHORS = new Set(['dependabot[bot]', 'sentry[bot]', 'claude[bot]']);
- const prAuthor = context.payload.pull_request.user.login;
- const defaultBranch = context.payload.repository.default_branch;
- const isBotAuthor = prAuthor.endsWith('[bot]');
-
- if (TRUSTED_BOT_AUTHORS.has(prAuthor)) {
- console.log(`Skipping trusted bot: ${prAuthor}`);
- return;
- }
-
- async function getPermission(username) {
- try {
- const { data: permissionLevel } = await github.rest.repos.getCollaboratorPermissionLevel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- username,
- });
- return permissionLevel.permission;
- } catch {
- return null;
- }
- }
-
- async function getTextFile(path) {
- const { data: fileContent } = await github.rest.repos.getContent({
- owner: context.repo.owner,
- repo: context.repo.repo,
- path,
- ref: defaultBranch,
- });
-
- if (!('content' in fileContent) || typeof fileContent.content !== 'string') {
- throw new Error(`Expected file content for ${path}`);
- }
-
- return Buffer.from(fileContent.content, 'base64').toString('utf8');
- }
-
- function parseApprovedUsers(content) {
- const users = new Map();
-
- for (const rawLine of content.split('\n')) {
- const line = rawLine.trim();
- if (!line || line.startsWith('#')) continue;
-
- const parts = line.split(/\s+/);
- if (parts.length !== 2) {
- console.log(`Skipping malformed line: ${rawLine}`);
- continue;
- }
-
- const [username, capability] = parts;
- const normalizedCapability = capability.toLowerCase();
- if (!VALID_CAPABILITIES.has(normalizedCapability)) {
- console.log(`Skipping line with invalid capability: ${rawLine}`);
- continue;
- }
-
- users.set(username.toLowerCase(), normalizedCapability);
- }
-
- return users;
- }
-
- async function closePullRequest(message) {
- await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.payload.pull_request.number,
- body: message,
- });
-
- await github.rest.pulls.update({
- owner: context.repo.owner,
- repo: context.repo.repo,
- pull_number: context.payload.pull_request.number,
- state: 'closed',
- });
- }
-
- const permission = await getPermission(prAuthor);
- if (!isBotAuthor && ['admin', 'maintain', 'write'].includes(permission)) {
- console.log(`${prAuthor} is a collaborator with ${permission} access`);
- return;
- }
-
- const approvedContent = await getTextFile(APPROVED_FILE);
- const approvedUsers = parseApprovedUsers(approvedContent);
- const capability = approvedUsers.get(prAuthor.toLowerCase());
-
- if (!isBotAuthor && capability === 'pr') {
- console.log(`${prAuthor} is approved for PRs`);
- return;
- }
-
- console.log(`${prAuthor} is not approved, closing PR`);
-
- const message = [
- 'This PR was auto-closed. Only contributors approved with `lgtm` can open PRs. Open an issue first and ask a maintainer for approval.',
- '',
- `Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${defaultBranch}/CONTRIBUTING.md) will not be reopened or receive a reply.`,
- '',
- 'If a maintainer replies `lgtmi`, your future issues will stay open. If a maintainer replies `lgtm`, your future issues and PRs will stay open. The command must be at the start of the reply (optionally after one or more `@username` mentions) or at the end.',
- '',
- `See [CONTRIBUTING.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${defaultBranch}/CONTRIBUTING.md).`,
- ].join('\n');
-
- await closePullRequest(message);
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a03daec7..8939aa7d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,21 +18,10 @@ Using AI to write code is fine. Submitting AI-generated slop without understandi
If you use an agent, run it from the repository root directory so it picks up `AGENTS.md` automatically. Your agent must follow the rules and guidelines in that file.
-## Contribution Gate
-
-All issues and PRs from new contributors are auto-closed by default.
+## Issue Review
Issues submitted Friday through Sunday are not guaranteed to be reviewed. If something is urgent, ask on Discord: https://discord.com/invite/3cU7Bz4UPx
-Maintainers review auto-closed issues daily and reopen worthwhile ones. Issues that do not meet the quality bar below will not be reopened or receive a reply.
-
-Approval happens through maintainer replies on issues:
-
-- `lgtmi`: your future issues will not be auto-closed
-- `lgtm`: your future issues and PRs will not be auto-closed
-
-The command must be at the start of the reply (optionally after one or more `@username` mentions) or at the end. `lgtmi` does not grant rights to submit PRs. Only `lgtm` grants rights to submit PRs.
-
## Quality Bar For Issues
If you open an issue, you must use one of the two GitHub issue templates.
@@ -45,8 +34,6 @@ If you open an issue, keep it short, concrete, and worth reading.
- Explain why it matters.
- If you want to implement the change yourself, say so.
-If the issue is real and written well, a maintainer may reopen it or reply with `lgtmi` or `lgtm` in the command position described above.
-
## Blocking
If you ignore this document twice, or if you spam the tracker with agent-generated issues, your GitHub account will be permanently blocked.
@@ -55,8 +42,6 @@ If you send a large volume of issues through automation, your GitHub account wil
## Before Submitting a PR
-Do not open a PR unless you have already been approved by a maintainer using `lgtm` in the command position described above.
-
Before submitting a PR:
```bash
@@ -74,10 +59,6 @@ Ask on [Discord](https://discord.com/invite/nKXTsAcmbT).
## FAQ
-### Why are new issues and PRs auto-closed?
-
-StepCode receives more issues than the maintainers can responsibly review in real time. Many reports do not meet the quality bar in this guide or do not follow CONTRIBUTING.md. Some are slung at the repository mindlessly via an agent instead of being reviewed and shaped by the person submitting them. Auto-closing creates a buffer so maintainers can review the tracker on their own schedule and reopen the issues that meet the quality bar.
-
### Why are weekend issues lower priority?
We triage the tracker during working hours. That means more issues can accumulate over the weekend. Anything submitted Friday through Sunday may be missed or given lower priority in the Monday review queue. If a problem is urgent, ask on Discord and include the short version, a repro, and the relevant logs.
diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md
index ee100816..6e5ae582 100644
--- a/packages/coding-agent/README.md
+++ b/packages/coding-agent/README.md
@@ -3,8 +3,6 @@
-> New issues and PRs from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. See [CONTRIBUTING.md](../../CONTRIBUTING.md).
-
---
Pi is a minimal terminal coding harness. Adapt pi to your workflows, not the other way around, without having to fork and modify pi internals. Extend it with TypeScript [Extensions](#extensions), [Skills](#skills), [Prompt Templates](#prompt-templates), and [Themes](#themes). Put your extensions, skills, prompt templates, and themes in [Pi Packages](#pi-packages) and share them with others via npm or git.
From 438dafcca986c87109719d05c8af9c075ad8cb76 Mon Sep 17 00:00:00 2001
From: "kylin1020@outlook.com"
Date: Wed, 23 Sep 2026 13:09:13 +0800
Subject: [PATCH 2/2] chore: remove remaining pi leftovers from .github
- Point issue template CONTRIBUTING links to stepfun-ai/Step-Code
- Use `step -ne` and the current version in the bug template
- Drop the new-contributor requirement from the proposal template
- Remove pi's Discord contact link and blank-issue restriction
- Remove pi's package-report template and inprogress label workflow
---
.github/ISSUE_TEMPLATE/bug.yml | 6 +--
.github/ISSUE_TEMPLATE/config.yml | 5 --
.github/ISSUE_TEMPLATE/contribution.yml | 4 +-
.github/ISSUE_TEMPLATE/package-report.yml | 47 -------------------
.../workflows/remove-inprogress-on-close.yml | 31 ------------
5 files changed, 5 insertions(+), 88 deletions(-)
delete mode 100644 .github/ISSUE_TEMPLATE/config.yml
delete mode 100644 .github/ISSUE_TEMPLATE/package-report.yml
delete mode 100644 .github/workflows/remove-inprogress-on-close.yml
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index 69c60e5f..763179da 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -5,11 +5,11 @@ body:
- type: markdown
attributes:
value: |
- **Before you start:** Read [CONTRIBUTING.md](https://github.com/stepfun-ai/step-harness/blob/main/CONTRIBUTING.md).
+ **Before you start:** Read [CONTRIBUTING.md](https://github.com/stepfun-ai/Step-Code/blob/main/CONTRIBUTING.md).
Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
- **Important:** before reporting an issue in core, please validate first with `pi -ne` that this is not caused by an extension you loaded.
+ **Important:** before reporting an issue in core, please validate first with `step -ne` that this is not caused by an extension you loaded.
- type: textarea
id: description
@@ -38,6 +38,6 @@ body:
id: version
attributes:
label: Version
- description: e.g. 0.49.0
+ description: e.g. 0.84.4
validations:
required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index 66b6798c..00000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-blank_issues_enabled: false
-contact_links:
- - name: Questions
- url: https://discord.com/invite/3cU7Bz4UPx
- about: Ask questions on Discord instead of opening an issue
diff --git a/.github/ISSUE_TEMPLATE/contribution.yml b/.github/ISSUE_TEMPLATE/contribution.yml
index 8f46e77a..fcc3535b 100644
--- a/.github/ISSUE_TEMPLATE/contribution.yml
+++ b/.github/ISSUE_TEMPLATE/contribution.yml
@@ -1,11 +1,11 @@
name: Contribution Proposal
-description: Propose a change or feature (required for new contributors before submitting a PR)
+description: Propose a change or feature
labels: []
body:
- type: markdown
attributes:
value: |
- **Before you start:** Read [CONTRIBUTING.md](https://github.com/stepfun-ai/step-harness/blob/main/CONTRIBUTING.md).
+ **Before you start:** Read [CONTRIBUTING.md](https://github.com/stepfun-ai/Step-Code/blob/main/CONTRIBUTING.md).
Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
diff --git a/.github/ISSUE_TEMPLATE/package-report.yml b/.github/ISSUE_TEMPLATE/package-report.yml
deleted file mode 100644
index 8a0308a5..00000000
--- a/.github/ISSUE_TEMPLATE/package-report.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: Package Report
-description: Report a problematic Step package
-labels: ["package-report"]
-body:
- - type: markdown
- attributes:
- value: |
- Use this form to report a Step package. For Step core bugs, use the bug report template instead.
-
- Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
-
- - type: input
- id: package-name
- attributes:
- label: Package name
- description: The npm package name.
- placeholder: "@scope/package"
- validations:
- required: true
-
- - type: input
- id: package-version
- attributes:
- label: Version
- description: The reported package version.
- placeholder: "0.1.0"
- validations:
- required: false
-
- - type: dropdown
- id: report-type
- attributes:
- label: What are you reporting?
- options:
- - Malicious or unsafe behavior
- - Impersonation
- - Trademark / TOS Violations
- validations:
- required: true
-
- - type: textarea
- id: details
- attributes:
- label: Details
- description: Describe the concern and include links, logs, or screenshots if helpful.
- validations:
- required: true
diff --git a/.github/workflows/remove-inprogress-on-close.yml b/.github/workflows/remove-inprogress-on-close.yml
deleted file mode 100644
index 4904067e..00000000
--- a/.github/workflows/remove-inprogress-on-close.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: Remove In Progress Label On Close
-
-on:
- issues:
- types: [closed]
-
-jobs:
- remove-label:
- runs-on: ubuntu-latest
- permissions:
- issues: write
- steps:
- - name: Remove inprogress label
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const labelName = 'inprogress';
- const labels = context.payload.issue.labels ?? [];
- const hasLabel = labels.some((label) => label.name === labelName);
-
- if (!hasLabel) {
- console.log(`Issue does not have ${labelName} label`);
- return;
- }
-
- await github.rest.issues.removeLabel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- name: labelName,
- });