fix(cli): stop pointing users at a device list that doesn't exist (BEA-13) (#63)

`bdrive logout` and the beardrive skill both told users the device token
"stays valid until it expires — revoke it from the hub's device list".
All three parts are false: there is no device list page or route, device
tokens carry no expiry field, and logout makes no server call at all — it
only rewrites the local settings file.

Both strings now say what is true. The CLI note moves to a package-level
`logoutNote` const so `login_test.go` can assert it, plus SKILL.md's logout
row, mentions neither a device list nor expiry.

Correcting the strings only; the real device list + revoke route touches
the `AuthProvider` seam and is filed separately.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Snow W. Lee (Sungwon)
2026-07-28 07:05:19 +09:00
committed by GitHub
co-authored by Claude Opus 5
parent 589be3a6de
commit eba6fe1a64
3 changed files with 45 additions and 2 deletions
+7 -1
View File
@@ -106,6 +106,12 @@ With no argument the remembered server is used, or ` + config.DefaultServer + `.
return c
}
// logoutNote is printed after every logout. It must stay honest: there is no
// device-list page and no revoke route on the hub, and device tokens carry no
// expiry (see internal/webapp/authlocal.go authToken) — logout only rewrites
// the local settings file. login_test.go guards the wording.
const logoutNote = "note: the token is only cleared locally — the server still accepts it, and there is no way to revoke it yet"
func logoutCmd() *cobra.Command {
var forget bool
c := &cobra.Command{
@@ -148,7 +154,7 @@ Your synced folders are untouched; this only affects this device's session.`,
if forget {
fmt.Println("forgot the remembered server (run `bdrive login <url>` to set a new one)")
}
fmt.Println("note: the device token stays valid on the server until it expires — revoke it from the hub's device list if needed")
fmt.Println(logoutNote)
return nil
},
}
+37
View File
@@ -0,0 +1,37 @@
package main
import (
"os"
"strings"
"testing"
)
// The hub has no device list and no revoke route, and device tokens never
// expire — so neither the CLI's logout note nor the skill may claim otherwise
// (BEA-13). Drop these asserts only when a real revoke surface ships.
func TestLogoutNoteClaimsNoRevokeSurface(t *testing.T) {
skill, err := os.ReadFile("../../plugin/skills/beardrive/SKILL.md")
if err != nil {
t.Fatalf("read SKILL.md: %v", err)
}
// Only the logout row: `bdrive share --expires` elsewhere is a real flag.
var logoutRow string
for _, line := range strings.Split(string(skill), "\n") {
if strings.HasPrefix(line, "| Sign this device out |") {
logoutRow = line
}
}
if logoutRow == "" {
t.Fatal("SKILL.md has no `Sign this device out` row — did it get renamed?")
}
for _, src := range []struct{ name, text string }{
{"logoutNote", logoutNote},
{"SKILL.md logout row", logoutRow},
} {
for _, claim := range []string{"device list", "expires"} {
if strings.Contains(strings.ToLower(src.text), claim) {
t.Errorf("%s mentions %q — no device list or token expiry exists", src.name, claim)
}
}
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ Use this skill whenever the user is working with the `bdrive` CLI: initializing
| Move a project to a different hub (cloud ↔ self-hosted) | `bdrive export [<folder>]` writes a portable `.tar.gz` of the whole project — every device's journal and every blob, so full history and authorship travel. Then `bdrive login <other-hub>` and `bdrive import <archive>` recreates it there as a new project (`--name` overrides; target must be empty); connect folders with `bdrive init --project <id>`. Sync first so the export is complete. |
| This device's identity | `bdrive whoami` |
| Sign this device in (once per device) | `bdrive login [url]` — bare form targets BearDrive Cloud (beardrive.ai): signing up there auto-creates a free personal workspace, no questions asked. Self-hosting teams pass their hub URL instead. Opens the sign-in page in a browser (sign-up available there); the terminal completes on its own and stores a per-device token. `--device` prints a code to approve from any browser (SSH/headless), and login falls back to that code flow automatically when there is no TTY (agent shells, CI) or no browser opens; `--status` shows server + account. Password reset: "Forgot password?" on the sign-in page (emailed via the server's SMTP config, or the link appears in the server log). **Switch hubs** with `bdrive login <new-url>`, then re-run `bdrive init` in each folder. |
| Sign this device out | `bdrive logout` — clears the saved token + account (folders untouched); `--forget` also drops the remembered server. The device token stays valid server-side until it expires — revoke it from the hub's device list to be sure. |
| Sign this device out | `bdrive logout` — clears the saved token + account (folders untouched); `--forget` also drops the remembered server. The token is only cleared locally: the hub still accepts it and there is no revoke yet. |
| Link a synced file for teammates | `bdrive url <file>` — prints the file's hub viewer URL (sign-in + project membership required; always the latest content). Computed locally, no network; `--sync` pushes first so a just-created file's link resolves immediately; no arg = the project home page. **After creating a shareable artifact (.md/.html/.csv/report/plan) in the shared folder, include this link in your reply** so teammates can open it. |
| Share a synced file publicly by URL | `bdrive share <file>` — prints a link anyone can open (HTML renders as a page, markdown rendered, PDFs inline; sandboxed; always the latest content; no account needed). `--expires 24h` for self-destructing links; `--list` / `--revoke <token-or-url>` to manage. Put generated reports in the shared folder, sync, then share. |
| Set up a project for a Claude Code team | `/beardrive:install` — installs the CLI, signs in, runs init (whole/shared folder), offers the two-file agent orientation (synced `<shared>/AGENTS.md` map + repo-root pointer), and registers agent sync hooks via `bdrive hooks install` (pull at turn start, push after edits, session-note stamping — for every detected platform, not just Claude) |