chore: merge origin/main into mintlify/af82bda4 and resolve conflicts

This commit is contained in:
mintlify[bot]
2026-09-16 11:46:52 +00:00
committed by GitHub
parent b5ae772eae
commit 08d9636491
693 changed files with 55668 additions and 22676 deletions
@@ -0,0 +1,135 @@
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
REPOSITORY_ROOT = ROOT.parents[1]
sys.path.insert(0, str(ROOT))
from build.build import ( # noqa: E402
build,
bundle_drift,
render_template,
replace_output,
)
from build.validate import validate_bundle # noqa: E402
def test_render_rejects_unknown_or_unresolved_tokens() -> None:
with pytest.raises(ValueError, match="UNKNOWN"):
render_template("run {{UNKNOWN}}", {})
def test_build_replaces_only_the_requested_output(tmp_path: Path) -> None:
staged = tmp_path / "staged"
staged.mkdir()
(staged / "plugin.json").write_text("{}", encoding="utf-8")
output = tmp_path / "output"
output.mkdir()
(output / "stale.py").write_text("stale", encoding="utf-8")
sibling = tmp_path / "keep.txt"
sibling.write_text("keep", encoding="utf-8")
replace_output(staged, output)
assert not (output / "stale.py").exists()
assert (output / "plugin.json").exists()
assert sibling.read_text(encoding="utf-8") == "keep"
def test_build_cannot_replace_an_installable_source_directory(tmp_path: Path) -> None:
staged = tmp_path / "staged"
staged.mkdir()
with pytest.raises(ValueError, match="protected output path"):
replace_output(staged, REPOSITORY_ROOT / "integrations" / "claude-code-plugin")
def test_portable_bundle_is_conformant_and_self_contained(tmp_path: Path) -> None:
root = build("mem0-agent-plugin", "portable", tmp_path / "mem0-agent-plugin")
assert validate_bundle(root, "portable") == []
assert json.loads((root / "plugin.json").read_text(encoding="utf-8"))["$schema"] == (
"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json"
)
server = json.loads((root / "mcp.json").read_text(encoding="utf-8"))["mcpServers"]["mem0"]
assert server["type"] == "stdio"
assert server["args"] == ["${PLUGIN_ROOT}/core/mcp_server.py"]
assert "env" not in server
assert not (root / "core" / "hook_runner.py").exists()
assert not (root / "core" / "flush_worker.py").exists()
assert not (root / "agents").exists()
for skill in (root / "skills").glob("*/SKILL.md"):
frontmatter = skill.read_text(encoding="utf-8").split("---", 2)[1]
keys = {line.split(":", 1)[0] for line in frontmatter.splitlines() if ":" in line}
assert keys <= {"name", "description", "license", "compatibility", "metadata", "allowed-tools"}
assert not any(path.is_symlink() for path in root.rglob("*"))
@pytest.mark.parametrize("host", ["claude-code", "cursor", "codex", "kimi", "antigravity"])
def test_native_bundle_is_self_contained(host: str, tmp_path: Path) -> None:
root = build(host, "native", tmp_path / host)
assert (root / "core" / "memory_core.py").is_file()
assert (root / "skills" / "remember" / "SKILL.md").is_file()
assert not any(path.is_symlink() for path in root.rglob("*"))
@pytest.mark.parametrize("host", ["claude-code", "cursor", "codex", "kimi", "antigravity"])
def test_only_claude_bundles_sidekick(host: str, tmp_path: Path) -> None:
root = build(host, "native", tmp_path / host)
if host == "claude-code":
agent = (root / "agents" / "sidekick.md").read_text()
assert "model: sonnet" in agent
assert "isolation: worktree" in agent
else:
assert not (root / "agents").exists()
for path in root.rglob("*.json"):
assert "sidekick" not in path.read_text().lower()
@pytest.mark.parametrize("host", ["claude-code", "cursor", "codex", "kimi", "antigravity"])
def test_native_control_skills_select_the_host_store(host: str, tmp_path: Path) -> None:
root = build(host, "native", tmp_path / host)
status = (root / "skills" / "status" / "SKILL.md").read_text(encoding="utf-8")
assert f'--harness "{host}"' in status
if host == "claude-code":
assert '--plugin-data-dir "${CLAUDE_PLUGIN_DATA}"' in status
elif host == "codex":
assert '--plugin-data-dir "${PLUGIN_DATA}"' in status
@pytest.mark.parametrize(
("host", "kind"),
[
("mem0-agent-plugin", "portable"),
("claude-code", "native"),
("cursor", "native"),
("codex", "native"),
("kimi", "native"),
("antigravity", "native"),
],
)
def test_installable_plugin_directories_are_current(host: str, kind: str) -> None:
assert bundle_drift(host, kind) == []
def test_marketplaces_keep_public_names_and_reference_real_plugins() -> None:
marketplace = json.loads((REPOSITORY_ROOT / "marketplace.json").read_text(encoding="utf-8"))
sources = {plugin["name"]: plugin["source"] for plugin in marketplace["plugins"]}
assert sources == {"mem0": "./integrations/claude-code-plugin"}
for source in sources.values():
assert (REPOSITORY_ROOT / source).exists()
codex_marketplace = json.loads(
(REPOSITORY_ROOT / ".agents" / "plugins" / "marketplace.json").read_text(encoding="utf-8")
)
assert [plugin["name"] for plugin in codex_marketplace["plugins"]] == ["mem0"]
codex = codex_marketplace["plugins"][0]
assert codex["source"]["path"] == "./integrations/codex-plugin"
@@ -0,0 +1,190 @@
from __future__ import annotations
import json
import os
import subprocess
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from conformance import run as conformance_run # noqa: E402
from conformance.run import _command_check # noqa: E402
PLUGIN_ROOT = Path(__file__).resolve().parents[1]
RUNNER = PLUGIN_ROOT / "conformance" / "run.py"
PYTHON_HOSTS = {"claude-code", "cursor", "codex", "kimi", "antigravity"}
def test_python_bundle_conformance_builds_every_host(tmp_path: Path) -> None:
report = tmp_path / "report.json"
artifacts = tmp_path / "artifacts"
result = subprocess.run(
[
sys.executable,
str(RUNNER),
"--group",
"python-bundles",
"--artifacts-dir",
str(artifacts),
"--report",
str(report),
],
cwd=PLUGIN_ROOT.parents[1],
text=True,
capture_output=True,
check=False,
)
assert result.returncode == 0, result.stdout + result.stderr
payload = json.loads(report.read_text(encoding="utf-8"))
assert payload["status"] == "passed"
assert {
entry["host"]
for entry in payload["checks"]
if entry["kind"] == "native"
} == PYTHON_HOSTS
assert {
entry["host"]
for entry in payload["checks"]
if entry["kind"] == "portable"
} == {"mem0-agent-plugin"}
for host in PYTHON_HOSTS:
assert (artifacts / host).is_dir()
assert (artifacts / "mem0-agent-plugin").is_dir()
def test_conformance_plan_covers_every_runtime(tmp_path: Path) -> None:
report = tmp_path / "plan.json"
result = subprocess.run(
[sys.executable, str(RUNNER), "--list", "--report", str(report)],
cwd=PLUGIN_ROOT.parents[1],
text=True,
capture_output=True,
check=False,
)
assert result.returncode == 0, result.stdout + result.stderr
payload = json.loads(report.read_text(encoding="utf-8"))
assert {entry["group"] for entry in payload["checks"]} == {
"python-bundles",
"python-tests",
"typescript-core",
"openclaw",
"opencode",
"pi-agent",
"deepseek",
}
assert all(entry["status"] == "planned" for entry in payload["checks"])
assert {
entry["group"]
for entry in payload["checks"]
if entry["name"].endswith("-artifact")
} == {"openclaw", "opencode", "pi-agent", "deepseek"}
def test_typescript_artifact_check_rejects_monorepo_imports(tmp_path: Path) -> None:
dist = tmp_path / "dist"
dist.mkdir()
(dist / "index.js").write_text(
'import { createMemoryLifecycle } from "../../agent-plugin-core/typescript/src/lifecycle.ts";\n',
encoding="utf-8",
)
artifact_check = getattr(conformance_run, "_typescript_artifact_check", None)
assert artifact_check is not None, "TypeScript package artifacts are not checked"
result = artifact_check("example", tmp_path, ("dist/index.js",))
assert result["status"] == "failed"
assert "monorepo source import" in result["output"]
def test_live_conformance_requires_an_explicit_mem0_key(tmp_path: Path) -> None:
environment = dict(os.environ)
environment.pop("MEM0_API_KEY", None)
result = subprocess.run(
[sys.executable, str(RUNNER), "--live", "--report", str(tmp_path / "report.json")],
cwd=PLUGIN_ROOT.parents[1],
env=environment,
text=True,
capture_output=True,
check=False,
)
assert result.returncode == 2
assert "MEM0_API_KEY is required for --live" in result.stderr
def test_live_conformance_reports_platform_failure_without_crashing(tmp_path: Path) -> None:
report = tmp_path / "report.json"
environment = {
**os.environ,
"MEM0_API_KEY": "m0-intentionally-invalid",
"MEM0_API_URL": "http://127.0.0.1:1",
}
result = subprocess.run(
[
sys.executable,
str(RUNNER),
"--group",
"live-platform",
"--live",
"--report",
str(report),
],
cwd=PLUGIN_ROOT.parents[1],
env=environment,
text=True,
capture_output=True,
check=False,
)
assert result.returncode == 1
payload = json.loads(report.read_text(encoding="utf-8"))
assert payload["status"] == "failed"
assert payload["checks"][0]["group"] == "live-platform"
def test_runtime_checks_preserve_the_callers_telemetry_setting(tmp_path: Path, monkeypatch) -> None:
monkeypatch.delenv("MEM0_TELEMETRY", raising=False)
result = _command_check(
"environment",
"test",
[sys.executable, "-c", "import os; print(os.environ.get('MEM0_TELEMETRY', 'unset'))"],
cwd=tmp_path,
)
assert result["status"] == "passed"
assert result["output"] == "unset"
def test_command_check_can_force_non_interactive_installs(tmp_path: Path) -> None:
result = _command_check(
"environment",
"test",
[sys.executable, "-c", "import os; print(os.environ['CI'])"],
cwd=tmp_path,
environment_overrides={"CI": "true"},
)
assert result["status"] == "passed"
assert result["output"] == "true"
def test_conformance_report_redacts_command_output(tmp_path: Path) -> None:
secret = "sk-eval-12345678901234567890"
result = _command_check(
"redaction",
"test",
[sys.executable, "-c", f"print('failure: {secret}')"],
cwd=tmp_path,
)
assert secret not in json.dumps(result)
assert "[REDACTED]" in result["output"]
@@ -0,0 +1,102 @@
"""Exercise bundled subagent hooks as separate host processes, without Mem0 calls."""
import json
import os
import sqlite3
import subprocess
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "python"))
from memory_core import EvidenceStore, RepoContext, checkpoint_stats # noqa: E402
def test_generic_tracking_preserves_legacy_runs_and_can_finish_them(tmp_path):
database = tmp_path / "evidence.sqlite3"
with sqlite3.connect(database) as connection:
connection.executescript("""
CREATE TABLE sidekick_runs (
repo_id TEXT NOT NULL, session_id TEXT NOT NULL,
agent_id TEXT NOT NULL, agent_type TEXT NOT NULL,
started_at TEXT NOT NULL, stopped_at TEXT, transcript_path TEXT,
context_chars INTEGER NOT NULL DEFAULT 0, final_message TEXT,
PRIMARY KEY(repo_id, session_id, agent_id)
);
INSERT INTO sidekick_runs VALUES
('repo', 'session', 'worker', 'default', '2026-09-10', NULL, NULL, 123, NULL);
""")
for _ in range(2):
store = EvidenceStore(database)
try:
assert store.status("repo")["subagent_runs"] == 1
row = store.conn.execute("SELECT * FROM sidekick_runs").fetchone()
assert row["agent_id"] == "worker"
assert row["context_chars"] == 123
repo = RepoContext(str(tmp_path), str(tmp_path), "repo", "app", "main", "")
store.stop_subagent(repo, "session", "worker", "default", "", "Completed after upgrade.")
assert store.status("repo")["last_subagent"]["stopped_at"]
assert store.conn.execute("SELECT final_message FROM sidekick_runs").fetchone()[0] == (
"Completed after upgrade."
)
finally:
store.close()
assert checkpoint_stats([{"kind": "sidekick_stop", "payload": {"final_message": "Legacy result."}}]) == (0, 1, 14)
@pytest.mark.parametrize("host", ["claude-code", "codex"])
def test_subagent_hooks_preserve_parent_scope_and_correlate_completion(tmp_path, host):
parent = tmp_path / "parent"
child = tmp_path / "child-worktree"
parent.mkdir()
child.mkdir()
database = tmp_path / "data" / "evidence.sqlite3"
store = EvidenceStore(database)
repo = store.repo_for_session("parent-session", str(parent))
store.mark_injected("parent-session", repo.identity, [{"id": "one", "memory": "Parent memory marker."}])
store.mark_injected("other-session", repo.identity, [{"id": "two", "memory": "Foreign memory marker."}])
store.close()
plugin = ROOT.parent / f"{host}-plugin"
adapter = plugin / ("adapters/claude/hook.py" if host == "claude-code" else "hooks/adapter.py")
start, stop = "sidekick-start", "sidekick-stop"
payload = {"session_id": "parent-session", "cwd": str(child), "agent_id": "worker", "agent_type": "default"}
response_key = "last_assistant_message"
if host == "codex":
start, stop = "subagent-start", "subagent-stop"
env = {key: value for key, value in os.environ.items() if not key.startswith(("MEM0_", "CLAUDE_PLUGIN_"))}
env.update(MEM0_CODE_DATA_DIR=str(database.parent), MEM0_TELEMETRY="false", MEM0_API_URL="http://127.0.0.1:1")
def invoke(event, body):
result = subprocess.run(
[sys.executable, str(adapter), event],
input=json.dumps({**body, "hook_event_name": event}),
text=True,
capture_output=True,
env=env,
timeout=15,
check=True,
)
return result.stdout
output = invoke(start, payload)
context = json.loads(output)["hookSpecificOutput"]["additionalContext"]
assert "Parent memory marker." in context
assert "Foreign memory marker." not in output
assert "Parent memory marker." not in invoke(start, payload)
invoke(stop, {**payload, response_key: "Finished the delegated task."})
store = EvidenceStore(database)
runs = store.conn.execute("SELECT * FROM sidekick_runs").fetchall()
store.close()
assert len(runs) == 1
assert (runs[0]["repo_id"], runs[0]["session_id"], runs[0]["agent_id"]) == (
repo.identity, "parent-session", "worker"
)
assert runs[0]["stopped_at"]
assert runs[0]["final_message"] == "Finished the delegated task."
assert runs[0]["context_chars"] > 0
@@ -0,0 +1,115 @@
from __future__ import annotations
import json
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
VALIDATE = ROOT / "build" / "validate.py"
PLUGIN_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json"
def run_validator(bundle: Path) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(VALIDATE), str(bundle), "--kind", "portable"],
capture_output=True,
check=False,
text=True,
)
def write_manifest(bundle: Path, schema: str = PLUGIN_SCHEMA) -> None:
bundle.mkdir(parents=True, exist_ok=True)
(bundle / "plugin.json").write_text(
json.dumps({"$schema": schema, "name": "mem0"}),
encoding="utf-8",
)
def test_rejects_wrong_agent_plugin_schema(tmp_path: Path) -> None:
bundle = tmp_path / "plugin"
write_manifest(bundle, "https://agent-plugins.org/v1.0.0/plugin.schema.json")
result = run_validator(bundle)
assert result.returncode == 1
assert result.stderr == (
"plugin.json.$schema: "
"'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json' was expected\n"
)
def test_rejects_symlink_outside_bundle(tmp_path: Path) -> None:
bundle = tmp_path / "plugin"
write_manifest(bundle)
outside = tmp_path / "outside"
outside.mkdir()
(bundle / "skills").symlink_to(outside, target_is_directory=True)
result = run_validator(bundle)
assert result.returncode == 1
assert result.stderr == "skills: symlinks are not allowed in release bundles\n"
def test_accepts_minimal_portable_bundle(tmp_path: Path) -> None:
bundle = tmp_path / "plugin"
write_manifest(bundle)
result = run_validator(bundle)
assert result.returncode == 0
assert result.stdout == f"Validated portable bundle: {bundle}\n"
assert result.stderr == ""
def test_rejects_nonconformant_agent_skill(tmp_path: Path) -> None:
bundle = tmp_path / "plugin"
write_manifest(bundle)
skill = bundle / "skills" / "Bad_Name"
skill.mkdir(parents=True)
(skill / "SKILL.md").write_text(
"---\nname: Bad_Name\ndescription: invalid\nunknown: true\n---\n",
encoding="utf-8",
)
result = run_validator(bundle)
assert result.returncode == 1
assert "skills/Bad_Name" in result.stderr
def run_native_validator(bundle: Path) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(VALIDATE), str(bundle), "--kind", "native"],
capture_output=True,
check=False,
text=True,
)
def test_native_bundle_rejects_malformed_json(tmp_path: Path) -> None:
bundle = tmp_path / "plugin"
bundle.mkdir(parents=True)
(bundle / "plugin.json").write_text("{bad json", encoding="utf-8")
result = run_native_validator(bundle)
assert result.returncode == 1
assert "plugin.json" in result.stderr
def test_native_bundle_accepts_valid_json(tmp_path: Path) -> None:
bundle = tmp_path / "plugin"
bundle.mkdir(parents=True)
(bundle / "plugin.json").write_text('{"name": "mem0"}', encoding="utf-8")
hooks = bundle / "hooks"
hooks.mkdir()
(hooks / "hooks.json").write_text('{"version": 1}', encoding="utf-8")
result = run_native_validator(bundle)
assert result.returncode == 0
assert "native" in result.stdout