@@ -1361,6 +1361,79 @@ def test_codex_skill_registration_resolves_script_placeholders(self, project_dir
13611361 assert "{ARGS}" not in content
13621362 assert '.specify/scripts/bash/setup-plan.sh --json "$ARGUMENTS"' in content
13631363
1364+ @pytest .mark .parametrize ("agent_name,skills_path" , [
1365+ ("codex" , ".agents/skills" ),
1366+ ("kimi" , ".kimi/skills" ),
1367+ ("claude" , ".claude/skills" ),
1368+ ("cursor-agent" , ".cursor/skills" ),
1369+ ("trae" , ".trae/skills" ),
1370+ ("agy" , ".agents/skills" ),
1371+ ])
1372+ def test_all_skill_agents_register_commands_with_resolved_placeholders (
1373+ self , project_dir , temp_dir , agent_name , skills_path
1374+ ):
1375+ """All SKILL.md agents must produce fully resolved SKILL.md files when commands are registered."""
1376+ import yaml
1377+
1378+ ext_dir = temp_dir / f"ext-{ agent_name } "
1379+ ext_dir .mkdir ()
1380+ (ext_dir / "commands" ).mkdir ()
1381+
1382+ manifest_data = {
1383+ "schema_version" : "1.0" ,
1384+ "extension" : {
1385+ "id" : f"ext-{ agent_name } " ,
1386+ "name" : "Scripted Extension" ,
1387+ "version" : "1.0.0" ,
1388+ "description" : "Test" ,
1389+ },
1390+ "requires" : {"speckit_version" : ">=0.1.0" },
1391+ "provides" : {
1392+ "commands" : [
1393+ {
1394+ "name" : f"speckit.ext-{ agent_name } .run" ,
1395+ "file" : "commands/run.md" ,
1396+ "description" : "Scripted command" ,
1397+ }
1398+ ]
1399+ },
1400+ }
1401+ with open (ext_dir / "extension.yml" , "w" ) as f :
1402+ yaml .dump (manifest_data , f )
1403+
1404+ (ext_dir / "commands" / "run.md" ).write_text (
1405+ "---\n "
1406+ "description: Scripted command\n "
1407+ "scripts:\n "
1408+ ' sh: ../../scripts/bash/setup-plan.sh --json "{ARGS}"\n '
1409+ "---\n \n "
1410+ "Run {SCRIPT}\n "
1411+ "Agent is __AGENT__.\n "
1412+ )
1413+
1414+ init_options = project_dir / ".specify" / "init-options.json"
1415+ init_options .parent .mkdir (parents = True , exist_ok = True )
1416+ init_options .write_text (f'{{"ai":"{ agent_name } ","script":"sh"}}' )
1417+
1418+ skills_dir = project_dir
1419+ for part in skills_path .split ("/" ):
1420+ skills_dir = skills_dir / part
1421+ skills_dir .mkdir (parents = True )
1422+
1423+ manifest = ExtensionManifest (ext_dir / "extension.yml" )
1424+ registrar = CommandRegistrar ()
1425+ registrar .register_commands_for_agent (agent_name , manifest , ext_dir , project_dir )
1426+
1427+ skill_dir_name = f"speckit-ext-{ agent_name } -run"
1428+ skill_file = skills_dir / skill_dir_name / "SKILL.md"
1429+ assert skill_file .exists (), f"SKILL.md not created for { agent_name } "
1430+
1431+ content = skill_file .read_text ()
1432+ assert "{SCRIPT}" not in content , f"{{SCRIPT}} not resolved for { agent_name } "
1433+ assert "__AGENT__" not in content , f"__AGENT__ not resolved for { agent_name } "
1434+ assert "{ARGS}" not in content , f"{{ARGS}} not resolved for { agent_name } "
1435+ assert '.specify/scripts/bash/setup-plan.sh' in content
1436+
13641437 def test_codex_skill_alias_frontmatter_matches_alias_name (self , project_dir , temp_dir ):
13651438 """Codex alias skills should render their own matching `name:` frontmatter."""
13661439 import yaml
0 commit comments