Commit Graph

18 Commits

Author SHA1 Message Date
Ramis 549895292c fix(frontend): stop screen MediaStreamTrack on PodView unmount
room.disconnect() removes the participant from LiveKit but doesn't stop
the underlying OS capture. Without track.stop() the screen share indicator
keeps running after Leave. beatRef already had cleanup; add the same for
screenTrackRef.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
2026-06-27 17:34:37 -07:00
Kartikeya 59e201fe93 fix(frontend): refresh pod list on leave so a deleted pod doesn't linger
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:23:47 -07:00
Kartikeya 891d4b12bd feat(livekit): close the room when a pod is deleted
DELETE /api/pods/:id now also calls closeRoom (RoomServiceClient.deleteRoom)
to end the live LiveKit room and disconnect anyone connected. PodView listens
for RoomEvent.Disconnected and returns the user to the pod list, so a deleted
pod cleanly kicks everyone out instead of stranding them in a dead room.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:22:07 -07:00
Kartikeya e29fabc3f1 fix(livekit): stable identity + room auto-cleanup
Use the member name as the LiveKit identity (was random per join) so a
refresh/rejoin replaces the existing session instead of leaving a ghost
participant in the room. Set roomConfig on the token (emptyTimeout 60s,
departureTimeout 20s) so empty rooms and departed participants clean up
promptly. Pods map 1:1 to a deterministic room name, so joins reuse the
same room rather than spawning new ones.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:13:32 -07:00
Yahya Alhinai b1b0761973 chore: format repo and fix lint config 2026-06-28 00:09:48 +00:00
Kartikeya 0f3b55a4f9 feat: one-click join + live pod presence
Join UX: click a member's name to join directly, or type a name and "Join"
(adds to roster + joins) — removes the redundant dropdown step. "Add" still
adds to the roster without joining.

Presence: new GET /api/presence (LiveKit RoomServiceClient) reports who's
connected per pod. The pod list polls it and shows a "N in room" badge plus a
green dot on members currently connected, so people can see active pods and jump in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:46:47 -07:00
Kartikeya 8271188cf1 feat(frontend): live room view, beat connectivity test, session resume
- PodView now shows LIVE LiveKit participants (updates as people join/leave,
  active-speaker highlight) instead of the static roster — no refresh needed.
- "Play beat" button publishes a generated 4/4 beat into the room so every
  participant hears the same audio (speaker lights up) — a real connectivity test.
- "Share my screen" is now a deliberate button; joining only connects to the
  room (fast/reliable), so a denied/slow screen prompt no longer fails the join.
- Session persisted in sessionStorage with auto-reconnect, so a refresh keeps
  you in the room instead of dropping back to the pod list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:37:32 -07:00
Kartikeya 7ff750ad5e harden: address adversarial review of Pods CRUD
Backend: atomic create with insert-retry-on-duplicate-key (removes slug
TOCTOU race + wrong 400s), resilient per-index creation so a unique-index
failure can't silently drop the constraint or block seeding, idempotent
race-safe seeding via $setOnInsert, type validation + size caps on all pod
fields/members, removeMember no-ops without a write, /api/outcome guarded.
Frontend: per-pod busy state (one mutation no longer disables every card),
joined pod derived from the list (can't go stale), create keeps inputs on error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:02:40 -07:00
Kartikeya 4ddc59be08 fix(frontend): self-destroying service worker to avoid stale UI during dev
The precaching PWA SW was serving an old bundle after deploys (stale UI).
Switch to selfDestroying so it unregisters + clears caches on all clients;
deploys are now always fresh. Re-add a tuned PWA before the demo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 15:52:24 -07:00
Kartikeya 5a03ad4d6b feat: Mongo-backed Pods with full CRUD + member management
Pods are persisted in MongoDB and CRUD'd via /api/pods (list/create/get/
update/delete + add/remove member). Shared Pod reshaped to a persisted entity
(members: string[], description, timestamps) + PodInput. Backend seeds Demo/
Frontend/Backend Pods on first run (Squad -> Pod rename). Frontend replaces
hardcoded teams with live data: PodCard (member chips add/remove, inline edit,
delete, join) + CreatePodForm; App fetches+mutates via API. Removes teams.ts/
TeamCard; gitignores test artifacts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 15:49:05 -07:00
Ramis b4c0107e82 chore(frontend): update demo teams — Zander out, Shakthi in
Demo Pod: remove Zander, keep Karti/Yahya/Ramis/Shakthi
Frontend Squad: replace Zander with Ramis

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFbfi4Cmb7BY75Wtne7bZn
2026-06-27 15:43:33 -07:00
Kartikeya e26961d526 feat(frontend): team-browsing GUI with pod view
Replace the single join form with a richer UI: team cards (members as
avatars, repo, description), a member picker, and a post-join PodView showing
pod members (you highlighted) plus a PodMan panel with a slot for live
intervention cards. Adds Avatar/TeamCard/PodView components.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 15:17:07 -07:00
Kartikeya fc3752bbe9 feat(frontend): dev mock-join fallback when LiveKit unconfigured
If the backend returns the placeholder LiveKit URL, skip the real connect and
screen capture and drop into the post-join state (with a DEV MODE banner) so
the connected UI is developable without LiveKit creds or HTTPS. Real joins
also guard getDisplayMedia behind isSecureContext.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:56:04 -07:00
Kartikeya 6bf359f4d4 fix: restore CORS + align frontend with /api/token endpoint
The canonical-architecture rewrite dropped app.use(cors()) and moved the
token route to POST /api/token ({room,identity,name}), but the frontend
still called the old /pods/:id/token — causing "Failed to fetch" in the
browser. Re-add CORS and update fetchPodToken to the new contract.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:53:26 -07:00
Kartikeya 48d8ed8aaf feat(frontend): team + engineer dropdowns on join screen
Replace free-text name/pod inputs with select-only dropdowns (pick a team,
then yourself from its members) for fast R&D iteration. Demo teams live in
lib/teams.ts until pods are persisted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:44:18 -07:00
Kartikeya da5b2622b2 Integrate canonical architecture: two-process backend + LiveKit agent
Promote all 12 staged canonical files from docs/generated/files/ to their
live paths, creating the full PodMan architecture:

Backend:
- server.ts: HTTP service (token mint, sync-PR, outcome recording, /health, WS relay)
- agent.ts: worker joining LiveKit room, grabbing screenshare frames at ~1fps
- agent/podman.ts: orchestrator loop (vision -> collision detection -> intervention)
- env.ts: flat env var accessors replacing nested stub
- vision/gemini.ts: JPEG -> Gemini vision -> EngineerContext (real implementation)
- collision/detector.ts: fused vision+GitHub collision detection (the moat)
- github/client.ts: Octokit wrapper with caching + sync PR creation
- memory/store.ts: extended with recordObservation/recordCollision/recordIntervention/recordOutcome helpers
- memory/vectors.ts: stub for Voyage+Atlas vector recall (Loop A)
- memory/policy.ts: stub for intervention policy gate (Loop B)
- voice/live.ts: stub for Gemini Live TTS voice output

Shared:
- messages.ts: LiveKit data-channel wire protocol (DataMessage, InterventionOutcome, TeamModel, LocalGitReport)
- index.ts: re-exports messages module

Frontend:
- livekit/useScreenPublish.ts: hook for joining pod and publishing screenshare
- livekit/useInterventions.ts: hook for receiving collision cards and responding
- lib/api.ts: fetchToken + postOutcome HTTP helpers

Database:
- database/init.ts: MongoDB Atlas collections + indexes + vector search index

Infra:
- infra/.do/app.yaml: DO App Platform spec (static_site + service + worker)

Retire stubs superseded by canonical decomposition:
- backend/src/index.ts (replaced by server.ts)
- backend/src/intervention/engine.ts (logic now in agent/podman.ts)
- backend/src/livekit/token.ts (token minting now in server.ts)

Install missing dependencies: @livekit/rtc-node, sharp, mongodb, ws, @types/ws

Type error fixes:
- vision/gemini.ts: use MediaResolution.MEDIA_RESOLUTION_LOW enum value (not string literal)
- agent/podman.ts: wrap SuggestedActionKind into { kind: action } SuggestedAction object

All packages pass pnpm -r typecheck and pnpm -r build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:27:14 -07:00
Kartikeya ca0ca37adc feat(frontend): scaffold PWA with LiveKit join flow
Vite + React + TS + Tailwind v4, installable PWA. Join-pod UI that fetches a
LiveKit token from the backend, connects to the pod room, and publishes screen
+ mic so PodMan can watch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:17:08 -07:00
Kartikeya 1bb15724c6 Initial monorepo scaffold
Set up top-level structure (backend, frontend, database, infra, shared,
docs) with .gitkeep placeholders, root README, and .gitignore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:00:20 -07:00