Skip to content

fix(pty): keep registration out of purged temp directories - #20

Merged
jlongster merged 6 commits into
masterfrom
state-runtime-dir
Oct 1, 2026
Merged

jlongster merged 6 commits into
masterfrom
state-runtime-dir

Conversation

@jlongster

@jlongster jlongster commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Replace OPENCODE_PTY_RUNTIME_DIR with explicit flags. Every command (daemon, play, status, list, watch, stop) requires --name NAME and accepts an optional --runtime-dir DIR; the runtime directory is DIR/NAME. Names must be one path component of letters, digits, ., _, or -.
  • DIR defaults to OpenCode's state directory, ${XDG_STATE_HOME:-~/.local/state}/opencode/pty, instead of $XDG_RUNTIME_DIR or the temp directory. macOS dirhelper deletes regular files in $TMPDIR whose creation and access times are over three days old, even while the daemon runs; this removed service.json and broke restart handoff discovery. The held service.lock survived because dirhelper skips open files.
  • Keep the socket under /tmp/opencode-pty-<uid>/ so its path always fits sun_path; macOS temp cleaners skip sockets.
  • On exit, remove the socket only if it is still this daemon's inode (matching remove_if_current for the registration), then remove the empty runtime directory.
  • At startup, sweep sibling runtime directories in DIR that are over ten minutes old, contain only registration files, and show daemon evidence: a lock that can be acquired, or, without a lock file, a valid registration whose PID is gone. Empty directories and directories with foreign or unparseable files are kept.
  • Document the flags, locations, and cleanup in README and SPEC.

Validation

  • cargo fmt --check, cargo clippy --all-targets --all-features -- -D warnings, and cargo test pass on macOS.
  • New tests cover default root resolution, name validation, sweep decisions (abandoned, young, foreign files, locked, live/dead PID, leftover socket, empty or foreign-registration directories kept), and that shutdown keeps a replaced socket. Existing daemon and playground tests use isolated --runtime-dir roots and assert the runtime directory is removed on exit.
  • Manual: play --name demo --runtime-dir DIR was found by status/list with the same flags, swept a backdated abandoned sibling, and left DIR empty after quit; a missing or invalid --name is rejected.

Rollout

Breaking CLI change: OpenCode must spawn daemon --runtime-dir <root> --name <id> instead of setting OPENCODE_PTY_RUNTIME_DIR, together with the release bump. OPENCODE_PTY_RUNTIME_DIR is removed entirely. Existing handoffs carry their directory, so daemons still running from the legacy temp directory remain adoptable: OpenCode moves their service.lock and service.json into <root>/<id> by rename (the inode, and so the old daemon's flock, is preserved) and uses that directory from then on. If any step fails, OpenCode abandons the old daemon and starts a fresh one in a new directory; it never respawns into a legacy temp directory.

@jlongster
jlongster merged commit 1a48d68 into master Oct 1, 2026
5 checks passed
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