Eg (given that my local bin path for the project is set to ./.bin in my stack.yaml):
$ ./install.hs
<lots out output>
$ ls .bin
haskell-code-indexer-8.0.2* haskell-code-indexer-8.4.4*
haskell-code-indexer-8.2.2* haskell-code-indexer-8.6.3*
haskell-code-indexer-8.4.3* haskell-code-server*
Note that it works by installing and then moving the `haskell-code-indexer` executable in your project's bin to `haskell-code-indexer-X-Y-Z`. So if you already have a plain `haskell-code-indexer` executable before the run it will be deleted.
It uses plain IO instead of Shake because Shake runs actions in unpredictable order. One of the goals of the script is that it will install haskell-code-server and the latest haskell-code-indexer as soon as possible, so that it's useful even if you have to cancel the run for some reason. Shake was running the haskell-code-indexer command at the correct time, but then waiting to copy it to its -X-Y-Z final home until near the end of the run.
(Also this is really just a simple install script, we don't need another layer of caching from Shake for it.)