     [shadow.cljs.devtools.server.runtime :as runtime]
     [clojure.set :as set]
     [clojure.core.async.impl.protocols :as async-prot])
-  (:import (java.io Writer InputStreamReader BufferedReader IOException ByteArrayOutputStream ByteArrayInputStream)))
+  (:import (java.io Writer InputStreamReader BufferedReader IOException ByteArrayOutputStream ByteArrayInputStream)
+           [java.net SocketException]))
 
 (defn chan? [x]
   (satisfies? async-prot/ReadPort x))

    (async/go
      (loop []
        (when-some [x (<! chan)]
          (try
            (print-worker-out x verbose)
            (catch Exception e
              (prn [:stdout-dump-ex e])))
          (recur)
          )))

    chan
    ))

(defmacro thread
  "same as core async thread but does not preserve bindings"

  #_ (errors/user-friendly-error e))

(defn print-worker-out [x verbose]
  (try

    (locking build-log/stdout-lock
      (binding [*out* *err*]
        (case (:type x)
          :build-log
          (when verbose
            (println (build-log/event-text (:event x))))

          :build-configure
          (println (format "[%s] Configuring build." (:build-id x)))

          :build-start
          (print-build-start x)

          :build-failure
          (print-build-failure x)

          :build-complete
          (print-build-complete x)

          :build-shutdown
          (println "Build shutdown.")

          :repl/action
          (let [warnings (get-in x [:action :warnings])]
            (print-warnings warnings))

          ;; should have been handled somewhere else
          :repl/result
          :ignored

          :repl/error
          :ignored ;; also handled by out

          :repl/runtime-connect
          (println "JS runtime connected.")

          :repl/runtime-disconnect
          (println "JS runtime disconnected.")

          :worker-shutdown
          (println "Worker shutdown.")

          :println
          (println (:msg x))

          ;; handled in dedicated channel as they should not mix with build output
          :repl/out
          :ignored

          :repl/err
          :ignored

          ;; default
          (prn [:log x]))))

    true
    (catch SocketException e
      ;; was printing to a socket that disconnected.
      ;; no need to continue printing
      false)
    (catch Exception e
      (log/debug-ex e ::stdout-ex {:x x})
      true)))

(defn stdout-dump [verbose]
  (let [chan
