refactor: remove deprecated global daemon support

Global daemon support has been deprecated for most of the project's
lifetime. This change removes the dead code entirely:

- Remove --global and --migrate-to-global daemon flags
- Remove runGlobalDaemon() and migrateToGlobalDaemon() functions
- Remove shouldUseGlobalDaemon() and getGlobalBeadsDir() functions
- Simplify functions that had global bool parameters
- Remove warning about old global socket in getSocketPath()

This reduces code complexity and removes 238 net lines of unused code.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-24 23:39:30 -08:00
parent 58f767121d
commit f3e1268b33
5 changed files with 68 additions and 306 deletions

View File

@@ -45,22 +45,20 @@ Run 'bd daemon' with no flags to see available options.`,
status, _ := cmd.Flags().GetBool("status") status, _ := cmd.Flags().GetBool("status")
health, _ := cmd.Flags().GetBool("health") health, _ := cmd.Flags().GetBool("health")
metrics, _ := cmd.Flags().GetBool("metrics") metrics, _ := cmd.Flags().GetBool("metrics")
migrateToGlobal, _ := cmd.Flags().GetBool("migrate-to-global")
interval, _ := cmd.Flags().GetDuration("interval") interval, _ := cmd.Flags().GetDuration("interval")
autoCommit, _ := cmd.Flags().GetBool("auto-commit") autoCommit, _ := cmd.Flags().GetBool("auto-commit")
autoPush, _ := cmd.Flags().GetBool("auto-push") autoPush, _ := cmd.Flags().GetBool("auto-push")
logFile, _ := cmd.Flags().GetString("log") logFile, _ := cmd.Flags().GetString("log")
global, _ := cmd.Flags().GetBool("global")
// If no operation flags provided, show help // If no operation flags provided, show help
if !start && !stop && !status && !health && !metrics && !migrateToGlobal { if !start && !stop && !status && !health && !metrics {
_ = cmd.Help() _ = cmd.Help()
return return
} }
// If auto-commit/auto-push flags weren't explicitly provided, read from config // If auto-commit/auto-push flags weren't explicitly provided, read from config
// (skip if --stop, --status, --health, --metrics, or --migrate-to-global) // (skip if --stop, --status, --health, --metrics)
if start && !stop && !status && !health && !metrics && !migrateToGlobal && !global { if start && !stop && !status && !health && !metrics {
if !cmd.Flags().Changed("auto-commit") { if !cmd.Flags().Changed("auto-commit") {
if dbPath := beads.FindDatabasePath(); dbPath != "" { if dbPath := beads.FindDatabasePath(); dbPath != "" {
ctx := context.Background() ctx := context.Background()
@@ -92,29 +90,24 @@ Run 'bd daemon' with no flags to see available options.`,
os.Exit(1) os.Exit(1)
} }
pidFile, err := getPIDFilePath(global) pidFile, err := getPIDFilePath()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err) fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1) os.Exit(1)
} }
if status { if status {
showDaemonStatus(pidFile, global) showDaemonStatus(pidFile)
return return
} }
if health { if health {
showDaemonHealth(global) showDaemonHealth()
return return
} }
if metrics { if metrics {
showDaemonMetrics(global) showDaemonMetrics()
return
}
if migrateToGlobal {
migrateToGlobalDaemon()
return return
} }
@@ -137,7 +130,7 @@ Run 'bd daemon' with no flags to see available options.`,
// Check if daemon is already running // Check if daemon is already running
if isRunning, pid := isDaemonRunning(pidFile); isRunning { if isRunning, pid := isDaemonRunning(pidFile); isRunning {
// Check if running daemon has compatible version // Check if running daemon has compatible version
socketPath := getSocketPathForPID(pidFile, global) socketPath := getSocketPathForPID(pidFile)
if client, err := rpc.TryConnectWithTimeout(socketPath, 1*time.Second); err == nil && client != nil { if client, err := rpc.TryConnectWithTimeout(socketPath, 1*time.Second); err == nil && client != nil {
health, healthErr := client.Health() health, healthErr := client.Health()
_ = client.Close() _ = client.Close()
@@ -145,7 +138,7 @@ Run 'bd daemon' with no flags to see available options.`,
// If we can check version and it's compatible, exit // If we can check version and it's compatible, exit
if healthErr == nil && health.Compatible { if healthErr == nil && health.Compatible {
fmt.Fprintf(os.Stderr, "Error: daemon already running (PID %d, version %s)\n", pid, health.Version) fmt.Fprintf(os.Stderr, "Error: daemon already running (PID %d, version %s)\n", pid, health.Version)
fmt.Fprintf(os.Stderr, "Use 'bd daemon --stop%s' to stop it first\n", boolToFlag(global, " --global")) fmt.Fprintf(os.Stderr, "Use 'bd daemon --stop' to stop it first\n")
os.Exit(1) os.Exit(1)
} }
@@ -159,22 +152,14 @@ Run 'bd daemon' with no flags to see available options.`,
} else { } else {
// Can't check version - assume incompatible // Can't check version - assume incompatible
fmt.Fprintf(os.Stderr, "Error: daemon already running (PID %d)\n", pid) fmt.Fprintf(os.Stderr, "Error: daemon already running (PID %d)\n", pid)
fmt.Fprintf(os.Stderr, "Use 'bd daemon --stop%s' to stop it first\n", boolToFlag(global, " --global")) fmt.Fprintf(os.Stderr, "Use 'bd daemon --stop' to stop it first\n")
os.Exit(1) os.Exit(1)
} }
} }
} }
// Global daemon doesn't support auto-commit/auto-push (no sync loop) // Validate we're in a git repo
if global && (autoCommit || autoPush) { if !isGitRepo() {
fmt.Fprintf(os.Stderr, "Error: --auto-commit and --auto-push are not supported with --global\n")
fmt.Fprintf(os.Stderr, "Hint: global daemon runs in routing mode and doesn't perform background sync\n")
fmt.Fprintf(os.Stderr, " Use local daemon (without --global) for auto-commit/auto-push features\n")
os.Exit(1)
}
// Validate we're in a git repo (skip for global daemon)
if !global && !isGitRepo() {
fmt.Fprintf(os.Stderr, "Error: not in a git repository\n") fmt.Fprintf(os.Stderr, "Error: not in a git repository\n")
fmt.Fprintf(os.Stderr, "Hint: run 'git init' to initialize a repository\n") fmt.Fprintf(os.Stderr, "Hint: run 'git init' to initialize a repository\n")
os.Exit(1) os.Exit(1)
@@ -188,30 +173,24 @@ Run 'bd daemon' with no flags to see available options.`,
} }
// Warn if starting daemon in a git worktree // Warn if starting daemon in a git worktree
if !global { // Ensure dbPath is set for warning
// Ensure dbPath is set for warning if dbPath == "" {
if dbPath == "" { if foundDB := beads.FindDatabasePath(); foundDB != "" {
if foundDB := beads.FindDatabasePath(); foundDB != "" { dbPath = foundDB
dbPath = foundDB
}
}
if dbPath != "" {
warnWorktreeDaemon(dbPath)
} }
} }
if dbPath != "" {
warnWorktreeDaemon(dbPath)
}
// Start daemon // Start daemon
scope := "local" fmt.Printf("Starting bd daemon (interval: %v, auto-commit: %v, auto-push: %v)\n",
if global { interval, autoCommit, autoPush)
scope = "global"
}
fmt.Printf("Starting bd daemon (%s, interval: %v, auto-commit: %v, auto-push: %v)\n",
scope, interval, autoCommit, autoPush)
if logFile != "" { if logFile != "" {
fmt.Printf("Logging to: %s\n", logFile) fmt.Printf("Logging to: %s\n", logFile)
} }
startDaemon(interval, autoCommit, autoPush, logFile, pidFile, global) startDaemon(interval, autoCommit, autoPush, logFile, pidFile)
}, },
} }
@@ -224,9 +203,7 @@ func init() {
daemonCmd.Flags().Bool("status", false, "Show daemon status") daemonCmd.Flags().Bool("status", false, "Show daemon status")
daemonCmd.Flags().Bool("health", false, "Check daemon health and metrics") daemonCmd.Flags().Bool("health", false, "Check daemon health and metrics")
daemonCmd.Flags().Bool("metrics", false, "Show detailed daemon metrics") daemonCmd.Flags().Bool("metrics", false, "Show detailed daemon metrics")
daemonCmd.Flags().Bool("migrate-to-global", false, "Migrate from local to global daemon")
daemonCmd.Flags().String("log", "", "Log file path (default: .beads/daemon.log)") daemonCmd.Flags().String("log", "", "Log file path (default: .beads/daemon.log)")
daemonCmd.Flags().Bool("global", false, "Run as global daemon (socket at ~/.beads/bd.sock)")
daemonCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format") daemonCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
rootCmd.AddCommand(daemonCmd) rootCmd.AddCommand(daemonCmd)
} }
@@ -243,7 +220,7 @@ func computeDaemonParentPID() int {
} }
return os.Getppid() return os.Getppid()
} }
func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, pidFile string, global bool) { func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, pidFile string) {
logF, log := setupDaemonLogger(logPath) logF, log := setupDaemonLogger(logPath)
defer func() { _ = logF.Close() }() defer func() { _ = logF.Close() }()
@@ -264,7 +241,7 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, p
// Write crash report to daemon-error file for user visibility // Write crash report to daemon-error file for user visibility
var beadsDir string var beadsDir string
if !global && dbPath != "" { if dbPath != "" {
beadsDir = filepath.Dir(dbPath) beadsDir = filepath.Dir(dbPath)
} else if foundDB := beads.FindDatabasePath(); foundDB != "" { } else if foundDB := beads.FindDatabasePath(); foundDB != "" {
beadsDir = filepath.Dir(foundDB) beadsDir = filepath.Dir(foundDB)
@@ -288,17 +265,14 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, p
}() }()
// Determine database path first (needed for lock file metadata) // Determine database path first (needed for lock file metadata)
daemonDBPath := "" daemonDBPath := dbPath
if !global { if daemonDBPath == "" {
daemonDBPath = dbPath if foundDB := beads.FindDatabasePath(); foundDB != "" {
if daemonDBPath == "" { daemonDBPath = foundDB
if foundDB := beads.FindDatabasePath(); foundDB != "" { } else {
daemonDBPath = foundDB log.log("Error: no beads database found")
} else { log.log("Hint: run 'bd init' to create a database or set BEADS_DB environment variable")
log.log("Error: no beads database found") return // Use return instead of os.Exit to allow defers to run
log.log("Hint: run 'bd init' to create a database or set BEADS_DB environment variable")
return // Use return instead of os.Exit to allow defers to run
}
} }
} }
@@ -311,11 +285,6 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, p
log.log("Daemon started (interval: %v, auto-commit: %v, auto-push: %v)", interval, autoCommit, autoPush) log.log("Daemon started (interval: %v, auto-commit: %v, auto-push: %v)", interval, autoCommit, autoPush)
if global {
runGlobalDaemon(ctx, log)
return
}
// Check for multiple .db files (ambiguity error) // Check for multiple .db files (ambiguity error)
beadsDir := filepath.Dir(daemonDBPath) beadsDir := filepath.Dir(daemonDBPath)
matches, err := filepath.Glob(filepath.Join(beadsDir, "*.db")) matches, err := filepath.Glob(filepath.Join(beadsDir, "*.db"))

View File

@@ -33,22 +33,11 @@ func shouldAutoStartDaemon() bool {
return config.GetBool("auto-start-daemon") // Defaults to true return config.GetBool("auto-start-daemon") // Defaults to true
} }
// shouldUseGlobalDaemon determines if global daemon should be preferred
// based on heuristics (multi-repo detection)
// Note: Global daemon is deprecated; this always returns false for now
func shouldUseGlobalDaemon() bool {
// Global daemon support is deprecated
// Always use local daemon (per-project .beads/ socket)
// Previously supported BEADS_PREFER_GLOBAL_DAEMON env var, but global
// daemon has issues with multi-workspace git workflows
return false
}
// restartDaemonForVersionMismatch stops the old daemon and starts a new one // restartDaemonForVersionMismatch stops the old daemon and starts a new one
// Returns true if restart was successful // Returns true if restart was successful
func restartDaemonForVersionMismatch() bool { func restartDaemonForVersionMismatch() bool {
// Use local daemon (global is deprecated) pidFile, err := getPIDFilePath()
pidFile, err := getPIDFilePath(false)
if err != nil { if err != nil {
debug.Logf("failed to get PID file path: %v", err) debug.Logf("failed to get PID file path: %v", err)
return false return false
@@ -173,8 +162,8 @@ func tryAutoStartDaemon(socketPath string) bool {
return true return true
} }
socketPath, isGlobal := determineSocketMode(socketPath) socketPath = determineSocketPath(socketPath)
return startDaemonProcess(socketPath, isGlobal) return startDaemonProcess(socketPath)
} }
func debugLog(msg string, args ...interface{}) { func debugLog(msg string, args ...interface{}) {
@@ -242,40 +231,22 @@ func handleExistingSocket(socketPath string) bool {
return false return false
} }
func determineSocketMode(socketPath string) (string, bool) { func determineSocketPath(socketPath string) string {
home, err := os.UserHomeDir() return socketPath
if err != nil {
return socketPath, false
}
globalSocket := filepath.Join(home, ".beads", "bd.sock")
if socketPath == globalSocket {
return socketPath, true
}
if shouldUseGlobalDaemon() {
debugLog("detected multiple repos, auto-starting global daemon")
return globalSocket, true
}
return socketPath, false
} }
func startDaemonProcess(socketPath string, isGlobal bool) bool { func startDaemonProcess(socketPath string) bool {
binPath, err := os.Executable() binPath, err := os.Executable()
if err != nil { if err != nil {
binPath = os.Args[0] binPath = os.Args[0]
} }
args := []string{"daemon", "--start"} args := []string{"daemon", "--start"}
if isGlobal {
args = append(args, "--global")
}
cmd := exec.Command(binPath, args...) cmd := exec.Command(binPath, args...)
setupDaemonIO(cmd) setupDaemonIO(cmd)
if !isGlobal && dbPath != "" { if dbPath != "" {
cmd.Dir = filepath.Dir(dbPath) cmd.Dir = filepath.Dir(dbPath)
} }
@@ -389,22 +360,9 @@ func recordDaemonStartFailure() {
} }
// getSocketPath returns the daemon socket path based on the database location // getSocketPath returns the daemon socket path based on the database location
// Always returns local socket path (.beads/bd.sock relative to database) // Returns local socket path (.beads/bd.sock relative to database)
func getSocketPath() string { func getSocketPath() string {
// Always use local socket (same directory as database: .beads/bd.sock) return filepath.Join(filepath.Dir(dbPath), "bd.sock")
localSocket := filepath.Join(filepath.Dir(dbPath), "bd.sock")
// Warn if old global socket exists
if home, err := os.UserHomeDir(); err == nil {
globalSocket := filepath.Join(home, ".beads", "bd.sock")
if _, err := os.Stat(globalSocket); err == nil {
fmt.Fprintf(os.Stderr, "Warning: Found old global daemon socket at %s\n", globalSocket)
fmt.Fprintf(os.Stderr, "Global sockets are deprecated. Each project now uses its own local daemon.\n")
fmt.Fprintf(os.Stderr, "To migrate: Stop the global daemon and restart with 'bd daemon' in each project.\n")
}
}
return localSocket
} }
// emitVerboseWarning prints a one-line warning when falling back to direct mode // emitVerboseWarning prints a one-line warning when falling back to direct mode

View File

@@ -9,21 +9,6 @@ import (
"github.com/steveyegge/beads/internal/beads" "github.com/steveyegge/beads/internal/beads"
) )
// getGlobalBeadsDir returns the global beads directory (~/.beads)
func getGlobalBeadsDir() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("cannot get home directory: %w", err)
}
beadsDir := filepath.Join(home, ".beads")
if err := os.MkdirAll(beadsDir, 0700); err != nil {
return "", fmt.Errorf("cannot create global beads directory: %w", err)
}
return beadsDir, nil
}
// ensureBeadsDir ensures the local beads directory exists (.beads in the current workspace) // ensureBeadsDir ensures the local beads directory exists (.beads in the current workspace)
func ensureBeadsDir() (string, error) { func ensureBeadsDir() (string, error) {
var beadsDir string var beadsDir string
@@ -74,26 +59,14 @@ func getEnvBool(key string, defaultValue bool) bool {
} }
// getSocketPathForPID determines the socket path for a given PID file // getSocketPathForPID determines the socket path for a given PID file
func getSocketPathForPID(pidFile string, global bool) string { func getSocketPathForPID(pidFile string) string {
if global { // Socket is in same directory as PID file
home, _ := os.UserHomeDir()
return filepath.Join(home, ".beads", "bd.sock")
}
// Local daemon: socket is in same directory as PID file
return filepath.Join(filepath.Dir(pidFile), "bd.sock") return filepath.Join(filepath.Dir(pidFile), "bd.sock")
} }
// getPIDFilePath returns the path to the daemon PID file // getPIDFilePath returns the path to the daemon PID file
func getPIDFilePath(global bool) (string, error) { func getPIDFilePath() (string, error) {
var beadsDir string beadsDir, err := ensureBeadsDir()
var err error
if global {
beadsDir, err = getGlobalBeadsDir()
} else {
beadsDir, err = ensureBeadsDir()
}
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -101,20 +74,12 @@ func getPIDFilePath(global bool) (string, error) {
} }
// getLogFilePath returns the path to the daemon log file // getLogFilePath returns the path to the daemon log file
func getLogFilePath(userPath string, global bool) (string, error) { func getLogFilePath(userPath string) (string, error) {
if userPath != "" { if userPath != "" {
return userPath, nil return userPath, nil
} }
var beadsDir string beadsDir, err := ensureBeadsDir()
var err error
if global {
beadsDir, err = getGlobalBeadsDir()
} else {
beadsDir, err = ensureBeadsDir()
}
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@@ -40,20 +40,15 @@ func formatUptime(seconds float64) string {
} }
// showDaemonStatus displays the current daemon status // showDaemonStatus displays the current daemon status
func showDaemonStatus(pidFile string, global bool) { func showDaemonStatus(pidFile string) {
if isRunning, pid := isDaemonRunning(pidFile); isRunning { if isRunning, pid := isDaemonRunning(pidFile); isRunning {
scope := "local"
if global {
scope = "global"
}
var started string var started string
if info, err := os.Stat(pidFile); err == nil { if info, err := os.Stat(pidFile); err == nil {
started = info.ModTime().Format("2006-01-02 15:04:05") started = info.ModTime().Format("2006-01-02 15:04:05")
} }
var logPath string var logPath string
if lp, err := getLogFilePath("", global); err == nil { if lp, err := getLogFilePath(""); err == nil {
if _, err := os.Stat(lp); err == nil { if _, err := os.Stat(lp); err == nil {
logPath = lp logPath = lp
} }
@@ -63,7 +58,6 @@ func showDaemonStatus(pidFile string, global bool) {
status := map[string]interface{}{ status := map[string]interface{}{
"running": true, "running": true,
"pid": pid, "pid": pid,
"scope": scope,
} }
if started != "" { if started != "" {
status["started"] = started status["started"] = started
@@ -75,7 +69,7 @@ func showDaemonStatus(pidFile string, global bool) {
return return
} }
fmt.Printf("Daemon is running (PID %d, %s)\n", pid, scope) fmt.Printf("Daemon is running (PID %d)\n", pid)
if started != "" { if started != "" {
fmt.Printf(" Started: %s\n", started) fmt.Printf(" Started: %s\n", started)
} }
@@ -92,23 +86,13 @@ func showDaemonStatus(pidFile string, global bool) {
} }
// showDaemonHealth displays daemon health information // showDaemonHealth displays daemon health information
func showDaemonHealth(global bool) { func showDaemonHealth() {
var socketPath string beadsDir, err := ensureBeadsDir()
if global { if err != nil {
home, err := os.UserHomeDir() fmt.Fprintf(os.Stderr, "Error: %v\n", err)
if err != nil { os.Exit(1)
fmt.Fprintf(os.Stderr, "Error: cannot get home directory: %v\n", err)
os.Exit(1)
}
socketPath = filepath.Join(home, ".beads", "bd.sock")
} else {
beadsDir, err := ensureBeadsDir()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
socketPath = filepath.Join(beadsDir, "bd.sock")
} }
socketPath := filepath.Join(beadsDir, "bd.sock")
client, err := rpc.TryConnect(socketPath) client, err := rpc.TryConnect(socketPath)
if err != nil { if err != nil {
@@ -159,23 +143,13 @@ func showDaemonHealth(global bool) {
} }
// showDaemonMetrics displays daemon metrics // showDaemonMetrics displays daemon metrics
func showDaemonMetrics(global bool) { func showDaemonMetrics() {
var socketPath string beadsDir, err := ensureBeadsDir()
if global { if err != nil {
home, err := os.UserHomeDir() fmt.Fprintf(os.Stderr, "Error: %v\n", err)
if err != nil { os.Exit(1)
fmt.Fprintf(os.Stderr, "Error: cannot get home directory: %v\n", err)
os.Exit(1)
}
socketPath = filepath.Join(home, ".beads", "bd.sock")
} else {
beadsDir, err := ensureBeadsDir()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
socketPath = filepath.Join(beadsDir, "bd.sock")
} }
socketPath := filepath.Join(beadsDir, "bd.sock")
client, err := rpc.TryConnect(socketPath) client, err := rpc.TryConnect(socketPath)
if err != nil { if err != nil {
@@ -242,71 +216,6 @@ func showDaemonMetrics(global bool) {
} }
} }
// migrateToGlobalDaemon migrates from local to global daemon
func migrateToGlobalDaemon() {
home, err := os.UserHomeDir()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: cannot get home directory: %v\n", err)
os.Exit(1)
}
localPIDFile := filepath.Join(".beads", "daemon.pid")
globalPIDFile := filepath.Join(home, ".beads", "daemon.pid")
// Check if local daemon is running
localRunning, localPID := isDaemonRunning(localPIDFile)
if !localRunning {
fmt.Println("No local daemon is running")
} else {
fmt.Printf("Stopping local daemon (PID %d)...\n", localPID)
stopDaemon(localPIDFile)
}
// Check if global daemon is already running
globalRunning, globalPID := isDaemonRunning(globalPIDFile)
if globalRunning {
fmt.Printf("Global daemon already running (PID %d)\n", globalPID)
return
}
// Start global daemon
fmt.Println("Starting global daemon...")
binPath, err := os.Executable()
if err != nil {
binPath = os.Args[0]
}
cmd := exec.Command(binPath, "daemon", "--global") // #nosec G204 - bd daemon command from trusted binary
devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0)
if err == nil {
cmd.Stdout = devNull
cmd.Stderr = devNull
cmd.Stdin = devNull
defer func() { _ = devNull.Close() }()
}
configureDaemonProcess(cmd)
if err := cmd.Start(); err != nil {
fmt.Fprintf(os.Stderr, "Error: failed to start global daemon: %v\n", err)
os.Exit(1)
}
go func() { _ = cmd.Wait() }()
// Wait for daemon to be ready
time.Sleep(2 * time.Second)
if isRunning, pid := isDaemonRunning(globalPIDFile); isRunning {
fmt.Printf("Global daemon started successfully (PID %d)\n", pid)
fmt.Println()
fmt.Println("Migration complete! The global daemon will now serve all your beads repositories.")
fmt.Println("Set BEADS_PREFER_GLOBAL_DAEMON=1 in your shell to make this permanent.")
} else {
fmt.Fprintf(os.Stderr, "Error: global daemon failed to start\n")
os.Exit(1)
}
}
// stopDaemon stops a running daemon // stopDaemon stops a running daemon
func stopDaemon(pidFile string) { func stopDaemon(pidFile string) {
isRunning, pid := isDaemonRunning(pidFile) isRunning, pid := isDaemonRunning(pidFile)
@@ -344,9 +253,7 @@ func stopDaemon(pidFile string) {
return return
} }
// Determine if this is global or local daemon socketPath := getSocketPathForPID(pidFile)
isGlobal := strings.Contains(pidFile, filepath.Join(".beads", "daemon.lock"))
socketPath := getSocketPathForPID(pidFile, isGlobal)
if err := process.Kill(); err != nil { if err := process.Kill(); err != nil {
// Ignore "process already finished" errors // Ignore "process already finished" errors
@@ -369,15 +276,15 @@ func stopDaemon(pidFile string) {
} }
// startDaemon starts the daemon in background // startDaemon starts the daemon in background
func startDaemon(interval time.Duration, autoCommit, autoPush bool, logFile, pidFile string, global bool) { func startDaemon(interval time.Duration, autoCommit, autoPush bool, logFile, pidFile string) {
logPath, err := getLogFilePath(logFile, global) logPath, err := getLogFilePath(logFile)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err) fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1) os.Exit(1)
} }
if os.Getenv("BD_DAEMON_FOREGROUND") == "1" { if os.Getenv("BD_DAEMON_FOREGROUND") == "1" {
runDaemonLoop(interval, autoCommit, autoPush, logPath, pidFile, global) runDaemonLoop(interval, autoCommit, autoPush, logPath, pidFile)
return return
} }
@@ -399,9 +306,6 @@ func startDaemon(interval time.Duration, autoCommit, autoPush bool, logFile, pid
if logFile != "" { if logFile != "" {
args = append(args, "--log", logFile) args = append(args, "--log", logFile)
} }
if global {
args = append(args, "--global")
}
cmd := exec.Command(exe, args...) // #nosec G204 - bd daemon command from trusted binary cmd := exec.Command(exe, args...) // #nosec G204 - bd daemon command from trusted binary
cmd.Env = append(os.Environ(), "BD_DAEMON_FOREGROUND=1") cmd.Env = append(os.Environ(), "BD_DAEMON_FOREGROUND=1")

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"os" "os"
"os/signal" "os/signal"
"path/filepath"
"time" "time"
"github.com/steveyegge/beads/internal/rpc" "github.com/steveyegge/beads/internal/rpc"
@@ -40,39 +39,6 @@ func startRPCServer(ctx context.Context, socketPath string, store storage.Storag
return server, serverErrChan, nil return server, serverErrChan, nil
} }
// runGlobalDaemon runs the global routing daemon
func runGlobalDaemon(ctx context.Context, log daemonLogger) {
globalDir, err := getGlobalBeadsDir()
if err != nil {
log.log("Error: cannot get global beads directory: %v", err)
os.Exit(1)
}
socketPath := filepath.Join(globalDir, "bd.sock")
serverCtx, cancel := context.WithCancel(ctx)
defer cancel()
server, _, err := startRPCServer(serverCtx, socketPath, nil, globalDir, "", log)
if err != nil {
return
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, daemonSignals...)
defer signal.Stop(sigChan)
sig := <-sigChan
log.log("Received signal: %v", sig)
log.log("Shutting down global daemon...")
cancel()
if err := server.Stop(); err != nil {
log.log("Error stopping server: %v", err)
}
log.log("Global daemon stopped")
}
// checkParentProcessAlive checks if the parent process is still running. // checkParentProcessAlive checks if the parent process is still running.
// Returns true if parent is alive, false if it died. // Returns true if parent is alive, false if it died.
// Returns true if parent PID is 0 or 1 (not tracked, or adopted by init). // Returns true if parent PID is 0 or 1 (not tracked, or adopted by init).