feat(01-01): implement FindClaudeProcesses and EncodePath

- Scan /proc for PIDs with "claude" in cmdline
- Read cwd via os.Readlink, skip errors silently
- EncodePath replaces / and . with - for ~/.claude/projects/ folder names

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pierre Martin
2026-03-23 13:25:27 +01:00
parent 81ee7dc49d
commit 166e44161d

62
proc.go Normal file
View File

@@ -0,0 +1,62 @@
package main
import (
"os"
"path/filepath"
"strconv"
"strings"
)
// FindClaudeProcesses scans procDir (typically "/proc") for active Claude Code processes.
// It returns a Process for each PID whose cmdline starts with "claude".
// Read errors (permission denied, vanished process) are silently skipped.
func FindClaudeProcesses(procDir string) ([]Process, error) {
entries, err := os.ReadDir(procDir)
if err != nil {
return nil, err
}
var procs []Process
for _, entry := range entries {
pid, err := strconv.Atoi(entry.Name())
if err != nil {
continue // not a PID directory
}
cmdlineData, err := os.ReadFile(filepath.Join(procDir, entry.Name(), "cmdline"))
if err != nil {
continue // permission denied or process vanished
}
parts := strings.Split(strings.TrimRight(string(cmdlineData), "\x00"), "\x00")
if len(parts) == 0 {
continue
}
// Match if the binary name ends with "claude" or is exactly "claude"
bin := filepath.Base(parts[0])
if bin != "claude" {
continue
}
cwd, err := os.Readlink(filepath.Join(procDir, entry.Name(), "cwd"))
if err != nil {
continue // cannot read cwd
}
procs = append(procs, Process{
PID: pid,
Cmd: parts,
Cwd: cwd,
})
}
return procs, nil
}
// EncodePath converts an absolute path to the folder name format used by
// ~/.claude/projects/. Slashes and dots are replaced with dashes.
func EncodePath(path string) string {
return strings.NewReplacer("/", "-", ".", "-").Replace(path)
}