diff --git a/.opencode/agents/dependency-auditor.md b/.opencode/agents/dependency-auditor.md new file mode 100644 index 0000000..6a9ea7e --- /dev/null +++ b/.opencode/agents/dependency-auditor.md @@ -0,0 +1,44 @@ +--- +description: Audits Go dependencies and vulnerabilities without changing files +mode: subagent +permissions: + - action: edit + resource: "*" + effect: deny + - action: shell + resource: "*" + effect: deny + - action: shell + resource: "go list *" + effect: allow + - action: shell + resource: "go mod download *" + effect: allow + - action: shell + resource: "go test *" + effect: allow + - action: shell + resource: "go vet *" + effect: allow + - action: shell + resource: "go build *" + effect: allow + - action: shell + resource: "go run golang.org/x/vuln/cmd/govulncheck@*" + effect: allow + - action: shell + resource: "git diff *" + effect: allow +--- + +Audit this Go module. Run: + +- `go list -m -u all` +- `govulncheck ./...` +- `go test ./... -race` +- `go vet ./...` +- `go build ./...` + +Report direct and indirect updates, deprecated modules, and any Go toolchain +bump required by dependencies. Do not edit `go.mod`, `go.sum`, or source files; +propose exact commands for the primary agent. diff --git a/.opencode/agents/reviewer.md b/.opencode/agents/reviewer.md new file mode 100644 index 0000000..d4b64e2 --- /dev/null +++ b/.opencode/agents/reviewer.md @@ -0,0 +1,29 @@ +--- +description: Reviews changes for correctness, safety, and regressions without editing files +mode: subagent +permissions: + - action: edit + resource: "*" + effect: deny + - action: shell + resource: "*" + effect: deny + - action: shell + resource: "git diff *" + effect: allow + - action: shell + resource: "git status" + effect: allow + - action: shell + resource: "git log *" + effect: allow +--- + +Review the current diff. Focus on: + +- `Analyze` remaining side-effect-free and `Clean` being the only mutating path +- correct command construction and error handling +- tests for parsers and fake `RunCommand` +- accidental destructive behavior on Arch Linux + +Report findings in severity order with file and line references. Do not edit files. diff --git a/.opencode/skills/cleaner-development/SKILL.md b/.opencode/skills/cleaner-development/SKILL.md new file mode 100644 index 0000000..8d3aa22 --- /dev/null +++ b/.opencode/skills/cleaner-development/SKILL.md @@ -0,0 +1,22 @@ +--- +name: Cleaner Development +description: Add or modify a Squeaky cleaner safely with fake-command tests +--- + +## Contract + +Implement `cleaner.Cleaner`: + +- `Name() string` +- `Analyze() (*Result, error)` — read-only +- `Clean() (*Result, error)` — mutating + +## Rules + +- Use the package-level `RunCommand` variable for external commands. +- In tests, replace `RunCommand` and restore it with `defer`. +- Extract output parsing into pure functions and table-test them. +- Register the cleaner in both `cmd/dry.go` and `cmd/clean.go`. +- Add config fields to `internal/config` and document them in + `squeaky.example.yaml`. +- Never run destructive host commands in tests; use `t.TempDir()`. diff --git a/.opencode/skills/dependency-audit/SKILL.md b/.opencode/skills/dependency-audit/SKILL.md new file mode 100644 index 0000000..e007684 --- /dev/null +++ b/.opencode/skills/dependency-audit/SKILL.md @@ -0,0 +1,20 @@ +--- +name: Dependency Audit +description: Check Go modules for outdated, deprecated, or vulnerable dependencies and validate upgrades safely +--- + +## Workflow + +1. Read `go.mod` and note the `go` directive. +2. Run `go list -m -u all` and separate direct from indirect updates. +3. Check whether any dependency requires a newer Go toolchain. +4. Treat `gopkg.in/yaml.v3` as deprecated; use `go.yaml.in/yaml/v3` for YAML v3. +5. Apply changes in a scratch copy or worktree first. +6. Run: + - `go mod tidy` + - `go test ./... -race` + - `go vet ./...` + - `go build ./...` + - `govulncheck ./...` +7. Report exact version changes and any toolchain bump. +8. Do not commit unless explicitly asked. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0f1d432 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,55 @@ +# Squeaky — agent instructions + +## What this project is + +`squeaky` is a Go CLI for Arch Linux that removes old pacman cache packages, +orphaned packages, old journal logs, stale `~/.cache` files, and old `/tmp` +files. `dry` is read-only. `clean` is the only mutating command. + +## Commands + +- Build: `make build` +- Test: `make test` (`go test ./... -race`) +- Vet: `go vet ./...` +- Lint: `golangci-lint run ./...` +- Vulnerability scan: `govulncheck ./...` +- Dependency audit: `go list -m -u all` + +## Layout + +- `cmd/` — Cobra commands. `dry.go` and `clean.go` each build the cleaner list. +- `internal/cleaner/` — one cleaner per file. Every cleaner implements: + - `Name() string` + - `Analyze() (*Result, error)` — must never modify the system + - `Clean() (*Result, error)` — performs the mutation +- `internal/config/` — YAML config and defaults. +- `internal/ui/` — terminal output and summaries. +- `squeaky.example.yaml` — documented user config template. + +## Conventions + +- `Analyze` must be side-effect-free. Only `Clean` may modify the host. +- Use the package-level `RunCommand` variable for external commands. + Tests must replace it and restore it with `defer`. +- Add table-driven tests for parsers and fake-command behavior. +- Register a new cleaner in BOTH `cmd/dry.go` and `cmd/clean.go`. +- Put user-configurable values in `internal/config` and document them in + `squeaky.example.yaml`. +- Prefer the standard library. Add dependencies only with a clear need. +- Do not commit the built `squeaky` binary. + +## Safety — non-negotiable + +- Never run `squeaky clean`, `paccache -r`, `pacman -Rns`, + `journalctl --vacuum-*`, or any `sudo` command from an agent session. +- Use unit tests, fake `RunCommand` implementations, or `t.TempDir()`. +- `squeaky dry` is acceptable for read-only inspection, but tests are preferred. +- Do not delete or modify files under `/tmp`, `~/.cache`, + `/var/cache/pacman`, or the system journal. + +## Verification before finishing + +- `go test ./... -race` +- `go vet ./...` +- `go build ./...` +- If dependencies changed: `go mod tidy` and `govulncheck ./...` diff --git a/go.mod b/go.mod index f7e83e5..d2e2fa9 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,17 @@ module github.com/jcstr/squeaky -go 1.25.7 +go 1.27.0 require ( - github.com/fatih/color v1.18.0 + github.com/fatih/color v1.19.0 github.com/spf13/cobra v1.10.2 - gopkg.in/yaml.v3 v3.0.1 + go.yaml.in/yaml/v3 v3.0.6 ) require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/spf13/pflag v1.0.9 // indirect - golang.org/x/sys v0.25.0 // indirect + github.com/mattn/go-colorable v0.1.16 // indirect + github.com/mattn/go-isatty v0.0.24 // indirect + github.com/spf13/pflag v1.0.10 // indirect + golang.org/x/sys v0.49.0 // indirect ) diff --git a/go.sum b/go.sum index d8f066d..722f67b 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,21 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-colorable v0.1.16 h1:+2YjeAe7xP1OQbZW1jERPWWCDLlNqFNCvjiqGiAt84A= +github.com/mattn/go-colorable v0.1.16/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +go.yaml.in/yaml/v3 v3.0.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM= +go.yaml.in/yaml/v3 v3.0.6/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= +golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/config/config.go b/internal/config/config.go index aee7e71..6a14f67 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) // Config holds all user-configurable thresholds. diff --git a/opencode.jsonc b/opencode.jsonc new file mode 100644 index 0000000..ab99da9 --- /dev/null +++ b/opencode.jsonc @@ -0,0 +1,9 @@ +{ + "$schema": "https://opencode.ai/config.json", + "permissions": [ + { "action": "shell", "resource": "sudo *", "effect": "deny" }, + { "action": "shell", "resource": "*sudo *", "effect": "deny" }, + { "action": "shell", "resource": "squeaky clean*", "effect": "deny" }, + { "action": "shell", "resource": "*squeaky clean*", "effect": "deny" } + ] +}