diff --git a/CHANGELOG.md b/CHANGELOG.md index dae39d5..ec7fb27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Changes +- Add cached release checks with `discrawl check-update` and passive terminal + notices when a newer OpenClaw release is available. + ### Fixes ## 0.9.0 - 2026-05-17 diff --git a/README.md b/README.md index 25daa5a..a7235d5 100644 --- a/README.md +++ b/README.md @@ -123,10 +123,21 @@ then copy the database/share/cache/log paths you want to move. Homebrew (recommended): ```bash -brew install steipete/tap/discrawl # auto-taps steipete/tap +brew install openclaw/tap/discrawl discrawl --version ``` +Check for newer releases manually with: + +```bash +discrawl check-update +``` + +Interactive terminal runs also perform a cached daily release check and print a +stderr notice when a newer OpenClaw release is available. Set +`DISCRAWL_NO_UPDATE_CHECK=1` or `CRAWLKIT_NO_UPDATE_CHECK=1` to disable that +passive notice. + Build from source: ```bash diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 437c923..cbcb9ac 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -85,9 +85,9 @@ Useful commands: curl -L -o /tmp/discrawl-darwin-arm64.tgz https://github.com/openclaw/discrawl/releases/download/vX.Y.Z/discrawl_X.Y.Z_darwin_arm64.tar.gz shasum -a 256 /tmp/discrawl-darwin-arm64.tgz brew uninstall discrawl || true -brew install steipete/tap/discrawl +brew install openclaw/tap/discrawl discrawl --version -brew info steipete/tap/discrawl +brew info openclaw/tap/discrawl ``` ## Notes diff --git a/docs/install.md b/docs/install.md index 61f7f86..2f8644c 100644 --- a/docs/install.md +++ b/docs/install.md @@ -5,11 +5,23 @@ Discrawl is a single Go binary. Install via Homebrew or build from source. ## Homebrew ```bash -brew install steipete/tap/discrawl +brew install openclaw/tap/discrawl discrawl --version ``` -The tap auto-installs from `steipete/tap`. +The tap auto-installs from `openclaw/tap`. + +## Check for updates + +```bash +discrawl check-update +discrawl check-update --json +``` + +Interactive terminal runs perform a cached daily release check and print a +stderr notice when a newer OpenClaw release is available. Scripted, JSON, CI, +and non-TTY runs skip the passive notice. Set `DISCRAWL_NO_UPDATE_CHECK=1` or +`CRAWLKIT_NO_UPDATE_CHECK=1` to disable it. ## From source diff --git a/go.mod b/go.mod index 9ea83da..f25bd46 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/pelletier/go-toml/v2 v2.3.1 // indirect - modernc.org/sqlite v1.50.0 // indirect + modernc.org/sqlite v1.50.1 // indirect ) require ( @@ -45,7 +45,7 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect - github.com/openclaw/crawlkit v0.5.2 + github.com/openclaw/crawlkit v0.6.0 github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect @@ -53,7 +53,7 @@ require ( golang.org/x/crypto v0.50.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/libc v1.72.1 // indirect + modernc.org/libc v1.72.3 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect ) diff --git a/go.sum b/go.sum index 5ff102c..ef284af 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/openclaw/crawlkit v0.5.2 h1:qUUGYvCdbMXjCpxc3m0+OBvsRWd7QGZvPTI+jVfVFyc= -github.com/openclaw/crawlkit v0.5.2/go.mod h1:2Ugac1hP4I5UPaN+Xw5mbOprg5jvgktBPf2hvGx0kqA= +github.com/openclaw/crawlkit v0.6.0 h1:7ef1UDl6qrV3KJu74mw2WJn1+G5zEMhzTFaktn0CMZ4= +github.com/openclaw/crawlkit v0.6.0/go.mod h1:+2kUqiyecwK/vWySHqZnu968wmdWGBebJ22uUhQEalM= github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -120,10 +120,10 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -modernc.org/cc/v4 v4.28.1 h1:XpLbkYVQ24E8tX5u8+yWGvaxerxkR/S4zqxI8ZoSBuc= -modernc.org/cc/v4 v4.28.1/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= -modernc.org/ccgo/v4 v4.33.0 h1:dspBCm75jsj8Y/ufwAMVfe375L2iYdMyQ2QG/v3hL54= -modernc.org/ccgo/v4 v4.33.0/go.mod h1:+RhXBoRYzRwaH21mV/aj6XvQRDtfjcZfAlPMsQo8CR0= +modernc.org/cc/v4 v4.28.2 h1:3tQ0lf2ADtoby2EtSP+J7IE2SHwEJdP8ioR59wx7XpY= +modernc.org/cc/v4 v4.28.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= +modernc.org/ccgo/v4 v4.34.0 h1:yRLPFZieg532OT4rp4JFNIVcquwalMX26G95WQDqwCQ= +modernc.org/ccgo/v4 v4.34.0/go.mod h1:AS5WYMyBakQ+fhsHhtP8mWB82KTGPkNNJDGfGQCe0/A= modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= @@ -132,8 +132,8 @@ modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.72.1 h1:db1xwJ6u1kE3KHTFTTbe2GCrczHPKzlURP0aDC4NGD0= -modernc.org/libc v1.72.1/go.mod h1:HRMiC/PhPGLIPM7GzAFCbI+oSgE3dhZ8FWftmRrHVlY= +modernc.org/libc v1.72.3 h1:ZnDF4tXn4NBXFutMMQC4vtbTFSXhhKzR73fv0beZEAU= +modernc.org/libc v1.72.3/go.mod h1:dn0dZNnnn1clLyvRxLxYExxiKRZIRENOfqQ8XEeg4Qs= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= @@ -142,8 +142,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.50.0 h1:eMowQSWLK0MeiQTdmz3lqoF5dqclujdlIKeJA11+7oM= -modernc.org/sqlite v1.50.0/go.mod h1:m0w8xhwYUVY3H6pSDwc3gkJ/irZT/0YEXwBlhaxQEew= +modernc.org/sqlite v1.50.1 h1:l+cQvn0sd0zJJtfygGHuQJ5AjlrwXmWPw4KP3ZMwr9w= +modernc.org/sqlite v1.50.1/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/internal/cli/cli.go b/internal/cli/cli.go index a7c20f2..eadad8f 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -88,6 +88,7 @@ func Run(ctx context.Context, args []string, stdout, stderr io.Writer) error { plain: global.Plain, logger: slog.New(slog.NewTextHandler(stderr, &slog.HandlerOptions{Level: level})), } + runtime.maybeNotifyRelease(rest) return runtime.dispatch(rest) } @@ -196,6 +197,8 @@ func (r *runtime) dispatch(rest []string) error { switch rest[0] { case "metadata": return r.runMetadata(rest[1:]) + case "check-update": + return r.runCheckUpdate(rest[1:]) case "init": return r.runInit(rest[1:]) case "sync": diff --git a/internal/cli/control_commands.go b/internal/cli/control_commands.go index d214785..a859c32 100644 --- a/internal/cli/control_commands.go +++ b/internal/cli/control_commands.go @@ -42,6 +42,7 @@ func (r *runtime) runMetadata(args []string) error { manifest.Privacy = control.Privacy{ContainsPrivateMessages: true, ExportsSecrets: false, LocalOnlyScopes: []string{"discord", "desktop-cache", "sqlite", "git-share"}} manifest.Commands = map[string]control.Command{ "status": {Title: "Status", Argv: []string{"discrawl", "status", "--json"}, JSON: true}, + "check-update": {Title: "Check for updates", Argv: []string{"discrawl", "check-update", "--json"}, JSON: true}, "doctor": {Title: "Doctor", Argv: []string{"discrawl", "doctor", "--json"}, JSON: true}, "sync": {Title: "Sync", Argv: []string{"discrawl", "--json", "sync"}, JSON: true, Mutates: true}, "tap": {Title: "Import desktop cache", Argv: []string{"discrawl", "--json", "tap"}, JSON: true, Mutates: true}, diff --git a/internal/cli/output.go b/internal/cli/output.go index 2ccd9b4..1186706 100644 --- a/internal/cli/output.go +++ b/internal/cli/output.go @@ -102,6 +102,7 @@ Usage: Commands: metadata + check-update version init sync @@ -140,6 +141,11 @@ func printCommandUsage(w io.Writer, args []string) error { } var commandUsage = map[string]string{ + "check-update": `Usage: + discrawl check-update [--json] [--force] + +Checks GitHub Releases for a newer discrawl build. +`, "search": `Usage: discrawl search [flags] diff --git a/internal/cli/releasecheck.go b/internal/cli/releasecheck.go new file mode 100644 index 0000000..9b87670 --- /dev/null +++ b/internal/cli/releasecheck.go @@ -0,0 +1,61 @@ +package cli + +import ( + "errors" + "flag" + "fmt" + "io" + + "github.com/openclaw/crawlkit/releasecheck" + "github.com/openclaw/discrawl/internal/config" +) + +const discrawlUpgradeHint = "brew upgrade openclaw/tap/discrawl" + +func discrawlReleaseCheckOptions(force bool) releasecheck.Options { + cfg := config.Default() + return releasecheck.Options{ + AppName: "discrawl", + Owner: "openclaw", + Repo: "discrawl", + CurrentVersion: version, + CacheDir: cfg.CacheDir, + Force: force, + } +} + +func (r *runtime) maybeNotifyRelease(args []string) { + _, _ = releasecheck.Notify(r.ctx, releasecheck.NotifyOptions{ + Options: discrawlReleaseCheckOptions(false), + Stderr: r.stderr, + InstallHint: discrawlUpgradeHint, + Args: args, + JSONOutput: r.json, + IsTerminal: releasecheck.StderrIsTerminal(), + }) +} + +func (r *runtime) runCheckUpdate(args []string) error { + fs := flag.NewFlagSet("check-update", flag.ContinueOnError) + fs.SetOutput(io.Discard) + jsonOut := fs.Bool("json", false, "") + force := fs.Bool("force", false, "") + if err := fs.Parse(args); err != nil { + return usageErr(err) + } + if fs.NArg() != 0 { + return usageErr(errors.New("check-update takes flags only")) + } + if *jsonOut { + r.json = true + } + result, err := releasecheck.Check(r.ctx, discrawlReleaseCheckOptions(*force)) + if err != nil && !errors.Is(err, releasecheck.ErrSkipped) { + return err + } + if r.json { + return r.print(result) + } + _, err = fmt.Fprint(r.stdout, releasecheck.StatusText("discrawl", discrawlUpgradeHint, result)) + return err +}