feat: lazysecrets list prints everything lazysecrets can find, for fzf and editor pickers (#70)

`lazysecrets list` prints every source, vault and secret lazysecrets can find, one per line, for fzf, editor pickers and scripts: what Go to searches, without the TUI. What's cached prints at once; what's missing or older than `--max-age` loads in the background and streams in. It stops when the reader goes (a pick in fzf), saving what it loaded.

- Text: kind, mark (✗/⚠, ★, ◷ and the provider icon), name, status (why it couldn't be read, or expired / expires in 12d), note, account and link, tab-separated; kind first and account and link last, so new fields go between. Coloured from the theme; `--color never`, `--icons=false`, `--stars=false`, `--recent`, `--notes=false`, `--expiry=false`.
- `--format json`: an object per line, with starred, recent, lastUsed and uses, expires, enabled, note, reference and url too.
- `--kind` lists only some kinds, and doesn't load lists only other kinds need; `--cached` loads nothing.
- `lazysecrets open --action go|copy|show` skips the "what to do" menu and ends in the list, like Go to; `open` and `get` take `--account`, the account list printed, rather than asking which.
- The cache file moved to `internal/cachefile`: saves merge with the file under a lock, so list and the TUI don't undo each other.
- `ui.recentIcon` marks items used lately with ◷ in the TUI's lists too; Recent now means the last 90 days.
- --demo has stars, notes, recent use, and expired, expiring and disabled secrets.
- docs/integration.md documents get, list and an fzf picker; docs/links.md is docs/sharing.md.

Reviewed-on: #70
Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
This commit was merged in pull request #70.
This commit is contained in:
keb authored and Karl-Einar Bergstrøm committed 2026-10-14 21:30:44 +02:00
1 parent dbb0eb2bbd
commit 39454d47a8
45 files changed
+2107 -222

No files matched your search

+6 -4
View File
@@ -5,7 +5,9 @@ import (
"fmt"
"slices"
"strings"
"time"
"git.kebcloud.no/keb/lazysecrets/internal/cachefile"
"git.kebcloud.no/keb/lazysecrets/internal/provider"
"git.kebcloud.no/keb/lazysecrets/internal/store"
"git.kebcloud.no/keb/lazysecrets/internal/ui/icons"
@@ -39,7 +41,7 @@ type sourceRow struct {
// sourceRowKey joins a provider ID and a source ID. "|" doesn't occur in
// either; provider IDs contain "/" (Azure:user/tenant).
func sourceRowKey(providerID, sourceID string) string { return providerID + "|" + sourceID }
func sourceRowKey(providerID, sourceID string) string { return cachefile.Row(providerID, sourceID) }
func splitSourceRow(row string) (providerID, sourceID string) {
providerID, sourceID, _ = strings.Cut(row, "|")
@@ -56,7 +58,7 @@ func sourceRowID(r sourceRow) string {
return sourceRowKey(r.provider, r.source.ID)
}
func newSourcesList(iconSet icons.Set, mem *store.Store) panes.List[sourceRow] {
func newSourcesList(iconSet icons.Set, mem *store.Store, recent bool) panes.List[sourceRow] {
return panes.NewList("[1] Sources", panes.Item[sourceRow]{
ID: sourceRowID,
// Headers have no filter text, so filtering shows just sources.
@@ -78,8 +80,8 @@ func newSourcesList(iconSet icons.Set, mem *store.Store) panes.List[sourceRow] {
node := mem.Node(sourceKey(r.source))
kind := st.Kind(r.group)
starred := ""
if r.kind == rowSource && node.StarredFor(r.source.Provider) {
starred = st.Favourite.Render(star)
if r.kind == rowSource {
starred = marks(st, node, r.source.Provider, recent, time.Now())
}
switch {
case r.kind == rowLinks: