Files
claude-code-action/CLAUDE.md
T
Vlad MocanuandClaude Opus 4.6 fba53fc8a0 chore: anonymize internal URLs for public release
Replace git.wxs.ro with forgejo.example.com in tests and docs.
Add public repo guidelines to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:36:34 +02:00

82 lines
7.3 KiB
Markdown

# CLAUDE.md
## Public Repository
This repo is open-source and synced to Codeberg. When making changes:
- **Never commit sensitive data** — no internal URLs, tokens, credentials, private infrastructure details, or instance-specific configuration in `src/`, `action.yml`, `base-action/`, or `docs/`. The `.forgejo/workflows/` directory is the only place with instance-specific config (runner labels, bot IDs, internal URLs) and that's fine — users write their own workflows.
- **Keep Forgejo support generic** — all Forgejo code must work for any Forgejo instance, not just ours. Don't hardcode assumptions about our setup. Use action inputs and environment variables for instance-specific values.
- **Use generic URLs in tests** — test fixtures use `forgejo.example.com` as the sample Forgejo URL. Never use real instance URLs in `src/` or `test/` code.
## Commands
```bash
bun test # Run tests
bun run typecheck # TypeScript type checking
bun run format # Format with prettier
bun run format:check # Check formatting
```
## What This Is
A GitHub Action that lets Claude respond to `@claude` mentions on issues/PRs (tag mode) or run tasks via `prompt` input (agent mode). Mode is auto-detected: if `prompt` is provided, it's agent mode; if triggered by a comment/issue event with `@claude`, it's tag mode. See `src/modes/detector.ts`.
## How It Runs
Single entrypoint: `src/entrypoints/run.ts` orchestrates everything — prepare (auth, permissions, trigger check, branch/comment creation), install Claude Code CLI, execute Claude via `base-action/` functions (imported directly, not subprocess), then cleanup (update tracking comment, write step summary). SSH signing cleanup and token revocation are separate `always()` steps in `action.yml`.
`base-action/` is also published standalone as `@anthropic-ai/claude-code-base-action`. Don't break its public API. It reads config from `INPUT_`-prefixed env vars (set by `action.yml`), not from action inputs directly.
## Key Concepts
**Auth priority**: `github_token` input (user-provided) > GitHub App OIDC token (default). The `claude_code_oauth_token` and `anthropic_api_key` are for the Claude API, not GitHub. Token setup lives in `src/github/token.ts`.
**Mode lifecycle**: `detectMode()` in `src/modes/detector.ts` picks the mode name ("tag" or "agent"). Trigger checking and prepare dispatch are inlined in `run.ts`: tag mode calls `prepareTagMode()` from `src/modes/tag/`, agent mode calls `prepareAgentMode()` from `src/modes/agent/`.
**Prompt construction**: Tag mode's `prepareTagMode()` builds the prompt by fetching GitHub data (`src/github/data/fetcher.ts`), formatting it as markdown (`src/github/data/formatter.ts`), and writing it to a temp file via `createPrompt()`. Agent mode writes the user's prompt directly. The prompt includes issue/PR body, comments, diff, and CI status. This is the most important part of the action — it's what Claude sees.
## Things That Will Bite You
- **Strict TypeScript**: `noUnusedLocals` and `noUnusedParameters` are enabled. Typecheck will fail on unused variables.
- **Discriminated unions for GitHub context**: `GitHubContext` is a union type — call `isEntityContext(context)` before accessing entity-specific fields like `context.issue` or `context.pullRequest`.
- **Token lifecycle matters**: The GitHub App token is obtained early and revoked in a separate `always()` step in `action.yml`. If you move token revocation into `run.ts`, it won't run if the process crashes. Same for SSH signing cleanup.
- **Error phase attribution**: The catch block in `run.ts` uses `prepareCompleted` to distinguish prepare failures from execution failures. The tracking comment shows different messages for each.
- **`action.yml` outputs reference step IDs**: Outputs like `execution_file`, `branch_name`, `github_token` reference `steps.run.outputs.*`. If you rename the step ID, update the outputs section too.
- **Integration testing** happens in a separate repo (`install-test`), not here. The tests in this repo are unit tests.
- **`allowed_tools` needs Bash sub-patterns**: Bare `Bash` in `allowed_tools` makes the tool available but individual commands still require interactive approval (which can't happen in CI). Use sub-patterns like `Bash(git:*)`, `Bash(bun:*)`, `Bash(curl:*)` to pre-approve command families. Tag mode adds `--allowedTools` to `claudeArgs` itself; agent mode relies on `run.ts` passing `ALLOWED_TOOLS_INPUT` as `options.allowedTools` to the SDK.
## Forgejo Platform Support
This fork adds Forgejo support via a lean adapter pattern — only 4 genuinely different areas have Forgejo-specific code:
- **`src/platform/detector.ts`** — Three-tier platform detection (explicit input > `FORGEJO` env > `GITHUB_SERVER_URL` heuristic) with cross-validation that rejects Forgejo override on github.com
- **`src/forgejo/token.ts`** — Direct token handling (skips OIDC exchange)
- **`src/forgejo/data/fetcher.ts`** — REST-based data fetching (replaces 3 GraphQL queries with 5-8 parallel REST calls)
- **`src/forgejo/comment-logic.ts`** — Forgejo URL patterns for tracking comments
All other `src/github/` modules work on Forgejo via Octokit REST as-is (permissions, comments, branches, git config, context, formatter).
**Bot identity on Forgejo**: A dedicated `claude` user provides bot identity (like GitHub's `claude[bot]`). The `bot_id`, `bot_name`, and `bot_email` action inputs control git commit attribution. When `bot_email` is set, it overrides the default noreply email format — set it to the bot user's registered email so Forgejo links commits to the profile. See `docs/forgejo.md` for setup.
**Key integration points** (these files have platform branches and are merge-conflict surface):
- `src/entrypoints/run.ts` — Platform branch at top for token setup
- `src/modes/tag/index.ts` — Data fetcher swap (`fetchForgejoData` vs `fetchGitHubData`)
- `src/github/operations/comments/create-initial.ts` — Platform-aware spinner/URL format
- `src/github/operations/comments/update-with-branch.ts` — Forgejo branch link in tracking comment
- `src/github/operations/branch.ts` — Uses `repos.getBranch()` on Forgejo (Forgejo has `/git/refs` not `/git/ref`)
- `src/github/validation/actor.ts` — Bot-type check skipped on Forgejo; self-trigger guard only blocks comment/review events (`issue_comment`, `issues`, `pull_request_review`, `pull_request_review_comment`). PR, workflow_dispatch, and schedule events pass through even when actor matches bot_name.
- `src/entrypoints/update-comment-link.ts` — Forgejo PR compare URL (`expand=1` instead of `quick_pull=1`)
- `src/mcp/install-mcp-server.ts` — Skips GitHub public MCP server on Forgejo
**MCP server names stay the same** (`github_comment`, `github_ci`, etc.) even on Forgejo — changing them would require updating hardcoded tool name lists in `src/modes/tag/index.ts`.
**CI**: `.forgejo/workflows/` contains `claude.yml` (tag mode), `ci.yml`, `test-action.yml`, and `upstream-sync.yml`. Unit tests run with `GITHUB_SERVER_URL=https://github.com` override on Forgejo runners.
## Code Conventions
- Runtime is Bun, not Node. Use `bun test`, not `jest`.
- `moduleResolution: "bundler"` — imports don't need `.js` extensions.
- GitHub API calls should use retry logic (`src/utils/retry.ts`).
- MCP servers are auto-installed at runtime to `~/.claude/mcp/github-{type}-server/`.