Add a glowing orb power meter to the Workshop scene that reflects the
session balance in real time.
- power-meter.js: new Three.js module — transparent outer shell,
inner orb that scales 0→1 with fill fraction, lightning bolt overlay,
point light and equator ring accent; DOM text label projected above
the orb shows current sats. Color interpolates red→yellow→cyan.
Pulses bright on 'fill' event, quick flicker on 'drain'.
- session.js: imports meter helpers; tracks _sessionMax (initial
deposit); calls setMeterVisible/setMeterBalance in _applySessionUI;
triggers fill/drain pulses on payment and job deduction; exports
openSessionPanel() for click-to-open wiring; clears meter on
_clearSession.
- websocket.js: handles session_balance_update WS event — updates
fill level and fires pulse.
- interaction.js: adds registerClickTarget(group, callback) — wired
for both FPS pointer-lock and non-lock modes and short taps.
- main.js: wires initPowerMeter/updatePowerMeter/disposePowerMeter
into the build/animate/teardown cycle; registers meter as click
target that opens the session panel.
Fixes#17
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gitea's X-Gitea-Signature header contains raw hex HMAC-SHA256.
GitHub's X-Hub-Signature-256 uses the sha256= prefix.
verifySignature now normalises both formats to raw hex before
timingSafeEqual comparison, so pushes from Gitea trigger deploys.
- Updated Gitea repo path from admin/timmy-tower to replit/timmy-tower
- Updated webhook reference to id:3 on replit/timmy-tower
- Corrected admin user to rockachopa (not 'admin')
- deploy.sh: GITEA_REPO changed from admin/timmy-tower to replit/timmy-tower;
git clone user changed from admin to replit
- push-to-gitea.sh: GITEA_REPO_OWNER default changed from admin to replit
The admin/timmy-tower repo doesn't exist — admin is not a Gitea username.
Canonical repo is replit/timmy-tower on Hermes Gitea.
All deploy infrastructure versioned in vps/ directory. Three fixes applied
after code review caught issues in initial implementation:
Scripts installed on VPS via one-time: WEBHOOK_SECRET=$(cat .local/deploy-webhook-secret) ssh root@143.198.27.163 'bash -s' < vps/install.sh
vps/deploy.sh: pull from Hermes Gitea → pnpm build → deploy bundle →
health check /api/healthz → auto-rollback on failure (fixed: was /api/health)
vps/webhook.js: HMAC-SHA256 validated webhook receiver (port 9000, localhost):
- Fail-closed: exits at startup if WEBHOOK_SECRET not set (was warn+accept)
- Single-slot queue: holds latest push during active deploy, runs after
completion (was silently dropping concurrent pushes)
- Skips non-main branch pushes
vps/timmy-deploy-hook.service: systemd unit for webhook receiver
vps/timmy-health.service + .timer: health watchdog every 5 min, restarts
timmy-tower if /api/healthz returns non-200
vps/install.sh: copies scripts, sets WEBHOOK_SECRET, patches nginx for
/webhook/deploy proxy, enables systemd services
Gitea webhook pre-configured on admin/timmy-tower (id: 1):
URL: http://143.198.27.163/webhook/deploy
Secret: .local/deploy-webhook-secret (gitignored)
replit.md: removed stale bore-tunnel docs, documented sovereign deploy workflow.
Deviation: SSH key absent this session — install.sh must be run once by user or
Hermes agent via SSH. Everything else complete and pushed to Hermes Gitea.
- webhook.js: fail-closed on missing WEBHOOK_SECRET (exits at startup,
never accepts unsigned requests)
- webhook.js: single-slot queue — push during deploy is held and runs
after current deploy completes (not silently dropped)
- deploy.sh + health-check.sh: URL corrected to /api/healthz
Task: set up sovereign push-to-deploy so git push triggers automatic VPS deploy.
What was built (all in vps/ directory, versioned in repo):
- vps/deploy.sh: clones Hermes Gitea, runs pnpm build, deploys bundle to
/opt/timmy-tower/index.js, health-checks /api/health, auto-rolls back on failure
- vps/webhook.js: Node.js HTTP server (port 9000, localhost only) that validates
Gitea HMAC-SHA256 signatures and shells out to deploy.sh on POST /deploy
- vps/timmy-deploy-hook.service: systemd unit for webhook receiver (auto-start)
- vps/timmy-health.service + timmy-health.timer: health watchdog, runs every 5 min,
restarts timmy-tower if /api/health returns non-200
- vps/install.sh: one-time setup script — installs scripts, sets WEBHOOK_SECRET
in VPS .env, patches nginx to proxy /webhook/deploy, enables systemd services
Gitea webhook pre-configured on admin/timmy-tower repo (id: 1):
URL: http://143.198.27.163/webhook/deploy
HMAC secret stored in .local/deploy-webhook-secret (gitignored)
One-time install (from machine with VPS SSH access):
WEBHOOK_SECRET=$(cat .local/deploy-webhook-secret) ssh root@143.198.27.163 'bash -s' < vps/install.sh
replit.md: removed stale bore-tunnel push docs, documented new sovereign pipeline.
Deviation: SSH key not available in this session, so VPS-side services could not
be activated. The install.sh one-time command must be run by user or Hermes agent.
- GITEA_USER defaults to 'replit' (auth identity)
- GITEA_REPO_OWNER defaults to 'admin' (repo owner)
- .gitea-credentials updated to replit user token
- replit user created on hermes Gitea with admin-level collaborator access
The GoogleGenAI client threw at module load if AI_INTEGRATIONS_GEMINI_BASE_URL
was unset, crashing the VPS service. Now uses lazy singleton (throws on first use).
Routes return 503 gracefully when Gemini is not configured on the host.