You can't insert them at completely arbitrary points in third-party code. But libraries can be written generically (in terms of e.g. a general monad) so as to propagate cross cutting concerns from your callbacks to the right place, even when those concerns are implemented later on and the library doesn't know about them. Look at e.g. fs2 and http4s: everything's written generically in terms of some F[_] type which the user supplies when they use the library, and it will all be plumbed through correctly. So if you want logging, you use something like treelog as your F[_] type; if you want transactions, you include a transaction type in there. And so on.
In my experience that covers almost all the use cases, while it means that library code can still behave predictably and be understood and tested (e.g. you don't have to worry that a library upgrade is going to break your application, which you do if you've used AOP to define pointcuts deep in its internals).
I'm not familiar with scala but will take a look. Completely agree over your last point. I very much prefer libraries over frameworks, and as you said pointcuts are a bit fragile, but my main point is that they behave differently because of bytecode transforms.
In my experience that covers almost all the use cases, while it means that library code can still behave predictably and be understood and tested (e.g. you don't have to worry that a library upgrade is going to break your application, which you do if you've used AOP to define pointcuts deep in its internals).