diff --git a/USER-MANUAL.md b/USER-MANUAL.md index 47493f1..dbd3327 100644 --- a/USER-MANUAL.md +++ b/USER-MANUAL.md @@ -547,7 +547,7 @@ Every agent action (`list`, `get`, `search`, `ack`, `send`) — allowed or block ```bash emcli audit list # most recent 50 -emcli audit list --account gmail # filter to one account +emcli audit list gmail # filter to one account emcli audit list --limit 200 ``` @@ -626,7 +626,7 @@ emcli account remove N [--yes] # delete an account (--yes o emcli whitelist N [addr…] --in|--out emcli config list # list all settings and descriptions emcli config set|get [value] # e.g. audit_retention_days -emcli audit list [--account N] [--limit K] +emcli audit list [account] [--limit K] emcli version # Agent (requires EMCLI_KEY or EMCLI_ADMIN_KEY; one line of JSON each) diff --git a/internal/cli/admin.go b/internal/cli/admin.go index 95c0fbb..e5bd57c 100644 --- a/internal/cli/admin.go +++ b/internal/cli/admin.go @@ -339,21 +339,30 @@ func runConfig(args []string, role store.Role, out, errOut io.Writer) int { } } -// runAudit handles `audit list [--account ] [--limit N]`. +// runAudit handles `audit list [account] [--limit N]`. func runAudit(args []string, role store.Role, out, errOut io.Writer) int { if len(args) > 0 && helpRequested(args[0]) { printCmdUsage(out, "audit") return 0 } - if len(args) == 0 || args[0] != "list" { - fmt.Fprintln(errOut, "usage: emcli audit list [--account ] [--limit N]") + if len(args) == 0 || normalizeVerb(args[0]) != "list" { + fmt.Fprintln(errOut, "usage: emcli audit list [account] [--limit N]") return 2 } + // Peel an optional positional account before flag parsing. + rest := args[1:] + var account string + if len(rest) > 0 && !strings.HasPrefix(rest[0], "-") { + account, rest = rest[0], rest[1:] + } fs := flag.NewFlagSet("audit list", flag.ContinueOnError) fs.SetOutput(errOut) - account := fs.String("account", "", "filter by account") limit := fs.Int("limit", 50, "max rows") - if err := fs.Parse(args[1:]); err != nil { + if err := fs.Parse(rest); err != nil { + return 2 + } + if fs.NArg() > 0 { + fmt.Fprintf(errOut, "unexpected argument %q\n", fs.Arg(0)) return 2 } st, err := openStore(role) @@ -362,7 +371,7 @@ func runAudit(args []string, role store.Role, out, errOut io.Writer) int { return 1 } defer st.Close() - if err := auditList(st, *account, *limit, out); err != nil { + if err := auditList(st, account, *limit, out); err != nil { fmt.Fprintf(errOut, "audit list: %v\n", err) return 1 } diff --git a/internal/cli/admin_test.go b/internal/cli/admin_test.go index 6c17a29..7d3eb15 100644 --- a/internal/cli/admin_test.go +++ b/internal/cli/admin_test.go @@ -224,6 +224,22 @@ func TestAuditListCoreRenders(t *testing.T) { } } +func TestAuditListPositionalAccount(t *testing.T) { + adminEnv(t) + // Positional account + `ls` alias must be accepted (empty log → exit 0). + if code, _, e := run(t, "audit", "ls", "someacct"); code != 0 { + t.Fatalf("audit ls should succeed: code=%d err=%q", code, e) + } + // Extra positional is a usage error. + if code, _, _ := run(t, "audit", "list", "a", "b"); code != 2 { + t.Fatal("extra positional must be a usage error") + } + // The removed --account flag is now a usage error. + if code, _, _ := run(t, "audit", "list", "--account", "x"); code != 2 { + t.Fatal("removed --account flag should now be a usage error") + } +} + func TestAccountEditFromValidationRejectsMalformed(t *testing.T) { adminEnv(t) run(t, "account", "add", "valacc", "--imap-host", "imap.x.com", "--username", "u@x.com")