@@ -642,6 +642,21 @@ def test_parse_frontmatter_no_frontmatter(self):
642642 assert frontmatter == {}
643643 assert body == content
644644
645+ def test_parse_frontmatter_non_mapping_returns_empty_dict (self ):
646+ """Non-mapping YAML frontmatter should not crash downstream renderers."""
647+ content = """---
648+ - item1
649+ - item2
650+ ---
651+
652+ # Command body
653+ """
654+ registrar = CommandRegistrar ()
655+ frontmatter , body = registrar .parse_frontmatter (content )
656+
657+ assert frontmatter == {}
658+ assert "Command body" in body
659+
645660 def test_render_frontmatter (self ):
646661 """Test rendering frontmatter to YAML."""
647662 frontmatter = {
@@ -899,6 +914,69 @@ def test_codex_skill_alias_frontmatter_matches_alias_name(self, project_dir, tem
899914 assert "name: speckit-alias.cmd" in primary .read_text ()
900915 assert "name: speckit-shortcut" in alias .read_text ()
901916
917+ def test_codex_skill_registration_uses_fallback_script_variant_without_init_options (
918+ self , project_dir , temp_dir
919+ ):
920+ """Codex placeholder substitution should still work without init-options.json."""
921+ import yaml
922+
923+ ext_dir = temp_dir / "ext-script-fallback"
924+ ext_dir .mkdir ()
925+ (ext_dir / "commands" ).mkdir ()
926+
927+ manifest_data = {
928+ "schema_version" : "1.0" ,
929+ "extension" : {
930+ "id" : "ext-script-fallback" ,
931+ "name" : "Script fallback" ,
932+ "version" : "1.0.0" ,
933+ "description" : "Test" ,
934+ },
935+ "requires" : {"speckit_version" : ">=0.1.0" },
936+ "provides" : {
937+ "commands" : [
938+ {
939+ "name" : "speckit.fallback.plan" ,
940+ "file" : "commands/plan.md" ,
941+ }
942+ ]
943+ },
944+ }
945+ with open (ext_dir / "extension.yml" , "w" ) as f :
946+ yaml .dump (manifest_data , f )
947+
948+ (ext_dir / "commands" / "plan.md" ).write_text (
949+ """---
950+ description: "Fallback scripted command"
951+ scripts:
952+ sh: scripts/bash/setup-plan.sh --json "{ARGS}"
953+ ps: scripts/powershell/setup-plan.ps1 -Json
954+ agent_scripts:
955+ sh: scripts/bash/update-agent-context.sh __AGENT__
956+ ---
957+
958+ Run {SCRIPT}
959+ Then {AGENT_SCRIPT}
960+ """
961+ )
962+
963+ # Intentionally do NOT create .specify/init-options.json
964+ skills_dir = project_dir / ".agents" / "skills"
965+ skills_dir .mkdir (parents = True )
966+
967+ manifest = ExtensionManifest (ext_dir / "extension.yml" )
968+ registrar = CommandRegistrar ()
969+ registrar .register_commands_for_agent ("codex" , manifest , ext_dir , project_dir )
970+
971+ skill_file = skills_dir / "speckit-fallback.plan" / "SKILL.md"
972+ assert skill_file .exists ()
973+
974+ content = skill_file .read_text ()
975+ assert "{SCRIPT}" not in content
976+ assert "{AGENT_SCRIPT}" not in content
977+ assert 'scripts/bash/setup-plan.sh --json "$ARGUMENTS"' in content
978+ assert "scripts/bash/update-agent-context.sh codex" in content
979+
902980 def test_register_commands_for_copilot (self , extension_dir , project_dir ):
903981 """Test registering commands for Copilot agent with .agent.md extension."""
904982 # Create .github/agents directory (Copilot project)
0 commit comments