From 3837e17724c4c1e6ae67f23d4b1402fd69bcaa7c Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Thu, 1 Oct 2026 15:22:17 -0700 Subject: [PATCH] Keep guard shims ahead of macOS login-shell path_helper --- toolchain/macos/performance_guard.py | 30 ++++++++++++++++++++++- toolchain/macos/test_performance_guard.py | 11 +++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/toolchain/macos/performance_guard.py b/toolchain/macos/performance_guard.py index bed8b11f39..67dbae52c1 100644 --- a/toolchain/macos/performance_guard.py +++ b/toolchain/macos/performance_guard.py @@ -20,7 +20,7 @@ STATE = Path.home() / ".local/share/slab/performance" FLOOR = 20 * 1024**3 INTERVAL = 30 MAX_LOG = 5 * 1024**2 -VERSION = "2026-10-01.1" +VERSION = "2026-10-01.2" def run(args, timeout=2): @@ -345,6 +345,33 @@ def sample(repair=False): return 0 +def ensure_shell_path(): + """macOS path_helper can reorder zsh PATH after .zshenv has run.""" + home = Path.home() + shell = os.environ.get("SHELL", "/bin/zsh") + expected = [str(home / ".local/bin/git"), str(home / ".local/bin/swift")] + if run([shell, "-lc", "command -v git; command -v swift"], timeout=8).splitlines() == expected: + return + name = Path(shell).name + if name == "zsh": + profile = home / ".zprofile" + block = '\n# AC performance guard PATH\nexport PATH="$HOME/.local/bin:$PATH"\n# End AC performance guard PATH\n' + elif name == "bash": + profile = next((home / p for p in (".bash_profile", ".bash_login", ".profile") if (home / p).exists()), home / ".profile") + block = '\n# AC performance guard PATH\nexport PATH="$HOME/.local/bin:$PATH"\n# End AC performance guard PATH\n' + elif name == "fish": + profile = home / ".config/fish/conf.d/ac-performance-guard.fish" + block = '\n# AC performance guard PATH\nfish_add_path --path --prepend --move "$HOME/.local/bin"\n# End AC performance guard PATH\n' + else: + raise RuntimeError(f"Add ~/.local/bin before system commands in {shell}") + profile = profile.resolve() + profile.parent.mkdir(parents=True, exist_ok=True) + old = profile.read_text() if profile.exists() else "" + atomic(profile, old.replace(block, "").rstrip() + "\n" + block) + if run([shell, "-lc", "command -v git; command -v swift"], timeout=8).splitlines() != expected: + raise RuntimeError(f"Shell still bypasses guards after updating {profile}") + + def install(preserve_git=False): home = Path.home() target = home / ".local/lib/ac-performance-guard" @@ -388,6 +415,7 @@ def install(preserve_git=False): replacement.unlink(missing_ok=True) replacement.symlink_to(target / source) os.replace(replacement, link) + ensure_shell_path() repo = os.environ.get("AC_REPO", str(home / "aesthetic-computer")) atomic(target / "repo-path", repo + "\n") config = {"Label": LABEL, "ProgramArguments": ["/bin/bash", str(target / "performance-guard.sh"), "--once", "--repair"], diff --git a/toolchain/macos/test_performance_guard.py b/toolchain/macos/test_performance_guard.py index f606fe044e..ea7e0399ea 100644 --- a/toolchain/macos/test_performance_guard.py +++ b/toolchain/macos/test_performance_guard.py @@ -136,6 +136,17 @@ class GuardTests(unittest.TestCase): result = subprocess.run(["/bin/bash", str(self.state / "swift-guard.sh"), "build", "--package-path", str(self.state)], capture_output=True) self.assertEqual(result.returncode, 75) + def test_login_path_repair_preserves_profile(self): + profile = self.state / ".zprofile" + profile.write_text("# existing setting\nexport MY_SETTING=yes\n") + expected = f"{self.state}/.local/bin/git\n{self.state}/.local/bin/swift" + with patch.object(guard.Path, "home", return_value=self.state), \ + patch.dict(os.environ, {"SHELL": "/bin/zsh"}), \ + patch.object(guard, "run", side_effect=["/usr/bin/git\n/usr/bin/swift", expected]): + guard.ensure_shell_path() + self.assertIn("export MY_SETTING=yes", profile.read_text()) + self.assertEqual(profile.read_text().count("# AC performance guard PATH"), 1) + if __name__ == "__main__": unittest.main() -- 2.51.2