@@ -217,6 +217,57 @@ def fake_run(argv, *, error_prefix, env=None, cwd=None):
217217 assert calls [0 ][1 ]["HOME" ] == str (backend_home )
218218
219219
220+ def test_install_managed_claude_plugin_replaces_symlinked_plugin_state (monkeypatch , tmp_path : Path ):
221+ backend_home = tmp_path / "claude-home"
222+ marketplace_source = tmp_path / "lean4-skills"
223+ plugin_source = marketplace_source / "plugins" / "lean4"
224+ install_path = backend_home / ".claude" / "plugins" / "cache" / "lean4-skills" / "lean4" / "4.4.0"
225+ legacy_plugins_root = tmp_path / "legacy-plugins"
226+ (marketplace_source / ".claude-plugin" ).mkdir (parents = True )
227+ (plugin_source / ".claude-plugin" ).mkdir (parents = True )
228+ (marketplace_source / ".claude-plugin" / "marketplace.json" ).write_text (
229+ json .dumps ({"name" : "lean4-skills" }),
230+ encoding = "utf-8" ,
231+ )
232+ (plugin_source / ".claude-plugin" / "plugin.json" ).write_text (
233+ json .dumps ({"name" : "lean4" , "version" : "4.4.0" }),
234+ encoding = "utf-8" ,
235+ )
236+ legacy_plugins_root .mkdir (parents = True )
237+ plugin_state_root = backend_home / ".claude" / "plugins"
238+ plugin_state_root .parent .mkdir (parents = True , exist_ok = True )
239+ plugin_state_root .symlink_to (legacy_plugins_root , target_is_directory = True )
240+
241+ def fake_run (argv , * , error_prefix , env = None , cwd = None ):
242+ stdout = ""
243+ if list (argv )[1 :3 ] == ["plugin" , "install" ]:
244+ install_path .mkdir (parents = True , exist_ok = True )
245+ if list (argv )[- 2 :] == ["list" , "--json" ]:
246+ stdout = json .dumps (
247+ [
248+ {
249+ "id" : "lean4@lean4-skills" ,
250+ "installPath" : str (install_path ),
251+ }
252+ ]
253+ )
254+ return SimpleNamespace (stdout = stdout )
255+
256+ monkeypatch .setattr (autoformalize , "_run" , fake_run )
257+
258+ result = autoformalize ._install_managed_claude_plugin (
259+ claude_executable = "/usr/bin/claude" ,
260+ backend_home = backend_home ,
261+ base_environment = {"PATH" : "/usr/bin" },
262+ marketplace_source = marketplace_source ,
263+ plugin_source = plugin_source ,
264+ )
265+
266+ assert result == install_path .resolve ()
267+ assert not plugin_state_root .is_symlink ()
268+ assert install_path .exists ()
269+
270+
220271def test_resolve_uv_runner_uses_default_user_scoped_package (monkeypatch ):
221272 monkeypatch .setattr (
222273 autoformalize .shutil ,
0 commit comments