Skip to content

Commit 979a30e

Browse files
committed
fix(codex): preserve existing .codex while skipping legacy prompt extraction
1 parent 9736af9 commit 979a30e

2 files changed

Lines changed: 13 additions & 45 deletions

File tree

src/specify_cli/__init__.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,10 @@ def download_and_extract_template(
10311031
console.print("[cyan]Found nested directory structure[/cyan]")
10321032

10331033
for item in source_dir.iterdir():
1034+
# In Codex skills mode, do not materialize legacy prompt
1035+
# templates under .codex/prompts.
1036+
if skip_legacy_codex_prompts and ai_assistant == "codex" and item.name == ".codex":
1037+
continue
10341038
dest_path = project_path / item.name
10351039
if item.is_dir():
10361040
if dest_path.exists():
@@ -2112,14 +2116,6 @@ def init(
21122116
# so leaving stale commands is non-fatal.
21132117
console.print("[yellow]Warning: could not remove extracted commands directory[/yellow]")
21142118

2115-
# In Codex skills mode, remove legacy prompt layout after skills
2116-
# installation/fallback completes so prompt artifacts are not left
2117-
# behind in the project tree.
2118-
if selected_ai == "codex" and ai_skills:
2119-
legacy_codex_dir = project_path / ".codex"
2120-
if legacy_codex_dir.is_dir():
2121-
shutil.rmtree(legacy_codex_dir, ignore_errors=True)
2122-
21232119
if not no_git:
21242120
tracker.start("git")
21252121
if is_git_repo(project_path):

tests/test_ai_skills.py

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -770,49 +770,20 @@ def fake_download(project_path, *args, **kwargs):
770770
assert result.exit_code == 0
771771
mock_skills.assert_called_once()
772772
assert mock_skills.call_args.kwargs.get("overwrite_existing") is True
773-
assert not (target / ".codex").exists()
774773

775-
def test_codex_ai_skills_removes_legacy_codex_dir_after_fallback(self, tmp_path):
776-
"""Codex skills init should not leave legacy .codex prompt directory behind."""
774+
def test_codex_ai_skills_here_mode_preserves_existing_codex_dir(self, tmp_path, monkeypatch):
775+
"""Codex --here skills init should not delete a pre-existing .codex directory."""
777776
from typer.testing import CliRunner
778777

779778
runner = CliRunner()
780-
target = tmp_path / "codex-cleanup-new"
781-
782-
def fake_download(project_path, *args, **kwargs):
783-
prompts_dir = project_path / ".codex" / "prompts"
784-
prompts_dir.mkdir(parents=True, exist_ok=True)
785-
(prompts_dir / "speckit.specify.md").write_text("---\ndescription: Legacy prompt\n---\n\nBody.\n")
786-
787-
with patch("specify_cli.download_and_extract_template", side_effect=fake_download), \
788-
patch("specify_cli.ensure_executable_scripts"), \
789-
patch("specify_cli.ensure_constitution_from_template"), \
790-
patch("specify_cli.install_ai_skills", return_value=True), \
791-
patch("specify_cli.is_git_repo", return_value=False), \
792-
patch("specify_cli.shutil.which", return_value="/usr/bin/codex"):
793-
result = runner.invoke(
794-
app,
795-
["init", str(target), "--ai", "codex", "--ai-skills", "--script", "sh", "--no-git"],
796-
)
797-
798-
assert result.exit_code == 0
799-
assert not (target / ".codex").exists()
800-
801-
def test_codex_ai_skills_here_mode_removes_legacy_codex_dir(self, tmp_path, monkeypatch):
802-
"""Codex --here skills init should not leave legacy .codex prompt directory behind."""
803-
from typer.testing import CliRunner
804-
805-
runner = CliRunner()
806-
target = tmp_path / "codex-cleanup-here"
779+
target = tmp_path / "codex-preserve-here"
807780
target.mkdir()
781+
existing_prompts = target / ".codex" / "prompts"
782+
existing_prompts.mkdir(parents=True)
783+
(existing_prompts / "custom.md").write_text("custom")
808784
monkeypatch.chdir(target)
809785

810-
def fake_download(project_path, *args, **kwargs):
811-
prompts_dir = project_path / ".codex" / "prompts"
812-
prompts_dir.mkdir(parents=True, exist_ok=True)
813-
(prompts_dir / "speckit.specify.md").write_text("---\ndescription: Legacy prompt\n---\n\nBody.\n")
814-
815-
with patch("specify_cli.download_and_extract_template", side_effect=fake_download), \
786+
with patch("specify_cli.download_and_extract_template", return_value=target), \
816787
patch("specify_cli.ensure_executable_scripts"), \
817788
patch("specify_cli.ensure_constitution_from_template"), \
818789
patch("specify_cli.install_ai_skills", return_value=True), \
@@ -825,7 +796,8 @@ def fake_download(project_path, *args, **kwargs):
825796
)
826797

827798
assert result.exit_code == 0
828-
assert not (target / ".codex").exists()
799+
assert (target / ".codex").exists()
800+
assert (existing_prompts / "custom.md").exists()
829801

830802
def test_commands_preserved_when_skills_fail(self, tmp_path):
831803
"""If skills fail, commands should NOT be removed (safety net)."""

0 commit comments

Comments
 (0)