@@ -57,14 +57,35 @@ def update(self, env_id, **kwargs):
5757 return SimpleNamespace (id = env_id , name = kwargs .get ("name" ))
5858
5959
60+ class FakeSkills :
61+ """Records create / versions.create and answers list() from a seeded set (mirrors
62+ test_deploy_skills.FakeSkills) — deploy_agents now publishes referenced skills itself."""
63+
64+ def __init__ (self , existing = None ):
65+ # existing: list of (skill_id, display_title)
66+ self ._existing = [SimpleNamespace (id = i , display_title = t ) for i , t in (existing or [])]
67+ self .create_calls = []
68+ self .version_calls = []
69+ self .versions = SimpleNamespace (create = self ._version_create )
70+
71+ def list (self ):
72+ return list (self ._existing )
73+
74+ def create (self , * , files , display_title ):
75+ self .create_calls .append ({"files" : files , "display_title" : display_title })
76+ return SimpleNamespace (id = "skill_new" , latest_version = 111 )
77+
78+ def _version_create (self , skill_id , * , files ):
79+ self .version_calls .append ({"skill_id" : skill_id , "files" : files })
80+ return SimpleNamespace (version = 222 )
81+
82+
6083class FakeClient :
6184 def __init__ (self , * , agents = None , environments = None , skills_list = None ):
6285 self .beta = SimpleNamespace (
6386 agents = FakeAgents (agents ),
6487 environments = FakeEnvironments (environments ),
65- skills = SimpleNamespace (
66- list = lambda : [SimpleNamespace (id = i , display_title = t ) for i , t in (skills_list or [])]
67- ),
88+ skills = FakeSkills (skills_list ),
6889 )
6990
7091
@@ -97,17 +118,25 @@ def __init__(self, *, agents=None, environments=None, skills_list=None):
97118"""
98119
99120
100- def _wire (tmp_path : Path , monkeypatch , * , agent = AGENT_YAML , env = ENV_YAML ):
121+ def _wire (tmp_path : Path , monkeypatch , * , agent = AGENT_YAML , env = ENV_YAML , skill = "lik-query-project-index" ):
101122 agents_root = tmp_path / "agents"
102123 envs_root = tmp_path / "environments"
124+ skills_root = tmp_path / "skills"
103125 agents_root .mkdir ()
104126 envs_root .mkdir ()
127+ skills_root .mkdir ()
105128 if agent is not None :
106129 (agents_root / "lik-query-project-index.yaml" ).write_text (agent , encoding = "utf-8" )
107130 if env is not None :
108131 (envs_root / "lik-ui.yaml" ).write_text (env , encoding = "utf-8" )
132+ if skill is not None :
133+ # The skill the agent references, so deploy_agents can publish it (dir name == SKILL.md name).
134+ sdir = skills_root / skill
135+ sdir .mkdir ()
136+ (sdir / "SKILL.md" ).write_text (f"---\n name: { skill } \n description: test\n ---\n # { skill } \n " , encoding = "utf-8" )
109137 monkeypatch .setattr (da , "AGENTS_ROOT" , agents_root )
110138 monkeypatch .setattr (da , "ENVIRONMENTS_ROOT" , envs_root )
139+ monkeypatch .setattr (da .ds , "SKILLS_ROOT" , skills_root )
111140 return agents_root , envs_root
112141
113142
@@ -148,27 +177,50 @@ def test_match_by_name_ambiguous_raises():
148177 da ._match_by_name (items , "A" )
149178
150179
151- # --- resolve_skills (name -> id substitution) --------------------------------------------------
180+ # --- resolve_skills (deploy referenced skills + name -> id substitution) -----------------------
181+
182+
183+ def test_resolve_skills_publishes_new_skill_and_substitutes_id (tmp_path , monkeypatch ):
184+ _wire (tmp_path , monkeypatch )
185+ client = FakeClient (skills_list = []) # skill not on platform yet -> create
186+ out = da .resolve_skills (client , [{"name" : "lik-query-project-index" }])
187+ assert out == [{"type" : "custom" , "skill_id" : "skill_new" , "version" : "latest" }]
188+ assert client .beta .skills .create_calls # the referenced skill was published
152189
153190
154- def test_resolve_skills_substitutes_ids ():
191+ def test_resolve_skills_publishes_new_version_when_skill_exists (tmp_path , monkeypatch ):
192+ _wire (tmp_path , monkeypatch )
155193 client = FakeClient (skills_list = [("skill_abc" , "lik-query-project-index" )])
156194 out = da .resolve_skills (client , [{"name" : "lik-query-project-index" }])
157195 assert out == [{"type" : "custom" , "skill_id" : "skill_abc" , "version" : "latest" }]
196+ assert client .beta .skills .version_calls # new version, not a duplicate create
197+ assert client .beta .skills .create_calls == []
158198
159199
160- def test_resolve_skills_missing_skill_fails_fast ():
161- client = FakeClient (skills_list = [("skill_abc" , "some-other-skill" )])
200+ def test_resolve_skills_missing_repo_dir_fails_fast (tmp_path , monkeypatch ):
201+ _wire (tmp_path , monkeypatch )
202+ client = FakeClient (skills_list = [])
162203 with pytest .raises (ValueError ):
163- da .resolve_skills (client , [{"name" : "lik-query-project-index" }])
204+ da .resolve_skills (client , [{"name" : "no-such-skill-in-repo" }])
205+ assert client .beta .skills .create_calls == [] # nothing published
164206
165207
166- def test_resolve_skills_entry_without_name_fails ():
208+ def test_resolve_skills_entry_without_name_fails (tmp_path , monkeypatch ):
209+ _wire (tmp_path , monkeypatch )
167210 client = FakeClient (skills_list = [])
168211 with pytest .raises (ValueError ):
169212 da .resolve_skills (client , [{"skill_id" : "skill_abc" }])
170213
171214
215+ def test_resolve_skills_dry_run_does_not_publish (tmp_path , monkeypatch ):
216+ _wire (tmp_path , monkeypatch )
217+ client = FakeClient (skills_list = [("skill_abc" , "lik-query-project-index" )])
218+ out = da .resolve_skills (client , [{"name" : "lik-query-project-index" }], deploy = False )
219+ assert out == [{"type" : "custom" , "skill_id" : "skill_abc" , "version" : "latest" }]
220+ assert client .beta .skills .create_calls == []
221+ assert client .beta .skills .version_calls == []
222+
223+
172224# --- deploy_agent: create vs update ------------------------------------------------------------
173225
174226
@@ -204,13 +256,15 @@ def test_deploy_existing_agent_updates_preserving_version(tmp_path, monkeypatch)
204256 assert call ["skills" ] == [{"type" : "custom" , "skill_id" : "skill_abc" , "version" : "latest" }]
205257
206258
207- def test_deploy_agent_missing_skill_makes_no_write (tmp_path , monkeypatch ):
208- agents_root , _ = _wire (tmp_path , monkeypatch )
209- client = FakeClient (agents = [], skills_list = []) # skill not on platform
259+ def test_deploy_agent_missing_skill_dir_makes_no_write (tmp_path , monkeypatch ):
260+ # The referenced skill has no directory under claude_platform/skills/ -> fail fast, nothing written.
261+ agents_root , _ = _wire (tmp_path , monkeypatch , skill = None ) # no skill dir in the repo
262+ client = FakeClient (agents = [], skills_list = [])
210263 with pytest .raises (ValueError ):
211264 da .deploy_agent (client , agents_root / "lik-query-project-index.yaml" )
212265 assert client .beta .agents .create_calls == []
213266 assert client .beta .agents .update_calls == []
267+ assert client .beta .skills .create_calls == []
214268
215269
216270def test_deploy_agent_dry_run_makes_no_write (tmp_path , monkeypatch ):
@@ -257,6 +311,8 @@ def test_main_syncs_envs_then_selected_agent(tmp_path, monkeypatch):
257311 # environment created before the agent
258312 assert client .beta .environments .create_calls [0 ]["name" ] == "lik-ui"
259313 assert client .beta .agents .create_calls [0 ]["name" ] == "LIK Query: Project Index"
314+ # the agent's referenced skill was published as part of the same run
315+ assert client .beta .skills .version_calls # skill existed -> new version published
260316
261317
262318def test_main_dry_run_mutates_nothing (tmp_path , monkeypatch ):
@@ -268,3 +324,5 @@ def test_main_dry_run_mutates_nothing(tmp_path, monkeypatch):
268324 assert rc == 0
269325 assert client .beta .agents .create_calls == []
270326 assert client .beta .environments .create_calls == []
327+ assert client .beta .skills .create_calls == [] # dry run publishes no skills either
328+ assert client .beta .skills .version_calls == []
0 commit comments