3.8 KiB
metin-release — CLI reference
Phase 1 commands. All subcommands share the top-level flags.
Top-level flags
| Flag | Description |
|---|---|
--version |
Print package version and exit. |
--json |
Emit only the JSON envelope on stdout (stderr may still carry logs). |
-v, --verbose |
Verbose stderr logging. |
-q, --quiet |
Suppress stderr logging entirely. |
Output envelope
Every command writes a JSON envelope on stdout:
{
"ok": true,
"command": "release inspect",
"status": "inspected",
"stats": { "...": "..." }
}
On failure:
{
"ok": false,
"command": "release inspect",
"status": "failed",
"error": { "code": "source_not_found", "message": "..." }
}
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Operator or validation error |
| 2 | Remote / network error |
| 3 | Signing or integrity error |
| 4 | Reserved (ERP sync, Phase 2+) |
release inspect
Scan a client source root and report file counts plus launcher/main-exe detection.
metin-release release inspect --source /path/to/client
No writes. JSON stats: source_path, file_count, total_bytes, launcher_present, main_exe_present.
release build-manifest
Wraps make-manifest.py to produce manifest.json for a source tree.
metin-release release build-manifest \
--source /path/to/client \
--version 2026.04.14-1 \
--out /tmp/release/manifest.json \
[--previous 2026.04.13-3] \
[--notes release-notes.md] \
[--launcher Metin2Launcher.exe] \
[--created-at 2026-04-14T12:00:00Z]
Override the wrapped script path via the METIN_RELEASE_MAKE_MANIFEST env var.
release sign
Wraps sign-manifest.py. Requires an absolute path to a chmod-600 raw 32-byte Ed25519 key.
metin-release release sign \
--manifest /tmp/release/manifest.json \
--key /home/you/.config/metin/launcher-signing-key \
[--out /tmp/release/manifest.json.sig]
Override the wrapped script path via METIN_RELEASE_SIGN_MANIFEST.
release diff-remote
HEADs every unique blob hash from a manifest against <base-url>/files/<hh>/<hash>.
metin-release release diff-remote \
--manifest /tmp/release/manifest.json \
--base-url https://updates.example.com
release upload-blobs
rsyncs the release directory (excluding manifest.json and .sig) to a target.
metin-release release upload-blobs \
--release-dir /tmp/release \
--rsync-target user@host:/var/www/updates/ \
[--dry-run] [--yes]
release promote
Pushes only manifest.json + manifest.json.sig to the target top-level — makes the new release live.
metin-release release promote \
--release-dir /tmp/release \
--rsync-target user@host:/var/www/updates/ \
[--dry-run] [--yes]
release verify-public
GETs manifest.json + manifest.json.sig from a public URL and verifies the Ed25519 signature. Optionally spot-checks random blobs with --sample-blobs N.
metin-release release verify-public \
--base-url https://updates.example.com \
--public-key <hex-or-path-to-hex-file> \
[--sample-blobs 5]
release publish
Composite: build-manifest → sign → stage blob tree → upload-blobs → promote → verify-public. Short-circuits on the first failure; the JSON envelope includes a stages array with {name, status, duration_ms, error?} per step.
metin-release release publish \
--source /path/to/client \
--version 2026.04.14-1 \
--out /tmp/release \
--key /home/you/.config/metin/launcher-signing-key \
--rsync-target user@host:/var/www/updates/ \
--base-url https://updates.example.com \
--public-key <hex-or-path-to-hex-file> \
[--previous ...] [--notes ...] [--launcher ...] \
[--created-at ...] [--sample-blobs N] \
[--yes] [--force] [--dry-run-upload]