support for invoke tests, and improved cli debugger: kill the debugger when the activation finishes
diff --git a/client/lib/debug-nodejs.js b/client/lib/debug-nodejs.js
index 894895e..cc9ecd0 100644
--- a/client/lib/debug-nodejs.js
+++ b/client/lib/debug-nodejs.js
@@ -15,19 +15,20 @@
  */
 
 var fs = require('fs'),
+    ok_ = require('./repl-messages').ok_,
     tmp = require('tmp'),
     open = require('open'),
     path = require('path'),
     spawn = require('child_process').spawn;
 
-exports.debug = function debugNodeJS(message, ws, echoChamberNames, done, commandLineOptions) {
+exports.debug = function debugNodeJS(message, ws, echoChamberNames, done, commandLineOptions, eventBus) {
     try {
-	exports._debug(message, ws, echoChamberNames, done, commandLineOptions);
+	exports._debug(message, ws, echoChamberNames, done, commandLineOptions, eventBus);
     } catch (e) {
 	console.error(e);
     }
 };
-exports._debug = function debugNodeJS(message, ws, echoChamberNames, done, commandLineOptions) {
+exports._debug = function debugNodeJS(message, ws, echoChamberNames, done, commandLineOptions, eventBus) {
     var code = message.action.exec.code;
 
     var r = new RegExp(/main[\s]*\([^\)]*\)/);
@@ -123,7 +124,7 @@
 		    }
 		    if (!addrInUse) {
 			try { tmpfileCleanupCallback(); } catch (e) { }
-			done();
+			ok_(done());
 		    }
 		}
 		child.on('close', cleanUpSubprocesses);
@@ -139,14 +140,21 @@
 		    var child = spawn('node',
 				      ['debug', tmpFilePath],
 				      spawnOpts);
-		    child.on('exit', (message) => console.error('EXIT',message));
-		    
+		    child.on('exit', (code) => {
+			if (code !== 0) {
+			    console.error('The debugger exited abnormally with code ' + code);
+			}
+		    });
+
+		    eventBus.on('invocation-done', () => child.kill());
+
 		    child.on('close', () => {
 			try { tmpfileCleanupCallback(); } catch (e) { }
-			done();
+			done(); // we don't need to "ok" here, as the invoker will do that for us
 		    });
 		} catch (e) {
 		    console.error('Error spawning debugger', e);
+		    console.error(e.stack);
 		    done();
 		}
 	    }
@@ -159,6 +167,7 @@
 	});
 	} catch (e) {
 	    console.error(e);
+	    console.error(e.stack);
 	}
     });
 };
diff --git a/client/lib/repl.js b/client/lib/repl.js
index 25b77f2..6824456 100644
--- a/client/lib/repl.js
+++ b/client/lib/repl.js
@@ -72,6 +72,7 @@
 var invoke = {
     handler: rewriter.invoke,
     description: 'Invoke an action',
+    needsEventBus: true,
     synchronous: true
 };
 var list = {
@@ -124,7 +125,7 @@
     '?': help
 };
 
-function repl(wskprops) {
+function repl(wskprops, eventBus) {
     prompt.prompt([{
 	name: 'command', message: '(wskdb)',
 	prefixMessage: '', // override the default question mark prefix
@@ -135,7 +136,7 @@
     }]).then(function(response) {
 	if (response.command.length === 0) {
 	    // user hit return;
-	    return repl(wskprops);
+	    return repl(wskprops, eventBus);
 	}
 	
 	var commandLine = response.command.split(/\s+/);
@@ -156,13 +157,17 @@
 	if (handler.synchronous) {
 	    // the second parameter is the call back to the repl
 	    // when done with the synchronous operation
-	    commandLine.unshift(repl.bind(undefined, wskprops));
+	    commandLine.unshift(repl.bind(undefined, wskprops, eventBus));
 	}
 
 	if (handler.options) {
 	    commandLine.unshift(options);
 	}
 
+	if (handler.needsEventBus) {
+	    commandLine.unshift(eventBus);
+	}
+
 	// the first parameter is wskprops
 	commandLine.unshift(wskprops);
 
@@ -175,7 +180,7 @@
 
 	if (!handler.synchronous) {
 	    // if async, then restart the repl right away
-	    repl(wskprops);
+	    repl(wskprops, eventBus);
 	}
     });
 }
diff --git a/client/lib/rewriter.js b/client/lib/rewriter.js
index b471c35..f8c2649 100644
--- a/client/lib/rewriter.js
+++ b/client/lib/rewriter.js
@@ -302,6 +302,12 @@
  */
 exports.attach = function attach(wskprops, options, next, entity) {
     if (options.help) {
+	// the user passed -h or --help, so there is nothing to do here
+	return next();
+    }
+    if (!entity) {
+	console.error('Error: Please specify an entity ');
+	console.error();
 	return next();
     }
 
@@ -317,7 +323,7 @@
 		//
 		// user asked not to instrument any rules or sequences
 		//
-		return next();
+		return ok_(next);
 	    }
 	    doPar(ow, 'action', entity, next, (otherEntityWithDetails, countDown) => {
 		if (SequenceRewriter.rewriteNeeded(otherEntityWithDetails, entity, entityNamespace)) {
@@ -461,6 +467,7 @@
 exports._invoke = function invoke() {
     var args = Array.prototype.slice.call(arguments);
     var wskprops = args.shift();
+    var eventBus = args.shift();
     var namespace = wskprops.NAMESPACE;
     var next = args.shift();
     var action = args.shift();
@@ -534,7 +541,8 @@
 			    clearInterval(timer);
 			    owForActivations.activations.get({ activation: activation.activationId }).then(function(activation) {
 				console.log(JSON.stringify(activation, undefined, 4));
-				next();
+				eventBus.emit('invocation-done', activation);
+				ok_(next);
 			    });
 			    break;
 			}
diff --git a/client/test/helpers/driver.js b/client/test/helpers/driver.js
index 19035a0..c40e397 100644
--- a/client/test/helpers/driver.js
+++ b/client/test/helpers/driver.js
@@ -1,57 +1,60 @@
 'use strict'
 
-var test = require('ava').test;
+const test = require('ava').test;
 const uuid = require('uuid');
 const spawn = require('child_process').spawn;
 
 function Driver() {
 }
-Driver.prototype.it = function it(shouldDoThisSuccessfully, stepFn, rootPath) {
+Driver.prototype.it = function it(shouldDoThisSuccessfully, stepFn, args, rootPath) {
     test(shouldDoThisSuccessfully, t => {
 	return new Promise((resolve,reject) => {
-	    const child = spawn('node', ['wskdb.js'], { cwd: rootPath || '../..' });
+	    const child = spawn('node', ['wskdb.js'].concat(args || []), { cwd: rootPath || '../..' });
 
-		var name = uuid.v4();
-		var steps = stepFn(name);
+	    const name = uuid.v4();
+	    const steps = stepFn(name);
 	    
-		var stepNumber = 0;
-		var goody = false;
+	    var stepNumber = 0;
+	    var goody = false;
 	    
-		function doStep() {
-		    child.stdin.write(steps[stepNumber++] + '\n');
-		}
-		doStep(); // do the first step
+	    function doStep() {
+		// console.log("STEP " + steps[stepNumber]);
+		child.stdout.pause();
+		child.stdin.write(steps[stepNumber++] + '\n');
+		child.stdout.resume();
+	    }
+	    doStep(); // do the first step
 		
-		child.stderr.on('data', (data) => {
-		    console.error('stderr: ' + data);
-		});
+	    child.stderr.on('data', (data) => {
+		console.error('stderr: ' + data);
+	    });
 		
-		child.stdout.on('data', (data) => {
-		    //console.log('stdout: ' + data)
-		    if (data.indexOf('Error') >= 0) {
-			goody = false;
-			reject('Step ' + (stepNumber - 1) + ' failed');
+	    child.stdout.on('data', (data) => {
+		//console.log('stdout: ' + data + " ||| " + data.indexOf('(wskdb)'))
+		if (data.indexOf('Error') >= 0) {
+		    goody = false;
+		    reject('Step ' + (stepNumber - 1) + ' failed');
 			
-		    } else if (data.indexOf('ok') >= 0) {
-			goody = true;
+		} else if (data.indexOf('ok') == 0 || data.indexOf('break in') >= 0) {
+		    goody = true;
 			
-			if (stepNumber === steps.length) {
-			    child.stdin.write('quit\n');
-			    child.stdin.end();
-			} else {
-			    doStep();
-			}
-		    }
-		});
-		child.on('exit', (code) => {
-		    if (code === 0 && goody) {
-			resolve();
+		    if (stepNumber === steps.length) {
+			child.stdin.write('quit\n');
+			child.stdin.end();
 		    } else {
-			reject('code=${code} goody=${goody}');
+			doStep();
 		    }
-		});
-	    }).then(result => t.is(result));
-	});
+		}
+	    });
+	    child.on('exit', (code) => {
+		if (code === 0 && goody) {
+		    resolve();
+		} else {
+		    reject('code=${code} goody=${goody}');
+		}
+	    });
+	}).then(result => t.is(result));
+    });
 } /* the end of it! */
 
 module.exports = new Driver().it;
diff --git a/client/test/rewriter/createAttachDetachDelete.js b/client/test/rewriter/createAttachDetachDelete.js
index 8e0218c..c03ccfe 100644
--- a/client/test/rewriter/createAttachDetachDelete.js
+++ b/client/test/rewriter/createAttachDetachDelete.js
@@ -1,6 +1,6 @@
 import it from '../helpers/driver'
 
-it('should create an attach, then attach, detach, delete, and finally quit without error', (name) => [
+it('should create an action, then attach, detach, delete, and finally quit without error', (name) => [
     `create ${name} nodejs function main(params) { return { message: "Hello " + params.name } }`,
     `attach ${name}`,
     `detach ${name}`,
diff --git a/client/test/rewriter/createAttachInvokeDetachDelete.js b/client/test/rewriter/createAttachInvokeDetachDelete.js
new file mode 100644
index 0000000..c62e6e0
--- /dev/null
+++ b/client/test/rewriter/createAttachInvokeDetachDelete.js
@@ -0,0 +1,12 @@
+import it from '../helpers/driver'
+
+it('should create an action, then attach, invoke, detach, delete, and finally quit without error', (name) => [
+    `create ${name} nodejs function main(params) { return { message: "Hello " + params.name } }`,
+    `attach ${name} -a`,
+    `invoke ${name}`,
+    `c`,
+    `c`,
+    `quit`, // quit the debugger
+    `detach ${name}`,
+    `delete ${name}`
+], ['-c']); // use the cli debugger
diff --git a/client/wskdb.js b/client/wskdb.js
index 7e1853c..685339a 100644
--- a/client/wskdb.js
+++ b/client/wskdb.js
@@ -17,6 +17,8 @@
 var argv = require('argv'),
     repl = require('./lib/repl').repl,
     colors = require('colors'),
+    events = require('events'),
+    eventBus = new events.EventEmitter(),
     WebSocket = require('ws'),
     debugNodeJS = require('./lib/debug-nodejs').debug,
     expandHomeDir = require('expand-home-dir'),
@@ -82,7 +84,7 @@
 });
 
 
-    repl(wskprops);
+    repl(wskprops, eventBus);
 });
 
 ws.on('close', function() {
@@ -125,7 +127,7 @@
 
 	    if (message.onDone_trigger) {
 		if (message.action && message.action.exec && message.action.exec.kind.indexOf('nodejs') >= 0) {
-		    debugNodeJS(message, ws, { trigger: message.onDone_trigger }, done, commandLineOptions);
+		    debugNodeJS(message, ws, { trigger: message.onDone_trigger }, done, commandLineOptions, eventBus);
 		} else {
 		    console.error('Unable to complete invocation: no action code to debug');
 		    circuitBreaker();