From 6b59b04adba6ecb5383186ac4a28052c85ca4023 Mon Sep 17 00:00:00 2001 From: michaelxer Date: Wed, 12 Aug 2026 22:51:03 +0700 Subject: [PATCH] fix(install): copy skill on opencode/codex always-on install `graphify opencode install` only wrote AGENTS.md + the plugin and never copied skill-opencode.md to ~/.config/opencode/skills/graphify/SKILL.md, so /graphify was not discoverable. Mirror amp/agents: copy the skill first, then the agents install path. Same gap fixed for the other platforms on that dispatch branch. Uninstall removes the skill too. Fixes #2670 --- graphify/__main__.py | 8 +++--- graphify/install.py | 11 ++++++++ tests/test_install.py | 62 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/graphify/__main__.py b/graphify/__main__.py index 924ae986d..153c69005 100644 --- a/graphify/__main__.py +++ b/graphify/__main__.py @@ -638,13 +638,13 @@ def _run_cli() -> None: print(" claude uninstall remove graphify section from CLAUDE.md + PreToolUse hook") print(" codebuddy install write graphify section to CODEBUDDY.md + PreToolUse hook (CodeBuddy)") print(" codebuddy uninstall remove graphify section from CODEBUDDY.md + PreToolUse hook") - print(" codex install write graphify section to AGENTS.md (Codex)") - print(" codex uninstall remove graphify section from AGENTS.md") + print(" codex install copy skill + write graphify section to AGENTS.md (Codex)") + print(" codex uninstall remove skill + graphify section from AGENTS.md") print( - " opencode install write graphify section to AGENTS.md + tool.execute.before plugin (OpenCode)" + " opencode install copy skill + write AGENTS.md + tool.execute.before plugin (OpenCode)" ) print( - " opencode uninstall remove graphify section from AGENTS.md + plugin" + " opencode uninstall remove skill + AGENTS.md section + plugin" ) print( " kilo install install native Kilo skill + command + AGENTS.md + .kilo plugin" diff --git a/graphify/install.py b/graphify/install.py index fbe135bcf..bfbef2857 100644 --- a/graphify/install.py +++ b/graphify/install.py @@ -2262,11 +2262,22 @@ def dispatch_install_cli(cmd: str) -> bool: if "--project" in sys.argv[3:]: _project_install(cmd, Path(".")) else: + # Mirror amp/agents user-scope install: skill file first, then + # AGENTS.md (+ platform plugin). Without this, `graphify + # opencode install` only wrote the AGENTS section/plugin and + # never copied skill-opencode.md to + # ~/.config/opencode/skills/graphify/SKILL.md, so /graphify + # was never discoverable (#2670). Same gap for the other + # always-on platforms in this branch. + _copy_skill_file(cmd) _agents_install(Path("."), cmd) elif subcmd == "uninstall": if "--project" in sys.argv[3:]: _project_uninstall(cmd, Path(".")) else: + removed = _remove_skill_file(cmd) + if removed: + print("skill removed") _agents_uninstall(Path("."), platform=cmd) if cmd == "codex": _uninstall_codex_hook(Path(".")) diff --git a/tests/test_install.py b/tests/test_install.py index 8cea17b4c..a91274821 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -765,6 +765,68 @@ def test_opencode_agents_uninstall_removes_plugin(tmp_path): assert not any("graphify.js" in p for p in config.get("plugin", [])) +def test_opencode_cli_install_copies_skill_file(tmp_path, monkeypatch): + """#2670: `graphify opencode install` must copy skill-opencode.md to the + user skill path, not only write AGENTS.md + the tool.execute.before plugin. + """ + from graphify.__main__ import main + + home = tmp_path / "home" + project = tmp_path / "project" + home.mkdir() + project.mkdir() + monkeypatch.chdir(project) + monkeypatch.setattr(sys, "argv", ["graphify", "opencode", "install"]) + with patch("graphify.install.Path.home", return_value=home): + main() + + skill = home / ".config" / "opencode" / "skills" / "graphify" / "SKILL.md" + assert skill.exists(), "user-scope OpenCode skill was not installed (#2670)" + assert skill.stat().st_size > 0 + assert (project / "AGENTS.md").exists() + assert (project / ".opencode" / "plugins" / "graphify.js").exists() + + +def test_opencode_cli_uninstall_removes_skill_file(tmp_path, monkeypatch): + """#2670: `graphify opencode uninstall` removes the user-scope skill too.""" + from graphify.__main__ import main + + home = tmp_path / "home" + project = tmp_path / "project" + home.mkdir() + project.mkdir() + monkeypatch.chdir(project) + + monkeypatch.setattr(sys, "argv", ["graphify", "opencode", "install"]) + with patch("graphify.install.Path.home", return_value=home): + main() + skill = home / ".config" / "opencode" / "skills" / "graphify" / "SKILL.md" + assert skill.exists() + + monkeypatch.setattr(sys, "argv", ["graphify", "opencode", "uninstall"]) + with patch("graphify.install.Path.home", return_value=home): + main() + assert not skill.exists() + + +def test_codex_cli_install_copies_skill_file(tmp_path, monkeypatch): + """Same always-on install branch as opencode: codex must also get its skill.""" + from graphify.__main__ import main + + home = tmp_path / "home" + project = tmp_path / "project" + home.mkdir() + project.mkdir() + monkeypatch.chdir(project) + monkeypatch.setattr(sys, "argv", ["graphify", "codex", "install"]) + with patch("graphify.install.Path.home", return_value=home): + main() + + skill = home / ".codex" / "skills" / "graphify" / "SKILL.md" + assert skill.exists() + assert (project / "AGENTS.md").exists() + + def test_kilo_agents_install_writes_agents_md(tmp_path): _agents_install(tmp_path, "kilo") assert (tmp_path / "AGENTS.md").exists()