2026-10-15 01:14:44 +02:00
|
|
|
# CLAUDE.md — MeWeb quick reference
|
|
|
|
|
|
|
|
|
|
Read `AGENT.md` first and cite `PATTERNS.md` for code rules. This file holds commands, the map and the pitfalls.
|
|
|
|
|
|
|
|
|
|
## Commands
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
dotnet build src/MeWeb.Desktop/MeWeb.Desktop.csproj
|
|
|
|
|
dotnet run --project src/MeWeb.Desktop
|
|
|
|
|
dotnet run --project src/MeWeb.Server # ASPNETCORE_URLS=http://127.0.0.1:5481
|
|
|
|
|
dotnet run tools/setup.cs -- --group jdk # pinned JDK 21 into tools/jdk
|
|
|
|
|
dotnet run tools/setup.cs -- --group packaging # pinned nfpm into tools/packaging
|
|
|
|
|
dotnet build src/MeWeb.Android/MeWeb.Android.csproj \
|
|
|
|
|
-p:JavaSdkDirectory=$PWD/tools/jdk/linux-x64/jdk-21.0.12+8 -p:AndroidSdkDirectory=$HOME/Android/Sdk
|
|
|
|
|
dotnet run --project tools/Screenshots -- dist/screenshots [en,it,...]
|
2026-10-15 01:18:13 +02:00
|
|
|
dotnet run tools/strings.cs -- check # every language against English
|
|
|
|
|
dotnet run tools/strings.cs -- set Key values.json # one key, every language at once
|
|
|
|
|
dotnet run tools/languages.cs # regenerate data/languages.json from CLDR
|
2026-10-15 01:14:44 +02:00
|
|
|
dotnet publish src/MeWeb.Desktop -c Release -r win-x64 --self-contained -p:PublishSingleFile=true \
|
|
|
|
|
-p:IncludeNativeLibrariesForSelfExtract=true -p:EnableCompressionInSingleFile=true
|
|
|
|
|
dotnet publish src/MeWeb.Desktop -c Release -r osx-arm64 --self-contained
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The Android workload installs into the user SDK (`dotnet workload install android`); the system SDK in `/opt/dotnet`
|
|
|
|
|
is root-owned, so CI uses the runner user's own `~/.dotnet` (passolo's `tools/release.sh` pattern).
|
|
|
|
|
|
2026-10-15 01:24:11 +02:00
|
|
|
## Repository, CI and the variables they read
|
|
|
|
|
|
|
|
|
|
| Name | Where | What |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
| `GITEA_URL` | shell, optional | Gitea base URL for `tools/gitea/*.sh`; default `https://git.thepra.dev` |
|
|
|
|
|
| `GITEA_ORG` | shell, optional | organisation; default `Arasaka` |
|
|
|
|
|
| `GITEA_REPO` | shell, optional | repository for `set_secret.sh`; default `MeWeb` |
|
|
|
|
|
| (git credential store) | `~/.git-credentials` | the only Gitea authentication the scripts use: `git credential fill` for `git.thepra.dev` |
|
|
|
|
|
| `MEWEB_KEYSTORE_B64` | Actions secret | the Android keystore, base64 (`tools/gitea/set_secret.sh`) |
|
|
|
|
|
| `MEWEB_KEYSTORE_PASS` | Actions secret | its password (store and key share it), alias `meweb` |
|
|
|
|
|
| `GITEA_TOKEN` | Actions, automatic | the job token; `release.sh` uses it as `RELEASE_TOKEN` to create the release and attach files |
|
|
|
|
|
| `VERSION`, `COMMIT` | job env | written by `.gitea/scripts/prepare.sh` from `Directory.Build.props` and the commit |
|
|
|
|
|
| `MEWEB_KEYSTORE` | release step | a temporary file in `$RUNNER_TEMP` decoded by `.gitea/scripts/android.sh`, removed on exit |
|
|
|
|
|
|
|
|
|
|
`build.yml` runs on every push to `master`; `release.yml` on a `v*` tag (publishes the Gitea release) or by hand
|
|
|
|
|
(`publish: false` builds every platform and deploys the server only). Both run on the Arasaka org runner `nuvola`,
|
|
|
|
|
user `gitea-runner`, home `/var/lib/gitea-runner`: `tools/sdk.sh` installs the SDK from `global.json` into its
|
|
|
|
|
`~/.dotnet` (the system SDK in `/opt/dotnet` is older and root-owned), and the JDK, nfpm and the Android SDK are
|
|
|
|
|
cached in `~/.cache/meweb`. There is deliberately no `pull_request` trigger: the runner is the production box.
|
|
|
|
|
|
|
|
|
|
The server's one-time root setup is `deploy/max/setup.sh` (user `meweb`, `/var/www/meweb.arasaka.software`,
|
|
|
|
|
`/etc/meweb/meweb.env`, the unit, the runner's sudoers line, the certificate, nginx), run on the box through
|
|
|
|
|
`arasaka.software`'s `tools/max/run.sh`.
|
|
|
|
|
|
|
|
|
|
The Android release key: alias `meweb`, certificate SHA-256
|
|
|
|
|
`5f52cff4f52f4e0b6da6cd044bfceaf78d1d42db24f2470602db7f19cbfdf846`. Never regenerate it.
|
|
|
|
|
|
2026-10-15 01:14:44 +02:00
|
|
|
## Map
|
|
|
|
|
|
|
|
|
|
| Path | What |
|
|
|
|
|
|---|---|
|
|
|
|
|
| `src/MeWeb.Shared` | `Endpoints.cs` (routes and hosts), wire contracts, `MeWebJsonContext`, generated `BuildInfo` |
|
2026-10-15 01:18:13 +02:00
|
|
|
| `src/MeWeb.App` | Avalonia views and view models, `Services/Localizer.cs` (+ `{s:Tr Key}`), `Strings/<code>.json`, `Resources/Colors.axaml` |
|
2026-10-15 01:14:44 +02:00
|
|
|
| `src/MeWeb.Desktop` | desktop head (`meweb` executable), Windows manifest |
|
|
|
|
|
| `src/MeWeb.Android` | Android head (`software.arasaka.meweb`), resources, manifest |
|
|
|
|
|
| `src/MeWeb.Server` | `meweb.arasaka.software`: `/api/info`, `/api/ip` |
|
2026-10-15 01:18:13 +02:00
|
|
|
| `data/languages.json` | 113 languages: code, autonym, English name, `rtl`, `reviewed` or `draft` |
|
2026-10-15 01:14:44 +02:00
|
|
|
| `tools/setup.cs` + `setup.json` | pinned build tools |
|
|
|
|
|
| `tools/Screenshots` | headless renders of every view in every language |
|
|
|
|
|
| `branding/` | the icon (SVG source, PNG, ICO) |
|
|
|
|
|
|
|
|
|
|
## Pitfalls
|
|
|
|
|
|
|
|
|
|
- **Avalonia 12 Android head:** `[Application] MainApplication : AvaloniaAndroidApplication<App>` plus a non-generic
|
|
|
|
|
`AvaloniaMainActivity`; the main view comes through `IActivityApplicationLifetime.MainViewFactory`, checked before
|
|
|
|
|
`ISingleViewApplicationLifetime`.
|
|
|
|
|
- **`ApplicationVersion` must be an integer**: computed from `Version` through separate `VersionMajor/Minor/Patch`
|
|
|
|
|
properties; one nested property function left it unevaluated (`XA0003`).
|
|
|
|
|
- **A headless Avalonia session does not end on its own** while the pulse animation runs: the screenshot tool calls
|
|
|
|
|
`Environment.Exit(0)` after dispatching.
|
|
|
|
|
- **The macOS apphost is ad-hoc signed by the .NET 10 SDK even on Linux** (`LC_CODE_SIGNATURE` present); Apple
|
|
|
|
|
Silicon refuses unsigned arm64 code, so never strip it.
|
|
|
|
|
- **The Windows single-file publish drops native `.pdb` files beside the exe**; only `meweb.exe` ships.
|