Agents naturally type 'bd mail' when working with beads, but mail functionality is provided by orchestrators like Gas Town. This command bridges that gap by delegating to a configured mail provider. Configuration options (checked in order): 1. BEADS_MAIL_DELEGATE or BD_MAIL_DELEGATE env var 2. mail.delegate config setting Example usage: export BEADS_MAIL_DELEGATE="gt mail" bd mail inbox # Runs: gt mail inbox bd mail send mayor/... # Runs: gt mail send mayor/... 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
112 lines
3.3 KiB
Go
112 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// mailCmd delegates to an external mail provider (e.g., gt mail)
|
|
// This enables agents to use 'bd mail' consistently, while the actual
|
|
// mail implementation is provided by the orchestrator (Gas Town, etc.)
|
|
var mailCmd = &cobra.Command{
|
|
Use: "mail [subcommand] [args...]",
|
|
Short: "Delegate to mail provider (e.g., gt mail)",
|
|
Long: `Delegates mail operations to an external mail provider.
|
|
|
|
Agents often type 'bd mail' when working with beads, but mail functionality
|
|
is typically provided by an orchestrator like Gas Town (gt). This command
|
|
bridges that gap by delegating to the configured mail provider.
|
|
|
|
Configuration (checked in order):
|
|
1. BEADS_MAIL_DELEGATE or BD_MAIL_DELEGATE environment variable
|
|
2. 'mail.delegate' config setting (bd config set mail.delegate "gt mail")
|
|
|
|
Examples:
|
|
# Configure delegation (one-time setup)
|
|
export BEADS_MAIL_DELEGATE="gt mail"
|
|
# or
|
|
bd config set mail.delegate "gt mail"
|
|
|
|
# Then use bd mail as if it were gt mail
|
|
bd mail inbox # Lists inbox
|
|
bd mail send mayor/ -s "Hi" # Sends mail
|
|
bd mail read msg-123 # Reads a message`,
|
|
DisableFlagParsing: true, // Pass all args through to delegate
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
// Handle --help and -h ourselves since flag parsing is disabled
|
|
for _, arg := range args {
|
|
if arg == "--help" || arg == "-h" {
|
|
_ = cmd.Help()
|
|
return
|
|
}
|
|
}
|
|
|
|
// Find the mail delegate command
|
|
delegate := findMailDelegate()
|
|
if delegate == "" {
|
|
fmt.Fprintf(os.Stderr, "Error: no mail delegate configured\n\n")
|
|
fmt.Fprintf(os.Stderr, "bd mail delegates to an external mail provider.\n")
|
|
fmt.Fprintf(os.Stderr, "Configure one of:\n")
|
|
fmt.Fprintf(os.Stderr, " export BEADS_MAIL_DELEGATE=\"gt mail\" # Environment variable\n")
|
|
fmt.Fprintf(os.Stderr, " bd config set mail.delegate \"gt mail\" # Per-project config\n")
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Parse the delegate command (e.g., "gt mail" -> ["gt", "mail"])
|
|
parts := strings.Fields(delegate)
|
|
if len(parts) == 0 {
|
|
fmt.Fprintf(os.Stderr, "Error: invalid mail delegate: %q\n", delegate)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Build the full command with our args appended
|
|
cmdName := parts[0]
|
|
cmdArgs := append(parts[1:], args...)
|
|
|
|
// Execute the delegate command
|
|
execCmd := exec.Command(cmdName, cmdArgs...)
|
|
execCmd.Stdin = os.Stdin
|
|
execCmd.Stdout = os.Stdout
|
|
execCmd.Stderr = os.Stderr
|
|
|
|
if err := execCmd.Run(); err != nil {
|
|
// Try to preserve the exit code
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
os.Exit(exitErr.ExitCode())
|
|
}
|
|
fmt.Fprintf(os.Stderr, "Error running %s: %v\n", delegate, err)
|
|
os.Exit(1)
|
|
}
|
|
},
|
|
}
|
|
|
|
// findMailDelegate checks for mail delegation configuration
|
|
// Priority: env vars > bd config
|
|
func findMailDelegate() string {
|
|
// Check environment variables first
|
|
if delegate := os.Getenv("BEADS_MAIL_DELEGATE"); delegate != "" {
|
|
return delegate
|
|
}
|
|
if delegate := os.Getenv("BD_MAIL_DELEGATE"); delegate != "" {
|
|
return delegate
|
|
}
|
|
|
|
// Check bd config (requires database)
|
|
// This works even without a database connection since we use direct mode
|
|
if store != nil {
|
|
if delegate, err := store.GetConfig(rootCtx, "mail.delegate"); err == nil && delegate != "" {
|
|
return delegate
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(mailCmd)
|
|
}
|