Skip to content

Commit 547f0c5

Browse files
committed
fix(codex): unify subscribed guideline storage
1 parent cfda16f commit 547f0c5

5 files changed

Lines changed: 81 additions & 41 deletions

File tree

platform-integrations/codex/plugins/evolve-lite/skills/recall/scripts/retrieve_entities.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ def load_entities_with_source(entities_dirs):
6363
for entities_dir in entities_dirs:
6464
entities_dir = Path(entities_dir)
6565
for md in sorted(entities_dir.glob("**/*.md")):
66+
if md.is_symlink():
67+
continue
6668
try:
6769
entity = markdown_to_entity(md)
6870
except (OSError, UnicodeError):

platform-integrations/codex/plugins/evolve-lite/skills/subscribe/scripts/subscribe.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ def main():
3636

3737
evolve_dir = Path(os.environ.get("EVOLVE_DIR", ".evolve"))
3838
project_root = str(evolve_dir.resolve()) if evolve_dir.name != ".evolve" else str(evolve_dir.resolve().parent)
39-
subscribed_base = (evolve_dir / "subscribed").resolve()
40-
dest = (evolve_dir / "subscribed" / args.name).resolve()
39+
subscribed_base = (evolve_dir / "entities" / "subscribed").resolve()
40+
dest = (evolve_dir / "entities" / "subscribed" / args.name).resolve()
41+
legacy_dest = (evolve_dir / "subscribed" / args.name).resolve()
4142
if args.name in {"", "."} or dest == subscribed_base or not dest.is_relative_to(subscribed_base):
4243
print(f"Error: invalid subscription name: {args.name!r}", file=sys.stderr)
4344
sys.exit(1)
@@ -52,7 +53,7 @@ def main():
5253
print(f"Error: subscription '{args.name}' already exists in config.", file=sys.stderr)
5354
sys.exit(1)
5455

55-
if dest.exists():
56+
if dest.exists() or legacy_dest.exists():
5657
print(f"Error: destination already exists: {dest}", file=sys.stderr)
5758
sys.exit(1)
5859
else:

platform-integrations/codex/plugins/evolve-lite/skills/sync/scripts/sync.py

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import argparse
55
import os
6-
import shutil
76
import subprocess
87
import sys
98
from pathlib import Path
@@ -37,19 +36,6 @@ def git_pull(repo_path, branch):
3736
)
3837

3938

40-
def copy_entities(subscribed_repo_path, entities_subscribed_path):
41-
"""Mirror .md files from the subscribed git clone into entities/subscribed/{name}/."""
42-
if entities_subscribed_path.exists():
43-
shutil.rmtree(entities_subscribed_path)
44-
for md in sorted(subscribed_repo_path.glob("**/*.md")):
45-
if md.is_symlink():
46-
continue
47-
rel = md.relative_to(subscribed_repo_path)
48-
dest = entities_subscribed_path / rel
49-
dest.parent.mkdir(parents=True, exist_ok=True)
50-
shutil.copy2(md, dest)
51-
52-
5339
def count_delta(repo_path):
5440
"""Count added, modified, and deleted markdown files since last pull."""
5541
result = subprocess.run(
@@ -123,13 +109,23 @@ def main():
123109
continue
124110
name = sub.get("name", "unknown")
125111
branch = sub.get("branch", "main")
126-
subscribed_base = (evolve_dir / "subscribed").resolve()
127-
repo_path = (evolve_dir / "subscribed" / name).resolve()
112+
subscribed_base = (evolve_dir / "entities" / "subscribed").resolve()
113+
repo_path = (evolve_dir / "entities" / "subscribed" / name).resolve()
114+
legacy_base = (evolve_dir / "subscribed").resolve()
115+
legacy_repo_path = (evolve_dir / "subscribed" / name).resolve()
128116

129117
if repo_path == subscribed_base or not repo_path.is_relative_to(subscribed_base):
130118
summaries.append(f"{name} (invalid subscription name)")
131119
continue
132120

121+
if legacy_repo_path != legacy_base and legacy_repo_path.is_relative_to(legacy_base):
122+
if legacy_repo_path.exists() and not repo_path.exists():
123+
repo_path.parent.mkdir(parents=True, exist_ok=True)
124+
legacy_repo_path.rename(repo_path)
125+
elif legacy_repo_path.exists() and repo_path.exists():
126+
summaries.append(f"{name} (duplicate subscription folders — remove .evolve/subscribed/{name})")
127+
continue
128+
133129
if not repo_path.is_dir():
134130
summaries.append(f"{name} (not cloned)")
135131
continue
@@ -146,9 +142,6 @@ def main():
146142
if any(value > 0 for value in delta.values()):
147143
any_changes = True
148144

149-
entities_subscribed = evolve_dir / "entities" / "subscribed" / name
150-
copy_entities(repo_path, entities_subscribed)
151-
152145
summaries.append(f"{name} (+{delta['added']} added, {delta['updated']} updated, {delta['removed']} removed)")
153146

154147
audit_append(project_root=str(audit_root.parent), action="sync", actor=actor, delta=total_delta)

platform-integrations/codex/plugins/evolve-lite/skills/unsubscribe/scripts/unsubscribe.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@ def main():
4848
return
4949

5050
name = args.name
51-
subscribed_base = (evolve_dir / "subscribed").resolve()
52-
dest = (evolve_dir / "subscribed" / name).resolve()
51+
subscribed_base = (evolve_dir / "entities" / "subscribed").resolve()
52+
dest = (evolve_dir / "entities" / "subscribed" / name).resolve()
5353
if not dest.is_relative_to(subscribed_base):
5454
print(f"Error: invalid subscription name: {name!r}", file=sys.stderr)
5555
sys.exit(1)
5656

57-
entities_base = (evolve_dir / "entities" / "subscribed").resolve()
58-
entities_dest = (evolve_dir / "entities" / "subscribed" / name).resolve()
59-
if not entities_dest.is_relative_to(entities_base):
57+
legacy_base = (evolve_dir / "subscribed").resolve()
58+
legacy_dest = (evolve_dir / "subscribed" / name).resolve()
59+
if not legacy_dest.is_relative_to(legacy_base):
6060
print(f"Error: invalid subscription name: {name!r}", file=sys.stderr)
6161
sys.exit(1)
6262

@@ -71,9 +71,9 @@ def main():
7171
else:
7272
print(f"Warning: {dest} did not exist.", file=sys.stderr)
7373

74-
if entities_dest.exists():
75-
shutil.rmtree(entities_dest)
76-
print(f"Deleted {entities_dest}")
74+
if legacy_dest.exists():
75+
shutil.rmtree(legacy_dest)
76+
print(f"Deleted {legacy_dest}")
7777

7878
cfg["subscriptions"] = new_subs
7979
save_config(cfg, project_root)

tests/platform_integrations/test_codex_sharing.py

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,13 @@ def test_subscribe_sync_and_unsubscribe_round_trip(self, temp_project_dir, local
220220
args=["--name", "alice", "--remote", str(local_repo["bare"]), "--branch", "main"],
221221
evolve_dir=evolve_dir,
222222
)
223-
assert (evolve_dir / "subscribed" / "alice").is_dir()
223+
assert (evolve_dir / "entities" / "subscribed" / "alice").is_dir()
224+
assert not (evolve_dir / "subscribed" / "alice").exists()
224225

225226
run_script(SYNC_SCRIPT, project_dir=temp_project_dir, evolve_dir=evolve_dir)
226-
mirrored = evolve_dir / "entities" / "subscribed" / "alice" / "guideline" / "tip-one.md"
227-
assert mirrored.exists()
228-
assert "Always write tests." in mirrored.read_text()
227+
synced = evolve_dir / "entities" / "subscribed" / "alice" / "guideline" / "tip-one.md"
228+
assert synced.exists()
229+
assert "Always write tests." in synced.read_text()
229230

230231
run_script(
231232
UNSUBSCRIBE_SCRIPT,
@@ -283,7 +284,7 @@ def test_subscribe_rejects_empty_or_dot_name(self, temp_project_dir, local_repo,
283284

284285
def test_subscribe_fails_when_destination_already_exists(self, temp_project_dir, local_repo):
285286
evolve_dir = temp_project_dir / ".evolve"
286-
existing_dest = evolve_dir / "subscribed" / "alice"
287+
existing_dest = evolve_dir / "entities" / "subscribed" / "alice"
287288
existing_dest.mkdir(parents=True)
288289

289290
result = run_script(
@@ -393,7 +394,7 @@ def test_sync_skips_invalid_subscription_name(self, temp_project_dir):
393394

394395
def test_sync_uses_workspace_config_with_custom_evolve_dir(self, temp_project_dir, local_repo):
395396
evolve_dir = temp_project_dir / "custom-evolve"
396-
subscribed_dir = evolve_dir / "subscribed"
397+
subscribed_dir = evolve_dir / "entities" / "subscribed"
397398
subscribed_dir.mkdir(parents=True)
398399
subprocess.run(
399400
["git", "clone", "--branch", "main", "--depth", "1", str(local_repo["bare"]), str(subscribed_dir / "alice")],
@@ -450,6 +451,12 @@ def test_session_start_sync_respects_on_session_start_false(self, temp_project_d
450451
args=["--name", "alice", "--remote", str(local_repo["bare"]), "--branch", "main"],
451452
evolve_dir=evolve_dir,
452453
)
454+
git_env = local_repo["env"]
455+
new_entity = local_repo["work"] / "guideline" / "tip-two.md"
456+
new_entity.write_text("---\ntype: guideline\n---\n\nDelete dead code promptly.\n")
457+
subprocess.run(["git", "-C", str(local_repo["work"]), "add", "."], check=True, env=git_env)
458+
subprocess.run(["git", "-C", str(local_repo["work"]), "commit", "-m", "add tip-two"], check=True, env=git_env)
459+
subprocess.run(["git", "-C", str(local_repo["work"]), "push", "origin", "main"], check=True, env=git_env)
453460
(temp_project_dir / "evolve.config.yaml").write_text(
454461
f'subscriptions:\n - name: "alice"\n remote: "{local_repo["bare"]}"\n branch: "main"\nsync:\n on_session_start: false\n'
455462
)
@@ -463,8 +470,8 @@ def test_session_start_sync_respects_on_session_start_false(self, temp_project_d
463470
)
464471

465472
assert result.returncode == 0
466-
mirrored = evolve_dir / "entities" / "subscribed" / "alice" / "guideline" / "tip-one.md"
467-
assert not mirrored.exists()
473+
synced = evolve_dir / "entities" / "subscribed" / "alice" / "guideline" / "tip-two.md"
474+
assert not synced.exists()
468475

469476
def test_sync_writes_audit_log(self, temp_project_dir, local_repo):
470477
evolve_dir = temp_project_dir / ".evolve"
@@ -521,9 +528,20 @@ def test_sync_skips_symlinked_markdown_files(self, temp_project_dir, local_repo)
521528

522529
run_script(SYNC_SCRIPT, project_dir=temp_project_dir, evolve_dir=evolve_dir)
523530

524-
mirrored_dir = evolve_dir / "entities" / "subscribed" / "alice" / "guideline"
525-
assert (mirrored_dir / "tip-one.md").exists()
526-
assert not (mirrored_dir / "tip-link.md").exists()
531+
subscribed_dir = evolve_dir / "entities" / "subscribed" / "alice" / "guideline"
532+
assert (subscribed_dir / "tip-one.md").exists()
533+
assert (subscribed_dir / "tip-link.md").exists()
534+
535+
result = run_script(
536+
RETRIEVE_SCRIPT,
537+
project_dir=temp_project_dir,
538+
evolve_dir=evolve_dir,
539+
stdin=HOOK_INPUT,
540+
expect_success=False,
541+
)
542+
assert result.returncode == 0
543+
assert "Always write tests." in result.stdout
544+
assert "tip-link" not in result.stdout
527545

528546
def test_sync_removed_entity_disappears_after_sync(self, temp_project_dir, local_repo):
529547
evolve_dir = temp_project_dir / ".evolve"
@@ -545,3 +563,29 @@ def test_sync_removed_entity_disappears_after_sync(self, temp_project_dir, local
545563

546564
run_script(SYNC_SCRIPT, project_dir=temp_project_dir, evolve_dir=evolve_dir)
547565
assert not tip_one.exists()
566+
567+
def test_sync_migrates_legacy_subscribed_repo(self, temp_project_dir, local_repo):
568+
evolve_dir = temp_project_dir / ".evolve"
569+
legacy_dir = evolve_dir / "subscribed"
570+
legacy_dir.mkdir(parents=True)
571+
subprocess.run(
572+
["git", "clone", "--branch", "main", "--depth", "1", str(local_repo["bare"]), str(legacy_dir / "alice")],
573+
check=True,
574+
env=local_repo["env"],
575+
)
576+
(temp_project_dir / "evolve.config.yaml").write_text(
577+
f'subscriptions:\n - name: "alice"\n remote: "{local_repo["bare"]}"\n branch: "main"\n'
578+
)
579+
580+
result = run_script(
581+
SYNC_SCRIPT,
582+
project_dir=temp_project_dir,
583+
evolve_dir=evolve_dir,
584+
expect_success=False,
585+
)
586+
587+
assert result.returncode == 0
588+
migrated_repo = evolve_dir / "entities" / "subscribed" / "alice"
589+
assert migrated_repo.is_dir()
590+
assert not (evolve_dir / "subscribed" / "alice").exists()
591+
assert (migrated_repo / "guideline" / "tip-one.md").exists()

0 commit comments

Comments
 (0)