From 05ea767149fceb15cf82c8ed22b4f0d427c07384 Mon Sep 17 00:00:00 2001 From: beads/crew/jane Date: Tue, 20 Jan 2026 20:24:07 -0800 Subject: [PATCH] fix: orphan-processes check only detects Gas Town processes Changed findRuntimeProcesses() to only detect Claude processes that have the --dangerously-skip-permissions flag. This is the signature of Gas Town managed processes - user's personal Claude sessions don't use this flag. Prevents false positives when users have personal Claude sessions running. Closes #611 Co-Authored-By: dwsmith1983 Co-Authored-By: Claude Opus 4.5 --- internal/doctor/orphan_check.go | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/doctor/orphan_check.go b/internal/doctor/orphan_check.go index 4192fc98..9173e721 100644 --- a/internal/doctor/orphan_check.go +++ b/internal/doctor/orphan_check.go @@ -5,7 +5,6 @@ import ( "os" "os/exec" "path/filepath" - "regexp" "strings" "github.com/steveyegge/gastown/internal/events" @@ -388,40 +387,41 @@ func (c *OrphanProcessCheck) getTmuxSessionPIDs() (map[int]bool, error) { //noli return pids, nil } -// findRuntimeProcesses finds all running runtime CLI processes. -// Excludes Claude.app desktop application and its helpers. +// findRuntimeProcesses finds Gas Town Claude processes (those with --dangerously-skip-permissions). +// Only detects processes started by Gas Town, not user's personal Claude sessions. func (c *OrphanProcessCheck) findRuntimeProcesses() ([]processInfo, error) { var procs []processInfo - // Use ps to find runtime processes - out, err := exec.Command("ps", "-eo", "pid,ppid,comm").Output() + // Use ps with args to get full command line (needed to check for Gas Town signature) + out, err := exec.Command("ps", "-eo", "pid,ppid,args").Output() if err != nil { return nil, err } - // Regex to match runtime CLI processes (not Claude.app) - // Match: "claude", "claude-code", or "codex" (or paths ending in those) - runtimePattern := regexp.MustCompile(`(?i)(^claude$|/claude$|^claude-code$|/claude-code$|^codex$|/codex$)`) - - // Pattern to exclude Claude.app and related desktop processes - excludePattern := regexp.MustCompile(`(?i)(Claude\.app|claude-native|chrome-native)`) - for _, line := range strings.Split(string(out), "\n") { fields := strings.Fields(line) if len(fields) < 3 { continue } - // Check if command matches runtime CLI - cmd := strings.Join(fields[2:], " ") + // Extract command name (without path) + cmd := fields[2] + if idx := strings.LastIndex(cmd, "/"); idx >= 0 { + cmd = cmd[idx+1:] + } - // Skip desktop app processes - if excludePattern.MatchString(cmd) { + // Only match claude/codex processes, not tmux or other launchers + // (tmux command line may contain --dangerously-skip-permissions as part of the launched command) + if cmd != "claude" && cmd != "claude-code" && cmd != "codex" { continue } - // Only match CLI runtime processes - if !runtimePattern.MatchString(cmd) { + // Get full args + args := strings.Join(fields[2:], " ") + + // Only match Gas Town Claude processes (have --dangerously-skip-permissions) + // This excludes user's personal Claude sessions + if !strings.Contains(args, "--dangerously-skip-permissions") { continue } @@ -436,7 +436,7 @@ func (c *OrphanProcessCheck) findRuntimeProcesses() ([]processInfo, error) { procs = append(procs, processInfo{ pid: pid, ppid: ppid, - cmd: cmd, + cmd: args, }) }