         if curr.mtime.getTime() isnt prev.mtime.getTime()
           fn file
 
+# Return current time formatted as HH:mm:ss.
+
+# Compile one CoffeeScript file.
+# Existing event handlers are synchronously invoked in the process.
+# Each event handler is passed a subject and a context (source file).
+compile = (info, file) ->
+  file = fs.realpathSync file
+  src = fs.readFileSync file, 'utf8'
+  try
+    src = coffee.compile src, bare: true
+  catch err
+    err.message = "In #{file}, #{err.message}"
+    throw err
+  source = file.substr(info.sourcePath.length)
+  target = info.targetPath + source.replace(/.coffee$/, '.js')
+  makeDir path.dirname(target)
+  fs.writeFileSync target, src
+  info.onCompile?(target, src)
+  ts = (new Date()).toLocaleTimeString()
+  source = info.sourcePath.substr(path.resolve('.').length + 1) + source
+  console.log ts + ' - compiled ' + source
+
 # Compile all CoffeeScript sources for Node.
 buildNode = (info, watch, fn) ->
-  ifInstalled 'coffee', ->
-    rmrf 'lib', ->
-      src = info.sourcePath
-      tryExec 'coffee', "-cb#{if watch then 'w' else ''} -o lib #{src}", ->
-        fn?()
+  rmrf info.targetPath, ->
+    withFiles path.join(info.sourcePath, '**/*.coffee'), (files) ->
+      for file in files
+        compile info, file
+      if watch
+        watchFiles files, (file) ->
+          compile info, file
 
 # Use Stitch to create a browser bundle.
 bundle = (info) ->

fs       = require 'fs'
glob     = require 'glob'
nodeunit = require 'nodeunit'

  browserRootModule: null
  copyrightFrom: (new Date).getFullYear()
  license: ''
  onCompile: null
  sourcePath: 'src'
  targetPath: 'lib'

# Load package information from multiple sources.
loadInfo = ->
