personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(service): macOS stop is sticky — KeepAlive only on non-zero exit

launchd plist now emits KeepAlive as {"SuccessfulExit": False} so a clean SIGTERM exit stays stopped while crashes still recover.

Mirrors Linux's Restart=on-failure semantics.

Test updates: round-trip assertion shape plus new test_keep_alive_is_sticky_stop regression guard.

+14 -2
+13 -1
tests/test_service.py
··· 47 47 ) 48 48 assert plist["ProgramArguments"][1] == "supervisor" 49 49 assert plist["EnvironmentVariables"] == env 50 - assert plist["KeepAlive"] is True 50 + assert plist["KeepAlive"] == {"SuccessfulExit": False} 51 51 assert plist["RunAtLoad"] is True 52 52 assert "StandardOutPath" not in plist 53 53 assert "StandardErrorPath" not in plist 54 + 55 + def test_keep_alive_is_sticky_stop(self): 56 + env = { 57 + "HOME": "/Users/test", 58 + "PATH": "/usr/bin", 59 + } 60 + data = service._generate_plist(env) 61 + plist = plistlib.loads(data) 62 + 63 + # Clean exits stay stopped; non-zero exits respawn. 64 + assert isinstance(plist["KeepAlive"], dict) 65 + assert plist["KeepAlive"]["SuccessfulExit"] is False 54 66 55 67 56 68 class TestSystemdUnit:
+1 -1
think/service.py
··· 116 116 "ProgramArguments": [sol, "supervisor", str(port)], 117 117 "EnvironmentVariables": env, 118 118 "RunAtLoad": True, 119 - "KeepAlive": True, 119 + "KeepAlive": {"SuccessfulExit": False}, 120 120 } 121 121 return plistlib.dumps(plist) 122 122