Skip to content

fix: support Linux procStart and socket dir - #62

Open
anton000 wants to merge 3 commits into
ExaDev:mainfrom
amstarlabs:fix/linux-procstart-socketdir
Open

anton000 wants to merge 3 commits into
ExaDev:mainfrom
amstarlabs:fix/linux-procstart-socketdir

Conversation

@anton000

Copy link
Copy Markdown

On Linux, Claude Code writes two registry values differently from what cc-peer 1.6.8 expects. As a
result, a cc-peer peer and real Claude Code sessions do not see each other.

procStart. Linux Claude Code records the process start time in clock ticks, field 22 of
/proc/<pid>/stat. cc-peer compares it with ps -o lstart= output, so it classes every real session as a
recycled pid and leaves it out of roster(). Claude Code in turn leaves cc-peer's own entry out of ListAgents.

Socket dir. Linux Claude Code binds its inbox under $XDG_RUNTIME_DIR/cc-socks. cc-peer binds
under /tmp/cc-socks first.

Changes

  • Add LinuxProcInfo. Its lstart() reads /proc/<pid>/stat and returns field 22. It parses after
    the last ), so a command name with spaces or parentheses does not shift the fields.
    CcPeer.create() uses it on Linux. macOS and Windows are unchanged.
  • On Linux, socketDirCandidates() puts $XDG_RUNTIME_DIR/cc-socks first when the variable is set.
    Other platforms and an explicit socketDir are unchanged.
  • Tests for both, plus a unit test for CachedPidCommand's cache hit. Linux no longer reaches that path
    through PsProcInfo, so it needs its own test. A Linux note in docs/PROTOCOL.md.

Evidence (Debian 13, kernel 6.12.101, Claude Code 2.1.294):

registry:  "procStart": "249560752", "messagingSocketPath": "/run/user/0/cc-socks/1780977.sock"
$ awk '{print $22}' /proc/1780977/stat
249560752
$ LC_ALL=C TZ=UTC ps -o lstart= -p 1780977
Sat Oct 10 04:39:34 2026

The same holds for 2.1.281 and 2.1.296.

Repro. On Linux with a Claude Code session running: CcPeer.create({ name: "probe" }), then
roster() returns no sessions, and the session's ListAgents does not show probe. With this branch,
roster() lists the session and ListAgents shows probe. Lint, typecheck, build and the 100% coverage
gate pass. I ran them as a non-root user: three existing tests expect an unreadable file, and root can read
every file. Mutation testing passes too, but its config only mutates src/domain and
src/schemas, so it does not cover these changes.

Linux Claude Code records procStart as /proc/<pid>/stat field 22
(starttime, clock ticks), not the ps -o lstart= date string the
existing PsProcInfo reads. Every real session was failing the
roster's proc-start comparison and getting classed as recycled, so
cc-peer and a live Claude Code session never saw each other on
Linux.

LinuxProcInfo reads that field, parsing after the last ")" so a
comm containing spaces or parens cannot shift the fields. cc-peer.ts
now picks it via a selectProcInfo() helper, kept as its own export so
the platform choice itself has direct unit coverage.
On Linux Claude Code binds its inbox under $XDG_RUNTIME_DIR/cc-socks,
not /tmp/cc-socks, so socketDirCandidates() tried the wrong directory
first and a default-path cc-peer peer never found a live session to
connect to. An explicit socketDir still overrides the whole list, on
every platform, as before.

Two existing tests asserted the old fixed order using this machine's
real platform and its real $XDG_RUNTIME_DIR, so they now pin the
platform and env they mean to exercise (a new withEnv test helper,
mirroring withPlatform), and the Linux-first order gets its own test.
PROTOCOL.md was verified on macOS and documents procStart and the
socket directory as if ps -o lstart= and /tmp/cc-socks were universal.
Neither holds on Linux: add the two notes next to the rules they
override, so an implementer reading this file does not reproduce the
same Linux mismatch cc-peer itself shipped with.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant