fix(mem0-plugin): accurate per-editor telemetry attribution + OpenCode telemetry (#5518)
This commit is contained in:
@@ -89,7 +89,7 @@ def test_system_props_override_caller_props(monkeypatch):
|
||||
# System props must win
|
||||
assert props["source"] == "plugin"
|
||||
assert props["platform"] == telemetry.detect_platform()
|
||||
assert props["plugin_version"] == telemetry.PLUGIN_VERSION
|
||||
assert props["plugin_version"] == telemetry._load_plugin_version(telemetry.detect_platform())
|
||||
# Caller-only props still present
|
||||
assert props["memory_count"] == 42
|
||||
|
||||
@@ -125,25 +125,31 @@ def test_hash_deterministic():
|
||||
def test_platform_claude_code(monkeypatch):
|
||||
import telemetry
|
||||
|
||||
monkeypatch.setenv("CLAUDECODE", "1")
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.delenv("ANTIGRAVITY_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CURSOR_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CODEX_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.setenv("CLAUDECODE", "1")
|
||||
assert telemetry.detect_platform() == "claude-code"
|
||||
|
||||
|
||||
def test_platform_cursor(monkeypatch):
|
||||
import telemetry
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.delenv("ANTIGRAVITY_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CLAUDECODE", raising=False)
|
||||
monkeypatch.delenv("CLAUDE_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.setenv("CURSOR_PLUGIN_ROOT", "/path")
|
||||
monkeypatch.delenv("CODEX_PLUGIN_ROOT", raising=False)
|
||||
assert telemetry.detect_platform() == "cursor"
|
||||
|
||||
|
||||
def test_platform_codex(monkeypatch):
|
||||
import telemetry
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.delenv("ANTIGRAVITY_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CLAUDECODE", raising=False)
|
||||
monkeypatch.delenv("CLAUDE_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CURSOR_PLUGIN_ROOT", raising=False)
|
||||
@@ -151,6 +157,48 @@ def test_platform_codex(monkeypatch):
|
||||
assert telemetry.detect_platform() == "codex"
|
||||
|
||||
|
||||
def test_platform_explicit_override(monkeypatch):
|
||||
"""MEM0_PLATFORM wins over auto-detection so each editor can label
|
||||
itself reliably even when host env vars are ambiguous or absent."""
|
||||
import telemetry
|
||||
|
||||
monkeypatch.setenv("CLAUDE_PLUGIN_ROOT", "/path") # conflicting auto-signal
|
||||
monkeypatch.setenv("MEM0_PLATFORM", "cursor")
|
||||
assert telemetry.detect_platform() == "cursor"
|
||||
|
||||
|
||||
def test_platform_antigravity(monkeypatch):
|
||||
"""Antigravity sets CLAUDE_PLUGIN_ROOT for compatibility but must be
|
||||
attributed to its own platform, not claude-code."""
|
||||
import telemetry
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.setenv("ANTIGRAVITY_PLUGIN_ROOT", "/ext")
|
||||
monkeypatch.setenv("CLAUDE_PLUGIN_ROOT", "/ext") # antigravity sets both
|
||||
assert telemetry.detect_platform() == "antigravity"
|
||||
|
||||
|
||||
def test_plugin_version_is_per_editor(monkeypatch):
|
||||
"""Each editor reports the version from its OWN manifest. Antigravity is on
|
||||
a 0.1.x line while Claude/Cursor/Codex are on 0.2.x, so they must not all
|
||||
report the same shared version."""
|
||||
import telemetry
|
||||
|
||||
plugin_dir = os.path.join(os.path.dirname(__file__), "..")
|
||||
manifests = {
|
||||
"antigravity": "plugin.json",
|
||||
"claude-code": os.path.join(".claude-plugin", "plugin.json"),
|
||||
"cursor": os.path.join(".cursor-plugin", "plugin.json"),
|
||||
"codex": os.path.join(".codex-plugin", "plugin.json"),
|
||||
}
|
||||
for plat, rel in manifests.items():
|
||||
monkeypatch.setenv("MEM0_PLATFORM", plat)
|
||||
with open(os.path.join(plugin_dir, rel)) as f:
|
||||
expected = json.load(f)["version"]
|
||||
payload = telemetry.build_posthog_payload("plugin.test")
|
||||
assert payload["properties"]["plugin_version"] == expected, f"{plat} should report {expected} from {rel}"
|
||||
|
||||
|
||||
def test_send_fails_silently(monkeypatch):
|
||||
import telemetry
|
||||
|
||||
@@ -175,3 +223,39 @@ def test_cli_no_args_exits_nonzero(monkeypatch):
|
||||
monkeypatch.delenv("MEM0_TELEMETRY", raising=False)
|
||||
monkeypatch.setattr(sys, "argv", ["telemetry.py"])
|
||||
assert telemetry.main() == 1
|
||||
|
||||
|
||||
def test_cursor_wrappers_pin_platform():
|
||||
"""Cursor wrappers delegate to the shared scripts, which auto-detect the
|
||||
platform from host env vars. Since Cursor may not export CURSOR_PLUGIN_ROOT
|
||||
to the subprocess, each wrapper must pin MEM0_PLATFORM=cursor so the
|
||||
delegated telemetry is attributed to cursor, not the 'plugin' fallback."""
|
||||
scripts_dir = os.path.join(os.path.dirname(__file__), "..", "scripts")
|
||||
cursor_wrappers = [
|
||||
"on_session_start_cursor.sh",
|
||||
"on_user_prompt_cursor.sh",
|
||||
"on_post_tool_use_cursor.sh",
|
||||
"on_pre_compact_cursor.sh",
|
||||
"on_stop_cursor.sh",
|
||||
]
|
||||
for name in cursor_wrappers:
|
||||
with open(os.path.join(scripts_dir, name)) as f:
|
||||
content = f.read()
|
||||
assert "export MEM0_PLATFORM=cursor" in content, f"{name} must `export MEM0_PLATFORM=cursor` before delegating"
|
||||
|
||||
|
||||
def test_codex_hooks_pin_platform():
|
||||
"""Codex installs standalone hooks (absolute paths) via install_codex_hooks.py,
|
||||
so PLUGIN_ROOT is not set at runtime and the platform falls back to 'plugin'.
|
||||
Codex runs hook commands through a shell, so every command pins
|
||||
MEM0_PLATFORM=codex inline for correct attribution."""
|
||||
hooks_path = os.path.join(os.path.dirname(__file__), "..", "hooks", "codex-hooks.json")
|
||||
with open(hooks_path) as f:
|
||||
config = json.load(f)
|
||||
|
||||
commands = [
|
||||
h["command"] for entries in config["hooks"].values() for entry in entries for h in entry.get("hooks", [])
|
||||
]
|
||||
assert commands, "expected at least one codex hook command"
|
||||
for cmd in commands:
|
||||
assert "MEM0_PLATFORM=codex" in cmd, f"codex hook command missing platform pin: {cmd}"
|
||||
|
||||
Reference in New Issue
Block a user