From 361d4e2cf710590242f66ed8206bcf75f6cece57 Mon Sep 17 00:00:00 2001
From: Oliver Nordbjerg <hi@notbjerg.me>
Date: Sun, 25 Mar 2018 20:53:14 +0200
Subject: [PATCH 1/3] Simplify reporter logic

---
 src/cli.js                       | 35 +++++++++++---------------------
 src/commands/grant.js            |  3 ++-
 src/commands/init.js             |  2 +-
 src/commands/publish.js          |  6 ++++--
 src/commands/version.js          |  2 +-
 src/commands/versions.js         |  2 +-
 src/middleware/index.js          |  2 --
 src/middleware/reporter.js       |  9 --------
 src/reporters/ConsoleReporter.js | 14 ++++++++++---
 9 files changed, 32 insertions(+), 43 deletions(-)
 delete mode 100644 src/middleware/reporter.js

diff --git a/src/cli.js b/src/cli.js
index 7829fd68f..497d43e1b 100755
--- a/src/cli.js
+++ b/src/cli.js
@@ -4,16 +4,15 @@ const {
   middlewaresDecorator
 } = require('./decorators')
 const {
-  reporterMiddleware,
   manifestMiddleware,
   moduleMiddleware
 } = require('./middleware')
 const {
   findProjectRoot
 } = require('./util')
+const ConsoleReporter = require('./reporters/ConsoleReporter')
 
 const MIDDLEWARES = [
-  reporterMiddleware,
   manifestMiddleware,
   moduleMiddleware
 ]
@@ -33,21 +32,6 @@ const cmd = require('yargs')
         cmd
       )
 
-      // Wrap command handler
-      const _handler = cmd.handler
-      cmd.handler = (argv) => {
-        // Handle errors
-        _handler(argv.reporter, argv)
-          .then((exitCode = 0) => {
-            process.exitCode = exitCode
-          })
-          .catch((err) => {
-            argv.reporter.error(err.message)
-            argv.reporter.debug(err.stack)
-            process.exitCode = 1
-          })
-      }
-
       return cmd
     }
   })
@@ -71,7 +55,6 @@ cmd.option('cwd', {
   }
 })
 
-
 // APM
 cmd.option('apm.ens-registry', {
   description: 'Address of the ENS registry',
@@ -92,24 +75,30 @@ cmd.group('apm.ipfs.rpc', 'APM providers:')
 // Ethereum
 cmd.option('eth-rpc', {
   description: 'An URI to the Ethereum node used for RPC calls',
-  default: 'http://localhost:8545',
+  default: 'http://localhost:8545'
 })
 
 cmd.option('keyfile', {
   description: 'Path to a local file containing a private key, rpc node and ENS. If provided it will overwrite eth-rpc (but not apm.ens-registry)',
-  default: require('homedir')()+'/.localkey.json',
+  default: require('homedir')() + '/.localkey.json',
   coerce: (file) => {
     try {
       return require(require('path').resolve(file))
-    } catch (e) {
+    } catch (e) {
       return {}
     }
   }
 })
 
-
 // Add epilogue
 cmd.epilogue('For more information, check out https://wiki.aragon.one')
 
 // Run
-cmd.argv // eslint-disable-line
+const reporter = new ConsoleReporter()
+cmd.fail((msg, err, a) => {
+  reporter.error(err.message || msg || 'An error occurred')
+  reporter.debug(err.stack)
+  process.exit(1)
+}).parse(process.argv.slice(2), {
+  reporter
+})
diff --git a/src/commands/grant.js b/src/commands/grant.js
index 1183c5242..6dfe0ea8e 100644
--- a/src/commands/grant.js
+++ b/src/commands/grant.js
@@ -16,8 +16,9 @@ exports.builder = function (yargs) {
   })
 }
 
-exports.handler = async function (reporter, {
+exports.handler = async function ({
   // Globals
+  reporter,
   cwd,
   ethRpc,
   keyfile,
diff --git a/src/commands/init.js b/src/commands/init.js
index a55a438c9..d2fd638e9 100644
--- a/src/commands/init.js
+++ b/src/commands/init.js
@@ -47,7 +47,7 @@ exports.builder = (yargs) => {
     })
 }
 
-exports.handler = function (reporter, { name, template }) {
+exports.handler = function ({ reporter, name, template }) {
   // Clone the template into the directory
   // TODO: Somehow write name to `manifest.json` in template?
   // TODO: Write human-readable app name to `arapp.json`
diff --git a/src/commands/publish.js b/src/commands/publish.js
index b4a38395a..d536d8792 100644
--- a/src/commands/publish.js
+++ b/src/commands/publish.js
@@ -11,7 +11,7 @@ const semver = require('semver')
 const EthereumTx = require('ethereumjs-tx')
 const namehash = require('eth-ens-namehash')
 const multimatch = require('multimatch')
-const { keccak256 } = require('js-sha3')
+const { keccak256 } = require('js-sha3')
 
 exports.command = 'publish [contract]'
 
@@ -127,7 +127,9 @@ async function prepareFilesForPublishing (files = [], ignorePatterns = null) {
   return tmpDir
 }
 
-exports.handler = async function (reporter, {
+exports.handler = async function ({
+  reporter,
+
   // Globals
   cwd,
   ethRpc,
diff --git a/src/commands/version.js b/src/commands/version.js
index 13de71234..90d9957dd 100644
--- a/src/commands/version.js
+++ b/src/commands/version.js
@@ -13,7 +13,7 @@ exports.builder = function (yargs) {
   })
 }
 
-exports.handler = async function (reporter, { bump, cwd }) {
+exports.handler = async function ({ reporter, bump, cwd }) {
   const manifestLocation = await findUp('arapp.json', { cwd })
   if (!manifestLocation) {
     throw new MessageError('This directory is not an Aragon project',
diff --git a/src/commands/versions.js b/src/commands/versions.js
index f5c6175ae..a14b59ab2 100644
--- a/src/commands/versions.js
+++ b/src/commands/versions.js
@@ -7,7 +7,7 @@ exports.command = 'versions'
 
 exports.describe = 'List all versions of the package'
 
-exports.handler = async function (reporter, { module, bump, cwd, keyfile, ethRpc, apm: apmOptions }) {
+exports.handler = async function ({ reporter, module, bump, cwd, keyfile, ethRpc, apm: apmOptions }) {
   const web3 = new Web3(keyfile.rpc ? keyfile.rpc : ethRpc)
 
   apmOptions.ensRegistry = !apmOptions.ensRegistry ? keyfile.ens : apmOptions.ensRegistry
diff --git a/src/middleware/index.js b/src/middleware/index.js
index 83e929343..67c1acfd1 100644
--- a/src/middleware/index.js
+++ b/src/middleware/index.js
@@ -1,9 +1,7 @@
-const reporterMiddleware = require('./reporter')
 const manifestMiddleware = require('./manifest')
 const moduleMiddleware = require('./module')
 
 module.exports = {
-  reporterMiddleware,
   manifestMiddleware,
   moduleMiddleware
 }
diff --git a/src/middleware/reporter.js b/src/middleware/reporter.js
deleted file mode 100644
index a9c4fd0fa..000000000
--- a/src/middleware/reporter.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const ConsoleReporter = require('../reporters/ConsoleReporter')
-
-module.exports = function reporterMiddleware (argv) {
-  return {
-    reporter: new ConsoleReporter({
-      silent: argv.silent
-    })
-  }
-}
diff --git a/src/reporters/ConsoleReporter.js b/src/reporters/ConsoleReporter.js
index 783ae8901..7dd386e9b 100644
--- a/src/reporters/ConsoleReporter.js
+++ b/src/reporters/ConsoleReporter.js
@@ -8,14 +8,22 @@ module.exports = class ConsoleReporter {
   message (category = 'info', message) {
     if (this.silent) return
 
-    const colors = {
+    const color = {
       debug: 'magenta',
       info: 'blue',
       warning: 'yellow',
       error: 'red',
       success: 'green'
-    }
-    console.log(`${chalk[colors[category]](category)}: ${message}`)
+    }[category]
+    const symbol = {
+      debug: '-',
+      info: 'i',
+      warning: '~',
+      error: '!',
+      success: '='
+    }[category]
+    const icon = chalk[color](`[${symbol}]`)
+    console.log(`${icon} ${message}`)
   }
 
   debug (message) {

From 600090f3b969840f3fb8e9a92ce7a1a269c3e36d Mon Sep 17 00:00:00 2001
From: Oliver Nordbjerg <hi@notbjerg.me>
Date: Sun, 25 Mar 2018 21:15:11 +0200
Subject: [PATCH 2/3] Add beautiful icons in reporter

---
 package-lock.json                | 547 +++++++++++++++++++++++++++++--
 package.json                     |   3 +
 src/reporters/ConsoleReporter.js |  15 +-
 3 files changed, 534 insertions(+), 31 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 9fd28beb2..3c8abdab5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -241,6 +241,11 @@
         "color-convert": "1.9.1"
       }
     },
+    "any-observable": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.2.0.tgz",
+      "integrity": "sha1-xnhwBYADV5AJCD9UrAq6+1wz0kI="
+    },
     "any-promise": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@@ -543,6 +548,32 @@
         "write-pkg": "3.1.0"
       },
       "dependencies": {
+        "cross-spawn": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "dev": true,
+          "requires": {
+            "lru-cache": "4.1.2",
+            "shebang-command": "1.2.0",
+            "which": "1.3.0"
+          }
+        },
+        "execa": {
+          "version": "0.7.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+          "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+          "dev": true,
+          "requires": {
+            "cross-spawn": "5.1.0",
+            "get-stream": "3.0.0",
+            "is-stream": "1.1.0",
+            "npm-run-path": "2.0.2",
+            "p-finally": "1.0.0",
+            "signal-exit": "3.0.2",
+            "strip-eof": "1.0.0"
+          }
+        },
         "load-json-file": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
@@ -555,6 +586,16 @@
             "strip-bom": "3.0.0"
           }
         },
+        "lru-cache": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
+          "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
+          "dev": true,
+          "requires": {
+            "pseudomap": "1.0.2",
+            "yallist": "2.1.2"
+          }
+        },
         "path-type": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
@@ -2203,23 +2244,21 @@
       }
     },
     "cross-spawn": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-      "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
       "requires": {
-        "lru-cache": "4.1.1",
+        "nice-try": "1.0.4",
+        "path-key": "2.0.1",
+        "semver": "5.5.0",
         "shebang-command": "1.2.0",
         "which": "1.3.0"
       },
       "dependencies": {
-        "lru-cache": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
-          "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
-          "requires": {
-            "pseudomap": "1.0.2",
-            "yallist": "2.1.2"
-          }
+        "semver": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+          "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
         }
       }
     },
@@ -2301,6 +2340,11 @@
         "assert-plus": "1.0.0"
       }
     },
+    "date-fns": {
+      "version": "1.29.0",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz",
+      "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw=="
+    },
     "date-now": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
@@ -2653,6 +2697,11 @@
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
+    "elegant-spinner": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz",
+      "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4="
+    },
     "elliptic": {
       "version": "6.4.0",
       "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
@@ -3470,11 +3519,11 @@
       }
     },
     "execa": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
-      "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz",
+      "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==",
       "requires": {
-        "cross-spawn": "5.1.0",
+        "cross-spawn": "6.0.5",
         "get-stream": "3.0.0",
         "is-stream": "1.1.0",
         "npm-run-path": "2.0.2",
@@ -3486,8 +3535,7 @@
     "exit-hook": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
-      "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
-      "dev": true
+      "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g="
     },
     "expand-brackets": {
       "version": "0.1.5",
@@ -3609,7 +3657,6 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
       "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
-      "dev": true,
       "requires": {
         "escape-string-regexp": "1.0.5"
       }
@@ -5147,8 +5194,7 @@
     "indent-string": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
-      "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
-      "dev": true
+      "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok="
     },
     "indexof": {
       "version": "0.0.1",
@@ -5724,7 +5770,6 @@
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-0.2.0.tgz",
       "integrity": "sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI=",
-      "dev": true,
       "requires": {
         "symbol-observable": "0.2.4"
       }
@@ -6353,6 +6398,223 @@
         }
       }
     },
+    "listr": {
+      "version": "0.13.0",
+      "resolved": "https://registry.npmjs.org/listr/-/listr-0.13.0.tgz",
+      "integrity": "sha1-ILsLowuuZg7oTMBQPfS+PVYjiH0=",
+      "requires": {
+        "chalk": "1.1.3",
+        "cli-truncate": "0.2.1",
+        "figures": "1.7.0",
+        "indent-string": "2.1.0",
+        "is-observable": "0.2.0",
+        "is-promise": "2.1.0",
+        "is-stream": "1.1.0",
+        "listr-silent-renderer": "1.1.1",
+        "listr-update-renderer": "0.4.0",
+        "listr-verbose-renderer": "0.4.1",
+        "log-symbols": "1.0.2",
+        "log-update": "1.0.2",
+        "ora": "0.2.3",
+        "p-map": "1.2.0",
+        "rxjs": "5.5.7",
+        "stream-to-observable": "0.2.0",
+        "strip-ansi": "3.0.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "requires": {
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
+          }
+        },
+        "cli-truncate": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz",
+          "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=",
+          "requires": {
+            "slice-ansi": "0.0.4",
+            "string-width": "1.0.2"
+          }
+        },
+        "figures": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+          "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+          "requires": {
+            "escape-string-regexp": "1.0.5",
+            "object-assign": "4.1.1"
+          }
+        },
+        "indent-string": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+          "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+          "requires": {
+            "repeating": "2.0.1"
+          }
+        },
+        "is-promise": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+          "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+        },
+        "slice-ansi": {
+          "version": "0.0.4",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
+          "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU="
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+        }
+      }
+    },
+    "listr-silent-renderer": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz",
+      "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4="
+    },
+    "listr-update-renderer": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz",
+      "integrity": "sha1-NE2YDaLKLosUW6MFkI8yrj9MyKc=",
+      "requires": {
+        "chalk": "1.1.3",
+        "cli-truncate": "0.2.1",
+        "elegant-spinner": "1.0.1",
+        "figures": "1.7.0",
+        "indent-string": "3.2.0",
+        "log-symbols": "1.0.2",
+        "log-update": "1.0.2",
+        "strip-ansi": "3.0.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "requires": {
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
+          }
+        },
+        "cli-truncate": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz",
+          "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=",
+          "requires": {
+            "slice-ansi": "0.0.4",
+            "string-width": "1.0.2"
+          }
+        },
+        "figures": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+          "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+          "requires": {
+            "escape-string-regexp": "1.0.5",
+            "object-assign": "4.1.1"
+          }
+        },
+        "slice-ansi": {
+          "version": "0.0.4",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
+          "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU="
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+        }
+      }
+    },
+    "listr-verbose-renderer": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz",
+      "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=",
+      "requires": {
+        "chalk": "1.1.3",
+        "cli-cursor": "1.0.2",
+        "date-fns": "1.29.0",
+        "figures": "1.7.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "requires": {
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
+          }
+        },
+        "cli-cursor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
+          "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+          "requires": {
+            "restore-cursor": "1.0.1"
+          }
+        },
+        "figures": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+          "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+          "requires": {
+            "escape-string-regexp": "1.0.5",
+            "object-assign": "4.1.1"
+          }
+        },
+        "onetime": {
+          "version": "1.1.0",
+          "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+          "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
+        },
+        "restore-cursor": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
+          "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+          "requires": {
+            "exit-hook": "1.1.1",
+            "onetime": "1.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+        }
+      }
+    },
     "load-json-file": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@@ -6573,6 +6835,76 @@
       "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=",
       "dev": true
     },
+    "log-symbols": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz",
+      "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=",
+      "requires": {
+        "chalk": "1.1.3"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "requires": {
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+        }
+      }
+    },
+    "log-update": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz",
+      "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=",
+      "requires": {
+        "ansi-escapes": "1.4.0",
+        "cli-cursor": "1.0.2"
+      },
+      "dependencies": {
+        "ansi-escapes": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
+          "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4="
+        },
+        "cli-cursor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
+          "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+          "requires": {
+            "restore-cursor": "1.0.1"
+          }
+        },
+        "onetime": {
+          "version": "1.1.0",
+          "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+          "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
+        },
+        "restore-cursor": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
+          "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+          "requires": {
+            "exit-hook": "1.1.1",
+            "onetime": "1.1.0"
+          }
+        }
+      }
+    },
     "longest": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
@@ -7157,6 +7489,11 @@
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
       "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
     },
+    "nice-try": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz",
+      "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA=="
+    },
     "node-fetch": {
       "version": "1.7.3",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
@@ -7441,6 +7778,68 @@
         }
       }
     },
+    "ora": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz",
+      "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=",
+      "requires": {
+        "chalk": "1.1.3",
+        "cli-cursor": "1.0.2",
+        "cli-spinners": "0.1.2",
+        "object-assign": "4.1.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "requires": {
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
+          }
+        },
+        "cli-cursor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
+          "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+          "requires": {
+            "restore-cursor": "1.0.1"
+          }
+        },
+        "cli-spinners": {
+          "version": "0.1.2",
+          "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz",
+          "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw="
+        },
+        "onetime": {
+          "version": "1.1.0",
+          "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+          "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
+        },
+        "restore-cursor": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
+          "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+          "requires": {
+            "exit-hook": "1.1.1",
+            "onetime": "1.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+        }
+      }
+    },
     "os-browserify": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
@@ -7487,6 +7886,11 @@
         "p-limit": "1.1.0"
       }
     },
+    "p-map": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
+      "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA=="
+    },
     "p-timeout": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz",
@@ -8617,6 +9021,21 @@
       "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
       "dev": true
     },
+    "rxjs": {
+      "version": "5.5.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.7.tgz",
+      "integrity": "sha512-Hxo2ac8gRQjwjtKgukMIwBRbq5+KAeEV5hXM4obYBOAghev41bDQWgFH4svYiU9UnQ5kNww2LgfyBdevCd2HXA==",
+      "requires": {
+        "symbol-observable": "1.0.1"
+      },
+      "dependencies": {
+        "symbol-observable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz",
+          "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ="
+        }
+      }
+    },
     "safe-buffer": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
@@ -9091,6 +9510,14 @@
         "xtend": "4.0.1"
       }
     },
+    "stream-to-observable": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.2.0.tgz",
+      "integrity": "sha1-WdbqOT2HwsDdrBCqDVYbxrpvDhA=",
+      "requires": {
+        "any-observable": "0.2.0"
+      }
+    },
     "stream-to-pull-stream": {
       "version": "1.7.2",
       "resolved": "https://registry.npmjs.org/stream-to-pull-stream/-/stream-to-pull-stream-1.7.2.tgz",
@@ -9275,8 +9702,7 @@
     "symbol-observable": {
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz",
-      "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=",
-      "dev": true
+      "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A="
     },
     "table": {
       "version": "3.8.3",
@@ -9486,6 +9912,44 @@
       "dev": true,
       "requires": {
         "execa": "0.7.0"
+      },
+      "dependencies": {
+        "cross-spawn": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "dev": true,
+          "requires": {
+            "lru-cache": "4.1.2",
+            "shebang-command": "1.2.0",
+            "which": "1.3.0"
+          }
+        },
+        "execa": {
+          "version": "0.7.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+          "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+          "dev": true,
+          "requires": {
+            "cross-spawn": "5.1.0",
+            "get-stream": "3.0.0",
+            "is-stream": "1.1.0",
+            "npm-run-path": "2.0.2",
+            "p-finally": "1.0.0",
+            "signal-exit": "3.0.2",
+            "strip-eof": "1.0.0"
+          }
+        },
+        "lru-cache": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
+          "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
+          "dev": true,
+          "requires": {
+            "pseudomap": "1.0.2",
+            "yallist": "2.1.2"
+          }
+        }
       }
     },
     "text-encoding": {
@@ -10890,11 +11354,30 @@
             "wrap-ansi": "2.1.0"
           }
         },
+        "cross-spawn": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "requires": {
+            "lru-cache": "4.1.2",
+            "shebang-command": "1.2.0",
+            "which": "1.3.0"
+          }
+        },
         "is-fullwidth-code-point": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
           "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
         },
+        "lru-cache": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
+          "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
+          "requires": {
+            "pseudomap": "1.0.2",
+            "yallist": "2.1.2"
+          }
+        },
         "os-locale": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
@@ -10903,6 +11386,22 @@
             "execa": "0.7.0",
             "lcid": "1.0.0",
             "mem": "1.1.0"
+          },
+          "dependencies": {
+            "execa": {
+              "version": "0.7.0",
+              "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+              "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+              "requires": {
+                "cross-spawn": "5.1.0",
+                "get-stream": "3.0.0",
+                "is-stream": "1.1.0",
+                "npm-run-path": "2.0.2",
+                "p-finally": "1.0.0",
+                "signal-exit": "3.0.2",
+                "strip-eof": "1.0.0"
+              }
+            }
           }
         },
         "string-width": {
diff --git a/package.json b/package.json
index c8f731abe..33e39e1e8 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,8 @@
     "chalk": "^2.1.0",
     "eth-ens-namehash": "^2.0.0",
     "ethereum-ens": "https://github.com/Arachnid/ensjs.git",
+    "execa": "^0.10.0",
+    "figures": "^2.0.0",
     "find-up": "^2.1.0",
     "fs-extra": "^4.0.2",
     "ganache-core": "~2.0.2",
@@ -41,6 +43,7 @@
     "homedir": "^0.6.0",
     "ipfs-api": "^14.3.7",
     "js-sha3": "^0.7.0",
+    "listr": "^0.13.0",
     "multimatch": "^2.1.0",
     "rimraf": "^2.6.2",
     "semver": "^5.4.1",
diff --git a/src/reporters/ConsoleReporter.js b/src/reporters/ConsoleReporter.js
index 7dd386e9b..64627def0 100644
--- a/src/reporters/ConsoleReporter.js
+++ b/src/reporters/ConsoleReporter.js
@@ -1,4 +1,5 @@
 const chalk = require('chalk')
+const figures = require('figures')
 
 module.exports = class ConsoleReporter {
   constructor (opts = { silent: false }) {
@@ -16,14 +17,14 @@ module.exports = class ConsoleReporter {
       success: 'green'
     }[category]
     const symbol = {
-      debug: '-',
-      info: 'i',
-      warning: '~',
-      error: '!',
-      success: '='
+      debug: figures.pointer,
+      info: figures.info,
+      warning: figures.warning,
+      error: figures.cross,
+      success: figures.tick
     }[category]
-    const icon = chalk[color](`[${symbol}]`)
-    console.log(`${icon} ${message}`)
+    const icon = chalk[color](symbol)
+    console.log(` ${icon} ${message}`)
   }
 
   debug (message) {

From 50d193df6b933615c1d4f39a012e066ff445bc7e Mon Sep 17 00:00:00 2001
From: Oliver Nordbjerg <hi@notbjerg.me>
Date: Thu, 5 Apr 2018 17:55:13 +0200
Subject: [PATCH 3/3] Remove `MessageError`

No longer needed because of the new reporter
---
 src/commands/grant.js    | 6 ++----
 src/commands/init.js     | 5 ++---
 src/commands/publish.js  | 7 ++-----
 src/commands/version.js  | 4 +---
 src/commands/versions.js | 4 +---
 src/errors.js            | 8 --------
 6 files changed, 8 insertions(+), 26 deletions(-)
 delete mode 100644 src/errors.js

diff --git a/src/commands/grant.js b/src/commands/grant.js
index 6dfe0ea8e..c71ed6951 100644
--- a/src/commands/grant.js
+++ b/src/commands/grant.js
@@ -1,5 +1,4 @@
 const Web3 = require('web3')
-const { MessageError } = require('../errors')
 const EthereumTx = require('ethereumjs-tx')
 const APM = require('../apm')
 const ACL = require('../acl')
@@ -39,14 +38,13 @@ exports.handler = async function ({
   const acl = ACL(web3)
 
   if (!module || !Object.keys(module).length) {
-    throw new MessageError('This directory is not an Aragon project',
-      'ERR_NOT_A_PROJECT')
+    throw new Error('This directory is not an Aragon project')
   }
 
   const repo = await apm.getRepository(module.appName)
     .catch(() => null)
   if (repo === null) {
-    throw new MessageError(`Repository ${module.appName} does not exist and it's registry does not exist`)
+    throw new Error(`Repository ${module.appName} does not exist and it's registry does not exist`)
   }
 
   reporter.info(`Granting permission to publish on ${module.appName} for ${address}`)
diff --git a/src/commands/init.js b/src/commands/init.js
index d2fd638e9..ac8bcc10c 100644
--- a/src/commands/init.js
+++ b/src/commands/init.js
@@ -1,4 +1,3 @@
-const { MessageError } = require('../errors')
 const { promisify } = require('util')
 const clone = promisify(require('git-clone'))
 
@@ -29,7 +28,7 @@ exports.builder = (yargs) => {
 
         if (!tmpl.includes('/')) {
           if (!aliases[tmpl]) {
-            throw new MessageError(`No template named ${tmpl} exists`)
+            throw new Error(`No template named ${tmpl} exists`)
           }
           tmpl = aliases[tmpl]
         }
@@ -40,7 +39,7 @@ exports.builder = (yargs) => {
     .check(function validateApplicationName ({ name }) {
       const isValidAppName = name.split('.').length >= 2
       if (!isValidAppName) {
-        throw new MessageError(`${name} is not a valid application name (should be e.g. "foo.aragonpm.eth")`, 'ERR_INVALID_APP_NAME')
+        throw new Error(`${name} is not a valid application name (should be e.g. "foo.aragonpm.eth")`)
       }
 
       return true
diff --git a/src/commands/publish.js b/src/commands/publish.js
index d536d8792..538373658 100644
--- a/src/commands/publish.js
+++ b/src/commands/publish.js
@@ -4,7 +4,6 @@ const tmp = require('tmp-promise')
 const path = require('path')
 const { promisify } = require('util')
 const { copy, readJson, writeJson } = require('fs-extra')
-const { MessageError } = require('../errors')
 const extract = require('../helpers/solidity-extractor')
 const APM = require('../apm')
 const semver = require('semver')
@@ -155,14 +154,12 @@ exports.handler = async function ({
   const apm = await APM(web3, apmOptions)
 
   if (!module || !Object.keys(module).length) {
-    throw new MessageError('This directory is not an Aragon project',
-      'ERR_NOT_A_PROJECT')
+    throw new Error('This directory is not an Aragon project')
   }
 
   // Validate version
   if (!semver.valid(module.version)) {
-    throw new MessageError(`${module.version} is not a valid semantic version`,
-      'ERR_INVALID_VERSION')
+    throw new Error(`${module.version} is not a valid semantic version`)
   }
 
   if (!onlyArtifacts) {
diff --git a/src/commands/version.js b/src/commands/version.js
index 90d9957dd..490df2759 100644
--- a/src/commands/version.js
+++ b/src/commands/version.js
@@ -1,7 +1,6 @@
 const fs = require('fs')
 const findUp = require('find-up')
 const semver = require('semver')
-const { MessageError } = require('../errors')
 
 exports.command = 'version <bump>'
 
@@ -16,8 +15,7 @@ exports.builder = function (yargs) {
 exports.handler = async function ({ reporter, bump, cwd }) {
   const manifestLocation = await findUp('arapp.json', { cwd })
   if (!manifestLocation) {
-    throw new MessageError('This directory is not an Aragon project',
-  'ERR_NOT_A_PROJECT')
+    throw new Error('This directory is not an Aragon project')
   }
 
   let manifest = JSON.parse(fs.readFileSync(manifestLocation))
diff --git a/src/commands/versions.js b/src/commands/versions.js
index a14b59ab2..d3b4e8456 100644
--- a/src/commands/versions.js
+++ b/src/commands/versions.js
@@ -1,6 +1,5 @@
 const Web3 = require('web3')
 const findUp = require('find-up')
-const { MessageError } = require('../errors')
 const apm = require('../apm')
 
 exports.command = 'versions'
@@ -14,8 +13,7 @@ exports.handler = async function ({ reporter, module, bump, cwd, keyfile, ethRpc
 
   const moduleLocation = await findUp('arapp.json', { cwd })
   if (!moduleLocation) {
-    throw new MessageError('This directory is not an Aragon project',
-  'ERR_NOT_A_PROJECT')
+    throw new Error('This directory is not an Aragon project')
   }
 
   return apm(web3, apmOptions).getAllVersions(module.appName)
diff --git a/src/errors.js b/src/errors.js
deleted file mode 100644
index 1e272ee5a..000000000
--- a/src/errors.js
+++ /dev/null
@@ -1,8 +0,0 @@
-exports.MessageError = class MessageError extends Error {
-  constructor (msg, code) {
-    super(msg)
-
-    this.code = code
-    Error.captureStackTrace(this, MessageError)
-  }
-}