Cockpit: a button that points an open VS Code window at a project
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 0
- Avg merge
- 1h 21m
- Merged PRs (30d)
- 41
Description
Covers the developer's ask 1. Builds on #122 and #123.
## Decided by the developer
Intake, Bench turn `b2a64f4e/4`. The question was what "connect to a project" should mean, given that a browser cannot address a VS Code window. Answer:
> **points the VS Code window I already have open at that project**
with the free-text clarifications:
> "just targets the plugin to the bench project"
>
> "I open it myself. the plugin should just link to bench daemon"
So this is explicitly **not** launching an editor. The developer opens VS Code themselves. The button binds an already-running window to a project so the extension knows what it is following.
That rules out the `vscode://` deep-link mechanism and settles it on the daemon socket, which is already connected.
## The evidence
The extension is already holding an authenticated socket to the daemon (`editor/vscode/src/follow.ts`) and already ignores frames it does not recognise. The daemon already has the pattern for pushing something down `/events` that is a moment rather than state — that is what `{ type: "edit" }` is (#122, `server.ts`).
The cockpit already has a per-project header with a button in it, so there is a precedent spot rather than a new surface: `RosterGroup.tsx:74`, the `` carrying `hide-project`.
Today the extension infers its project purely from `insideWorkspace()` — the folders the window happens to have open (`editor/vscode/src/inside.ts`). That is implicit and cannot be corrected by the developer. This makes it explicit and overridable.
## What to build
- A button in the cockpit's project group header. Posts to a new daemon route naming the project.
- The daemon broadcasts it on `/events`, e.g. `{ type: "target", project }`.
- The extension, on receiving it, binds itself to that project and says so — the status bar is where it already reports its state (`status.ts`).
- The binding replaces the implicit workspace-folder inference for scoping, or narrows it. **Decide and document which**, because "I have two folders open and Bench targeted one" must have a defined answer.
- It must survive a daemon restart, or visibly stop claiming to be bound. The extension already reconnects; a binding that silently outlives the connection is worse than none.
## The failure mode to handle honestly
If no VS Code window is listening, the button does nothing. That was stated in the intake and accepted. It must not *look* like it worked — the cockpit should say whether any editor is listening, or the button should be absent when none is. A button that silently no-ops is the thing that makes people stop trusting a feature.
This implies the daemon needs to know whether an extension is connected at all. It can: `/events` sockets are already tracked in `wss.clients` (`server.ts`). Distinguishing an extension socket from a cockpit socket is new — a query parameter on connect is the cheap way.
## Acceptance criteria
- [ ] A button in the cockpit's project group header targets an open VS Code window at that project.
- [ ] The extension shows which project it is bound to.
- [ ] The binding survives a daemon restart, or the extension visibly drops it.
- [ ] With no editor connected, the cockpit does not present the action as having succeeded.
- [ ] The interaction between an explicit binding and the open workspace folders is documented in `docs/specs/2026-09-15-editor-follow.md` and is not left to be inferred from the code.
- [ ] The daemon can tell an extension socket from a cockpit socket, and cockpit sockets are unaffected by the new frame type.
- [ ] `pnpm typecheck`, `pnpm typecheck:editor` clean.
## Out of scope
- Launching a new VS Code window, or any `vscode://` deep link. Explicitly not what was asked for.
- Choosing *which* window when several are open and all have that project. Pick a rule, document it, move on.
- The sidebar view and badge — #128.
## Verification
```
pnpm typecheck
pnpm typecheck:editor
pnpm test
```
Manual and required: open VS Code, click the button in the cockpit, confirm the extension says it is bound. Then restart the daemon and confirm it either rebinds or says it is not bound.
## Blocked by
#128 is not a blocker, but they share the extension's status surface and are cheaper reviewed together.
Contributor guide
Research direction
Start with RosterGroup.tsx:74, server.ts, and editor/vscode/src/follow.ts, inside.ts, and status.ts to trace the cockpit button, daemon events, workspace inference, and status reporting. Read docs/specs/2026-09-15-editor-follow.md and run pnpm typecheck, pnpm typecheck:editor, and pnpm test. Done means the explicit binding behavior, restart handling, editor detection, and workspace interaction are documented and verified manually.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript, vscode
- Domain
- backend, developer-experience, frontend, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100