Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/planning/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "planning",
"version": "0.58.3",
"version": "0.58.4",
"userConfig": {
"surface": {
"type": "string",
Expand Down
6 changes: 6 additions & 0 deletions plugins/planning/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
All notable changes to the `planning` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.58.4] - 2026-10-01

### Fixed

- **The `watch.test.sh` clean-stop case kills the server by native pid on Windows Git Bash.** `kill` does not know a native Windows pid, so the server kept answering and the case failed while `watch.sh` was correct; the case now uses `taskkill` on `MINGW*`, `MSYS*` and `CYGWIN*` and `kill` elsewhere. The suite passes 27 of 27 on Windows Git Bash, and after `round.sh stop` the watcher exits 3 with the stop message and no `watch.sh` or curl long-poll is left, which the surface README now states ([#5723](https://github.com/melodic-software/claude-code-plugins/issues/5723)).

## [0.58.3] - 2026-10-01

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion plugins/planning/surface/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ bash round.sh --dir '<data_dir>' ensure-running [--port P] [--open] [--user-sett
bash round.sh --dir '<data_dir>' stop
```

`ensure-running` checks for curl, reuses the server already running for the data dir (same PID), and otherwise starts one in the background (on Windows through the base interpreter, with no console window) on the first free port of `--port`, the recorded port, and the resolved `port` setting (an explicit `--port 0` skips the setting), else a free port. It waits for the server's own session files, prints the URL, and with `--open` opens the page unless the resolved `openBrowser` is `false`, through the `browserCommand` of the `--user-settings` file this same call passes, else the default browser. Without `--user-settings`, the user file the running server recorded still supplies `openBrowser` and `waitTimeout`, but never the opener. The URL is always built from the recorded port as `http://127.0.0.1:<port>/`. `--emoji-markers` takes any value: only `true`, `1`, `yes` and `on` (any case) mean true, and anything else, an empty string or an unexpanded `user_config` token included, means false. The value is written to `meta.emojiMarkers`; an absent flag keeps the recorded value, and a new file records false, so pass the session's value each time, including on a restart. `stop` ends the recorded PID only after `/api/ping` on the recorded port answers with that PID; otherwise it only clears the session files. Before it ends the server, `stop` posts a `finish` (`by: "stop"`, no Brief path) when the skill posted none, and waits one second so open tabs receive it; the tab then reads the stop as a finished interview, not a lost connection. Each `watch.sh` poll sends its process id (`&pid=`), which the lease records and `/api/state` shows; after the finish, `stop` sends that PID SIGTERM when its command line is a `watch.sh` for this data dir, so no watcher for it is left running (a watcher on an older poll gets a refused connection once the env file is gone and exits 3 within one 5 s retry). It signals nothing on Windows, where Git Bash's `$$` is not a native PID; a watcher there ends through the refused-poll exit. That path has not been exercised on Windows Git Bash. `stop` removes the pid, token and nonce but leaves the port in `.interview-session.json`, so the next `ensure-running` on the data dir reuses that port when it is free, and open tabs and their per-origin browser settings carry over. `ensure-running` removes a `finished` left by an earlier stop. A restart issues a new token: an armed watcher exits 2 at once with "token changed: re-run ensure-running", so re-arm it.
`ensure-running` checks for curl, reuses the server already running for the data dir (same PID), and otherwise starts one in the background (on Windows through the base interpreter, with no console window) on the first free port of `--port`, the recorded port, and the resolved `port` setting (an explicit `--port 0` skips the setting), else a free port. It waits for the server's own session files, prints the URL, and with `--open` opens the page unless the resolved `openBrowser` is `false`, through the `browserCommand` of the `--user-settings` file this same call passes, else the default browser. Without `--user-settings`, the user file the running server recorded still supplies `openBrowser` and `waitTimeout`, but never the opener. The URL is always built from the recorded port as `http://127.0.0.1:<port>/`. `--emoji-markers` takes any value: only `true`, `1`, `yes` and `on` (any case) mean true, and anything else, an empty string or an unexpanded `user_config` token included, means false. The value is written to `meta.emojiMarkers`; an absent flag keeps the recorded value, and a new file records false, so pass the session's value each time, including on a restart. `stop` ends the recorded PID only after `/api/ping` on the recorded port answers with that PID; otherwise it only clears the session files. Before it ends the server, `stop` posts a `finish` (`by: "stop"`, no Brief path) when the skill posted none, and waits one second so open tabs receive it; the tab then reads the stop as a finished interview, not a lost connection. Each `watch.sh` poll sends its process id (`&pid=`), which the lease records and `/api/state` shows; after the finish, `stop` sends that PID SIGTERM when its command line is a `watch.sh` for this data dir, so no watcher for it is left running (a watcher on an older poll gets a refused connection once the env file is gone and exits 3 within one 5 s retry). It signals nothing on Windows, where Git Bash's `$$` is not a native PID; a watcher there ends through the refused-poll exit. On Windows Git Bash that exit ends the watcher: it exits 3 with the stop message, and no `watch.sh` or curl long-poll is left within 10 s of `stop`. `stop` removes the pid, token and nonce but leaves the port in `.interview-session.json`, so the next `ensure-running` on the data dir reuses that port when it is free, and open tabs and their per-origin browser settings carry over. `ensure-running` removes a `finished` left by an earlier stop. A restart issues a new token: an armed watcher exits 2 at once with "token changed: re-run ensure-running", so re-arm it.

## Watcher protocol

Expand Down
6 changes: 5 additions & 1 deletion plugins/planning/surface/watch.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,11 @@ if bash "$here/round.sh" --dir "$fast" ensure-running --port 0 >/dev/null 2>&1;
until_waiting "$(sed -n 's/^PORT=//p' "$fast/.interview-session.env" | tr -d '\r')"
spid=$(sed -n 's/.*"pid": *\([0-9]*\).*/\1/p' "$fast/.interview-session.json")
rm -f "$fast/.interview-session.env"
kill "$spid" 2>/dev/null
# On Windows $spid is a native pid, which Git Bash's kill does not know.
case "$(uname -s)" in
MINGW* | MSYS* | CYGWIN*) taskkill //F //PID "$spid" >/dev/null 2>&1 ;;
*) kill "$spid" 2>/dev/null ;;
esac
end=$((SECONDS + 10))
while kill -0 "$wpid" 2>/dev/null && [[ "$SECONDS" -lt "$end" ]]; do sleep 0.1; done
if kill -0 "$wpid" 2>/dev/null; then
Expand Down
Loading