Use the command’s exit status to choose a cue, and preserve that status afterward. Otherwise a successful sound player can accidentally become the final result of a failed build.
A small interactive wrapper
This example runs your project’s existing build and returns its result. Use it in an ordinary interactive shell; scripts with set -e need their own deliberate error-handling structure.
notify_build() {
npm run build
build_status=$?
if [ "$build_status" -eq 0 ]; then
afplay /System/Library/Sounds/Glass.aiff || true
else
afplay /System/Library/Sounds/Basso.aiff || true
fi
return "$build_status"
}
notify_build
Replace the build command only with one you understand. The || true applies to audio playback so a missing device or sound file does not overwrite the saved build result.
Interpret the result narrowly
Exit status zero means the command reported success. It does not guarantee that the build script ran tests, that the tests cover the changed behaviour or that the generated application is correct.
Read output when a cue sounds. If a build runs through a pipeline, account for the shell’s pipeline-status rules rather than assuming the last command represents every earlier step.
Keep notification logic local
For a one-off task, success-only playback is shorter. For an agent, use the supported connection so command completion and agent lifecycle are not confused.
Sources: macOS afplay -h, POSIX shell exit-status behaviour; TapNoise cue meanings.
TapNoise