What you really want is a way for scripts to describe their dependencies, and then the runner figures out what order to run them in, and cache scripts that don't need to be run because their inputs didn't change.
Wireit[1] is an npm script runner that adds that incrementally on top of package.json. I can't manage an npm monorepo without it now.
Deno started integrating the idea directly into their built-in script runner. I think this is an important enough feature that more runtimes should follow Deno's lead.
< "ci": "CI=true bun run check && bun run test && bun run build && bun run docs && bun run zip && bun run zip:firefox"
> "ci": "CI=true bun run --parallel check test build docs && bun run --parallel zip zip:firefox"