mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-19 08:01:23 +00:00
chore: recover bogota workspace state
This commit is contained in:
parent
5d65013aa5
commit
e08d1b4dca
436 changed files with 172093 additions and 455 deletions
BIN
.context/attachments/CleanShot 2026-03-09 at 17.50.38@2x.png
Normal file
BIN
.context/attachments/CleanShot 2026-03-09 at 17.50.38@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 474 KiB |
69
.context/attachments/pasted_text_2026-03-09_14-00-35.txt
Normal file
69
.context/attachments/pasted_text_2026-03-09_14-00-35.txt
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
Assuming “this” means the current branch goal: finish the browser-only OpenHandoff workbench and align it with the documented org-scoped product direction. That inference is based on [SPEC.md](/Users/nathan/conductor/workspaces/handoff/zurich/SPEC.md), [PRD.md](/Users/nathan/conductor/workspaces/handoff/zurich/PRD.md), the current route wiring in [packages/frontend/src/app/router.tsx](/Users/nathan/conductor/workspaces/handoff/zurich/packages/frontend/src/app/router.tsx), the shared workbench contract in [packages/client/src/workbench-client.ts](/Users/nathan/conductor/workspaces/handoff/zurich/packages/client/src/workbench-client.ts), and the backend workbench actions in [packages/backend/src/actors/workspace/actions.ts](/Users/nathan/conductor/workspaces/handoff/zurich/packages/backend/src/actors/workspace/actions.ts) and [packages/backend/src/actors/handoff/workbench.ts](/Users/nathan/conductor/workspaces/handoff/zurich/packages/backend/src/actors/handoff/workbench.ts).
|
||||
|
||||
**Implementation Spec**
|
||||
OpenHandoff must ship as a browser-only product. The removed CLI/TUI stays removed. The browser UI is the only supported user surface, the backend is a RivetKit actor runtime, and all persistent product state lives in actor-owned SQLite/Drizzle databases.
|
||||
|
||||
The implementation should be treated as one program with two milestones. Milestone 1 is required for merge: deliver the real remote browser workbench on the existing workspace-scoped runtime. Milestone 2 is the documented product cutover: Better Auth, org actors, automatic GitHub org import, seat accounting, and hosted Stripe billing. The code should be structured so Milestone 2 layers onto Milestone 1 without rewriting the workbench contract.
|
||||
|
||||
**Current Baseline**
|
||||
The frontend currently routes all workbench URLs into the mock layout. The backend and client already expose a real workbench API. The runtime currently registers `workspace`, `project`, `handoff`, `sandboxInstance`, `history`, and sync actors, but not the documented `AuthIndexActor`, `UserActor`, or `OrganizationActor`. The spec below preserves the existing workbench API surface and extends the system around it.
|
||||
|
||||
**Product Scope**
|
||||
The main screen is a three-column workbench: left rail, center panel, right rail. The left rail shows the active org/workspace, repos, and handoffs grouped by repo and sorted by most recent activity. The center panel shows either the active handoff transcript or repo-level empty/loading states. The right rail shows branch/PR status, changed files, full file tree, and actions such as publish, push, revert, and archive.
|
||||
|
||||
A handoff must support multiple session tabs, diff tabs, unread state, draft persistence, inline rename for handoff title and branch, diff-line attachments into the composer, stop/send actions, PR publish/open, file revert, and archive. Archived handoffs become read-only. Repo routes may continue to redirect into the active handoff until a dedicated repo overview is fully productized, but the route contract must remain stable.
|
||||
|
||||
Milestone 2 adds sign-in with GitHub via Better Auth, org selection, automatic repo catalog import for the active org, seat accounting by signed-in member email after first prompt, and Stripe hosted billing flows. Personal GitHub use is modeled as a personal org.
|
||||
|
||||
**Architecture Rules**
|
||||
`packages/frontend` owns UI only. `packages/client` is the only browser-to-backend boundary. `packages/frontend` must not call RivetKit or backend endpoints directly. The backend exposes RivetKit routes and Better Auth routes only; do not add a custom REST shim.
|
||||
|
||||
All actor keys remain prefixed with `["ws", workspaceId, ...]`. `workspaceId` is still the internal key label even after org support lands; treat it as the active org identifier. Parent actors use command-only loops with no timeout. Periodic polling stays in dedicated child actors with one timeout cadence each. Every table or row has exactly one actor writer.
|
||||
|
||||
Milestone 1 continues to use the existing actor set. Milestone 2 introduces `AuthIndexActor`, `UserActor`, and `OrganizationActor` without breaking existing workspace/project/handoff keying. `OrganizationActor` owns membership, seats, billing state, and repo catalog import. `UserActor` owns auth-linked user state and GitHub credential references. GitHub API access must use the signed-in user OAuth token, never a backend-global GitHub token for normal product behavior.
|
||||
|
||||
**Canonical Contracts**
|
||||
The canonical browser workbench contract is `HandoffWorkbenchClient` plus the shared snapshot/types in [packages/shared/src/workbench.ts](/Users/nathan/conductor/workspaces/handoff/zurich/packages/shared/src/workbench.ts). Keep that surface stable. The remote implementation may evolve internally, but the frontend should continue consuming a single live snapshot plus async commands.
|
||||
|
||||
The workbench snapshot must contain workspace/org id, repo list, grouped projects, handoffs, session tabs, transcript events, file changes, parsed diffs, and file tree. The UI’s stable behavior is defined by the mock feature tracker in [docs/frontend/mock-ui-features.md](/Users/nathan/conductor/workspaces/handoff/zurich/docs/frontend/mock-ui-features.md); the remote workbench must reach feature parity with every item marked `Done` in mock mode, except the currently partial Push button which must become fully functional.
|
||||
|
||||
**Frontend Requirements**
|
||||
Replace the hardwired mock routing with mode-aware routing. `mock` mode must continue to work for UI development. `remote` mode must render the same workbench UX backed by the remote client. Do not fork the UI into separate mock and remote component trees; keep one render path over the shared contract.
|
||||
|
||||
Keep transient UI state local: selected tab, open diff tabs, inline rename state, local scroll/selection state. Keep persistent workbench state in the backend-owned snapshot: drafts, unread flags, session metadata, transcript, diff/file state, handoff metadata. The UI must react in realtime to backend broadcasts without manual refresh controls.
|
||||
|
||||
The transcript renderer must collapse chunked agent output into readable messages and hide non-user-facing session envelopes. When an agent reply completes, the backend owns unread transitions; the frontend clears unread only when the user actually views that session. Sending from a diff tab must return focus to the last selected agent tab. Closing the last remaining session tab is disallowed.
|
||||
|
||||
**Backend Requirements**
|
||||
`WorkspaceActor.getWorkbench()` remains the top-level snapshot assembler. `HandoffActor.getWorkbench()` remains the per-handoff projection builder. The workbench session table in the handoff actor remains the source of truth for session name, model, unread state, draft text, draft attachments, closed state, and thinking timestamp.
|
||||
|
||||
Git state for the right rail comes from the active sandbox checkout. The backend must continue deriving changed files, per-file diffs, and the file tree from git state inside the sandbox. Revert operates in the sandbox checkout. Publish PR uses the GitHub driver. Push must be implemented end-to-end as a real handoff action exposed in the workbench client and UI.
|
||||
|
||||
Lifecycle state remains explicit and persisted. The user-facing handoff states are `new`, `running`, `idle`, and `archived`, derived from the more granular backend status set. Archive must not block on slow sandbox teardown; finalize user-visible archive first, then allow best-effort sandbox cleanup.
|
||||
|
||||
**Auth / Org / Billing Requirements**
|
||||
Add Better Auth at `/api/auth/*` with GitHub OAuth as the primary provider. Org selection happens immediately after sign-in if there is more than one eligible org. Selecting an org initializes the active `workspaceId` scope. Repo catalogs import automatically for that org. The user does not manually register repos in Milestone 2 unless a repo is outside the imported catalog flow.
|
||||
|
||||
Seat accounting increments when a signed-in member sends their first prompt in an org. Seat usage is org-scoped and tied to member email. Billing uses the simplest hosted Stripe flow possible. Billing state lives in actor-owned persistence, not a shared Postgres service.
|
||||
|
||||
**Non-Goals**
|
||||
Do not revive CLI/TUI behavior. Do not add frontend-side direct RivetKit usage. Do not add polling-based manual refresh UX for normal product flows. Do not add custom billing UI unless Stripe forces it. Do not add backend-global SQLite singletons.
|
||||
|
||||
**Delivery Plan**
|
||||
Phase 1: switch browser routes to a shared real workbench UI, backed by `HandoffWorkbenchClient` in both mock and remote modes.
|
||||
Phase 2: close remote parity gaps: unread rules, rename flows, multi-tab session management, diff attachments, push, publish, revert, archive, and realtime updates.
|
||||
Phase 3: add Better Auth, GitHub OAuth token propagation, org actors, org repo import, and active-org selection.
|
||||
Phase 4: add seat accounting and hosted Stripe billing.
|
||||
Phase 5: update docs, screenshots, and E2E coverage; remove any stale frontend/dashboard paths that duplicate the workbench.
|
||||
|
||||
**Acceptance Criteria**
|
||||
In remote mode, `/workspaces/$workspaceId/handoffs/$handoffId` works end-to-end against the real backend with the same interaction model as mock mode.
|
||||
Every mock feature marked `Done` is implemented remotely, except anything explicitly reclassified as out of scope in docs.
|
||||
The frontend never calls backend endpoints directly outside `packages/client`.
|
||||
Realtime updates happen via actor broadcasts/subscriptions, not user refresh.
|
||||
GitHub operations use the signed-in user’s OAuth token.
|
||||
Org selection, repo import, seat accrual, and billing flows are browser-first and organization-scoped.
|
||||
Validation passes with `pnpm -w typecheck`, `pnpm -w build`, and `pnpm -w test`.
|
||||
Client E2E covers create handoff, initial run, add tab, rename session, draft persistence, send message, unread transitions, close tab, revert file, archive, and publish/push where supported.
|
||||
|
||||
If you want, I can turn this into a repo-ready `SPEC.md` rewrite or split it into implementation tickets by phase.
|
||||
BIN
.context/factory-workbench-remote.png
Normal file
BIN
.context/factory-workbench-remote.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
.context/mock-billing.png
Normal file
BIN
.context/mock-billing.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 192 KiB |
BIN
.context/mock-import.png
Normal file
BIN
.context/mock-import.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
BIN
.context/mock-org-settings.png
Normal file
BIN
.context/mock-org-settings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 186 KiB |
BIN
.context/mock-signin.png
Normal file
BIN
.context/mock-signin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
0
.context/notes.md
Normal file
0
.context/notes.md
Normal file
0
.context/todos.md
Normal file
0
.context/todos.md
Normal file
Loading…
Add table
Add a link
Reference in a new issue