validate source path etc. before async installation of agent

- separate OpenWhiskInvoker.prepare() phase for validation
- better error msg if sourcePath points to folder
- fix race condition on early error related shutdown
diff --git a/src/agentmgr.js b/src/agentmgr.js
index 4405b8d..f96c6fa 100644
--- a/src/agentmgr.js
+++ b/src/agentmgr.js
@@ -264,6 +264,8 @@
     }
 
     async shutdown() {
+        this.shuttingDown = true;
+
         try {
             // make sure we finished creating the backup
             await this.createBackup;
@@ -529,6 +531,11 @@
         // this is to support older openwhisks for which nodejs:default is less than version 8
         const nodejs8 = await this.openwhiskSupports("nodejs8");
 
+        if (this.shuttingDown) {
+            // race condition on shutdown during startup due to errors
+            return;
+        }
+
         await this.wsk.actions.update({
             name: this.actionName,
             action: {
diff --git a/src/debugger.js b/src/debugger.js
index 8e2fb42..879d497 100644
--- a/src/debugger.js
+++ b/src/debugger.js
@@ -71,16 +71,18 @@
         this.invoker = new OpenWhiskInvoker(this.actionName, actionMetadata, this.argv, this.wskProps, this.wsk);
 
         try {
+            // run build initially (would be required by starting container)
+            if (this.argv.onBuild) {
+                console.info("=> Build:", this.argv.onBuild);
+                spawnSync(this.argv.onBuild, {shell: true, stdio: "inherit"});
+            }
+            await this.invoker.prepare();
+
             // parallelize slower work using promises
 
             // task 1 - start local container
             const containerTask = (async () => {
                 const debugTask = debug.task();
-                // run build initially (would be required by starting container)
-                if (this.argv.onBuild) {
-                    console.info("=> Build:", this.argv.onBuild);
-                    spawnSync(this.argv.onBuild, {shell: true, stdio: "inherit"});
-                }
 
                 // start container - get it up fast for VSCode to connect within its 10 seconds timeout
                 await this.invoker.startContainer();
diff --git a/src/invoker.js b/src/invoker.js
index 35fff0e..eed849a 100644
--- a/src/invoker.js
+++ b/src/invoker.js
@@ -119,15 +119,12 @@
         return kinds.images[kind];
     }
 
-    async startContainer() {
+    async prepare() {
         const action = this.action;
 
-        // this must run after initial build was kicked off in Debugger.startSourceWatching()
-        // so that built files are present
+        // this must run after initial build was kicked off in Debugger so that built files are present
 
-        // kind and image
-
-        // precendence:
+        // kind and image - precendence:
         // 1. arguments (this.image)
         // 2. action (action.exec.image)
         // 3. defaults (kinds.images[kind])
@@ -138,7 +135,6 @@
             throw new Error("Action is of kind 'blackbox', must specify kind using `--kind` argument.");
         }
 
-        // const runtime = kinds[kind] || {};
         this.image = this.image || action.exec.image || await this.getImageForKind(kind);
 
         if (!this.image) {
@@ -174,7 +170,7 @@
         }
 
         // limits
-        const memory = (action.limits.memory || OPENWHISK_DEFAULTS.memory) * 1024 * 1024;
+        this.memory = (action.limits.memory || OPENWHISK_DEFAULTS.memory) * 1024 * 1024;
 
         // source mounting
         if (this.sourcePath) {
@@ -184,9 +180,15 @@
             }
         }
 
-        const dockerArgsFromKind = resolveValue(this.debug.dockerArgs, this) || "";
-        const dockerArgsFromUser = this.dockerArgs || "";
+        this.dockerArgsFromKind = resolveValue(this.debug.dockerArgs, this) || "";
+        this.dockerArgsFromUser = this.dockerArgs || "";
 
+        if (this.sourcePath && this.debug.mountAction) {
+            this.sourceMountAction = resolveValue(this.debug.mountAction, this);
+        }
+    }
+
+    async startContainer() {
         let showDockerRunOutput = this.verbose;
 
         // quick fail for missing requirements such as docker not running
@@ -220,11 +222,11 @@
                 -d
                 --name ${this.name()}
                 --rm
-                -m ${memory}
+                -m ${this.memory}
                 -p ${RUNTIME_PORT}
                 -p ${this.debug.port}:${this.debug.internalPort}
-                ${dockerArgsFromKind}
-                ${dockerArgsFromUser}
+                ${this.dockerArgsFromKind}
+                ${this.dockerArgsFromUser}
                 ${this.image}
                 ${this.debug.command}
             `,
@@ -262,12 +264,13 @@
 
     async init(actionWithCode) {
         let action;
-        if (this.sourcePath && this.debug.mountAction) {
-            action = resolveValue(this.debug.mountAction, this);
-
+        if (this.sourceMountAction) {
             if (this.verbose) {
                 console.log(`Mounting sources onto local debug container: ${this.sourcePath}`);
             }
+
+            action = this.sourceMountAction;
+
         } else {
             if (this.verbose) {
                 console.log(`Pushing action code to local debug container: ${this.action.name}`);
diff --git a/src/kinds/nodejs/nodejs.js b/src/kinds/nodejs/nodejs.js
index 38d6396..1791def 100644
--- a/src/kinds/nodejs/nodejs.js
+++ b/src/kinds/nodejs/nodejs.js
@@ -39,7 +39,7 @@
         let args = "";
         if (invoker.sourceDir) {
             if (!invoker.sourceFile) {
-                throw new Error("[source-path] or --build-path must point to the action javascript source file, it cannot be a folder.");
+                throw new Error(`[source-path] or --build-path must point to a source file, it cannot be a folder: '${invoker.sourcePath}'`);
             }
 
             args += ` -v "${invoker.sourceDir}:${CODE_MOUNT}"`;
@@ -59,6 +59,10 @@
     mountAction: function(invoker) {
         // bridge that mounts local source path
 
+        if (fs.statSync(invoker.sourcePath).isDirectory()) {
+            throw new Error(`[source-path] or --build-path must point to a source file, it cannot be a folder: '${invoker.sourcePath}'`);
+        }
+
         // test if code uses commonjs require()
         const isCommonJS = /(\s|=)require\(\s*['"`]/.test(fs.readFileSync(invoker.sourcePath));