- agent-defs.js: add Kimi (Long Context Analysis, cyan) and Perplexity
(Real-time Research, pink) with world positions at (-10,-10) and (10,-10)
- agents.js: add 3D geometric bodies for both agents — Kimi as an
octahedron with orbital rings, Perplexity as an icosahedron with
scanning tori; idle/active/dormant animations driven by agent state;
restrict Timmy mood derivation to workshop agents only
- hud-labels.js: show specialization and last-task summary in inspect
popup; export setLabelLastTask() for WS updates
- websocket.js: handle agent_task_summary messages; call setLabelLastTask
on job_completed events
- world-state.ts: add kimi and perplexity to initial agentStates; restrict
_deriveTimmy() to workshop agents only
- event-bus.ts: add AgentExternalEvent type for external agent state changes
- events.ts: handle agent:external_state bus events, broadcast agent_state
and agent_task_summary WS messages
Fixes#11
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.