From 5c10ea511291550e56640c6dd2c1003eda76f6e8 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 3 Jun 2026 23:54:32 +0200 Subject: [PATCH] fix: serve companion-tokens at the user-scoped path the web UI calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Account → Companion always showed "No computers connected" even with a companion linked. The list/revoke routes were mounted under /api/projects/:projectId/companion-tokens, but the handlers are user-scoped (listCompanionTokensByUser, ignores projectId) and the web client calls the top-level /api/companion-tokens. Every request 404'd, so the query came back empty. Register the routes where the client actually calls them: GET /api/companion-tokens DELETE /api/companion-tokens/:tokenId Both still sit before the /api/* catch-all, so matching is unchanged. Server-only fix; the frontend already used the correct paths. --- server/index.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server/index.ts b/server/index.ts index d7032c6..68c02c3 100644 --- a/server/index.ts +++ b/server/index.ts @@ -353,9 +353,12 @@ app.post("/api/projects/:projectId/tasks/:taskId/run", h(handleRunTaskNow)); app.get("/api/projects/:projectId/tasks/:taskId/runs", h(handleGetTaskRuns)); // Companion tokens (laptop-side `zero` companion auth) — list + revoke only; -// tokens are minted by the device-authorization flow below. -app.get("/api/projects/:projectId/companion-tokens", h(handleListCompanionTokens)); -app.delete("/api/projects/:projectId/companion-tokens/:tokenId", h(handleRevokeCompanionToken)); +// tokens are minted by the device-authorization flow below. These are +// USER-scoped (a user manages every connected computer from Account → +// Companion, across all projects), so they live at the top level — NOT under +// /api/projects/:projectId — matching what the web client calls. +app.get("/api/companion-tokens", h(handleListCompanionTokens)); +app.delete("/api/companion-tokens/:tokenId", h(handleRevokeCompanionToken)); // Device-authorization login (`zero login`). start/poll are unauthenticated // (the CLI has no credential yet); info/approve/deny require a human session.