lots more initial work on the client side
diff --git a/invoker/init.sh b/invoker/init.sh
index 4cb5a50..74b69af 100755
--- a/invoker/init.sh
+++ b/invoker/init.sh
@@ -1,4 +1,4 @@
 #!/bin/bash
 
-wsk package create owdbg -p broker "https://owdbg.mybluemix.net" -p action ""
+wsk package create owdbg -p broker "https://owdbg-broker.mybluemix.net" -p action ""
 wsk action create owdbg/invoker owdbg-invoker.js
diff --git a/invoker/owdbg-invoker.js b/invoker/owdbg-invoker.js
index 920e067..d5af951 100644
--- a/invoker/owdbg-invoker.js
+++ b/invoker/owdbg-invoker.js
@@ -2,8 +2,13 @@
 
 function main(params) {
     return new Promise(function(resolve, reject) {
-	console.log('Invoking ' + JSON.stringify(params) + ' ' + JSON.stringify(whisk));
+	console.log('Invoking ' + JSON.stringify(actualParameters));
 
+	var actualParameters = Object.assign({}, params);
+	delete actualParameters.action;
+	delete actualParameters.namespace;
+	delete actualParameters.onDone_trigger;
+	
 	var opts = {
 	    url: params.broker + '/invoke/begin',
 	    method: 'POST',
@@ -15,7 +20,8 @@
 		key: whisk.getAuthKey(),
 		action: params.action,
 		namespace: params.namespace,
-		params: params
+		onDone_trigger: params.onDone_trigger,
+		actualParameters: actualParameters
 	    }
 	};
 
@@ -27,41 +33,45 @@
 		else console.log('OOPS1b ' + JSON.stringify(response) + ' ' + JSON.stringify(body));
 		reject(body);
 	    } else {
-		console.log('YUMMO ' + body);
+		console.log('YUMMO ' + JSON.stringify(body));
 		var activationId = body.activationId;
 
 		console.log('Ok, so far so good with activationId ' + activationId);
-		var timer = setInterval(function() {
-		    request({
-			url: params.broker + '/invoke/status/' + activationId,
-			method: 'GET',
-			headers: {
-			    'Accept': 'application/json',
-			    'Content-Type': 'application/json',
-			    'AuthKey': whisk.getAuthKey()
-			},
-		    }, function(err, response, body) {
-			if (err || response.statusCode != 200) {
-			    if (err) console.log('OOPS2 ' + JSON.stringify(err));
-			    else console.log('OOPS2b ' + JSON.stringify(response));
-			    reject(body);
-			} else {
-			    try {
-				body = JSON.parse(body);
-				console.log("Result? " + body.result + " " + body);
-				if (body.result !== undefined) {
-				    clearInterval(timer);
-				    resolve(body);
-				}
-			    } catch (e) {
-				console.log("Could not parse result");
+		if (params.onDone_trigger) {
+		    resolve({ status: "ok" });
+		} else {
+		    var timer = setInterval(function() {
+			request({
+			    url: actualParameters.broker + '/invoke/status/' + activationId,
+			    method: 'GET',
+			    headers: {
+				'Accept': 'application/json',
+				'Content-Type': 'application/json',
+				'AuthKey': whisk.getAuthKey()
+			    },
+			}, function(err, response, body) {
+			    if (err || response.statusCode != 200) {
+				if (err) console.log('OOPS2 ' + JSON.stringify(err));
+				else console.log('OOPS2b ' + JSON.stringify(response));
 				reject(body);
+			    } else {
+				try {
+				    // body = JSON.parse(body);
+				    //console.log("Result? " + body.result + " " + body);
+				    if (body.result !== undefined) {
+					clearInterval(timer);
+					resolve(body);
+				    }
+				} catch (e) {
+				    console.log("Could not parse result");
+				    reject(body);
+				}
 			    }
-			}
-		    }); 
-		}, 1000);
+			}); 
+		    }, 1000);
+		}
 	    }
 	});
     });
 }
-//main({'broker':'https://owdbg.mybluemix.net','action':'foo/bar15'})
+main({'broker':'https://owdbg.mybluemix.net','action':'foo/bar15'})
diff --git a/nodejs/client/lib/continuations.js b/nodejs/client/lib/continuations.js
new file mode 100644
index 0000000..40cb8b0
--- /dev/null
+++ b/nodejs/client/lib/continuations.js
@@ -0,0 +1,61 @@
+var request = require('request'),
+    uuid = require('uuid');
+
+module.exports = function exports(api) {
+    var module = {};
+    
+    module.makeEchoChamber = function makeEchoChamber(key, namespace, next, nextOnErr) {
+	var names = {
+	    rule: 'rule_' + uuid.v4(),
+	    trigger: 'trigger_' + uuid.v4(),
+	    action: 'action_' + uuid.v4()
+	}
+
+	makeTrigger(key, namespace, names.trigger,
+		    makeAction.bind(undefined, key, namespace, names.action, 
+				    makeRule.bind(undefined,
+						  { trigger: names.trigger, action: names.action },
+						  key, namespace, names.rule, function allDone() {
+						      next(names);
+						  }, nextOnErr),
+				    nextOnErr),
+		    nextOnErr);
+
+	return names;
+    }
+
+    function makeEntity(type, body, key, namespace, name, next, nextOnErr) {
+	var opts = {
+	    url: api.host + api.path + '/namespaces/' + encodeURIComponent(namespace) + '/' + type + 's/' + encodeURIComponent(name),
+	    method: 'PUT',
+	    json: true,
+	    body: body || {},
+	    headers: {
+		'Content-Type': 'application/json',
+		'Authorization': 'basic ' + new Buffer(key).toString('base64')
+	    },
+	};
+
+	request(opts, function(err, response, body) {
+	    if (err || response.statusCode != 200) {
+		console.log('makeEchoChamber:Error ' + JSON.stringify(err, undefined, 4) + ' ' + (response && response.statusCode) + ' ' + JSON.stringify(body, undefined, 4));
+		nextOnErr();
+	    } else {
+		next();
+	    }
+	});
+    }
+
+    var echo = {
+	exec: {
+	    kind: 'nodejs:default',
+	    code: 'function main(params) { return params; }'
+	}
+    };
+
+    var makeTrigger = makeEntity.bind(undefined, 'trigger', undefined);
+    var makeAction = makeEntity.bind(undefined, 'action', echo);
+    var makeRule = makeEntity.bind(undefined, 'rule');
+
+    return module;
+};
diff --git a/nodejs/client/lib/debug-bootstrap.js b/nodejs/client/lib/debug-bootstrap.js
new file mode 100644
index 0000000..6b230cf
--- /dev/null
+++ b/nodejs/client/lib/debug-bootstrap.js
@@ -0,0 +1,23 @@
+var openwhisk = require('openwhisk'),
+    api = {
+	host: 'https://openwhisk.ng.bluemix.net',
+	path: '/api/v1'
+    };
+
+module.exports = function(key, namespace, triggerName) {
+    return function(main, actualParameters) {
+	var result = main(actualParameters || {});
+
+	var ow = openwhisk({
+	    api: api.host + api.path,
+	    api_key: key,
+	    namespace: namespace
+	});
+	//	debugger;
+
+	ow.triggers.invoke({
+	    triggerName: triggerName,
+	    params: result
+	});
+    };
+};
diff --git a/nodejs/client/lib/echo.js b/nodejs/client/lib/echo.js
new file mode 100644
index 0000000..240bf37
--- /dev/null
+++ b/nodejs/client/lib/echo.js
@@ -0,0 +1,3 @@
+function main(params) {
+    return params;
+}
diff --git a/nodejs/client/package.json b/nodejs/client/package.json
index c169339..9fb35e1 100644
--- a/nodejs/client/package.json
+++ b/nodejs/client/package.json
@@ -9,9 +9,16 @@
   "author": "",
   "license": "ISC",
   "dependencies": {
+    "colors": "^1.1.2",
     "expand-home-dir": "0.0.3",
+    "node-inspector": "^0.12.8",
+    "open": "0.0.5",
+    "openwhisk": "^2.1.3",
     "prompt": "^1.0.0",
     "properties-parser": "^0.3.1",
+    "request": "^2.75.0",
+    "tmp": "0.0.29",
+    "uuid": "^2.0.3",
     "ws": "^1.1.1"
   }
 }
diff --git a/nodejs/client/wskdb b/nodejs/client/wskdb
new file mode 100755
index 0000000..5b84853
--- /dev/null
+++ b/nodejs/client/wskdb
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+node wskdb.js
diff --git a/nodejs/client/wskdb.js b/nodejs/client/wskdb.js
index 3cdcf35..e757e14 100644
--- a/nodejs/client/wskdb.js
+++ b/nodejs/client/wskdb.js
@@ -1,19 +1,31 @@
-var WebSocket = require('ws'),
+var fs = require('fs'),
+    tmp = require('tmp'),
+    open = require('open'),
+    path = require('path'),
+    spawn = require('child_process').spawn,
+    colors = require('colors'),
+    prompt = require('prompt'),
+    openwhisk = require('openwhisk'),
+    WebSocket = require('ws'),
     expandHomeDir = require('expand-home-dir'),
-    prompt = require('prompt');
+    propertiesParser = require('properties-parser'),
 
-var host = 'https://owdbg.mybluemix.net';
-var path = '/ws/client/register';
+    api = {
+	host: 'https://openwhisk.ng.bluemix.net',
+	path: '/api/v1'
+    },
+    broker = {
+	host: 'https://owdbg-broker.mybluemix.net',
+	path: '/ws/client/register'
+    },
+    continuations = require('./lib/continuations')(api);
 
-var uri = host + path;
-var ws = new WebSocket(uri);
-var key = require('properties-parser').read(expandHomeDir('~/.wskprops'))['AUTH'];
+var ws = new WebSocket(broker.host + broker.path);
 
-console.log(uri);
-console.log(key);
- 
 ws.on('open', function open() {
-    console.log('CONNECTION OPEN');
+    console.log('The wskdb client is ready to debug!');
+
+    var key = propertiesParser.read(expandHomeDir('~/.wskprops'))['AUTH'];
     ws.send(JSON.stringify({
 	type: 'init',
 	key: key
@@ -21,11 +33,12 @@
 });
 
 ws.on('close', function() {
-    console.log('CONNECTION CLOSED ' + JSON.stringify(arguments));
+    console.log('Remote connection closed');
 });
  
 ws.on('message', function(data, flags) {
-    console.log('MESSAGE ' + data + ' ||| ' + JSON.stringify(flags));
+    //console.log('MESSAGE ' + data + ' ||| ' + JSON.stringify(flags));
+    
     //
     // flags.binary will be set if a binary data is received. 
     // flags.masked will be set if the data was masked.
@@ -34,37 +47,143 @@
 	var message = JSON.parse(data);
 	switch (message.type) {
 	case 'invoke':
-	    console.log('INVOKE');
-	    console.log(JSON.stringify(message, undefined, 4));
+	    console.log('Debug session requested');
+	    //console.log(JSON.stringify(message, undefined, 4));
 
-	    prompt.start();
-	    prompt.get({
-		name: "result", description: "Return value",
-		conform: function(result) {
-		    try {
-			JSON.parse(result);
-			return true;
-		    } catch (e) {
-			console.log("NOPE " + result);
-			return false;
-		    }
-		}
-	    }, function(err, values) {
+	    var keepAlive = setInterval(function poke() {
 		ws.send(JSON.stringify({
-		    type: 'end',
+		    type: 'keep-alive'
+		}));
+	    }, 5000);
+	    
+	    function done(err, result) {
+		console.log('Finishing up this debug session');
+
+		clearInterval(keepAlive);
+
+		ws.send(JSON.stringify({
+		    type: err ? 'circuit-breaker' : 'end',
 		    key: message.key,
 		    activationId: message.activationId,
-		    result: values.result
+		    result: result
 		}));
-	    });
-	    
+
+		ws.close();
+	    }
+	    function next(echoChamberNames) {
+		if (message.action && message.action.exec && message.action.exec.kind.indexOf('nodejs') >= 0) {
+		    debugNodeJS(message, ws, echoChamberNames, done);
+		} else {
+		    ws.send(JSON.stringify({
+			type: 'circuit-breaker',
+			key: message.key,
+			activationId: message.activationId,
+		    }));
+		}
+	    }
+	    var nextOnErr = done.bind(undefined, true);
+
+	    // console.log("OOOOOOOOOOOOOOOOOO " + message.onDone_trigger + " " + JSON.stringify(message, undefined, 4))
+	    if (message.onDone_trigger) {
+		next({ trigger: message.onDone_trigger });
+	    } else {
+		continuations.makeEchoChamber(message.key, message.action.namespace, next, nextOnErr);
+	    }
+
 	    break;
 	}
     } catch (e) {
 	console.log(e);
     }
 });
- 
+
+function debugDebug(message, ws, done) {
+    prompt.start();
+    prompt.get({
+	name: 'result', description: 'Return value',
+	conform: function(result) {
+	    try {
+		JSON.parse(result);
+		return true;
+	    } catch (e) {
+		console.log('NOPE ' + result);
+		return false;
+	    }
+	}
+    }, function(err, values) {
+	done(values.result);
+    });
+}
+
+function debugNodeJS(message, ws, echoChamberNames, done) {
+    var code = message.action.exec.code;
+
+    var r = new RegExp(/main[\s]*\([^\)]*\)/)
+    var startOfMethodBody = code.search(r);
+    if (startOfMethodBody >= 0) {
+	var paren = code.indexOf('{', startOfMethodBody);
+	code = code.substring(0, paren + 1) + '\n // This is your main method\n    debugger;\n' + code.substring(paren + 1);
+    }
+
+/*    var bootstrap = '\n\n\nvar result = main.apply(undefined, ' + JSON.stringify([message.actualParameters || {}]) + ');';
+
+    // fire our echo chamber trigger when the code is done
+    bootstrap += '\n\nvar openwhisk = require(\'openwhisk\');\n';
+    bootstrap += 'ow = openwhisk({api: \'' + api.host + api.path + '\', api_key: \'' + message.key + '\', namespace: \'' + message.action.namespace + '\' });\n';
+    bootstrap += 'ow.triggers.invoke({ triggerName: \'' + echoChamberNames.trigger + '\', params: result });\n';*/
+
+    code += '\n\n//\n'
+    code += '// Welcome to the OpenWhisk debugger.\n';
+    code += '//\n';
+    code += '// To proceed with debugging, press the continue => button.\n';
+    code += '// The first breakpoint will be in your main method\n';
+    code += '//\n';
+    code += '\n\nvar bootstrap = require(\'debug-bootstrap\')(\'' + message.key + '\', \'' + message.action.namespace + '\', \'' + echoChamberNames.trigger + '\');\nbootstrap(main, ' + JSON.stringify(message.actualParameters || {}) + ');';
+    
+    tmp.file(function onTempFileCreation(err, tmpFilePath, fd, tmpfileCleanupCallback) {
+	// console.log('TMP ' + tmpFilePath);
+
+	fs.write(fd, code, 0, 'utf8', function onFileWriteCompletion(err, written, string) {
+	    var env = Object.assign({}, process.env);
+	    env['NODE_PATH'] = path.join(process.cwd(), 'node_modules')
+		+ ':' + path.join(process.cwd(), 'lib');
+
+	    var spawnOpts = {
+		cwd: process.cwd(),
+		//stdio: ['inherit', 'pipe', 'pipe'],
+		env: env
+	    };
+	    //console.log('SPAWN ' + JSON.stringify(spawnOpts, undefined, 4));
+	    //var child = spawn('node', ['debug', tmpFilePath], spawnOpts);
+	    var child = spawn(path.join('node_modules', '.bin', 'node-debug'), [tmpFilePath], spawnOpts);
+	    /*var child = spawn('node', ['--debug', '--debug-brk', tmpFilePath], spawnOpts);
+	      console.log('SPAWN2');
+	      var child2 = spawn(path.join('node_modules', '.bin', 'node-inspector'), spawnOpts);
+	      console.log('OPEN');
+	      var child3 = open('http://127.0.0.1:8080/?port=5858', 'Google Chrome');*/
+
+	    /*child.stderr.on('data', function(data) {
+	      console.log(data);
+	      });*/
+	    console.log("");
+	    console.log("");
+	    console.log("\tVisit " + "http://127.0.0.1:8080/?port=5858".underline.blue + " in the " + "Chrome".red + " browser that just popped up");
+	    console.log("\tClose that browser tab to complete your debugging session".bold);
+	    console.log("");
+	    console.log("");
+	    function cleanUpSubprocesses(err, stdout, stderr) {
+		/*console.log('ERR: ' + err);
+		  console.log('stdout: ' + stdout);
+		  console.log('stderr: ' + stderr);*/
+		tmpfileCleanupCallback();
+		done();
+	    }
+	    child.on('close', cleanUpSubprocesses);
+	});
+    });
+    
+}
+
 /*
 sending binary data 
 ws.on('open', function open() {
diff --git a/nodejs/client/wskinvoke.sh b/nodejs/client/wskinvoke.sh
new file mode 100755
index 0000000..0af255b
--- /dev/null
+++ b/nodejs/client/wskinvoke.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+NAMESPACE="`grep NAMESPACE ~/.wskprops | awk -F = '{print $2}'`"
+
+TRIGGER="`uuidgen`"
+ACTION="`uuidgen`"
+RULE="`uuidgen`"
+
+function allDone() {
+    (wsk trigger delete ${TRIGGER} >& /dev/null) &
+    (wsk action delete ${ACTION} >& /dev/null) &
+    wsk rule delete ${RULE} >& /dev/null
+    wait
+
+    echo
+    echo "Debug session complete"
+    
+    exit
+}
+
+trap allDone INT
+
+wsk trigger create ${TRIGGER} >& /dev/null
+wsk action create ${ACTION} lib/echo.js >& /dev/null
+wsk rule create ${RULE} ${TRIGGER} ${ACTION} >& /dev/null
+
+wait
+
+wsk action invoke owdbg/invoker -p namespace "${NAMESPACE}" -p onDone_trigger ${TRIGGER} -p action $@
+
+echo -n "Your debugging session should now be active."
+
+while true; do
+    sleep 2
+
+    activationId=`wsk activation list | grep ${ACTION} | awk '{print $1}'`
+
+    if [ -n "$activationId" ]; then
+	wsk activation get $activationId
+	allDone
+	break
+    fi
+
+    echo -n "."
+done