Enable `SQLITE_JOURNAL_MODE = WAL` for the sqlite integration test
config. With modernc as the default driver, concurrent writers serialize
on SQLite's single write lock and the tail of the queue can exceed the
20s busy timeout under CI load. WAL drains the queue fast enough to stay
inside the timeout (removes rollback's fsync-per-commit and
reader-vs-commit blocking) and covers all sqlite integration tests in
one change.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Two test-only changes that cut the `-race` backend unit job's critical
path, with no behavior change.
- **`modules/auth/password/hash`** — `TestHashing`/`TestVectors`
exercised the CPU-bound KDFs (scrypt `N=65536`, pbkdf2, bcrypt, argon2)
serially on one core. Marking the subtests `t.Parallel()` fans them
across cores. The hasher registry they read is only mutated by the
non-parallel `Test_registerHasher`, so this is race-free.
- **`services/release`** — `TestRelease_Update`/`TestRelease_createTag`
slept `6x time.Sleep(2s)` only to cross the 1-second `CreatedUnix`
boundary. Replaced with an advancing mocked clock (`timeutil.MockSet`),
making the timestamp assertions deterministic and removing the real
waits.
---
This PR was written with the help of Claude Opus 4.8
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Updates `github.com/urfave/cli/v3` to
[v3.9.0](https://github.com/urfave/cli/releases/tag/v3.9.0) and removes
the renovate pin now that
[urfave/cli#2319](https://github.com/urfave/cli/pull/2319) (the `-c`
help flag parsing fix) is merged.
v3.9.0 prepends the default command name to the root command's args,
which broke the old `Root().Args()` check in `isValidDefaultSubCommand`.
It now uses the command's own `Args()`.
Behavior change: `./gitea web <extra-positional-arg>` now errors with
`unknown command` instead of starting the web server and ignoring the
trailing arg. `web` takes no positional args, so this is stricter (and
arguably more correct) input handling. The intended `./gitea bad-cmd`
rejection is unchanged.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Removes redundant/obsolete WebKit prefixes:
- `-webkit-mask-*` — duplicate the unprefixed `mask-*` siblings already
present; every supported browser handles unprefixed CSS Masking
longhands.
- `-webkit-overflow-scrolling: touch` — a no-op outside iOS Safari <13.
Browser floor (all support unprefixed `mask`): Chrome 120+, Safari
15.4+, Firefox 53+, and PaleMoon/Goanna (verified: unprefixed `mask`
longhands implemented unconditionally in UXP).
---
This PR was written with the help of Claude Opus 4.8
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
At a 512m heap the CI Elasticsearch GC-thrashes under the jobs' memory
pressure and goes unresponsive, flaking `test-unit` (ES indexer tests
time out) and `test-mysql` (the ES-backed issue indexer blocks the
per-test queue flush). Raise the heap to 1g and disable ML + the startup
GeoIP download.
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
Bump the pinned `giteabot` action to the
[`v1.0.3`](https://github.com/go-gitea/giteabot/releases/tag/v1.0.3)
release in both `giteabot.yml` and `giteabot-backport.yml`. v1.0.3 moves
label/state queries off the search API on top of the existing retry
logic.
---
This PR was written with the help of Claude Opus 4.8
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
In dev mode `/api/swagger` returned HTTP 500 (`Failed to locate local
path for managed asset URI: css/swagger.css`): the backend synthesised
asset keys from the Vite entry name instead of reading the manifest,
which only worked by coincidence and broke once a source file name
diverged from its entry name.
This keys the manifest by its source path (e.g. `web_src/js/index.ts`)
and resolves entries directly — hashed `file` in prod, dev-server source
in dev. A new `AssetCSSLinks` helper renders a JS entry's stylesheet
`<link>` tags from the manifest (the entry's CSS plus the CSS of its
statically-imported chunks).
Fixes: https://github.com/go-gitea/gitea/issues/37830
Fixes: https://github.com/go-gitea/gitea/pull/37832
Fixes: https://github.com/go-gitea/gitea/pull/37876
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: prakhar0x01 <prakharporwal2004@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
After posting a comment the page reloads via fetch-action. Clicking
"Close Issue" before the form re-initializes triggers a native form
submit, which navigates to the raw JSON redirect response
(`{"redirect":...}`) instead of the issue, so "Reopen Issue" never
appears and the test times out (observed on Firefox in CI).
Wait for the comment button to become disabled — which only happens once
the form re-initializes — before clicking "Close Issue".
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
- Update `github.com/alecthomas/chroma/v2` to `v2.25.0`.
- Migrate `github.com/dlclark/regexp2` to `/v2` (incorporates
https://github.com/go-gitea/gitea/pull/37664); drop the renovate pin.
- Replace the unmaintained `github.com/dimiro1/reply` (the last consumer
of `regexp2` v1 in our own code) with a small built-in reply parser for
incoming mail.
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Nicolas <bircni@icloud.com>
The modernc SQLite driver (default since
https://github.com/go-gitea/gitea/pull/37562) returns `SQLITE_BUSY` once
the busy timeout is reached, unlike mattn which waited indefinitely.
`TestResourceIndex` fires many concurrent `NewIssue` writers, but SQLite
serializes all writers, so they queue on a single `BEGIN IMMEDIATE`
write lock. Under `-race` (modernc is much slower) the goroutines at the
back of the queue exceeded the hardcoded 5s test timeout, producing
`database is locked (5) (SQLITE_BUSY)`.
Changes:
- Reduce the concurrent inserts from 25 to 10. Since SQLite serializes
writers, the extra goroutines only deepen the busy-lock queue without
adding coverage. 10 still exercises concurrent index allocation while
cutting the test's `-race` runtime ~3x (2.76s to 0.86s locally).
- Share the busy-timeout constant: export `DefaultSQLiteBusyTimeout`
(20s, the production default) and reference it from the test engine
instead of the hardcoded `5000`.
Observed flake:
https://github.com/go-gitea/gitea/actions/runs/26394082930/job/77690496092
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
`TestAPIRepoMigrate` migrated from
`https://github.com/go-gitea/test_repo.git`, so it required internet
access, was slow, and could hit GitHub rate limits.
It now clones a local fixture repo (`user2/repo1`) served by the
`onGiteaRun` test server, split into two subtests:
- `Permitted` (`AllowLocalNetworks=true`) — the success/permission
cases, cloning the local repo.
- `DisallowedHost` (`AllowLocalNetworks=false`) — the private-IP
rejection cases.
The split is needed because those two settings are mutually exclusive.
The clone address is built from the live listener (`u`) so it can't
drift from the bound host/port. The permission matrix and
disallowed-host assertions are unchanged.
Test is now roughly 2.5 times as fast with while asserting the same as
before without a GitHub dependency.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Reduces CI minutes consumption by narrowing the `files-changed` filters.
- DB matrix (`pgsql`/`mysql`/`mssql`/`unit`) now runs only on real
backend changes. `test-sqlite` stays gated on `actions`, so it remains
the smoke check that validates CI-infra changes (composite-action edits,
workflow edits, renovate action-pin bumps) without spinning up the full
matrix.
- Fix the `templates` filter: the SVG template linter is
`tools/lint-templates-svg.ts`, so the `tools/lint-templates-*.js` glob
matched nothing.
- Add missed paths: `tsconfig.json` and
`tools/generate-svg-vscode-extensions.json` to `frontend`,
`eslint.json.config.ts` to `json`, and
`.github/actions/docker-dryrun/**` to `docker`.
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Elasticsearch JVM heap defaults to ~50% of detected host RAM, typically
way too much for our little tests and it starved the other runner
processes from memory.
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
- Adds `make lint-shell`. uses local `shellcheck` if its version
matches, otherwise runs the pinned image via docker or podman
- `.shellcheckrc` disables the most annoying rules
- Fixes findings across existing scripts
Fixes: #37648
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
1. Split the psql matrix jobs into composite actions. Matrix jobs that
can skip do not work with required checks on GitHub because skipped and
unskipped emit different job names (GitHub bug
https://github.com/orgs/community/discussions/9141).
2. Dedupe node and go setup steps into composite actions
Currently test-psql branch protection is disabled, will re-enable when
merging this.
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Adds Playwright e2e coverage for five high-value workflows, each driven
through semantic locators with API-based setup:
- comment on and close an issue
- publish a release
- star and watch a repository
- create a pull request from the compare page
- fork a repository
Also passes `autoInit: false` in existing tests that only exercise
DB-backed units (issues, reactions, milestones, projects, events),
skipping an unused initial commit to speed up their setup and reduce
parallel git contention.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Critical path ~25:42 → ~19:56 (−22%), ~0% CI minutes.
- `test-pgsql` shards 2-way. Branch protection: replace `test-pgsql`
with `test-pgsql-shards (1)` + `test-pgsql-shards (2)`; `test-unit`,
sqlite/mysql/mssql unchanged — pgsql dominates the critical path.
- `test-unit` runs `bindata` then `bindata gogit` sequentially.
cache-seeder pre-warms the race-instrumented test compile cache and the
integration test binary so PR jobs warm-start.
- Cache writes restricted to cache-seeder; PR jobs use
`actions/cache/restore`. Defends against PR cache poisoning and frees
the 10 GB cap from PR churn.
- `go-cache` action: dropped the `cache-name` input. One gobuild cache,
one golangci-lint cache. Seeder lint job restores but doesn't save
gobuild, so only one writer populates it.
- `tools/test-integration.sh` shards the integration binary via
`-test.list`; `TestMain` short-circuits DB init in list mode.
`TestAPILFSNotStarted` / `TestAPILFSLocksNotStarted` switched to
`test.MockVariableValue` — latent `setting.LFS.StartServer` global-state
leak uncovered by sharding.
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Indented (4-space) code blocks were emitted by goldmark's default
renderer as plain `<pre><code>` without the `code-block-container`
wrapper that the JS `initMarkupCodeCopy` keys on. As a result, only
fenced code blocks received the copy button. Register
`ast.KindCodeBlock` with a renderer that produces the same wrapper as
the highlighting renderer so both syntaxes get the button.
Extends `TestMarkdownFencedCodeBlock` to assert the wrapper is emitted
for indented blocks (and that HTML inside is escaped).
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Fixes two recurring CI failures:
1. `cache-seeder.yml` lint-backend missing a `make generate-go` before
linting with `TAGS=bindata`, and `pull-compliance.yml` lint-on-demand
failing its post-step pnpm cache save when no pnpm-using conditional
step runs.
2. Drops `cache: pnpm` from lint-on-demand and adds `make generate-go`
to cache-seeder's lint job.
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Drop the broad `tools/*.{js,ts}` globs from the `frontend` filter so
edits to CI-only or backend helper scripts in `tools/` stop triggering
frontend and e2e jobs. Only `tools/generate-svg.ts` is kept.
Also renames `tools/lint-pr-title.js` to `.ts` for consistency, drops
the empty root `*.js` glob, fixes stray indentation in the `dockerfile`
filter and adds missing `setup-node`.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
The truncated `ActionRunner` struct in
`AddCancellingSupportToActionRunner` declares only the new
`HasCancellingSupport` column. When xorm's `SyncWithOptions` compares it
against the live `action_runner` table, every index/constraint absent
from the local struct is a candidate for removal.
Walking [xorm v1.3.11
sync.go:250-266](https://gitea.com/xorm/xorm/src/tag/v1.3.11/sync.go#L250-L266):
- `IndexType` indices skip the drop when `IgnoreIndices ||
IgnoreDropIndices` — already covered.
- `UniqueType` indices skip the drop only when `IgnoreConstrains` —
**not** set in #37275, so the existing `UNIQUE` on `token_hash` (and any
other uniques) would be dropped on upgrade.
Adding `IgnoreConstrains: true` matches v333's pattern and preserves the
existing unique constraints. Spotted by @wxiaoguang in
https://github.com/go-gitea/gitea/pull/37275#discussion_r3254168680.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
`act/workflowpattern` in runner is only consumed by Gitea and dead code
there. Move it to this repo. Use `modules/glob` for glob pattern match.
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Adds [zizmor](https://docs.zizmor.sh/) to `make lint-actions` with
`--min-confidence=medium`. Fixes the remaining findings:
- Pin floating-tag service images in `pull-db-tests.yml` to
`tag@sha256:digest`
- Move `github.ref` / `github.ref_name` (and surrounding secrets/step
outputs for consistency) out of `run:` into `env:`
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Enables Renovate's `dockerfile` manager so the base images in
`Dockerfile` and `Dockerfile.rootless`
(`docker.io/library/golang:1.26-alpine3.23`,
`docker.io/library/alpine:3.23`) get tracked alongside the other
dependencies. Updates are grouped under "docker dependencies" and follow
the existing weekly schedule.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Add two rules to `AGENTS.md` for recurring issues.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
`UpdateLog` short-circuits on `len(Rows)==0` before honoring `NoMore`,
so a final empty `UpdateLog{NoMore:true}` never runs `TransferLogs`. The
task's `dbfs_data` rows are then never moved to log storage and never
deleted.
Fix: let `NoMore=true` with no new rows fall through to `TransferLogs`.
Bail when the runner has outrun the server (`Index > ack`) even with
`NoMore`, since archiving a log with a gap is worse than retrying.
Always call `WriteLogs` so `offset==0` bootstraps an empty DBFS file in
the no-output case (otherwise `TransferLogs` would fail at `dbfs.Open`).
Fixes: https://github.com/go-gitea/gitea/issues/37623
Ref: https://gitea.com/gitea/runner/pulls/952
Ref: https://gitea.com/gitea/runner/pulls/950
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Enable `gomodUpdateImportPaths` so Renovate rewrites import paths (e.g.
`foo/v2` → `foo/v3`) across the repo when bumping Go modules across
major versions.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
- Replace fomantic `search` code with minimal first-party code
- Added a small fix to vertically align search box and search button
- Manually tested all search forms.
- Add `errorName` helper, similar to `errorMessage`.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Action runs, jobs and steps have 8 statuses but the UI only showed 5
(from the commit status api) for the latter two. Align all 8 to GitHub
as closely as possible:
- waiting — `octicon-circle` (hollow circle), gray
- blocked — `octicon-blocked` (slashed circle), yellow
- running — `gitea-running` (rotating spinner), yellow
- cancelled — `octicon-stop` (gray), was `octicon-x` (red)
Descriptions also aligned with GitHub:
- "Has started running" → "In progress"
- "Has been cancelled" → "Cancelled after {dur}"
- "Has been skipped" → "Skipped"
Fixes: https://github.com/go-gitea/gitea/issues/32228
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Replace the [slow `goheader` linter](https://github.com/denis-tingaikin/go-header/issues/70) with a
custom check.
Local go lint time is down from 247s to 32s. 6 new files that were
previously undetected because of `//go:build ignore` are fixed. The exit
code of the make target preserves the golangci-lint exit code, if
present.
Also refactors and consolidates the linting targets.
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
1. Pin all makefile go deps to exact version, renovate will bump them in the future
2. Bump all deps and golangci-lint and fix all new issues, most are from modernize
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
- fix detection of Makefile tools and group them separately
- Enable `go.mod` `go` directive bumps, schedule it at any time and
exempt it from the release-age delay
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
- make `scale-unlimited/declaration-strict-value` cover fill and stroke
- add new color vars for color series in gitgraph
- move most rule disablement to per-line
- remove dead highlight colors since https://github.com/go-gitea/gitea/pull/34948
- move stylelint config to ts now that the linked issue is fixed
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
1. Sync `RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS` with the recent
`renovate.json5` change (#37537) — the npm group now runs `make svg
nolyfill`, but the workflow allowlist still only matched `^make
(tidy|svg)$`, so the post-upgrade task was being rejected.
2. Bump the cron from daily at 01:00 UTC to hourly at :23, matching the
cadence of Mend's hosted Renovate App. Hourly gives sub-hour
responsiveness to dependency-dashboard checkbox interactions and
PR-close reactions; the `:23` offset avoids the GHA scheduler congestion
at multiples of 15.
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Run `nolyfill` as a renovate post-upgrade step alongside `make svg`, so
npm dep bumps keep `pnpm.overrides` in sync.
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Fixes#37446.
The job-status resolver in `checkJobsOfCurrentRunAttempt` only
considered `needs` and job-level concurrency when transitioning jobs out
of `Blocked`. When something drove the resolver against a run blocked
solely by workflow-level concurrency — for example, a sibling run in the
same group entering the queue and triggering `EmitJobsIfReadyByRun` —
the run's job silently became `Waiting` while another run still held the
concurrency group, and the runner could pick it up, defeating the
concurrency guarantee.
The fix bails out of the resolver when the run's latest attempt is still
blocked by run-level concurrency. `checkRunConcurrency` re-evaluates
when the holding run finishes.
Covered by a unit test
(`Test_checkJobsOfCurrentRunAttempt_RunLevelConcurrencyKeepsJobsBlocked`
in `services/actions/job_emitter_test.go`) that sets up a Running holder
attempt and a Blocked sibling attempt in the same concurrency group
directly in the DB, calls `checkJobsOfCurrentRunAttempt`, and asserts
the blocked job stays `Blocked`. Fails on master, passes with the fix.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Drops `github.com/olivere/elastic/v7` (unmaintained) and replaces it
with a small in-house wrapper that speaks the Elasticsearch REST API
directly via `net/http`. The subset used by Gitea (`_cluster/health`,
`_bulk`, `_doc`, `_delete_by_query`, `_refresh`, `_search`, `HEAD`/`PUT`
index) is stable across the targeted servers, so no client library is
needed.
**Targets tested**
- Elasticsearch 7, 8, 9
- OpenSearch 1, 2, 3
**Why not `go-elasticsearch`?**
The official client enforces an `X-Elastic-Product` server-identity
check that OpenSearch deliberately fails, which would force shipping a
transport shim to defeat it. Going direct over `net/http` removes that
fight along with several MB of transitive deps (`elastic-transport-go`,
`go.opentelemetry.io/otel{,/metric,/trace}`, `auto/sdk`, `easyjson`,
`intern`, `logr`, `stdr`).
Replaces: #30755
Fixes: https://github.com/go-gitea/gitea/issues/30752
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
1. Make the content area stretch the box, enabling text selection to
start over empty space.
2. Disable linter for markdown, it can never produce lint errors, this
hides the unnecessary lint gutter on markdown files.
3. Verified all languages linter enablement, all accurate.
4. Refactor `getLinterExtension` to not rely on file extensions.
5. Include jsonc/json5 extensions in regex.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Make the watch, star, and fork buttons in the repo header consistent for
logged-out users:
- Apply the same look to all three buttons (number labels
included), instead of only the action button being grayed.
- Clicking any of them while logged out now leads to the login page
(with a redirect back) instead of being inert.
- Split the per-button markup out of `header.tmpl` into a dedicated
`templates/repo/header/` folder (`fork.tmpl`, `star.tmpl`,
`watch.tmpl`).
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Replaces Dependabot with Renovate. The new setup:
- One PR per ecosystem (GitHub Actions, Go modules + Makefile go-tool
pins, npm, Python via uv, Nix flake), opened weekly on Mondays with a
5-day release-age cooldown. Vulnerability PRs ship next-day via daily
cron + Renovate's `vulnerabilityAlerts` schedule bypass.
- All `uses:` action refs SHA-pinned with patch-level version comments
(same format as #36971, which this supersedes);
`helpers:pinGitHubActionDigests` keeps future bumps in that format.
- `renovatebot/github-action` runtime image pinned via the
upstream-recommended `RENOVATE_VERSION` env + magic comment +
`customManagers:githubActionsVersions` preset, so Renovate keeps the pin
updated.
- Custom regex manager tracks the `*_PACKAGE ?= <import-path>@<version>`
lines in `Makefile` (golangci-lint, swagger, actionlint, etc.) and
groups them into the same Go PR via `matchDatasources: ["go"]`.
- Post-upgrade tasks regenerate `assets/go-licenses.json` (`make tidy`)
and the SVG sprite (`make svg`), gated by an env-level command
allowlist.
- Replaces the standalone `cron-flake-updater` workflow — Renovate's nix
manager tracks `flake.nix` inputs and produces the same `flake.lock`
bump PRs on the regular weekly schedule.
- npm and gomod-replace pins live in `renovate.json5` only;
`updates@17.16.3` reads them from there too, so the standalone
`updates.config.ts` is gone and one source of truth covers both tools.
Fixes: https://github.com/go-gitea/gitea/issues/33386
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Cache includes go, lint and unittests. Integration tests with their
standalone binaries are uncacheable with their current architecture.
Every Go job uses a new composite action (`.github/actions/go-cache`)
that restores and saves the Go module cache, a shared build cache, and
the golangci-lint cache. A `cache-seeder` workflow runs on `push: main`
to pre-populate those slots; PRs read them via GitHub's default-branch
fallback, so the common case is warm from the first commit.
Also dropped `-coverprofile` from `test-unit` (it silently disabled Go's
test result cache), and `-race` from `test-pgsql` and `test-mysql` (kept
on `test-unit` and `test-sqlite`).
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
`make test-sqlite#TestName` was much too slow, suggest `go test`. Also
added a similar instruction for js tests.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
- fix markup attention block regressions on 2 colors
- added new color "priority" color for important severity in markup
- all message-box style, and error form elements use monochrome text
- tweaked and improved action logs colors
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
The `events › logout propagation` e2e test ([example
flake](https://github.com/go-gitea/gitea/actions/runs/24878089698/job/72839454932))
was racing the SSE connection setup: if page2's SharedWorker had not
finished registering its messenger by the time page1 triggered logout,
the event was silently dropped and page2 stayed on the authenticated
page.
Wait 500ms after verifying page2 is signed in, before triggering the
logout from page1, so the SharedWorker has time to register. Comment
points at a cleaner future fix (expose a ready attribute on the page)
that will also work for the planned WebSocket SharedWorker.
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Adds points to `AGENTS.md` how to run single tests because AIs get these
wrong too often (either they trigger the whole suite or run into other
errors).
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Removes CSS rules that have zero usages across templates, Go source,
JS/TS/Vue, and `options/`. Each selector was cross-checked for runtime
additions (Fomantic JS, library classes) before removal.
A few rules with no current usages are kept as symmetric pairs of
heavily-used classes likely to be needed:
- `.ui.bottom.attached.header` / `.ui.bottom.attached.message` — pair
with the widely-used `top.attached` variants
- `.ui.warning.header` / `.ui.warning.segment` — warning-themed variants
of error-themed classes that are kept
- `.btn.small` — size variant alongside the kept `.btn.tiny`
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
- add pr-review e2e test
- speed up most tests by logging in via POST to avoid the login form,
login form is still exercised in a dedicated test
- speed up most tests be removing post-test cleanup, unnecessary because
each repo is created with a unique name
- misc parallelization and api call reduction
- total suite runtime is about the same as before
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Clean up the fomantic helpers that nothing inside fomantic depends on.
Manually tested all functionality.
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Fix#36859
Replace live third-party API calls in migration tests with a
fixture-based HTTP mock server. Fixtures are committed so tests run
offline by default; live recording is gated per service on an API-token
env var.
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Extend the issue context popup beyond markdown. Any link rendered with
the `ref-issue` class now gets the popup, which covers commit titles and
issue titles everywhere they appear (repo home, commits list, blame,
branches, graph, PR commits, issue/PR pages, compare, …). For surfaces
that synthesize links without markdown autolinking (dashboard activity
feed, pulse page, commit merged-PR line), opt in by adding
`data-ref-issue-container` on a parent (or `ref-issue` on the link).
- Use `html_url` from the backend payload instead of synthesizing links
client-side
- Fetch outside the component, stateless, with a per-URL cache
- Small hover delay so passing over a link doesn't fire a request
- Drop the loading state (shifted layout)
- Make both links in the tooltip work; prevent nested tooltips
- Fix feed title `<a>` width so the tooltip only shows on link hover
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Fail the vite build on any rolldown warnings when `NODE_ENV=test` is
set. This gate is set on the CI `make frontend` steps (compliance and
e2e workflows) and on the local `make test-e2e` target, so warnings fail
the build both in CI and when running e2e tests locally. Regular `make
frontend` / production builds are unaffected.
Example output:
```
[plugin test-warning-injector] first synthetic warning
[plugin test-warning-injector] second synthetic warning
transforming...✗ Build failed in 14ms
error during build:
Build failed with 1 error:
[plugin fail-on-warnings]
Error: 2 warnings present
at PluginContextImpl.buildEnd (vite.config.ts:50:13)
...
```
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
## Problem
Workflow-level concurrency groups were evaluated — and jobs were parsed
— before the run was persisted, so `run.ID` was `0` and `github.run_id`
in the expression context resolved to an empty string. Expressions like:
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
```
collapsed to `<workflow>-` on every push event (`head_ref` is empty on
push), so `cancel-in-progress` cancelled in-progress runs across
**unrelated branches**, not just the current one.
Reproduced on a 1.26 instance:
- push to `master` → `ci` run starts
- push to `feature-branch` → the `master` run gets cancelled
GitHub Actions' documented semantic: on push events `github.run_id` is
unique per run, so the group is unique → no cancellation; on PR events
`github.head_ref` is the source branch → cancellation is per-PR.
## Fix
Insert the run **before** parsing jobs or evaluating workflow-level
concurrency, so `run.ID` is populated in time for every expression that
reads `github.run_id` — not just the concurrency group, but also
`run-name`, job names, and `runs-on`.
`jobparser.Parse` now runs inside the `InsertRun` transaction, after
`db.Insert(ctx, run)`. Workflow-level concurrency evaluation runs next
and only mutates `run` in memory. All concurrency-derived fields
(`raw_concurrency`, `concurrency_group`, `concurrency_cancel`) plus
`status` and `title` are persisted in a single final `UpdateRun` at
end-of-transaction — one `INSERT` + one `UPDATE` per run in both the
concurrency and non-concurrency paths (matches pre-branch parity, one
fewer `UpdateRepoRunsNumbers` `COUNT` than the interim state).
`GenerateGiteaContext` now sets `run_id` from `run.ID` unconditionally;
every caller passes a persisted run.
**Verification**: tested end-to-end on a 1.26 deployment. Before the
patch, two successive `ci` pushes (one to master, one to a feature
branch) cross-cancelled each other. After the patch, the same pushes —
in both orders (master→branch, branch→master) — run to completion
simultaneously across 15+ runs with zero cancellations.
**Regression tests** in `services/actions/context_test.go`:
- `TestEvaluateRunConcurrency_RunIDFallback` — unit check that
`EvaluateRunConcurrencyFillModel` resolves `github.run_id` from
`run.ID`.
- `TestPrepareRunAndInsert_ExpressionsSeeRunID` — full-flow check: calls
`PrepareRunAndInsert` with `${{ github.run_id }}` in both `run-name` and
the concurrency group, then asserts the persisted `Title`,
`ConcurrencyGroup`, and `RawConcurrency` contain / survive the run's ID.
Re-ordering `db.Insert` relative to either parse or concurrency eval
fails this test.
## Relation to #37119
[#37119](https://github.com/go-gitea/gitea/pull/37119) also moves
concurrency evaluation into `InsertRun` but keeps it **before**
`db.Insert`, then tries to populate `run_id` only when `run.ID > 0` —
which is still `0` at that call site, so the cross-branch leak would
survive that PR as written. This PR fixes the ordering so that `run.ID`
is actually populated at eval time, and broadens it to cover parse-time
expression interpolation too.
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Replaces `@silverwind/vue3-calendar-heatmap` with an inlined SVG
implementation. Renders pixel-identically to `main`, drops the
`onMounted` legend viewBox workaround, and uses tippy's
`createSingleton` for the hover tooltip. Adds an e2e test for tooltip
display.
This is a prereq for migrating tippy.js to
[floating-ui](https://github.com/floating-ui/floating-ui) to avoid
having two tooltip libs active.
<img width="861" height="168" alt="image"
src="https://github.com/user-attachments/assets/99343cf6-6e09-42c7-a80d-63dbf33cf56a"
/>
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Enable full TypeScript `strict` mode and fix issues discovered during
this refactor. Introduced a `errorMessage` helper function to cleanly
extract a error messages from the `unknown` type.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (claude-opus-4-7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Moves the manifest patching from `closeBundle` to `writeBundle`. Thrown
errors in `writeBundle` work correctly and exit the build.
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Verified locally with 50 runs, averaging 9 seconds per local test suite
run. Total suite took 15s.
`--with-deps` is needed because webkit's dependencies are not
pre-installed on GHA runners (as opposed to firefox/chrome which are
preinstalled).
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Fixes GHSA-3xc5-wrhm-f963 (credential exposure on HTTP redirects).
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Introduces a frontend external-render framework that runs renderer
plugins inside an `iframe` (loaded via `srcdoc` to keep the CSP
`sandbox` directive working without origin-related console noise), and
migrates the 3D viewer and OpenAPI/Swagger renderers onto it. PDF and
asciicast paths are refactored to share the same `data-render-name`
mechanism.
Adds e2e coverage for 3D, PDF, asciicast and OpenAPI render paths, plus
a regression for the `RefTypeNameSubURL` double-escape on non-ASCII
branch names.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Use `golangci-lint fmt` to format code, replacing the previous custom
formatter tool. https://github.com/daixiang0/gci is used to order the
imports.
`make fmt` performs ~13% faster while consuming ~57% less cpu while
formatting for me.
`GOFUMPT_PACKAGE` is gone because it's using the builtin package from
golangci-lint.
Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
The `Run As Username` field on the install page was a `readonly` input
that looked editable but wasn't, confusing users. Style `readonly`
inputs with a subtle background, matching other frameworks.
Fixes: #37174
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Remove CSS rules whose HTML classes/IDs are no longer referenced in any
template, Go source, or JavaScript/TypeScript file:
- `.archived-icon`: removed from templates in c85bb62635
- `.bottom-line`: removed from blame rendering in 9c6aeb47f7
- `.commit-status-link`: removed from templates in f3c4baa84b
- `.instruct-toggle`: removed from templates in 75e85c25c1
- `.runner-new-text`, `#runner-new`: never referenced outside CSS
- `.ap-terminal`: stale, asciinema-player uses `.ap-term`, still not
needed
- `.scrolling.dimmable.dimmed`: dimmer stand-in never adds this class
- `.markup span.align-center/align-right/float-left/float-right`: never
produced by any renderer, sanitizer strips class attributes
- `.markup ul.no-list`, `.markup ol.no-list`: same as above
---
This PR was written with the help of Claude Opus 4.6
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
When running `golangci-lint` without `GOEXPERIMENT=jsonv2`, a lint error
`import 'encoding/json' is not allowed` is seen.
All other files in the module that import `encodings/json` have
`//nolint` already, so add it.
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Replace `rollup-plugin-license` and `wrap-ansi` with
[`rolldown-license-plugin`](https://github.com/silverwind/rolldown-license-plugin),
a zero-dependency plugin with async parallel I/O and built-in word
wrapping.
- Removes `rollup-plugin-license` (pulls in `lodash`, `moment`) and
`wrap-ansi` from the dependency tree
- License build time reduced by ~40% (370ms vs 640ms)
- Added e2e test for `licenses.txt`
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
1. Filter out errors that contain `chrome-extension://` etc protocols
2. Extract filtering into its own function and test it
3. Fix the `window.config.assetUrlPrefix` mock, guaranteed to end with
`/assets`
4. Remove useless `??` and `?.` for properties that always exist
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Follow-up to #37078.
- Use Unicode Control Pictures](U+2400-U+2421) to render C0 control characters
- Make it work in diff view too
- Replace escape warning emoji with SVG
- Align escape warning button with code lines
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Keep `swagger` and `external-render-helper` as a standalone entries for
external render.
- Move `devtest.ts` to `modules/` as init functions
- Make external renders correctly load its helper JS and Gitea's current theme
- Make external render iframe inherit Gitea's iframe's background color to avoid flicker
- Add e2e tests for external render and OpenAPI iframe
---------
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Add a new e2e test for toggling issue reactions via the reaction picker
dropdown.
Add `aria-label` attributes to improve reaction accessibility:
- Add `aria-label="Reaction"` to the reaction picker dropdown
- Add `role="group"` with `aria-label="Reactions"` to the reactions
container, giving it a semantic identity for screen readers
- Include the reaction key in each reaction button's `aria-label` (e.g.
`+1: user1, user2`) so screen readers announce which reaction a button
represents
E2e test improvements:
- Simplify `randomString` to use `Math.random` instead of `node:crypto`
- Replace `generatePassword` with a static password, remove unused
`clickDropdownItem`
- Enable `fullyParallel: true` and `workers: '50%'` in Playwright config
- Run both chromium and firefox in all environments (not just CI)
- Parallelize `login` and `apiCreateRepo` setup where possible
- Use dedicated test user in `user-settings` test for concurrency safety
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Wrap `zip.NewReader` errors in NuGet `ParsePackageMetaData` and
`ExtractPortablePdb` as `ErrInvalidArgument` so invalid packages return
HTTP 400 (Bad Request) instead of 500 (Internal Server Error).
Add integration test for multipart/form-data NuGet upload path (used by
`dotnet nuget push`) which was previously untested.
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Desaturate all structural grey colors in the dark theme from blue-grey
(H≈210°, S≈12-15%) to near-monochrome (H=220°, S=6%), using `#1e1f20` as
the page background color.
All colors preserve their original HSL lightness values. Semantic colors
(primary accent, named colors, diff, alerts, badges, brand) are
unchanged.
Motivation: The previous blue tint looked bad (kind of green-ish) on
certain screens and I think a near-monochrome color is more neutral
because its closer to being an inversion of the light theme.
Before and after:
<img width="280" alt="Screenshot 2026-04-02 at 00 18 38"
src="https://github.com/user-attachments/assets/544c71b9-fdaf-4222-822c-c5b87bc5b76d"
/>
<img width="280" alt="image"
src="https://github.com/user-attachments/assets/5d6de5d0-05c6-4a49-a649-063da4d136ce"
/>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
- Update all JS deps
- Regenerate SVGs
- Add new eslint rules from unicorn
- Update typescript config for 6.0, remove deprecated options in favor
of `strict` with disablements, remove implicit dom libs.
- Set vite log level during `watch-frontend` to `warn` to avoid
confusing URLs or HMR spam from the dev server to keep the log concise.
Overridable via `FRONTEND_DEV_LOG_LEVEL`.
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Update all non-locked Go dependencies and pin incompatible ones.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
- Replace monaco-editor with CodeMirror 6
- Add `--color-syntax-*` CSS variables for all syntax token types,
shared by CodeMirror, Chroma and EasyMDE
- Consolidate chroma CSS into a single theme-independent file
(`modules/chroma.css`)
- Syntax colors in the code editor now match the code view and
light/dark themes
- Code editor is now 12px instead of 14px font size to match code view
and GitHub
- Use a global style for kbd elements
- When editing existing files, focus will be on codemirror instead of
filename input.
- Keyboard shortcuts are roughtly the same as VSCode
- Add a "Find" button, useful for mobile
- Add context menu similar to Monaco
- Add a command palette (Ctrl/Cmd+Shift+P or F1) or via button
- Add clickable URLs via Ctrl/Cmd+click
- Add e2e test for the code editor
- Remove `window.codeEditors` global
- The main missing Monaco features are hover types and semantic rename
but these were not fully working because monaco operated only on single
files and only for JS/TS/HTML/CSS/JSON.
| | Monaco (main) | CodeMirror (cm) | Delta |
|---|---|---|---|
| **Build time** | 7.8s | 5.3s | **-32%** |
| **JS output** | 25 MB | 14 MB | **-44%** |
| **CSS output** | 1.2 MB | 1012 KB | **-17%** |
| **Total (no maps)** | 23.3 MB | 12.1 MB | **-48%** |
Fixes: #36311Fixes: #14776Fixes: #12171
<img width="1333" height="555" alt="image"
src="https://github.com/user-attachments/assets/f0fe3a28-1ed9-4f22-bf25-2b161501d7ce"
/>
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Remove the experimental strip types check and `NODE_VARS` mechanism from
the Makefile, as Node.js 22.18.0+ has native TypeScript type stripping
support.
https://nodejs.org/en/blog/release/v22.18.0 was released 8 months ago
and has now trickled into all major Linux distros like Alpine 3.23+.
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Update golangci-lint from v2.11.2 to v2.11.4 and fix new `modernize`
lint warnings:
- Use `strings.Builder` instead of string concatenation in loop
(`evaluator.go`)
- Use `atomic.Int64` instead of `int64` with atomic free functions
(`logchecker.go`, `timer_test.go`, `integration_test.go`)
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>