diff --git a/cmd/bdrive/login.go b/cmd/bdrive/login.go index a8f69ef..ddb4a05 100644 --- a/cmd/bdrive/login.go +++ b/cmd/bdrive/login.go @@ -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 ` 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 }, } diff --git a/cmd/bdrive/login_test.go b/cmd/bdrive/login_test.go new file mode 100644 index 0000000..f70623a --- /dev/null +++ b/cmd/bdrive/login_test.go @@ -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) + } + } + } +} diff --git a/plugin/skills/beardrive/SKILL.md b/plugin/skills/beardrive/SKILL.md index 6790e22..d410e36 100644 --- a/plugin/skills/beardrive/SKILL.md +++ b/plugin/skills/beardrive/SKILL.md @@ -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 []` 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 ` and `bdrive import ` recreates it there as a new project (`--name` overrides; target must be empty); connect folders with `bdrive init --project `. 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 `, 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 ` — 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 ` — 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 ` 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 `/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) |