mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
Staleness today is age and only age: Insights.tsx's STALE_DAYS = 30 flags a fresh doc nobody reads and misses the one that costs a team — a doc edited last week describing code that moved yesterday. `bdrive stale` measures the other thing. It scans synced markdown for references to other synced files and reports every doc that links to something written after the doc itself. It is `bdrive grep` with a different per-file predicate, and keeps that command's whole posture: LoadProject not ResolveMount (a read must not enroll the device), a Stat-guarded store.Open (a read must not create a volume), no session, no flock, no network, safeField on everything printed. The one place it must not copy the obvious approach is dating a file. materialize never calls os.Chtimes, so a peer's January edit carries this device's mtime — on a freshly cloned machine every mtime is within seconds of every other, and mtime comparison would report nothing on exactly the machine that most needs the answer. Dates come from the journal: st.AllOps() folded to the max syncer.DisplayTime per path, which also drops a forged year-9999 stamp rather than dating that path to year 1 and flagging everything that links to it. Resolution is the filter — a URL, a ../ escape, a made-up path is silently ignored — so a .bdriveignore rule or a narrowed `bdrive scope` excludes a file here exactly as it excludes it from sync. Exit status is 0 whether or not anything is stale. grep's "1 means nothing found" convention inverts here: it would fail on a clean project, and this is advisory in the same sense the agent hook's context is. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
124 lines
3.4 KiB
Go
124 lines
3.4 KiB
Go
// bdrive is the BearDrive CLI: mount a folder, and its
|
|
// contents stay synchronized across devices and teammates through a
|
|
// BearDrive hub, with full per-file change history and offline support.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime/debug"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/runbear-io/beardrive/internal/config"
|
|
)
|
|
|
|
// version is set at release time via -ldflags "-X main.version=...".
|
|
// `go install …@vX.Y.Z` builds skip ldflags, so fall back to the module
|
|
// version Go stamps into the binary.
|
|
var version = "0.1.0-dev"
|
|
|
|
func resolvedVersion() string {
|
|
if version != "0.1.0-dev" {
|
|
return version
|
|
}
|
|
if bi, ok := debug.ReadBuildInfo(); ok && bi.Main.Version != "" && bi.Main.Version != "(devel)" {
|
|
return strings.TrimPrefix(bi.Main.Version, "v")
|
|
}
|
|
return version
|
|
}
|
|
|
|
func main() {
|
|
root := &cobra.Command{
|
|
Use: "bdrive",
|
|
Short: "BearDrive: a synced file system for AI agents",
|
|
Long: `bdrive — the BearDrive CLI. A mountable, offline-first, synced file
|
|
system for AI agents.
|
|
|
|
Mount any folder and BearDrive keeps it synchronized across your devices and
|
|
teammates through a BearDrive hub (bdrive serve — self-hosted or BearDrive
|
|
Cloud). Every change is journaled — you can always see which device and
|
|
author changed which file, and when. Files are real files on disk, so
|
|
everything keeps working offline; changes sync when the remote is reachable.`,
|
|
SilenceUsage: true,
|
|
Version: resolvedVersion(),
|
|
}
|
|
root.SetVersionTemplate("beardrive {{.Version}}\n")
|
|
root.AddCommand(
|
|
loginCmd(),
|
|
logoutCmd(),
|
|
initCmd(),
|
|
shareCmd(),
|
|
urlCmd(),
|
|
stopCmd(),
|
|
scopeCmd(),
|
|
grepCmd(),
|
|
staleCmd(),
|
|
forgetCmd(),
|
|
syncCmd(),
|
|
readLogCmd(),
|
|
hooksCmd(),
|
|
resumeCmd(),
|
|
autostartCmd(),
|
|
statusCmd(),
|
|
logCmd(),
|
|
restoreCmd(),
|
|
exportCmd(),
|
|
importCmd(),
|
|
webCmd(),
|
|
whoamiCmd(),
|
|
daemonCmd(),
|
|
versionCmd(),
|
|
)
|
|
if err := root.Execute(); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func versionCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "version",
|
|
Short: "Print the bdrive version",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
fmt.Println("beardrive", resolvedVersion())
|
|
},
|
|
}
|
|
}
|
|
|
|
func whoamiCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "whoami",
|
|
Short: "Show this device's identity used in change tracking",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
dev, err := config.LoadDevice()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
home, err := config.Home()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("device id: %s\n", dev.ID)
|
|
fmt.Printf("device name: %s\n", dev.Name)
|
|
settings, serr := config.LoadSettings()
|
|
if serr != nil {
|
|
fmt.Printf("account: unknown — cannot read settings: %v\n", serr)
|
|
} else if settings.Email != "" {
|
|
who := settings.Email
|
|
if settings.Name != "" {
|
|
who = settings.Name + " <" + settings.Email + ">"
|
|
}
|
|
// Name and email are whatever the hub answered at sign-in.
|
|
fmt.Printf("account: %s (from `bdrive login`; changes are attributed to this)\n", safeField(who, 160))
|
|
fmt.Printf("author: %s (git/OS fallback, used only when signed out)\n", dev.Author)
|
|
} else {
|
|
fmt.Printf("account: not signed in — changes are attributed to the author below (run `bdrive login`)\n")
|
|
fmt.Printf("author: %s (detected from git config / OS user)\n", dev.Author)
|
|
}
|
|
fmt.Printf("beardrive home: %s\n", home)
|
|
return nil
|
|
},
|
|
}
|
|
}
|