fix: relocate daemon socket for deep paths (GH#1001)

On Unix systems, socket paths are limited to 104 chars (macOS) or 108 chars
(Linux). Deep workspace paths like /Volumes/External Drive/Dropbox/...
would exceed this limit and cause daemon startup failures.

This fix:
- Adds ShortSocketPath() which computes /tmp/beads-{hash}/bd.sock for
  paths that would exceed the limit
- Keeps backward compatibility: short paths still use .beads/bd.sock
- Updates daemon discovery to check both locations
- Uses SHA256 hash of canonical workspace path for unique directories

Closes GH#1001

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
wolf
2026-01-10 12:30:13 -08:00
committed by Steve Yegge
parent 77b9d4762f
commit 3ecffa111b
6 changed files with 334 additions and 6 deletions

View File

@@ -214,15 +214,28 @@ func FindDaemonByWorkspace(workspacePath string) (*DaemonInfo, error) {
// For worktrees, .beads is in the main repository root, not the worktree
beadsDir := findBeadsDirForWorkspace(workspacePath)
// First try the socket in the determined .beads directory
socketPath := filepath.Join(beadsDir, "bd.sock")
if _, err := os.Stat(socketPath); err == nil {
daemon := discoverDaemon(socketPath)
// Try short socket path first (GH#1001 - avoids macOS 104-char limit)
// This is computed from the workspace path, not the beads dir
mainWorkspace := filepath.Dir(beadsDir) // Get workspace from .beads dir
shortSocketPath := rpc.ShortSocketPath(mainWorkspace)
if _, err := os.Stat(shortSocketPath); err == nil {
daemon := discoverDaemon(shortSocketPath)
if daemon.Alive {
return &daemon, nil
}
}
// Try legacy socket path in .beads directory (backwards compatibility)
legacySocketPath := filepath.Join(beadsDir, "bd.sock")
if legacySocketPath != shortSocketPath {
if _, err := os.Stat(legacySocketPath); err == nil {
daemon := discoverDaemon(legacySocketPath)
if daemon.Alive {
return &daemon, nil
}
}
}
// Fall back to discovering all daemons
daemons, err := DiscoverDaemons([]string{workspacePath})
if err != nil {