package cli import ( "bufio" "context" "fmt" "io" "os" "strings" frameworkcli "gitea.lclr.dev/AI/mcp-framework/cli" "email-mcp/internal/secretstore" ) type InteractiveConfigPrompter struct { reader *bufio.Reader stdinFile *os.File output io.Writer } func NewInteractiveConfigPrompter(input io.Reader, output io.Writer) *InteractiveConfigPrompter { if input == nil { input = strings.NewReader("") } if output == nil { output = io.Discard } prompter := &InteractiveConfigPrompter{ reader: bufio.NewReader(input), output: output, } if file, ok := input.(*os.File); ok { prompter.stdinFile = file } return prompter } func (p *InteractiveConfigPrompter) PromptCredential(_ context.Context, existing secretstore.Credential, hasStoredPassword bool) (secretstore.Credential, error) { host, err := frameworkcli.PromptLine(p.reader, p.output, "IMAP host", existing.Host) if err != nil { return secretstore.Credential{}, err } username, err := frameworkcli.PromptLine(p.reader, p.output, "Username", existing.Username) if err != nil { return secretstore.Credential{}, err } password, err := p.promptPassword(existing.Password, hasStoredPassword) if err != nil { return secretstore.Credential{}, err } cred := secretstore.Credential{ Host: host, Username: username, Password: password, } if err := cred.Validate(); err != nil { return secretstore.Credential{}, err } return cred, nil } func (p *InteractiveConfigPrompter) promptPassword(storedPassword string, hasStoredPassword bool) (string, error) { if p.stdinFile != nil { return frameworkcli.PromptSecret(p.stdinFile, p.output, "Password", hasStoredPassword, storedPassword) } if hasStoredPassword { fmt.Fprint(p.output, "Password [stored, leave blank to keep]: ") } else { fmt.Fprint(p.output, "Password: ") } line, err := p.reader.ReadString('\n') if err != nil && err != io.EOF { return "", err } password := strings.TrimSpace(line) if password == "" && hasStoredPassword { return storedPassword, nil } return password, nil }