From 7e16ac4800bff5a052929e99c0e4a800fcfd936f Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sat, 20 Dec 2025 22:01:16 -0800 Subject: [PATCH] fix: recover orphaned mail migration to bd v0.32.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The merge at 96c773f lost changes from 5791752 (beads-sync branch). Re-implementing: - router.go: Use bd create --type=message with labels - mailbox.go: Use bd list/show/close instead of bd mail commands - types.go: Add Pinned field to Message struct Original work was in commits 5791752 and 4c060f4 on beads-sync. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/mail/mailbox.go | 24 ++++++++++++++++-------- internal/mail/router.go | 37 ++++++++++++++++++------------------- internal/mail/types.go | 3 +++ 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/internal/mail/mailbox.go b/internal/mail/mailbox.go index ceb3a774..2e047aa5 100644 --- a/internal/mail/mailbox.go +++ b/internal/mail/mailbox.go @@ -85,11 +85,15 @@ func (m *Mailbox) List() ([]*Message, error) { } func (m *Mailbox) listBeads() ([]*Message, error) { - // bd mail inbox --json - cmd := exec.Command("bd", "mail", "inbox", "--json") + // bd list --type=message --assignee= --json --status=open + cmd := exec.Command("bd", "list", + "--type", "message", + "--assignee", m.identity, + "--status", "open", + "--json", + ) cmd.Dir = m.workDir cmd.Env = append(cmd.Environ(), - "BD_IDENTITY="+m.identity, "BEADS_DIR="+m.beadsDir, ) @@ -189,7 +193,7 @@ func (m *Mailbox) Get(id string) (*Message, error) { } func (m *Mailbox) getBeads(id string) (*Message, error) { - cmd := exec.Command("bd", "mail", "read", id, "--json") + cmd := exec.Command("bd", "show", id, "--json") cmd.Dir = m.workDir cmd.Env = append(cmd.Environ(), "BEADS_DIR="+m.beadsDir) @@ -208,12 +212,16 @@ func (m *Mailbox) getBeads(id string) (*Message, error) { return nil, err } - var bm BeadsMessage - if err := json.Unmarshal(stdout.Bytes(), &bm); err != nil { + // bd show --json returns an array + var bms []BeadsMessage + if err := json.Unmarshal(stdout.Bytes(), &bms); err != nil { return nil, err } + if len(bms) == 0 { + return nil, ErrMessageNotFound + } - return bm.ToMessage(), nil + return bms[0].ToMessage(), nil } func (m *Mailbox) getLegacy(id string) (*Message, error) { @@ -238,7 +246,7 @@ func (m *Mailbox) MarkRead(id string) error { } func (m *Mailbox) markReadBeads(id string) error { - cmd := exec.Command("bd", "mail", "ack", id) + cmd := exec.Command("bd", "close", id) cmd.Dir = m.workDir cmd.Env = append(cmd.Environ(), "BEADS_DIR="+m.beadsDir) diff --git a/internal/mail/router.go b/internal/mail/router.go index 37646ef4..f54c022f 100644 --- a/internal/mail/router.go +++ b/internal/mail/router.go @@ -105,31 +105,31 @@ func isTownLevelAddress(address string) bool { func (r *Router) Send(msg *Message) error { // Convert addresses to beads identities toIdentity := addressToIdentity(msg.To) - fromIdentity := addressToIdentity(msg.From) - // Build command: bd mail send -s -m - args := []string{"mail", "send", toIdentity, - "-s", msg.Subject, - "-m", msg.Body, + // Build labels for from/thread/reply-to + var labels []string + labels = append(labels, "from:"+msg.From) + if msg.ThreadID != "" { + labels = append(labels, "thread:"+msg.ThreadID) + } + if msg.ReplyTo != "" { + labels = append(labels, "reply-to:"+msg.ReplyTo) + } + + // Build command: bd create --type=message --assignee= -d + args := []string{"create", msg.Subject, + "--type", "message", + "--assignee", toIdentity, + "-d", msg.Body, } // Add priority flag beadsPriority := PriorityToBeads(msg.Priority) args = append(args, "--priority", fmt.Sprintf("%d", beadsPriority)) - // Add message type if set - if msg.Type != "" && msg.Type != TypeNotification { - args = append(args, "--type", string(msg.Type)) - } - - // Add thread ID if set - if msg.ThreadID != "" { - args = append(args, "--thread-id", msg.ThreadID) - } - - // Add reply-to if set - if msg.ReplyTo != "" { - args = append(args, "--reply-to", msg.ReplyTo) + // Add labels + if len(labels) > 0 { + args = append(args, "--labels", strings.Join(labels, ",")) } // Resolve the correct beads directory for the recipient @@ -137,7 +137,6 @@ func (r *Router) Send(msg *Message) error { cmd := exec.Command("bd", args...) cmd.Env = append(cmd.Environ(), - "BEADS_AGENT_NAME="+fromIdentity, "BEADS_DIR="+beadsDir, ) cmd.Dir = filepath.Dir(beadsDir) // Run in parent of .beads diff --git a/internal/mail/types.go b/internal/mail/types.go index 1f3b1e31..0ae8a986 100644 --- a/internal/mail/types.go +++ b/internal/mail/types.go @@ -94,6 +94,9 @@ type Message struct { // ReplyTo is the ID of the message this is replying to. ReplyTo string `json:"reply_to,omitempty"` + + // Pinned marks the message as pinned (won't be auto-archived). + Pinned bool `json:"pinned,omitempty"` } // NewMessage creates a new message with a generated ID and thread ID.