feat(mail): add deacon/ identity support

Add deacon/ as a town-level mail identity alongside mayor/.
Both addressToIdentity() and identityToAddress() now handle
deacon/deacon/ consistently with trailing slash preservation.

Tested with bd mail send deacon/ and bd mail inbox --identity deacon/

🤖 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-19 17:26:54 -08:00
parent f9c973c23d
commit 50accc9cb2
3 changed files with 292 additions and 198 deletions

View File

@@ -217,16 +217,21 @@ func ParseMessageType(s string) MessageType {
// Examples:
// - "mayor/" → "mayor/"
// - "mayor" → "mayor/"
// - "deacon/" → "deacon/"
// - "deacon" → "deacon/"
// - "gastown/Toast" → "gastown-Toast"
// - "gastown/refinery" → "gastown-refinery"
// - "gastown/" → "gastown" (rig broadcast)
func addressToIdentity(address string) string {
// Mayor special case - always use "mayor/" for consistency
// Town-level agents: mayor and deacon keep trailing slash
if address == "mayor" || address == "mayor/" {
return "mayor/"
}
if address == "deacon" || address == "deacon/" {
return "deacon/"
}
// Trim trailing slash for non-mayor addresses
// Trim trailing slash for rig-level addresses
if len(address) > 0 && address[len(address)-1] == '/' {
address = address[:len(address)-1]
}
@@ -248,12 +253,19 @@ func addressToIdentity(address string) string {
//
// Examples:
// - "mayor" → "mayor/"
// - "mayor/" → "mayor/"
// - "deacon" → "deacon/"
// - "deacon/" → "deacon/"
// - "gastown-Toast" → "gastown/Toast"
// - "gastown-refinery" → "gastown/refinery"
func identityToAddress(identity string) string {
if identity == "mayor" {
// Town-level agents
if identity == "mayor" || identity == "mayor/" {
return "mayor/"
}
if identity == "deacon" || identity == "deacon/" {
return "deacon/"
}
// Find first dash and replace with /
// gastown-Toast → gastown/Toast

View File

@@ -0,0 +1,63 @@
package mail
import "testing"
func TestAddressToIdentity(t *testing.T) {
tests := []struct {
address string
expected string
}{
// Town-level agents keep trailing slash
{"mayor", "mayor/"},
{"mayor/", "mayor/"},
{"deacon", "deacon/"},
{"deacon/", "deacon/"},
// Rig-level agents use dash separator
{"gastown/Toast", "gastown-Toast"},
{"gastown/refinery", "gastown-refinery"},
{"gastown/witness", "gastown-witness"},
// Rig broadcast (trailing slash removed)
{"gastown/", "gastown"},
}
for _, tt := range tests {
t.Run(tt.address, func(t *testing.T) {
got := addressToIdentity(tt.address)
if got != tt.expected {
t.Errorf("addressToIdentity(%q) = %q, want %q", tt.address, got, tt.expected)
}
})
}
}
func TestIdentityToAddress(t *testing.T) {
tests := []struct {
identity string
expected string
}{
// Town-level agents
{"mayor", "mayor/"},
{"mayor/", "mayor/"},
{"deacon", "deacon/"},
{"deacon/", "deacon/"},
// Rig-level agents
{"gastown-Toast", "gastown/Toast"},
{"gastown-refinery", "gastown/refinery"},
{"gastown-witness", "gastown/witness"},
// Rig name only (adds trailing slash)
{"gastown", "gastown/"},
}
for _, tt := range tests {
t.Run(tt.identity, func(t *testing.T) {
got := identityToAddress(tt.identity)
if got != tt.expected {
t.Errorf("identityToAddress(%q) = %q, want %q", tt.identity, got, tt.expected)
}
})
}
}