fix(mail): Use town beads for all mail (two-level architecture)
Replace complex address-based routing with simple town root lookup. All mail goes to ~/gt/.beads/ (town beads), eliminating the broken rig-level routing. Two-level model: - Town beads (~/gt/.beads/): ALL mail and coordination - Clone beads (<rig>/crew/*/.beads/): Project issues only Fixes: gt-4qey 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -220,8 +220,8 @@ func init() {
|
||||
func runMailSend(cmd *cobra.Command, args []string) error {
|
||||
to := args[0]
|
||||
|
||||
// Find workspace - we need a directory with .beads
|
||||
workDir, err := findBeadsWorkDir()
|
||||
// All mail uses town beads (two-level architecture)
|
||||
workDir, err := findMailWorkDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
@@ -288,12 +288,6 @@ func runMailSend(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
func runMailInbox(cmd *cobra.Command, args []string) error {
|
||||
// Find workspace
|
||||
workDir, err := findBeadsWorkDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
// Determine which inbox to check (priority: --identity flag, positional arg, auto-detect)
|
||||
address := ""
|
||||
if mailInboxIdentity != "" {
|
||||
@@ -304,6 +298,12 @@ func runMailInbox(cmd *cobra.Command, args []string) error {
|
||||
address = detectSender()
|
||||
}
|
||||
|
||||
// All mail uses town beads (two-level architecture)
|
||||
workDir, err := findMailWorkDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
// Get mailbox
|
||||
router := mail.NewRouter(workDir)
|
||||
mailbox, err := router.GetMailbox(address)
|
||||
@@ -367,15 +367,15 @@ func runMailInbox(cmd *cobra.Command, args []string) error {
|
||||
func runMailRead(cmd *cobra.Command, args []string) error {
|
||||
msgID := args[0]
|
||||
|
||||
// Find workspace
|
||||
workDir, err := findBeadsWorkDir()
|
||||
// Determine which inbox
|
||||
address := detectSender()
|
||||
|
||||
// All mail uses town beads (two-level architecture)
|
||||
workDir, err := findMailWorkDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
// Determine which inbox
|
||||
address := detectSender()
|
||||
|
||||
// Get mailbox and message
|
||||
router := mail.NewRouter(workDir)
|
||||
mailbox, err := router.GetMailbox(address)
|
||||
@@ -435,15 +435,15 @@ func runMailRead(cmd *cobra.Command, args []string) error {
|
||||
func runMailDelete(cmd *cobra.Command, args []string) error {
|
||||
msgID := args[0]
|
||||
|
||||
// Find workspace
|
||||
workDir, err := findBeadsWorkDir()
|
||||
// Determine which inbox
|
||||
address := detectSender()
|
||||
|
||||
// All mail uses town beads (two-level architecture)
|
||||
workDir, err := findMailWorkDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
// Determine which inbox
|
||||
address := detectSender()
|
||||
|
||||
// Get mailbox
|
||||
router := mail.NewRouter(workDir)
|
||||
mailbox, err := router.GetMailbox(address)
|
||||
@@ -459,11 +459,21 @@ func runMailDelete(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// findBeadsWorkDir finds a directory with a .beads database.
|
||||
// Walks up from CWD looking for .beads/ directory.
|
||||
func findBeadsWorkDir() (string, error) {
|
||||
// Walk up from CWD looking for .beads - prefer closest one (rig-level)
|
||||
// This finds the rig's .beads before the town's .beads
|
||||
// findMailWorkDir returns the town root for all mail operations.
|
||||
//
|
||||
// Two-level beads architecture:
|
||||
// - Town beads (~/gt/.beads/): ALL mail and coordination
|
||||
// - Clone beads (<rig>/crew/*/.beads/): Project issues only
|
||||
//
|
||||
// Mail ALWAYS uses town beads, regardless of sender or recipient address.
|
||||
// This ensures messages are visible to all agents in the town.
|
||||
func findMailWorkDir() (string, error) {
|
||||
return workspace.FindFromCwdOrError()
|
||||
}
|
||||
|
||||
// findLocalBeadsDir finds the nearest .beads directory by walking up from CWD.
|
||||
// Used for project work (molecules, issue creation) that uses clone beads.
|
||||
func findLocalBeadsDir() (string, error) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -482,14 +492,6 @@ func findBeadsWorkDir() (string, error) {
|
||||
path = parent
|
||||
}
|
||||
|
||||
// Fall back to town root if nothing found walking up
|
||||
townRoot, err := workspace.FindFromCwdOrError()
|
||||
if err == nil {
|
||||
if _, err := os.Stat(filepath.Join(townRoot, ".beads")); err == nil {
|
||||
return townRoot, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no .beads directory found")
|
||||
}
|
||||
|
||||
@@ -536,16 +538,6 @@ func detectSender() string {
|
||||
}
|
||||
|
||||
func runMailCheck(cmd *cobra.Command, args []string) error {
|
||||
// Find workspace
|
||||
workDir, err := findBeadsWorkDir()
|
||||
if err != nil {
|
||||
if mailCheckInject {
|
||||
// Inject mode: always exit 0, silent on error
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
// Determine which inbox (priority: --identity flag, auto-detect)
|
||||
address := ""
|
||||
if mailCheckIdentity != "" {
|
||||
@@ -554,6 +546,16 @@ func runMailCheck(cmd *cobra.Command, args []string) error {
|
||||
address = detectSender()
|
||||
}
|
||||
|
||||
// All mail uses town beads (two-level architecture)
|
||||
workDir, err := findMailWorkDir()
|
||||
if err != nil {
|
||||
if mailCheckInject {
|
||||
// Inject mode: always exit 0, silent on error
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
// Get mailbox
|
||||
router := mail.NewRouter(workDir)
|
||||
mailbox, err := router.GetMailbox(address)
|
||||
@@ -621,8 +623,8 @@ func runMailCheck(cmd *cobra.Command, args []string) error {
|
||||
func runMailThread(cmd *cobra.Command, args []string) error {
|
||||
threadID := args[0]
|
||||
|
||||
// Find workspace
|
||||
workDir, err := findBeadsWorkDir()
|
||||
// All mail uses town beads (two-level architecture)
|
||||
workDir, err := findMailWorkDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
@@ -689,8 +691,8 @@ func runMailThread(cmd *cobra.Command, args []string) error {
|
||||
func runMailReply(cmd *cobra.Command, args []string) error {
|
||||
msgID := args[0]
|
||||
|
||||
// Find workspace
|
||||
workDir, err := findBeadsWorkDir()
|
||||
// All mail uses town beads (two-level architecture)
|
||||
workDir, err := findMailWorkDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("not in a Gas Town workspace: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user