josh f118c179cd Preserve case in !rt token input
The !rt token is case-sensitive and often contains capitals, but the
input CSS lowercased typed characters visually (misleading) and the
placeholder "abcd" implied lowercase-only. Server-side validation and
loginWithToken() already preserved case — only the UI was wrong.

- Drop text-transform: lowercase from the input
- Placeholder abcd -> aB3d
2026-09-12 01:04:06 -04:00
2026-09-12 01:04:06 -04:00

electric-cherry

Web app that manages a fleet of T5 Plutonium servers running under Komodo. Successor to push_scripts.sh — same job (push shared GSC scripts, run beta tests, restart empty servers, track deployments) with a live UI, real audit diffs, and a hard pause when the IW4MAdmin !rt token goes stale.

Stack

  • SvelteKit (adapter-node) + TypeScript
  • SQLite via better-sqlite3 (replaces script_metadata.json as the source of truth)
  • Server-sent events for live pipeline / auth-state / server-status streams
  • Runs as a single Komodo-managed container on the same host as the game servers, with /root/zombies bind-mounted in

Layout

  • src/lib/server/db/ — schema, migrations, better-sqlite3 handle
  • src/lib/server/fleet/ — file walking, push/beta engines
  • src/lib/server/integrations/ — Komodo, IW4MAdmin, !rt token state
  • src/lib/server/pipeline/ — sweep loop, event bus, worker singleton
  • src/routes/api/ — REST + SSE endpoints
  • src/routes/ — UI pages (dashboard, deployments, betas, per-server)
  • docker/ — Dockerfile, entrypoint, docker-compose
  • komodo/ — Komodo stack definition
  • scripts/ — legacy JSON importer, fixture seeder
  • tests/ — vitest unit tests

Local dev

Windows or macOS — no /root/zombies on disk, so seed a fixture tree first.

npm install
npm run seed:fixture

# Point env at the fixture (PowerShell)
$env:SHARED_SCRIPTS = "$PWD/test-fixtures/zombies/shared/scripts"
$env:SERVERS_ROOT   = "$PWD/test-fixtures/zombies/t5"
$env:DB_PATH        = "$PWD/data/cherry.db"

npm run dev
# open http://localhost:3000

The !rt modal will block deployments until you paste a valid token. In local dev you can bypass it for exploration by leaving IW4M_ADDRESS unset and calling sweep() in a test that force-transitions the auth state (see tests/unit/sweep.test.ts).

Tests

npm test

Covers push (add/update/skip), beta lifecycle (open → rollback, open → promote, conflict blocks), sweep (frozen / manual branches), and IW4M login/status parsing (fetch mocked).

Deploy to the Komodo host

  1. Build the image once locally or on the host:

    docker compose build
    
  2. Import the shape of the stack into Komodo using komodo/stack.toml (or copy the compose file into a Komodo stack).

  3. First boot triggers the legacy import: if /root/zombies/script_metadata.json exists and /data/cherry.db is empty, docker/entrypoint.sh runs scripts/import-legacy.ts before starting the server. The source JSON gets renamed to .migrated.

  4. Load the app on the LAN or over tailscale (no web-app auth by design). Paste an !rt token to unfreeze the pipeline.

What still lives in the shell script

Nothing that's needed at runtime. Move push_scripts.sh to archive/ once you've run a side-by-side parity check between the shell's dry-run and the app's POST /api/push { dryRun: true }.

Non-goals

  • Editing GSC files in-browser. Do that in your editor of choice; the web app only cares about what's on disk in SHARED_SCRIPTS.
  • Multi-user auth. LAN/tailscale scoping is the security model.
  • Two-way sync with script_metadata.json. The importer runs once. If the shell script is ever used again after that, it'll write to the JSON file and the web app won't see it.

References into the old script

Every port carries a // Ports push_scripts.sh:NN comment pointing back to the original for the parts that had non-obvious behavior. Grep those if a behavior seems wrong — the shell script is the reference implementation until the parity check passes.

S
Description
Electric Cherry manages T5 and T6 Plutonium Zombies servers through its own host agents.
Readme
30 MiB
Languages
TypeScript 65.7%
Svelte 23.2%
Python 9.9%
JavaScript 0.5%
Shell 0.5%
Other 0.2%