Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_016eTor2tpxKb4dXbd8RqnvZ
104 lines
4.9 KiB
Markdown
104 lines
4.9 KiB
Markdown
# Working on this repo with Claude
|
||
|
||
CI runs on **Gitea Actions** at `git.wallacenet.ca/devadmin/ProLibertateGames`
|
||
(workflows in `.github/workflows/`), publishing to Cloudflare Pages
|
||
(`plg.wallacenet.ca`). The workflow below was measured on the dev machine
|
||
(`~/ProLibertateGames`); it replaces the earlier GitHub-sandbox notes, which no
|
||
longer apply.
|
||
|
||
## Build, test and lint locally
|
||
|
||
Gradle works on the dev machine. Two environment variables are required: the
|
||
default JDK is 25, which Gradle 8.14 cannot use, and the Android SDK lives in the
|
||
home directory.
|
||
|
||
```
|
||
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
|
||
export ANDROID_HOME=$HOME/android-sdk # platform 34, build-tools 34.0.0
|
||
./gradlew testDebugUnitTest lintDebug assembleDebug
|
||
```
|
||
|
||
The Katan tests run in seconds; a clean build takes a few minutes. Run the full
|
||
suite, lint and `assembleDebug` before pushing: they are what CI runs. There is
|
||
no KVM, so no emulator; the engine and the UI logic are covered by unit tests
|
||
(see `docs/UI-catan.md`).
|
||
|
||
## Shipping: branch, PR, CI, merge
|
||
|
||
1. Branch from `dev`; before pushing, merge `origin/dev` in (it moves between
|
||
sessions).
|
||
2. Plain `git push` has no credentials. Use the Gitea token as a one-off header:
|
||
`git -c "http.extraheader=Authorization: token $(cat ~/.config/gitea/token)" push -u origin <branch>`.
|
||
3. Open the PR with `POST /api/v1/repos/devadmin/ProLibertateGames/pulls`
|
||
(same token, `Authorization: token ...`). CI (`ci.yml`) runs on the PR: build,
|
||
unit tests and Android lint; it publishes nothing. Poll
|
||
`/actions/runs` until it completes (about 7 minutes).
|
||
4. Merge with `POST .../pulls/N/merge {"Do":"merge"}`. The push to `dev` runs
|
||
`ci.yml` again and publishes the build (about 9 minutes).
|
||
|
||
## Merging is a shipping action
|
||
|
||
Both long-lived branches publish, so a merge is a release, not just an
|
||
integration:
|
||
|
||
- **`dev`** publishes a `v<series>.N-dev` build to
|
||
`https://plg.wallacenet.ca/dev/latest.json`, offered by the in-app updater to
|
||
anyone on the Dev channel.
|
||
- **`main`** runs `release.yml` and publishes a **production** release for
|
||
everyone on the Production channel. Confirm before merging to `main`.
|
||
`release.yml` runs `assembleDebug` only (no tests, no lint), so a `main`
|
||
release is only as verified as the `dev` build it replays.
|
||
|
||
## Katan
|
||
|
||
The island game is catalogue id `catan`, shown as **Katan**. It has two rule
|
||
sets chosen at setup: the base game (`docs/RULES-catan.md`) and Cities & Knights
|
||
(`docs/RULES-catan-ck.md`, code in `game/catan/CatanCk*.kt`, state behind
|
||
`CatanState.ck`, which is null in the base game). The screen is layered; see
|
||
`docs/UI-catan.md` before changing it.
|
||
|
||
## Bash output is filtered before it reaches the model
|
||
|
||
`.claude/settings.json` registers a `PreToolUse` hook on `Bash` that rewrites
|
||
each command through [rtk](https://github.com/rtk-ai/rtk): `git status` runs as
|
||
`rtk git status`, and rtk compresses the output. Write commands normally — the
|
||
rewrite is transparent and costs nothing to invoke.
|
||
|
||
Measured on this repo rather than quoted from rtk's README:
|
||
|
||
| Command | Raw | Filtered | Saved |
|
||
| --- | --- | --- | --- |
|
||
| `git diff HEAD~3` | 521 KB | 28 KB | 95% |
|
||
| `grep -rn "fun " app/src/main` | 117 KB | 19 KB | 84% |
|
||
| `find . -name "*.kt"` | 7.7 KB | 1.7 KB | 79% |
|
||
| `git log -20` | 20 KB | 5.3 KB | 74% |
|
||
| `git diff --stat` | 4.0 KB | 4.0 KB | 1% |
|
||
| `ls` of a single package | 50 B | 62 B | −24% |
|
||
|
||
The saving is all in the large outputs, which is the point — a full diff of a
|
||
few commits is otherwise most of a context window. Already-compact output grows
|
||
slightly, because rtk adds a header; at those sizes it does not matter. `rtk
|
||
gain` reports what the current session has actually saved.
|
||
|
||
Two limits are worth knowing. The `Read`, `Grep` and `Glob` tools are not
|
||
`Bash`, so they never reach the hook and are unaffected; a deliberate `rg` or
|
||
`find` in a shell *is* filtered. And filtering never truncates a file: `cat`
|
||
becomes `rtk read`, which was checked byte-for-byte against this repo's longest
|
||
Kotlin source (`GameSetupScreen.kt`, 946 lines) and came back identical. Commit
|
||
messages survive the rewrite intact, quotes and colons included. To bypass
|
||
filtering for one command, run `rtk proxy <cmd>`.
|
||
|
||
## rtk is reinstalled at the start of every session
|
||
|
||
The container starts empty, so `.claude/hooks/session-start.sh` installs rtk
|
||
before the session does anything. It pins `RTK_VERSION`, because the installer
|
||
otherwise asks `api.github.com` for the latest tag and the proxy answers 403 for
|
||
every repository except this one — the lookup fails and takes the install with
|
||
it. Bump that variable by hand.
|
||
|
||
The hook is written not to matter when it fails. Outside the sandbox it installs
|
||
nothing and just prints the command to run, since dropping a binary into
|
||
someone's `~/.local/bin` uninvited is not its business; if the download fails it
|
||
says so and exits clean. With rtk absent the rewrite hook no-ops, and the only
|
||
consequence is verbose output.
|