test(smoke): follow the #1180 Hermes home and Claude detection

The client-detection fix moved the Windows Hermes home to
%LOCALAPPDATA%\hermes and stopped counting a bare ~/.claude directory as a
Claude Code install. The smoke script followed only part of the way.

Hermes: 8x and 8x-i read the new HERMES_HOME_DIR, but 8x-ii still looked
for the pre_llm_call hook in ~/.hermes/config.yaml, and the uninstall
absence checks 9m and 9n still named ~/.hermes. On Linux and macOS
HERMES_HOME_DIR is ~/.hermes, so the stale paths pointed at the right
directory and nothing showed. Only on Windows do the two differ: 8x-ii
failed on a hook that install had written to the new home, and 9m and 9n
passed without looking at any file install had produced. All three now use
HERMES_HOME_DIR. The assertions are unchanged.

Claude Code: the fixtures of 9b-2, 9b-3, 9b-8 and both Phase 13 legs
created only an empty ~/.claude, which is no longer a Claude Code home.
Wherever no claude executable is installed, 9b-2 then finds no .claude.json
entry and 13e finds no agent config, and 9b-3, 9b-8 and the install.ps1 leg
stop exercising the Claude paths without saying so. The Linux test
container reproduces both failures. The Windows job never got that far,
because 8x-ii stops it in Phase 8. The fixtures now seed the .claude.json
user config through one helper, the same seed the unit tests use.

9b-1b pins the new rule end to end: where the empty-home control shows no
Claude Code, a home with only a bare ~/.claude gets no Claude config. A
venue that has a claude executable skips it, with the reason at the case.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-10-02 06:45:39 +02:00
1 parent 2b329fe75d
commit 810d677d41
1 file changed
+57 -13
+57 -13
View File
@@ -116,6 +116,16 @@ copy_smoke_binary() {
cp "$BINARY" "$destination"
}
# A fixture home that belongs to a Claude Code user. An empty ~/.claude is not
# evidence of one (#1180: other tools create that directory, and install then
# configured a client the user never had); the user config Claude Code itself
# writes is. Same seed as test_mark_claude_code_installed in tests/test_cli.c.
mark_claude_code_installed() {
local home="$1"
mkdir -p "$home/.claude"
echo '{}' > "$home/.claude.json"
}
# Retire this run's private account daemon (if one is running) and wait until
# it reports not-running. Install/uninstall flows leave an ephemeral daemon
# draining asynchronously whose mapped generation backing and open logs
@@ -2149,10 +2159,10 @@ if ! grep -q '^name: codebase-memory$' "$HERMES_HOME_DIR/skills/codebase-memory/
exit 1
fi
echo "OK 8x-i: Hermes durable delegation skill"
if ! grep -q '^hooks:' "$FAKE_HOME/.hermes/config.yaml" 2>/dev/null ||
! grep -q '^ pre_llm_call:' "$FAKE_HOME/.hermes/config.yaml" 2>/dev/null ||
! grep -q 'hook-augment' "$FAKE_HOME/.hermes/config.yaml" 2>/dev/null ||
! grep -q -- '--dialect hermes' "$FAKE_HOME/.hermes/config.yaml" 2>/dev/null; then
if ! grep -q '^hooks:' "$HERMES_HOME_DIR/config.yaml" 2>/dev/null ||
! grep -q '^ pre_llm_call:' "$HERMES_HOME_DIR/config.yaml" 2>/dev/null ||
! grep -q 'hook-augment' "$HERMES_HOME_DIR/config.yaml" 2>/dev/null ||
! grep -q -- '--dialect hermes' "$HERMES_HOME_DIR/config.yaml" 2>/dev/null; then
echo "FAIL 8x-ii: Hermes pre_llm_call context hook missing"
exit 1
fi
@@ -3154,8 +3164,8 @@ fi
echo "OK 9l: JSON agents, lifecycle hooks, and Kilo cleaned; foreign settings preserved"
# 9m: YAML/TOML new agents are cleaned.
if grep -q '^ codebase-memory-mcp:' "$FAKE_HOME/.hermes/config.yaml" 2>/dev/null ||
grep -q '^ pre_llm_call:' "$FAKE_HOME/.hermes/config.yaml" 2>/dev/null ||
if grep -q '^ codebase-memory-mcp:' "$HERMES_HOME_DIR/config.yaml" 2>/dev/null ||
grep -q '^ pre_llm_call:' "$HERMES_HOME_DIR/config.yaml" 2>/dev/null ||
grep -q '^ codebase-memory-mcp:' "$GOOSE_CFG" 2>/dev/null ||
grep -q 'codebase-memory-mcp' "$FAKE_HOME/.grok/config.toml" 2>/dev/null ||
grep -q '^name = "codebase-memory-mcp"' "$FAKE_HOME/.vibe/config.toml" 2>/dev/null; then
@@ -3209,7 +3219,7 @@ echo "OK 9m-i: durable instruction blocks removed"
# 9n: Skills removed (consolidated skill dir)
if [ -d "$FAKE_HOME/.claude/skills/codebase-memory" ] ||
[ -d "$FAKE_HOME/.hermes/skills/codebase-memory" ] ||
[ -d "$HERMES_HOME_DIR/skills/codebase-memory" ] ||
[ -d "$FAKE_HOME/.agents/skills/codebase-memory" ] ||
[ -d "$FAKE_HOME/.qoder/skills/codebase-memory" ] ||
[ -d "$CUSTOM_KIMI_HOME/skills/codebase-memory" ] ||
@@ -3287,9 +3297,40 @@ echo "OK 9b-1: install with minimal agents exits cleanly"
retire_account_daemon "9b-1-cleanup"
smoke_rmtree "$EMPTY_HOME"
# 9b-1b (#1180): an empty ~/.claude directory is not a Claude Code install.
# The empty home above is this venue's control: where it showed no Claude Code,
# the same home plus a bare ~/.claude must not be configured for it either.
#
# SKIP_WHITELIST: a venue with a claude executable (a developer machine) detects
# Claude Code in every home, so there is nothing for the bare directory to
# change. Narrowing PATH for this one install does not make such a venue
# claude-free: with HOME as the scanned home the product also probes fixed
# locations (/usr/local/bin, /opt/homebrew/bin). A venue without one, such as
# the Linux test image, runs the check.
if grep -q 'Detected agents:.* Claude-Code' <<<"$INSTALL_OUT"; then
echo "SKIP 9b-1b: a claude executable is installed in this venue (whitelisted above)"
else
BARE_HOME=$(smoke_mktemp_dir)
mkdir -p "$BARE_HOME/.claude" "$BARE_HOME/.local/bin"
BARE_RC=0
BARE_OUT=$(HOME="$BARE_HOME" LOCALAPPDATA="$BARE_HOME/AppData/Local" "$BINARY" install -y 2>&1) || BARE_RC=$?
if [ "$BARE_RC" -ge 128 ] ||
! grep -q 'Detected agents:' <<<"$BARE_OUT" ||
grep -q 'Detected agents:.* Claude-Code' <<<"$BARE_OUT" ||
[ -e "$BARE_HOME/.claude.json" ] ||
[ -n "$(ls -A "$BARE_HOME/.claude" 2>/dev/null)" ]; then
echo "FAIL 9b-1b: a bare ~/.claude directory was configured as a Claude Code install"
exit 1
fi
echo "OK 9b-1b: a bare ~/.claude directory is not configured as Claude Code"
retire_account_daemon "9b-1b-cleanup"
smoke_rmtree "$BARE_HOME"
fi
# 9b-2: Install twice (idempotent)
IDEM_HOME=$(smoke_mktemp_dir)
mkdir -p "$IDEM_HOME/.claude" "$IDEM_HOME/.local/bin"
mkdir -p "$IDEM_HOME/.local/bin"
mark_claude_code_installed "$IDEM_HOME"
copy_smoke_binary "$IDEM_HOME/.local/bin/codebase-memory-mcp"
run_no_crash 9b-2 env HOME="$IDEM_HOME" LOCALAPPDATA="$IDEM_HOME/AppData/Local" "$BINARY" install -y
IDEM_INSTALLER="$BINARY"
@@ -3313,7 +3354,8 @@ smoke_rmtree "$IDEM_HOME"
# 9b-3: Uninstall without prior install
CLEAN_HOME=$(smoke_mktemp_dir)
mkdir -p "$CLEAN_HOME/.claude" "$CLEAN_HOME/.local/bin"
mkdir -p "$CLEAN_HOME/.local/bin"
mark_claude_code_installed "$CLEAN_HOME"
UNINSTALL_RC=0
UNINSTALL_OUT=$(HOME="$CLEAN_HOME" "$BINARY" uninstall -y -n 2>&1) || UNINSTALL_RC=$?
if [ "$UNINSTALL_RC" -ge 128 ]; then
@@ -3337,7 +3379,8 @@ smoke_rmtree "$CORRUPT_HOME"
# 9b-8: Double uninstall
DBL_HOME=$(smoke_mktemp_dir)
mkdir -p "$DBL_HOME/.claude" "$DBL_HOME/.local/bin"
mkdir -p "$DBL_HOME/.local/bin"
mark_claude_code_installed "$DBL_HOME"
copy_smoke_binary "$DBL_HOME/.local/bin/codebase-memory-mcp"
run_no_crash 9b-8-install env HOME="$DBL_HOME" "$BINARY" install -y
DBL_UNINSTALLER="$BINARY"
@@ -3834,7 +3877,7 @@ if [ "$DL_OS" != "windows" ] && [ -f "$REPO_ROOT/install.sh" ]; then
echo "--- Phase 13: install.sh E2E ---"
INSTALL_TEST_HOME=$(smoke_mktemp_dir)
INSTALL_TEST_DIR=$(smoke_mktemp_dir)
mkdir -p "$INSTALL_TEST_HOME/.claude"
mark_claude_code_installed "$INSTALL_TEST_HOME"
mkdir -p "$INSTALL_TEST_HOME/.local/bin"
# 13a: run install.sh with local URL + isolated HOME
@@ -3871,7 +3914,8 @@ if [ "$DL_OS" != "windows" ] && [ -f "$REPO_ROOT/install.sh" ]; then
echo "OK 13d: no signing needed ($DL_OS)"
fi
# 13e: agent configs created (at least Claude Code since we made ~/.claude)
# 13e: agent configs created (at least Claude Code: the fixture home is a
# Claude Code user's)
if [ -f "$INSTALL_TEST_HOME/.claude.json" ] && grep -q 'codebase-memory-mcp' "$INSTALL_TEST_HOME/.claude.json" 2>/dev/null; then
echo "OK 13e: agent configs created by install.sh"
else
@@ -3898,7 +3942,7 @@ elif [ -f "$REPO_ROOT/install.ps1" ] && command -v powershell.exe &>/dev/null; t
echo "--- Phase 13: install.ps1 E2E (Windows) ---"
PS1_TEST_HOME=$(smoke_mktemp_dir)
PS1_TEST_DIR=$(smoke_mktemp_dir)
mkdir -p "$PS1_TEST_HOME/.claude"
mark_claude_code_installed "$PS1_TEST_HOME"
# Convert MSYS paths to Windows paths for PowerShell
if command -v cygpath &>/dev/null; then