       env "<cljs repl>"
       '(set! *print-fn* (fn [x] (js/node_repl_print (pr-str x)))))))
 
-(extend-protocol repl/IJavaScriptEnv
-  clojure.lang.IPersistentMap
-  (-setup [this] (setup this))
-  (-evaluate [this filename line js] (node-eval this js))
-  (-load [this ns url] (load-javascript this ns url))
-  (-tear-down [this] (close-socket this)))
-
-;; do we need to implement our own version of goog.require ? - David
+(defrecord NodeEnv [socket loaded-libs]
+  repl/IJavaScriptEnv
+  (-setup [this]
+    (setup this))
+  (-evaluate [this filename line js]
+    (node-eval this js))
+  (-load [this ns url]
+    (load-javascript this ns url))
+  (-tear-down [this]
+    (close-socket socket)))
 
 (defn repl-env
   [& {:keys [host port] :or {host "localhost" port 5001}}]
-  (let [repl-env (socket host port)
+  (let [repl-env (NodeEnv. (socket host port) (atom {}))
         base     (io/resource "goog/base.js")
         deps     (io/resource "goog/deps.js")]
     (node-eval repl-env (slurp (io/reader base)))

               (.append sb (char c))
               (recur sb (.read in)))))))

(defn node-eval [{:keys [in out]} js]
  (write out js)
  {:status :success :value (read-response in)})

(defn load-javascript [ctx ns url]
  (node-eval ctx (slurp url)))

(defn setup [repl-env]
  (let [env   (ana/empty-env)
        scope (:scope repl-env)]
    (repl/load-file repl-env "cljs/core.cljs")
    (swap! loaded-libs conj "cljs.core")
    (repl/evaluate-form repl-env
      env "<cljs repl>"
      '(ns cljs.user))

           java.net.Socket
           java.lang.StringBuilder
           [java.io BufferedReader BufferedWriter]))

(defn socket [host port]
  (let [socket (Socket. host port)
