Skip to content

fix(cli): make grob stop recognise its daemon on macOS - #481

Merged
Destynova2 merged 1 commit into
mainfrom
fix/macos-grob-stop-identity
Jul 27, 2026
Merged

fix(cli): make grob stop recognise its daemon on macOS#481
Destynova2 merged 1 commit into
mainfrom
fix/macos-grob-stop-identity

Conversation

@Destynova2

Copy link
Copy Markdown
Contributor

The bug

On macOS, grob stop refused to stop its own running daemon:

❌ Failed to stop service (PID: 41257): refusing to stop PID 41257: not a running Grob process

…and grob start -d (restart) silently left the old daemon running, so a
restart never actually took effect.

Cause

command_invokes_grob (the PID-identity guard) split the process command line
only on NUL. That matches Linux /proc/<pid>/cmdline (grob\0start\0) but not
macOS ps -o command=, which is space-separated:

/opt/homebrew/bin/grob start

With no NUL, the whole string reached Path::file_name, giving "grob start"
(≠ "grob"). So is_process_running returned false for a live daemon, and both
grob stop and the restart path in grob start refused to act.

Reproduced:

executable = "grob start"  → == "grob" ? false

Fix

Pick the separator by which one is present — NUL when the string contains it
(Linux), whitespace otherwise (macOS):

let first_arg = if command.contains('\0') {
    command.split('\0').next()
} else {
    command.split_whitespace().next()
}

All existing negative cases still hold (grob-upgrade, python …/grob.py,
agrob-helper).

Verification

  • Unit tests: added command_identity_accepts_space_separated_macos_form
    (the exact ps string); existing test still green.
  • End to end on macOS: a daemon started with the fixed binary is now stopped by
    grob stop✅ Service stopped successfully (was refusing to stop).

Note (single-daemon model)

The pid file is a single global ~/.grob/grob.pid. With identity now working,
grob start on any port stops whatever that file points at — so a second daemon
on another port replaces the first. That's consistent with the one-daemon
design; a port-scoped pid file would be a separate change if parallel daemons
are ever wanted.

🤖 Generated with Claude Code

`command_invokes_grob` split the process command line only on NUL. That fits
Linux `/proc/<pid>/cmdline` (`grob\0start\0`) but not macOS `ps -o command=`,
which is space-separated (`/opt/homebrew/bin/grob start`). The whole string
then reached `Path::file_name`, yielding `"grob start"` (≠ `"grob"`), so
`is_process_running` returned false for a live daemon and `grob stop` / the
restart path in `grob start` both refused to act — the daemon could not be
stopped or cleanly restarted on macOS.

Pick the separator by which one is present: NUL when the string contains it
(Linux), whitespace otherwise (macOS). Existing negative cases still hold
(`grob-upgrade`, `python …/grob.py`, `agrob-helper`).

Verified end to end: a daemon started with the fixed binary is now stopped by
`grob stop` ("Service stopped successfully") instead of "refusing to stop".

Note: the pid file is a single global `~/.grob/grob.pid` (one-daemon model), so
with identity now working, `grob start` on any port stops whatever that file
points at. Running a second daemon on another port therefore replaces the first
— expected for the single-daemon design, but worth knowing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Destynova2
Destynova2 enabled auto-merge (squash) July 26, 2026 09:49
@Destynova2
Destynova2 merged commit e323056 into main Jul 27, 2026
67 of 70 checks passed
@Destynova2
Destynova2 deleted the fix/macos-grob-stop-identity branch July 27, 2026 06:31
Destynova2 added a commit that referenced this pull request Jul 27, 2026
## 🤖 New release

* `grob`: 0.36.83 -> 0.36.84

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

##
[0.36.84](v0.36.83...v0.36.84)
- 2026-07-27

### Fixed

- *(cli)* make grob stop recognise its daemon on macOS
([#481](#481))

### Other

- switch merge policy to squash-only for reliable release-plz
([#480](#480))
- *(release-plz)* allow manual workflow_dispatch
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
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