package cli import ( "context" "fmt" "io" "os" "email-mcp/internal/secretstore" ) type MCPRunner interface { Run(ctx context.Context) error } type App struct { prompter SetupPrompter store secretstore.Store runner MCPRunner stderr io.Writer } func NewApp() *App { return NewAppWithDependencies(nil, nil, nil, os.Stderr) } func NewAppWithDependencies(prompter SetupPrompter, store secretstore.Store, runner MCPRunner, stderr io.Writer) *App { if stderr == nil { stderr = io.Discard } return &App{ prompter: prompter, store: store, runner: runner, stderr: stderr, } } func (a *App) Run(args []string) error { if len(args) == 0 { return fmt.Errorf("usage: email-mcp ") } switch args[0] { case "setup": return a.runSetup(context.Background()) case "mcp": return a.runMCP(context.Background()) default: return fmt.Errorf("unknown command: %s", args[0]) } } func (a *App) runSetup(ctx context.Context) error { if a.prompter == nil { return fmt.Errorf("setup prompter is not configured") } if a.store == nil { return fmt.Errorf("secret store is not configured") } cred, err := a.prompter.PromptSetup(ctx) if err != nil { return err } if err := cred.Validate(); err != nil { return err } if err := a.store.Save(ctx, secretstore.DefaultAccountKey, cred); err != nil { return err } return nil } func (a *App) runMCP(ctx context.Context) error { if a.runner == nil { return fmt.Errorf("mcp runner is not configured") } return a.runner.Run(ctx) }