From e8a1aebba7989e93b764ae54838018e0fc3315a5 Mon Sep 17 00:00:00 2001 From: DarkSlaayer Date: Thu, 9 Apr 2026 09:54:48 -0700 Subject: [PATCH] Fix codex install idempotency --- graphify/__main__.py | 16 +++++++++++----- tests/test_install.py | 25 ++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/graphify/__main__.py b/graphify/__main__.py index 31f54fff0..8ae48d0de 100644 --- a/graphify/__main__.py +++ b/graphify/__main__.py @@ -343,18 +343,24 @@ def _uninstall_codex_hook(project_dir: Path) -> None: def _agents_install(project_dir: Path, platform: str) -> None: """Write the graphify section to the local AGENTS.md (Codex/OpenCode/OpenClaw).""" target = (project_dir or Path(".")) / "AGENTS.md" + agents_already_configured = False if target.exists(): content = target.read_text(encoding="utf-8") if _AGENTS_MD_MARKER in content: - print(f"graphify already configured in AGENTS.md") - return - new_content = content.rstrip() + "\n\n" + _AGENTS_MD_SECTION + agents_already_configured = True + else: + new_content = content.rstrip() + "\n\n" + _AGENTS_MD_SECTION else: new_content = _AGENTS_MD_SECTION - target.write_text(new_content, encoding="utf-8") - print(f"graphify section written to {target.resolve()}") + if agents_already_configured: + print("graphify already configured in AGENTS.md") + if platform not in ("codex", "opencode"): + return + else: + target.write_text(new_content, encoding="utf-8") + print(f"graphify section written to {target.resolve()}") if platform == "codex": _install_codex_hook(project_dir or Path(".")) diff --git a/tests/test_install.py b/tests/test_install.py index 34d1761e2..60acc4fa5 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -1,4 +1,5 @@ """Tests for graphify install --platform routing.""" +import json from pathlib import Path from unittest.mock import patch import pytest @@ -122,11 +123,17 @@ def _agents_uninstall(tmp_path): def test_codex_agents_install_writes_agents_md(tmp_path): + from graphify.__main__ import _CODEX_HOOK + _agents_install(tmp_path, "codex") agents_md = tmp_path / "AGENTS.md" assert agents_md.exists() assert "graphify" in agents_md.read_text() assert "GRAPH_REPORT.md" in agents_md.read_text() + hooks_path = tmp_path / ".codex" / "hooks.json" + assert hooks_path.exists() + hooks = json.loads(hooks_path.read_text()) + assert hooks["hooks"]["PreToolUse"] == _CODEX_HOOK["hooks"]["PreToolUse"] def test_opencode_agents_install_writes_agents_md(tmp_path): @@ -140,11 +147,27 @@ def test_claw_agents_install_writes_agents_md(tmp_path): def test_agents_install_idempotent(tmp_path): - """Installing twice does not duplicate the section.""" + """Installing twice does not duplicate the section or Codex hook.""" _agents_install(tmp_path, "codex") _agents_install(tmp_path, "codex") content = (tmp_path / "AGENTS.md").read_text() assert content.count("## graphify") == 1 + hooks = json.loads((tmp_path / ".codex" / "hooks.json").read_text()) + assert len(hooks["hooks"]["PreToolUse"]) == 1 + + +def test_codex_agents_install_repairs_missing_hook_after_partial_install(tmp_path): + """A rerun heals a partial Codex install where only AGENTS.md exists.""" + from graphify.__main__ import _AGENTS_MD_SECTION + + (tmp_path / "AGENTS.md").write_text(_AGENTS_MD_SECTION, encoding="utf-8") + + _agents_install(tmp_path, "codex") + + hooks_path = tmp_path / ".codex" / "hooks.json" + assert hooks_path.exists() + hooks = json.loads(hooks_path.read_text()) + assert len(hooks["hooks"]["PreToolUse"]) == 1 def test_agents_install_appends_to_existing(tmp_path):