feat(cli): agent-readable account list (reduced JSON view)
account list now routes to the agent role; an agent (EMCLI_KEY only) gets a JSON envelope of name/from/can_send, while the admin keeps the full text table. account add/edit/remove stay admin-only. Also emit the agent path's missing-key/open failure as a JSON Failure envelope (per spec), and update the stale run_test case that asserted the old admin-only behavior. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+30
-2
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"git.dcglab.co.uk/steve/emcli/internal/crypto"
|
||||
"git.dcglab.co.uk/steve/emcli/internal/store"
|
||||
"git.dcglab.co.uk/steve/emcli/internal/tui"
|
||||
)
|
||||
@@ -23,7 +24,14 @@ func runAccount(args []string, role store.Role, out, errOut io.Writer) int {
|
||||
sub, rest := args[0], args[1:]
|
||||
st, err := openStore(role)
|
||||
if err != nil {
|
||||
fmt.Fprintf(errOut, "emcli: %v\n", err)
|
||||
// account list is an agent command (a JSON consumer), so its
|
||||
// open/key failures are emitted as an envelope, like the other agent
|
||||
// commands; the admin subcommands stay human-readable.
|
||||
if sub == "list" {
|
||||
_ = Failure(CodeConfig, err.Error()).Write(out)
|
||||
} else {
|
||||
fmt.Fprintf(errOut, "emcli: %v\n", err)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
defer st.Close()
|
||||
@@ -171,11 +179,31 @@ func runAccount(args []string, role store.Role, out, errOut io.Writer) int {
|
||||
fmt.Fprintf(out, "account %q removed\n", *name)
|
||||
return 0
|
||||
case "list":
|
||||
// Holding the admin key means the caller is the human admin (full
|
||||
// detail). An agent holds only EMCLI_KEY and gets a reduced JSON view.
|
||||
_, adminErr := crypto.AdminKeyFromEnv()
|
||||
isAdmin := adminErr == nil
|
||||
accs, err := st.ListAccounts()
|
||||
if err != nil {
|
||||
fmt.Fprintf(errOut, "list: %v\n", err)
|
||||
if isAdmin {
|
||||
fmt.Fprintf(errOut, "list: %v\n", err)
|
||||
} else {
|
||||
_ = Failure(CodeDB, err.Error()).Write(out)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
if !isAdmin {
|
||||
items := make([]map[string]any, 0, len(accs))
|
||||
for _, a := range accs {
|
||||
items = append(items, map[string]any{
|
||||
"name": a.Name,
|
||||
"from": a.SendFrom(),
|
||||
"can_send": a.Mode == "RW",
|
||||
})
|
||||
}
|
||||
_ = Success(map[string]any{"accounts": items}).Write(out)
|
||||
return 0
|
||||
}
|
||||
fmt.Fprintf(out, "%-16s %-4s %-28s %s\n", "NAME", "MODE", "IMAP", "USER")
|
||||
for _, a := range accs {
|
||||
fmt.Fprintf(out, "%-16s %-4s %-28s %s\n",
|
||||
|
||||
Reference in New Issue
Block a user