Instrument-first for the macOS Python-3.9 cohort.
v2.0.6 telemetry: ~13.6% of macOS sessions (~6,337 users) run on Apple's
Python 3.9 → HOOK_PY_INCOMPATIBLE → the agentic reviewer can't load (needs
3.10+ syntax). That's ~12x macOS's build-failure rate and the single
biggest macOS degradation. sg-python.sh only probes `python3.1x` on PATH,
so these users have nothing newer ON PATH — but they may still have a
3.10+ installed at a standard location that isn't on the hook's PATH
(Homebrew /opt/homebrew, python.org framework, etc.).
Before building an explicit-path interpreter search, size the RECOVERABLE
fraction: `_probe_alt_python()` checks Homebrew / python.org / distro
locations for a 3.10+ binary and emits the highest found as `sdk_alt_py`
(major*100+minor, or 0 = genuinely 3.9-only). Telemetry-only; probed ONLY
on the HOOK_PY_INCOMPATIBLE path, so healthy sessions never run it.
After a data cycle: non-zero sdk_alt_py = recoverable by an explicit-path
search in sg-python.sh; 0 = needs a user-side Python install (the one-time
notice is the only lever). That decides whether the search is worth building.
Verified locally on macOS Python 3.13:
- py_compile clean; probe returns 314 on this Mac (homebrew 3.14 present).
- 7 new tests (test_altpython_probe.py): highest-version selection,
0-when-none (mocked os.access), framework/distro path parsing, only
counts 3.10+, and emit gated on outcome==HOOK_PY_INCOMPATIBLE.
- Full suite 575/575 + 2 skipped.
No behavior change — purely additive telemetry on the incompatible path.
Version 2.0.6 -> 2.0.7 per the per-PR-bump policy (#2114).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(telegram): honor TELEGRAM_STATE_DIR/CLAUDE_CONFIG_DIR in skills and server
The server already reads TELEGRAM_STATE_DIR for multi-bot setups, but the
/telegram:access and /telegram:configure skills hardcoded
~/.claude/channels/telegram/ in 11 places. So with a custom state dir the
skill writes access.json to the default location while the server reads
from the override — pairing and allowlist edits silently don't take effect.
Skills now resolve the state dir via shell expansion (TELEGRAM_STATE_DIR →
CLAUDE_CONFIG_DIR/channels/telegram → ~/.claude/channels/telegram) before
any read/write. Server gets the same CLAUDE_CONFIG_DIR fallback. Also adds
Bash(echo)/Bash(chmod) to configure skill's allowed-tools (chmod was already
documented but not allowlisted).
* fix(telegram): verify stale PID is a server.ts process before SIGTERM
PID files race with OS PID recycling. The lockfile from #1349 stored only a
PID; after enough churn that PID can be reassigned to anything — including
the new launch's own bun-run wrapper. SIGTERMing the wrapper closes our
stdin and triggers immediate self-shutdown ('replacing stale poller' then
'shutting down' within seconds — matches #1459 item 3).
Now check 'ps -p <pid> -o args=' contains 'server.ts' before killing.
execFileSync (no shell); whole block already try/catch so Windows/ps-missing
falls through to just overwriting the lockfile.
* fix(telegram): drop ppid watchdog check; redirect bun install stdout to stderr
Two v0.0.5/0.0.6 regressions causing the plugin to fail at startup:
1. The orphan watchdog's process.ppid !== bootPpid check false-fires when the
bun-run/shell wrapper exits or execs during normal startup and we get
reparented to init — plugin self-terminates ~5s after launch. Stdin-close
alone is the correct signal: the kernel closes the MCP pipe on any CLI
death regardless of intermediate wrappers, so the ppid check was both
unnecessary and harmful. (#1467; also the actual cause of #1459 item 3
and likely #1425.)
2. 'bun install --no-summary' in the start script writes to stdout, which is
the MCP JSON-RPC transport. The harness sees non-JSON bytes during the
handshake and drops the connection ('Failed to connect'). Redirect install
output to stderr. (#1470; also explains #1425 on Windows.)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Bryan Thompson <238056179+bryan-anthropic@users.noreply.github.com>
Claude Code's /plugin install now registers the official marketplace
automatically and activates the plugin in the same session, so the
/reload-plugins step these READMEs document is no longer needed.
discord and telegram keep a conditional note because their MCP servers
can't always be activated mid-session.