Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
24 changes: 24 additions & 0 deletions .cursor/rules/no-upstream-pr.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
description: Fork PRs must target SanHsien origin; upstream PRs need explicit contribute-back consent
alwaysApply: true
---

# 禁止對上游開 PR

本 repo 是 `lidge-jun/opencodex` 的 fork。日常 PR 只能打進 `SanHsien/opencodex`。

**根因是機制不是粗心:** `gh` 在 fork clone 的預設 repo 就是上游。

```powershell
gh repo set-default SanHsien/opencodex # 每個 clone 先跑一次
gh repo set-default --view # 必須回 SanHsien/opencodex
gh pr create --repo SanHsien/opencodex --base main --head <分支>
```

建完核對 URL 必須是 `https://github.com/SanHsien/opencodex/pull/...`。

裸跑 `gh pr create` 會打到上游。2026-08-22 一天內兩個工具各誤開一次(`lidge-jun/opencodex#2373`、
`hamanpaul/paulsha-cortex#787`),禁止再犯。兩次都是「指令成功了」的錯覺——開錯的 owner 就寫在
輸出的 URL 裡;批次跑多個 repo 時最容易略過那一眼。

**唯一例外:** 使用者在這次對話明確同意回貢上游。fork、建環境、開 PR、比照其他 repo、合併回 main 都不是例外。
19 changes: 19 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 2
updates:
# 不幫上游 bun.lock / package.json 開 npm Dependabot:上游幾乎每天發版,
# lockfile PR 會跟 merge 持續打架。本線只看 workflow 釘住的 actions。
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "07:00"
timezone: "Asia/Taipei"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "github-actions"
groups:
codeql-action:
patterns:
- "github/codeql-action*"
1 change: 1 addition & 0 deletions .github/workflows/cleanup-orphaned-workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ concurrency:

jobs:
cleanup:
if: github.repository == 'lidge-jun/opencodex'
name: Delete orphaned workflow runs
runs-on: ubuntu-latest
timeout-minutes: 10
Expand Down
46 changes: 46 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: CodeQL

# The proxy handles provider tokens, ChatGPT account-pool credentials, and
# request bodies. Fork overlay tools also parse Markdown and shell out to git.
# Weekly CodeQL asks the questions unit tests do not: injection, secret leak,
# and unsafe workflow interpolation.

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "41 4 * * 6"
workflow_dispatch:

permissions:
contents: read
security-events: write

concurrency:
group: codeql-${{ github.ref }}
cancel-in-progress: true

jobs:
analyze:
name: JavaScript security scan
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
languages: javascript-typescript
queries: security-extended

- name: Analyze
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
category: "/language:javascript-typescript"
2 changes: 2 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ concurrency:

jobs:
build:
if: github.repository == 'lidge-jun/opencodex'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand All @@ -33,6 +34,7 @@ jobs:

deploy:
needs: build
if: github.repository == 'lidge-jun/opencodex'
runs-on: ubuntu-latest
timeout-minutes: 10
environment:
Expand Down
10 changes: 6 additions & 4 deletions .github/workflows/enforce-issue-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ jobs:
translate:
name: Translate non-English issues
if: >
github.event_name == 'issues' ||
github.repository == 'lidge-jun/opencodex' &&
(github.event_name == 'issues' ||
(github.event_name == 'workflow_dispatch' &&
inputs.backfill_open_areas != true &&
inputs.issue_number != '')
inputs.issue_number != ''))
runs-on: ubuntu-latest
# Serialize per-issue control-state RMW; workflow concurrency still cancels
# superseded runs, but this queue avoids interleaved comment upserts.
Expand Down Expand Up @@ -442,7 +443,7 @@ jobs:

translate-comment:
name: Translate non-English issue comments
if: github.event_name == 'issue_comment' && github.event.issue.pull_request == null && github.event.comment.user.type != 'Bot'
if: github.repository == 'lidge-jun/opencodex' && github.event_name == 'issue_comment' && github.event.issue.pull_request == null && github.event.comment.user.type != 'Bot'
runs-on: ubuntu-latest
concurrency:
# Shares the per-issue queue with the `translate` job: both jobs RMW the
Expand Down Expand Up @@ -750,6 +751,7 @@ jobs:
# quality closure must not depend on translation success.
needs: translate
if: >
github.repository == 'lidge-jun/opencodex' &&
always() &&
needs.translate.result != 'cancelled' &&
(github.event_name == 'issues' ||
Expand Down Expand Up @@ -1187,7 +1189,7 @@ jobs:

backfill-open-areas:
name: Backfill open issue area labels
if: github.event_name == 'workflow_dispatch' && inputs.backfill_open_areas == true
if: github.repository == 'lidge-jun/opencodex' && github.event_name == 'workflow_dispatch' && inputs.backfill_open_areas == true
runs-on: ubuntu-latest
permissions:
# Read-only checkout of trusted scripts from the default branch.
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/enforce-pr-target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ jobs:
# before the write-capable job starts. The PR number is the stable identity
# used by both gate writers even when a contributor pushes a new head SHA.
if: >-
(github.event_name == 'status' &&
github.repository == 'lidge-jun/opencodex' &&
((github.event_name == 'status' &&
github.event.context == 'CodeRabbit' &&
github.event.state == 'success' &&
github.event.sender.login == 'coderabbitai[bot]' &&
Expand All @@ -44,7 +45,7 @@ jobs:
github.event.label.name == 'test-exception-approved' ||
github.event.label.name == 'suppression-approved' ||
github.event.label.name == 'generated-change-approved' ||
github.event.label.name == 'dependency-change-approved'))
github.event.label.name == 'dependency-change-approved')))
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down Expand Up @@ -138,7 +139,7 @@ jobs:

enforce-target:
needs: resolve-pr
if: needs.resolve-pr.outputs.pull-number != ''
if: github.repository == 'lidge-jun/opencodex' && needs.resolve-pr.outputs.pull-number != ''
runs-on: ubuntu-latest
# Job-scoped permissions replace, rather than extend, the workflow default.
permissions:
Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/fork-maintenance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Fork maintenance

on:
push:
branches: [main]
paths:
- FORK.md
- NOTICE.md
- CLAUDE.md
- SKILL.md
- REVIEW.md
- AGENTS.md
- docs/fork/**
- tools/**
- tests/fork-hygiene.test.ts
- .github/workflows/fork-maintenance.yml
- .github/workflows/upstream-check.yml
- .github/workflows/codeql.yml
- .github/workflows/*.yml
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: fork-maintenance-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: fork gate (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup project Bun
uses: ./.github/actions/setup-project-bun

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Canonical fork gate
if: runner.os == 'Windows'
shell: pwsh
run: pwsh -NoProfile -File tools/dev_check.ps1

- name: Canonical fork gate
if: runner.os != 'Windows'
run: |
bun test tests/fork-hygiene.test.ts
bun tools/check-links.ts
3 changes: 2 additions & 1 deletion .github/workflows/issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ concurrency:

jobs:
find-duplicates:
if: github.repository == 'lidge-jun/opencodex'
name: Find similar issues
runs-on: ubuntu-latest
permissions:
Expand Down Expand Up @@ -161,7 +162,7 @@ jobs:
post-duplicates:
name: Post duplicate result
needs: find-duplicates
if: needs.find-duplicates.outputs.matches
if: github.repository == 'lidge-jun/opencodex' && needs.find-duplicates.outputs.matches
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pr-hygiene.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ concurrency:

jobs:
hygiene:
if: github.repository == 'lidge-jun/opencodex'
runs-on: ubuntu-latest
# contents: read for the trusted script checkout; issues/pull-requests write
# maintain the blocked label and one bot comment.
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pr-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ permissions:

jobs:
label:
if: github.repository == 'lidge-jun/opencodex'
runs-on: ubuntu-latest
steps:
- name: Checkout labeler script (default-branch trusted code)
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ concurrency:

jobs:
validate-dispatch:
if: github.repository == 'lidge-jun/opencodex'
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down Expand Up @@ -71,6 +72,7 @@ jobs:
NODE
publish:
needs: validate-dispatch
if: github.repository == 'lidge-jun/opencodex'
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/service-lifecycle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ concurrency:

jobs:
linux-systemd:
if: github.repository == 'lidge-jun/opencodex'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
Expand Down Expand Up @@ -155,6 +156,7 @@ jobs:
fi

macos-launchd:
if: github.repository == 'lidge-jun/opencodex'
runs-on: macos-latest
timeout-minutes: 10
steps:
Expand Down Expand Up @@ -233,6 +235,7 @@ jobs:
fi

windows-schtasks:
if: github.repository == 'lidge-jun/opencodex'
runs-on: windows-latest
timeout-minutes: 10
steps:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/stale-needs-info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ concurrency:

jobs:
stale:
if: github.repository == 'lidge-jun/opencodex'
name: Stale needs-info issues
runs-on: ubuntu-latest
steps:
Expand Down
49 changes: 49 additions & 0 deletions .github/workflows/upstream-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Upstream check

on:
push:
branches: [main]
paths:
- tools/check-upstream-updates.ts
- tools/upstream_baseline.json
- .github/workflows/upstream-check.yml
schedule:
- cron: "0 3 * * 1"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: upstream-check
cancel-in-progress: true

jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Check out full history
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Setup project Bun
uses: ./.github/actions/setup-project-bun

- name: Check upstream
id: upstream
continue-on-error: true
run: bun tools/check-upstream-updates.ts --strict

- name: Publish report
if: always()
run: cat upstream-review-report.md >> "$GITHUB_STEP_SUMMARY"

- name: Require review when upstream changed
if: steps.upstream.outcome == 'failure'
run: |
echo "::error::Upstream changed or the check failed. Review the workflow summary."
exit 1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,6 @@ tests/.tmp-*
# `git add` three separate times and reached `dev` once — see
# tests/repo-hygiene.test.ts, which fails if any path here becomes tracked again.
go/

# SanHsien fork generated reports
upstream-review-report.md
7 changes: 7 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
# are explicit guards so dev-only content never leaks into the published tarball.
devlog/
docs-site/
docs/fork/
.github/
tools/
FORK.md
NOTICE.md
CLAUDE.md
SKILL.md
REVIEW.md
.codex/

# GUI: ship only the built gui/dist (via "files"); never the source/deps/config.
Expand Down
Loading
Loading