feat(mail): sort pinned messages first in inbox (gt-ngu1)

Add Pinned field to Message and BeadsMessage types, and implement
sorting in listBeads() to show pinned messages first, then by
priority, then by date.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-20 18:02:53 -08:00
parent a9d204aa22
commit b3ef048c28
3 changed files with 41 additions and 0 deletions

View File

@@ -105,9 +105,41 @@ func (m *Mailbox) listBeads() ([]*Message, error) {
messages = append(messages, bm.ToMessage())
}
// Sort: pinned first, then by priority (urgent first), then by date (newest first)
sort.Slice(messages, func(i, j int) bool {
// Pinned messages always come first
if messages[i].Pinned != messages[j].Pinned {
return messages[i].Pinned
}
// Within same pinned status, sort by priority (urgent > high > normal > low)
pi := priorityOrder(messages[i].Priority)
pj := priorityOrder(messages[j].Priority)
if pi != pj {
return pi < pj
}
// Within same priority, sort by date (newest first)
return messages[i].Timestamp.After(messages[j].Timestamp)
})
return messages, nil
}
// priorityOrder returns sort order for priority (lower = more urgent).
func priorityOrder(p Priority) int {
switch p {
case PriorityUrgent:
return 0
case PriorityHigh:
return 1
case PriorityNormal:
return 2
case PriorityLow:
return 3
default:
return 2
}
}
func (m *Mailbox) listLegacy() ([]*Message, error) {
file, err := os.Open(m.path)
if err != nil {

View File

@@ -78,6 +78,9 @@ type Message struct {
// Read indicates if the message has been read (closed in beads).
Read bool `json:"read"`
// Pinned indicates if the message is pinned (persistent context marker).
Pinned bool `json:"pinned,omitempty"`
// Priority is the message priority.
Priority Priority `json:"priority"`
@@ -151,6 +154,7 @@ type BeadsMessage struct {
Assignee string `json:"assignee"` // To identity
Priority int `json:"priority"` // 0=urgent, 1=high, 2=normal, 3=low
Status string `json:"status"` // open=unread, closed=read
Pinned bool `json:"pinned"` // Persistent context marker
CreatedAt time.Time `json:"created_at"`
Type string `json:"type,omitempty"` // Message type
ThreadID string `json:"thread_id,omitempty"` // Thread identifier
@@ -187,6 +191,7 @@ func (bm *BeadsMessage) ToMessage() *Message {
Body: bm.Description,
Timestamp: bm.CreatedAt,
Read: bm.Status == "closed",
Pinned: bm.Pinned,
Priority: priority,
Type: msgType,
ThreadID: bm.ThreadID,