diff --git a/mempalace/convo_miner.py b/mempalace/convo_miner.py index a91cf33..2cf57e4 100644 --- a/mempalace/convo_miner.py +++ b/mempalace/convo_miner.py @@ -394,7 +394,9 @@ def mine_convos( convo_path = Path(convo_dir).expanduser().resolve() if not wing: - wing = convo_path.name.lower().replace(" ", "_").replace("-", "_") + from .config import normalize_wing_name + + wing = normalize_wing_name(convo_path.name) files = scan_convos(convo_dir) if limit > 0: diff --git a/mempalace/miner.py b/mempalace/miner.py index 2d610ea..ba0c630 100644 --- a/mempalace/miner.py +++ b/mempalace/miner.py @@ -286,7 +286,15 @@ def load_config(project_dir: str) -> dict: if legacy_path.exists(): config_path = legacy_path else: - wing_name = resolved_project_dir.name + from .config import normalize_wing_name + + # Normalize the dirname-derived fallback wing the same way + # ``cmd_init`` and ``room_detector_local`` do — otherwise a + # hyphenated project mined without a yaml file lands under a + # raw-name wing while ``topics_by_wing`` was keyed under the + # normalized slug, silently dropping every topic tunnel + # (the no-yaml branch of issue #1194). + wing_name = normalize_wing_name(resolved_project_dir.name) print( f" No mempalace.yaml found in {resolved_project_dir} " f"— using auto-detected defaults (wing='{wing_name}'). " diff --git a/tests/test_miner.py b/tests/test_miner.py index 0619dbb..10124ee 100644 --- a/tests/test_miner.py +++ b/tests/test_miner.py @@ -67,6 +67,24 @@ def test_load_config_uses_defaults_when_yaml_missing(): shutil.rmtree(tmpdir) +def test_load_config_no_yaml_normalizes_hyphenated_wing(): + """Fallback wing name is normalized so it matches topics_by_wing keys. + + Regression for the no-yaml branch of #1194: ``cmd_init`` writes + ``topics_by_wing`` under the normalized slug, so the miner's + fallback wing must use the same normalization or the tunnel lookup + misses every key for hyphenated dirnames. + """ + parent = tempfile.mkdtemp() + try: + project_root = Path(parent) / "my-cool-app" + project_root.mkdir() + config = load_config(str(project_root)) + assert config["wing"] == "my_cool_app" + finally: + shutil.rmtree(parent) + + def test_scan_project_skips_mempalace_generated_files(): with tempfile.TemporaryDirectory() as tmpdir: project_root = Path(tmpdir).resolve()