diff --git a/.github/workflows/agents-md-guard.yml b/.github/workflows/agents-md-guard.yml new file mode 100644 index 00000000..c9ac0cb4 --- /dev/null +++ b/.github/workflows/agents-md-guard.yml @@ -0,0 +1,81 @@ +name: agents-md-guard + +on: + pull_request_target: + types: + - opened + - synchronize + - reopened + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + close-when-agents-md-changed: + runs-on: ubuntu-latest + steps: + - name: Detect AGENTS.md changes and close PR + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + const { owner, repo } = context.repo; + + const files = await github.paginate(github.rest.pulls.listFiles, { + owner, + repo, + pull_number: prNumber, + per_page: 100, + }); + + const touchesAgentsMd = (path) => + typeof path === "string" && + (path === "AGENTS.md" || path.endsWith("/AGENTS.md")); + + const touched = files.filter( + (f) => touchesAgentsMd(f.filename) || touchesAgentsMd(f.previous_filename), + ); + + if (touched.length === 0) { + core.info("No AGENTS.md changes detected."); + return; + } + + const changedList = touched + .map((f) => + f.previous_filename && f.previous_filename !== f.filename + ? `- ${f.previous_filename} -> ${f.filename}` + : `- ${f.filename}`, + ) + .join("\n"); + + const body = [ + "This repository does not allow modifying `AGENTS.md` in pull requests.", + "", + "Detected changes:", + changedList, + "", + "Please revert these changes and open a new PR without touching `AGENTS.md`.", + ].join("\n"); + + try { + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body, + }); + } catch (error) { + core.warning(`Failed to comment on PR #${prNumber}: ${error.message}`); + } + + await github.rest.pulls.update({ + owner, + repo, + pull_number: prNumber, + state: "closed", + }); + + core.setFailed("PR modifies AGENTS.md"); diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..d4a07e19 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,58 @@ +# AGENTS.md + +Go 1.26+ proxy server providing OpenAI/Gemini/Claude/Codex compatible APIs with OAuth and round-robin load balancing. + +## Repository +- GitHub: https://github.com/router-for-me/CLIProxyAPI + +## Commands +```bash +gofmt -w . # Format (required after Go changes) +go build -o cli-proxy-api ./cmd/server # Build +go run ./cmd/server # Run dev server +go test ./... # Run all tests +go test -v -run TestName ./path/to/pkg # Run single test +go build -o test-output ./cmd/server && rm test-output # Verify compile (REQUIRED after changes) +``` +- Common flags: `--config `, `--tui`, `--standalone`, `--local-model`, `--no-browser`, `--oauth-callback-port ` + +## Config +- Default config: `config.yaml` (template: `config.example.yaml`) +- `.env` is auto-loaded from the working directory +- Auth material defaults under `auths/` +- Storage backends: file-based default; optional Postgres/git/object store (`PGSTORE_*`, `GITSTORE_*`, `OBJECTSTORE_*`) + +## Architecture +- `cmd/server/` — Server entrypoint +- `internal/api/` — Gin HTTP API (routes, middleware, modules) +- `internal/api/modules/amp/` — Amp integration (Amp-style routes + reverse proxy) +- `internal/thinking/` — Thinking/reasoning token processing (`internal/thinking/provider/` for per-provider config) +- `internal/runtime/executor/` — Per-provider runtime executors (incl. Codex WebSocket) +- `internal/translator/` — Provider protocol translators (and shared `common`) +- `internal/registry/` — Model registry + remote updater (`StartModelsUpdater`); `--local-model` disables remote updates +- `internal/store/` — Storage implementations and secret resolution +- `internal/managementasset/` — Config snapshots and management assets +- `internal/cache/` — Request signature caching +- `internal/watcher/` — Config hot-reload and watchers +- `internal/wsrelay/` — WebSocket relay sessions +- `internal/usage/` — Usage and token accounting +- `internal/tui/` — Bubbletea terminal UI (`--tui`, `--standalone`) +- `sdk/cliproxy/` — Embeddable SDK entry (service/builder/watchers/pipeline) +- `test/` — Cross-module integration tests + +## Code Conventions +- Keep changes small and simple (KISS) +- Comments in English only +- If editing code that already contains non-English comments, translate them to English (don’t add new non-English comments) +- For user-visible strings, keep the existing language used in that file/area +- New Markdown docs should be in English unless the file is explicitly language-specific (e.g. `README_CN.md`) +- As a rule, do not make standalone changes to `internal/translator/`. You may modify it only as part of broader changes elsewhere. +- If a task requires changing only `internal/translator/`, run `gh repo view --json viewerPermission -q .viewerPermission` to confirm you have `WRITE`, `MAINTAIN`, or `ADMIN`. If you do, you may proceed; otherwise, file a GitHub issue including the goal, rationale, and the intended implementation code, then stop further work. +- `internal/runtime/executor/` should contain executors and their unit tests only. Place any helper/supporting files under `internal/runtime/executor/helps/`. +- Follow `gofmt`; keep imports goimports-style; wrap errors with context where helpful +- Do not use `log.Fatal`/`log.Fatalf` (terminates the process); prefer returning errors and logging via logrus +- Shadowed variables: use method suffix (`errStart := server.Start()`) +- Wrap defer errors: `defer func() { if err := f.Close(); err != nil { log.Errorf(...) } }()` +- Use logrus structured logging; avoid leaking secrets/tokens in logs +- Avoid panics in HTTP handlers; prefer logged errors and meaningful HTTP status codes +- Timeouts are allowed only during credential acquisition; after an upstream connection is established, do not set timeouts for any subsequent network behavior. Intentional exceptions that must remain allowed are the Codex websocket liveness deadlines in `internal/runtime/executor/codex_websockets_executor.go`, the wsrelay session deadlines in `internal/wsrelay/session.go`, the management APICall timeout in `internal/api/handlers/management/api_tools.go`, and the `cmd/fetch_antigravity_models` utility timeouts