Files
chainbase-labs__agentkey/tests/helpers.bash
T
lxcong f830f2947d feat: agent install telemetry (skill side, spec §8.1) (#31)
## Summary

Skill-side half of the agent-install telemetry rollout (spec §8.1).
`check-update.sh` emits `TELEMETRY ...` lines on stdout, SKILL.md parses
them and dispatches via MCP. Adds 3-layer opt-out (file / env /
installer flag — file path checked here), 24h client-side dedup, and a
bats test harness.

- `skills/agentkey/scripts/check-update.sh` — `emit_telemetry()` +
`auto_upgrade_flag()` helpers, opt-out checks, 7 emit calls at 5 exit
points, 24h heartbeat dedup keyed by `LOCAL_VERSION`. Includes Linux
`stat` order fix (`-c %Y` first, `-f %m` second — `-f` on Linux means
filesystem mountpoint, not mtime)
- `skills/agentkey/SKILL.md` — Step 0 instructions for parsing
`TELEMETRY` lines and dispatching via
`execute_tool(\"agentkey_internal\", {path:\"telemetry/event\", ...})`;
upgrade-flow each branch dispatches `upgrade_decision` /
`upgrade_result` with mapped choice values
- `tests/check-update.bats` + `tests/helpers.bash` — 10 contract tests
with isolated `\$HOME` / `\$TMPDIR` / mocked curl
- `.github/workflows/scripts-test.yml` — bats CI on ubuntu + macos
- `README.md` + `docs/README_zh.md` — FAQ replacement for the old
\"nothing to collect\" sentence, new FAQ entry \"How do I opt out of
telemetry?\" / \"我如何关闭遥测?\"
- `scripts/uninstall.sh` — adds Step 7b to clean `~/.config/agentkey/`
(telemetry-disabled, update-disabled, snooze state)

## Blocked on

**AgentKey-Server PR** that registers the
`agentkey_internal/telemetry/event` MCP tool (must be filtered out of
`list_tools` / `find_tools` so the LLM doesn't accidentally call it).
SKILL.md falls back silently when the tool doesn't exist, so this PR is
safe to merge first — but the telemetry signal isn't recorded until the
server side lands.

Spec §11 mandates server-first merge order to keep the agent-side debug
log clean.

## Test plan

- [x] `bats tests/check-update.bats` — 10/10 passing locally
- [x] E2E smoke (skill-side plan Task 8 steps 1-3, 5):
  - Default emit on `up_to_date`
- `~/.config/agentkey/telemetry-disabled` early-return (no TELEMETRY
line)
  - `AGENTKEY_TELEMETRY=0` env override
  - 24h heartbeat dedup (2nd invocation within window does not re-emit)
  - `uninstall.sh` Step 7b cleans `~/.config/agentkey/`
- [ ] **Manual** — open Claude Code, ask an AgentKey-routed query.
Verify SKILL.md silently swallows the missing `agentkey_internal` tool
error (server not shipped yet) and the actual query still completes
- [ ] Verify bats CI runs green on ubuntu + macos matrix

## Pre-existing bug surfaced during testing (not in this PR)

`check-update.sh` line 130-ish cache fast-path uses the same wrong `stat
-f %m ... || stat -c %Y` order. Same Linux bug as the one fixed here in
`emit_telemetry`. Worth a separate one-line fix PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: lxcong <lxcong@chainbase.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 16:41:35 +08:00

62 lines
2.0 KiB
Bash

#!/usr/bin/env bash
# Shared bats helpers — isolate HOME, TMPDIR, network per test.
# main 上的 check-update.sh 把版本内嵌在脚本里
# (`LOCAL_VERSION="x.y.z" # x-release-please-version`),本 helper 提供
# `set_local_version` 直接覆盖那一行以模拟不同的本地版本。
setup_isolated_env() {
REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/.." && pwd)"
export TEST_TMP="$(mktemp -d)"
export HOME="$TEST_TMP/home"
export TMPDIR="$TEST_TMP/tmp"
export XDG_CONFIG_HOME="$HOME/.config"
mkdir -p "$HOME" "$TMPDIR" "$XDG_CONFIG_HOME/agentkey"
# Copy the script into the test sandbox so we can mutate LOCAL_VERSION.
export SCRIPT_DIR="$TEST_TMP/scripts"
export SCRIPT="$SCRIPT_DIR/check-update.sh"
mkdir -p "$SCRIPT_DIR"
cp "$REPO_ROOT/skills/agentkey/scripts/check-update.sh" "$SCRIPT"
# Block real network — every test must call mock_curl_release explicitly.
mkdir -p "$TEST_TMP/bin"
cat > "$TEST_TMP/bin/curl" <<'EOF'
#!/usr/bin/env bash
echo "ERROR: curl not mocked in this test" >&2
exit 7
EOF
chmod +x "$TEST_TMP/bin/curl"
export PATH="$TEST_TMP/bin:$PATH"
}
teardown_isolated_env() {
[ -n "$TEST_TMP" ] && rm -rf "$TEST_TMP"
}
# Mock curl to return a fixed GitHub /releases/latest payload.
mock_curl_release() {
local tag="$1"
cat > "$TEST_TMP/bin/curl" <<EOF
#!/usr/bin/env bash
echo '{"tag_name":"$tag"}'
EOF
chmod +x "$TEST_TMP/bin/curl"
}
# Override the embedded LOCAL_VERSION in the sandboxed copy of check-update.sh.
set_local_version() {
local v="$1"
# GNU sed and BSD sed both accept this in-place form on Linux/macOS via the
# trailing empty string trick: use a portable sed wrapper.
if sed --version >/dev/null 2>&1; then
sed -i "s/^LOCAL_VERSION=.*/LOCAL_VERSION=\"$v\" # x-release-please-version/" "$SCRIPT"
else
sed -i '' "s/^LOCAL_VERSION=.*/LOCAL_VERSION=\"$v\" # x-release-please-version/" "$SCRIPT"
fi
}
# Run the sandboxed check-update.sh and capture status + output.
run_check_update() {
run bash "$SCRIPT" "$@"
}