package cli import ( "io" "os" "email-mcp/internal/imapclient" "email-mcp/internal/mcpserver" "email-mcp/internal/secretstore" "email-mcp/internal/secretstore/kwallet" ) type runtimeFactories struct { newPrompter func(io.Reader, io.Writer) SetupPrompter newWalletClient func() kwallet.Client newStore func(kwallet.Client) secretstore.Store newMailService func() mcpserver.MailService newRunner func(secretstore.Store, mcpserver.MailService, io.Reader, io.Writer, io.Writer) MCPRunner } func BuildApp() *App { return buildApp(os.Stdin, os.Stdout, os.Stderr, runtimeFactories{}) } func buildApp(stdin io.Reader, stdout io.Writer, stderr io.Writer, factories runtimeFactories) *App { factories = factories.withDefaults() prompter := factories.newPrompter(stdin, stderr) store := factories.newStore(factories.newWalletClient()) mailService := factories.newMailService() runner := factories.newRunner(store, mailService, stdin, stdout, stderr) return NewAppWithDependencies(prompter, store, runner, stderr) } func (f runtimeFactories) withDefaults() runtimeFactories { if f.newPrompter == nil { f.newPrompter = func(input io.Reader, output io.Writer) SetupPrompter { return NewInteractiveSetupPrompter(input, output) } } if f.newWalletClient == nil { f.newWalletClient = kwallet.NewDefaultWalletClient } if f.newStore == nil { f.newStore = func(client kwallet.Client) secretstore.Store { return kwallet.NewStore(client) } } if f.newMailService == nil { f.newMailService = func() mcpserver.MailService { return imapclient.NewService(imapclient.NewDefaultBackend()) } } if f.newRunner == nil { f.newRunner = func(store secretstore.Store, mail mcpserver.MailService, input io.Reader, output io.Writer, errOut io.Writer) MCPRunner { return mcpserver.NewRunner(mcpserver.New(store, mail), input, output, errOut) } } return f }