feat: simplify mail wisps - single DB with --wisp flag (gt-fgms)

Removed dual-routing architecture that used separate .beads-wisp/ directory.
Now uses single .beads/ with --wisp flag passed to bd create.

Changes:
- router.go: Remove resolveWispDir(), simplify shouldBeWisp()
- mailbox.go: Remove wispDir field and dual-source query logic
- types.go: Rename Ephemeral to Wisp, remove MessageSource
- mail.go: Rename --ephemeral to --wisp flag
- spawn.go: Use Wisp field for lifecycle messages

🤖 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-24 20:16:14 -08:00
parent 200a09a02d
commit 4801a98793
5 changed files with 52 additions and 124 deletions

View File

@@ -88,33 +88,23 @@ func isTownLevelAddress(address string) bool {
return addr == "mayor" || addr == "deacon"
}
// resolveWispDir returns the .beads-wisp/.beads directory for ephemeral mail.
// Like resolveBeadsDir, mail wisps use town-level storage.
// Note: bd init creates .beads/ subdirectory, so the full path is .beads-wisp/.beads
func (r *Router) resolveWispDir() string {
if r.townRoot == "" {
return filepath.Join(r.workDir, ".beads-wisp", ".beads")
}
return filepath.Join(r.townRoot, ".beads-wisp", ".beads")
}
// shouldBeEphemeral determines if a message should be stored as a wisp.
// shouldBeWisp determines if a message should be stored as a wisp.
// Returns true if:
// - Message.Ephemeral is explicitly set
// - Message.Wisp is explicitly set
// - Subject matches lifecycle message patterns (POLECAT_*, NUDGE, etc.)
func (r *Router) shouldBeEphemeral(msg *Message) bool {
if msg.Ephemeral {
func (r *Router) shouldBeWisp(msg *Message) bool {
if msg.Wisp {
return true
}
// Auto-detect lifecycle messages by subject prefix
subjectLower := strings.ToLower(msg.Subject)
ephemeralPrefixes := []string{
wispPrefixes := []string{
"polecat_started",
"polecat_done",
"start_work",
"nudge",
}
for _, prefix := range ephemeralPrefixes {
for _, prefix := range wispPrefixes {
if strings.HasPrefix(subjectLower, prefix) {
return true
}
@@ -154,18 +144,12 @@ func (r *Router) Send(msg *Message) error {
args = append(args, "--labels", strings.Join(labels, ","))
}
// Resolve the correct beads directory based on ephemeral status
var beadsDir string
if r.shouldBeEphemeral(msg) {
beadsDir = r.resolveWispDir()
// Ensure wisp directory exists
if err := os.MkdirAll(beadsDir, 0755); err != nil {
return fmt.Errorf("creating wisp dir: %w", err)
}
} else {
beadsDir = r.resolveBeadsDir(msg.To)
// Add --wisp flag for ephemeral messages (stored in single DB, filtered from JSONL export)
if r.shouldBeWisp(msg) {
args = append(args, "--wisp")
}
beadsDir := r.resolveBeadsDir(msg.To)
cmd := exec.Command("bd", args...)
cmd.Env = append(cmd.Environ(),
"BEADS_DIR="+beadsDir,