diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 5a6b0d90e..d9b66a1bf 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -57,6 +57,8 @@ vim.api.nvim_create_autocmd("VimLeavePre", { }) ``` +The real cleanup runs from `init.lua`: its `VimLeavePre` autocmd calls `stop` when the server runs, `stop` calls `lockfile.remove`, and `stop` only logs a warning when the removal fails, so a lock file that the removal failed to delete stays. + ### 3. MCP Tool System (`tools/`) Dynamic tool registration with JSON schema validation: @@ -172,7 +174,7 @@ Automatic cleanup on shutdown: ```lua vim.api.nvim_create_autocmd("VimLeavePre", { callback = function() - M.stop() -- Stop server, remove lock file + M.stop() -- Stop server, try to remove lock file (only logs a warning when it cannot) end }) ``` diff --git a/scripts/README.md b/scripts/README.md index efe986894..38efc43b8 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -87,9 +87,9 @@ The Lua repros run from the repository root with `nvim --headless -u NONE -l scr - `run_integration_tests_individually.sh` creates two `mktemp` files and two `mktemp -d` folders per test (the output, the process group id, and the `XDG_STATE_HOME` and `XDG_CONFIG_HOME` that the file's two Neovims share) and deletes all four after the file ran. When it gets SIGTERM it kills the process group of the running file, deletes them and exits 143. It sets `VIMINIT`, `CLAUDECODE_MINIMAL_INIT`, `XDG_STATE_HOME` and `XDG_CONFIG_HOME` for that file's Neovims and the processes they start only, as a prefix of one command, and leaves `XDG_DATA_HOME` alone because plenary lives there. A run writes nothing under `~/.local/state/nvim`, and the developer's `ftplugin` and `after` files under `~/.config/nvim` do not run [run_integration_tests_individually.sh:temp_output, group_file, state_dir, config_dir]. - `repro_issue_231.lua` deletes `/__issue_231_repro__.md` [repro_issue_231.lua:try_open_diff]. - `repro_issue_70.sh` and `repro_issue_277.sh` make a work dir with `mktemp -d` (`${TMPDIR:-/tmp}/issue70.XXXXXX` or `issue277.XXXXXX`) and an `att-home` folder in it before they check their tools. They install `trap cleanup EXIT` after that check, so an exit 3 for a missing tool leaves the work dir behind. The trap also runs on SIGTERM, SIGINT and SIGHUP. It destroys the `agent-tty` sessions and removes the work dir. agent-tty still leaves an empty socket folder `/tmp/agent-tty/<8 hex digits>` (it ignores `TMPDIR`) and an entry for the deleted home in `${XDG_STATE_HOME:-$HOME/.local/state}/agent-tty/homes.json`, one of each per run. The sessions inherit the caller's environment, so `CLAUDE_CONFIG_DIR` and the `XDG_*` variables reach the Neovim and the `claude` CLI that they run. `repro_issue_70.sh` launches the real `claude` CLI, and it also runs `claude --version` once outside agent-tty. Its cleanup runs `pkill -f "repro_issue_70_probe.lua $REPO_ROOT"`, which also kills the probe of another run in the same checkout [repro_issue_70.sh:WORK, cleanup] [repro_issue_277.sh:WORK, cleanup]. -- `repro_issue_70_probe.lua` starts the real server with `auto_start = true`, so the plugin writes a real `PORT.lock` into the user's lock directory. Other Claude CLIs can see that lock file until `claudecode.stop()` removes it at the end [repro_issue_70_probe.lua:claudecode.setup, claudecode.stop]. -- `repro_issue_70.sh` starts one background `nvim --headless -u NONE -l repro_issue_70_probe.lua` per scenario, three in all, with output sent to `/dev/null`. Each probe writes `.json` in the work dir and stops when the script touches `.stop`, after 120 s, or when cleanup sends it SIGTERM. A probe stopped by SIGTERM still removes its `PORT.lock`, but a SIGKILL leaves the lock file behind. Scenarios B and C set `http_proxy`, `https_proxy` and `all_proxy` to `http://127.0.0.1:1`, a closed port, in the agent-tty shell [repro_issue_70.sh:start_probe, run_scenario, DEAD_PROXY]. -- `repro_issue_277.sh` starts Neovim with the `issue-277` fixture in a detached agent-tty session. The fixture calls `claudecode.setup` with `auto_start = true`, so the plugin writes a real `PORT.lock` into the lock directory (`$CLAUDE_CONFIG_DIR/ide`, else `~/.claude/ide`) while the script runs. Other Claude CLIs can see that lock file. Neovim also listens on `nvim.sock` in the work dir. Cleanup runs `agent-tty destroy`, Neovim exits, and the plugin removes the lock. When the script dies by SIGKILL, the trap does not run, so the agent-tty host, both Neovim processes, the lock file and the work dir stay until you run `agent-tty --home /att-home destroy ` [fixtures/issue-277/init.lua:claudecode.setup] [repro_issue_277.sh:NVIM_SOCK, cleanup]. +- `repro_issue_70_probe.lua` starts the real server with `auto_start = true`, so the plugin writes a real `PORT.lock` into the user's lock directory. Other Claude CLIs can see that lock file until `claudecode.stop()` removes it at the end. When the removal fails, `stop` only logs a warning, so a lock file that the removal failed to delete stays [repro_issue_70_probe.lua:claudecode.setup, claudecode.stop] [lua/claudecode/init.lua:M.stop]. +- `repro_issue_70.sh` starts one background `nvim --headless -u NONE -l repro_issue_70_probe.lua` per scenario, three in all, with output sent to `/dev/null`. Each probe writes `.json` in the work dir and stops when the script touches `.stop`, after 120 s, or when cleanup sends it SIGTERM. A probe stopped by SIGTERM still tries to remove its `PORT.lock` (when that fails, `stop` only logs a warning, so a lock file that the removal failed to delete stays), but a SIGKILL leaves the lock file behind. Scenarios B and C set `http_proxy`, `https_proxy` and `all_proxy` to `http://127.0.0.1:1`, a closed port, in the agent-tty shell [repro_issue_70.sh:start_probe, run_scenario, DEAD_PROXY]. +- `repro_issue_277.sh` starts Neovim with the `issue-277` fixture in a detached agent-tty session. The fixture calls `claudecode.setup` with `auto_start = true`, so the plugin writes a real `PORT.lock` into the lock directory (`$CLAUDE_CONFIG_DIR/ide`, or `~/.claude/ide` when that variable is unset or empty) while the script runs. Other Claude CLIs can see that lock file. Neovim also listens on `nvim.sock` in the work dir. Cleanup runs `agent-tty destroy`, Neovim exits, and the plugin removes the lock, or only logs a warning when it cannot. When the script dies by SIGKILL, the trap does not run, so the agent-tty host, both Neovim processes, the lock file and the work dir stay until you run `agent-tty --home /att-home destroy ` [fixtures/issue-277/init.lua:claudecode.setup] [repro_issue_277.sh:NVIM_SOCK, cleanup]. - `repro_issue_277.sh` clones diffview.nvim with `git clone --depth=1` from GitHub into `${XDG_DATA_HOME:-$HOME/.local/share}/issue-277/diffview.nvim` when that folder is absent, so the first run needs the network. The clone is not pinned, and the script keeps it after exit. Its Neovim runs with `NVIM_APPNAME=issue-277`, so it writes its ShaDa file and logs under `${XDG_STATE_HOME:-$HOME/.local/state}/issue-277/`, and diffview.nvim writes `${XDG_CACHE_HOME:-$HOME/.cache}/issue-277/diffview.log`. The script ends each `nvim --remote-expr` call after 10 s and each `websocat` call after 15 s with `perl -e 'alarm N; exec ...'`, and it sleeps with `perl`, because macOS has no `timeout` [repro_issue_277.sh:DIFFVIEW_DIR, rexpr, mcp_call]. - When `ISSUE277_ARTIFACTS` is unset, the screen snapshots go to `artifacts/` in the work dir, and cleanup removes them. A run that reaches its summary (exit 0 or 1) first copies them with `cp -R` to `${TMPDIR:-/tmp}/issue277-artifacts-latest`. When that folder already exists, the copy lands in `issue277-artifacts-latest/artifacts/`, and the files at the top level stay from the first run. A setup failure (exit 2) copies nothing. When `ISSUE277_ARTIFACTS` is set, the script creates that folder before its tool check and keeps it [repro_issue_277.sh:ARTIFACTS, snap]. - `repro_issue_218.sh` runs `Lazy! sync`, which downloads fixture plugins. It does not remove its temp directory [repro_issue_218.sh:cleanup].