diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6984a96
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+features
+node_modules
diff --git a/README.md b/README.md
index a208f5c..5614a6b 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,101 @@
-# behave-pro-node
+# Behave Pro NodeJS Client
+
+```
+$ npm install behavepro -g
+```
+
+See [API Key setup](introduction.html) to retrieve the required credentials.
+
+## Using from the command line
+
+Parameters can either be passed from the command line:
+
+```
+$ behavepro [--id PROJECT ID] [--userId USER] [--apiKey KEY]
+```
+
+Available parameters:
+
+* [**--host HOST**] *Behave Pro host - default: 'http://behave.pro'*
+* [**--id PROJECT ID**] *JIRA project id*
+* [**--userId USER**] *Behave Pro user id*
+* [**--apiKey KEY**] *Behave Pro api key*
+* [**--output DIRECTORY**] *Output directory - default: 'features'*
+* [**--manual**] *Include scenarios marked as manual*
+* [**--config CONFIG**] *JSON config file - relative to current directory*
+
+If the three required parameters are missing, they will be attempted to be read from a json config file in the current directory:
+
+```
+$ behavepro
+```
+
+config.json
+```
+[{
+ "id": 10000,
+ "userId": "amlyYToyNDM0ZG.....ZiNzQwNGI=",
+ "apiKey": "44993b0481838e.....a246c723e8e"
+}, {
+ "id": 10100,
+ "userId": "amlyYToyNDM0ZG.....ZiNzQwNGI=",
+ "apiKey": "b038a67e0f15e5.....fae00662c8a"
+}]
+```
+
+Any additional parameters are to be specified from the command line.
+
+The host can vary between products, see table below.
+
+
+
+ Product |
+ Host |
+
+
+
+ Behave Pro Cloud (default) |
+ https://behave.pro |
+
+
+
+ Behave Pro Server |
+ Address of the VM |
+
+
+
+ Behave for JIRA |
+ JIRA address |
+
+
+
+
+## Using from within a script
+
+You can use the client in your own scripts to download features from Behave Pro.
+
+```
+$ npm install behavepro --save
+```
+
+
+```
+var BehavePro = require('behavepro');
+
+BehavePro({
+ "id": 10000,
+ "userId": "amlyYToyNDM0ZG.....ZiNzQwNGI=",
+ "apiKey": "44993b0481838e.....a246c723e8e"
+}, function() {
+ // done
+});
+```
+
+Available parameters:
+
+* **"host": HOST** - *Behave Pro host - default: 'http://behave.pro'*
+* **"id": ID** - *JIRA project id*
+* **"userId": USERID** - *Behave Pro user id*
+* **"apiKey": APIKEY** - *Behave Pro api key*
+* **"output": DIRECTORY** - *Output directory - default: 'features'*
+* **"manual": true** - *Include scenarios marked as manual*
diff --git a/bin/cli.js b/bin/cli.js
new file mode 100755
index 0000000..baf1aa0
--- /dev/null
+++ b/bin/cli.js
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+'use strict'
+var BehavePro = require('../lib/behavepro');
+var args = require('minimist')(process.argv.slice(2));
+var packageJson = require('../package.json');
+
+if (args.help) {
+ console.log(
+ 'Behave Pro NodeJS client v' + packageJson.version + '\n'+
+ '$ behavepro [--id PROJECT ID] [--userId USER] [--apiKey KEY]\n\n' +
+ '[--host HOST] Behave Pro host - default: \'http://behave.pro\'\n' +
+ '[--id PROJECT ID] JIRA project id\n' +
+ '[--userId USER] Behave Pro user id\n' +
+ '[--apiKey KEY] Behave Pro api key\n' +
+ '[--output DIRECTORY] Output directory - default: \'features\'\n' +
+ '[--manual] Include scenarios marked as manual\n' +
+ '[--config CONFIG] JSON config file - relative to current directory\n' +
+ 'Further docs at http://docs.behave.pro'
+ );
+ return;
+}
+
+var settings = {
+ host: args.host || 'https://behave.pro',
+ id: args.key || args.project || args.id,
+ userId: args.user || args.userId,
+ apiKey: args.api || args.apiKey || args.password,
+ output: args.output || args.dir || args.directory || 'features',
+ manual: args.manual || args.m || false,
+ config: args.config || 'config.json'
+};
+
+// if these aren't defined, attempt to read them from config.json
+if (settings.id && settings.userId && settings.apiKey) {
+ BehavePro.fetchFeatures(settings);
+} else {
+ BehavePro.fetchFeaturesFromConfig(settings);
+}
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100755
index 0000000..c1f9634
--- /dev/null
+++ b/index.js
@@ -0,0 +1,19 @@
+#!/usr/bin/env node
+'use strict'
+var BehavePro = require('./lib/behavepro');
+var _ = require('underscore');
+
+var defaultSettings = {
+ host: 'https://behave.pro',
+ output: 'features',
+ manual: false,
+ config: 'config.json'
+};
+
+module.exports = function(settings, callback) {
+ _.defaults(settings, defaultSettings);
+ BehavePro.fetchFeatures(settings, function() {
+ console.log(settings);
+ if (callback) callback();
+ });
+}
\ No newline at end of file
diff --git a/lib/behavepro.js b/lib/behavepro.js
new file mode 100644
index 0000000..aa173ba
--- /dev/null
+++ b/lib/behavepro.js
@@ -0,0 +1,115 @@
+#!/usr/bin/env node
+'use strict'
+var request = require('request');
+var unzip = require('unzip2');
+var fs = require('fs');
+var mkdir = require('mkdirp');
+var _ = require('underscore');
+
+module.exports.fetchFeaturesFromConfig = function(settings, callback) {
+ fs.exists(process.cwd() + '/' + settings.config, function(exists) {
+ if (exists) {
+ var configuration = require(process.cwd() + '/' + settings.config);
+ configuration.forEach(function(config) {
+ _.extend(settings, config);
+ fetchFeatures(settings, callback);
+ });
+ } else {
+ var err = new Error('Could not find config at ' + process.cwd() + '/' + settings.config);
+ throw err;
+ }
+ });
+}
+
+var fetchFeatures = function(settings, callback) {
+ var url = settings.host + '/rest/cucumber/1.0/project/' + settings.id+ '/features?manual=' + settings.manual;
+ var path = settings.output + '/' + settings.id;
+
+ ensureSettingsExist(settings.id, settings.userId, settings.apiKey, function() {
+ console.log('Downloading features from JIRA project ' + settings.id + '...');
+ request({
+ url: url,
+ headers: {
+ Authorization: 'Basic ' + new Buffer(settings.userId + ':' + settings.apiKey).toString('base64')
+ },
+ encoding: null
+ }, function(error, response, body) {
+ if (error) throw error;
+ var err = null;
+ switch(response.statusCode) {
+ case 500:
+ err = new Error('Server error - Are you using the correct host?');
+ throw err;
+ return;
+ case 401:
+ err = new Error('Unauthorized - ensure keys are valid');
+ throw err;
+ return;
+ case 200:
+ break;
+ default:
+ err = new Error(response.statusCode + ' http error when downloading');
+ throw err;
+ return;
+ }
+
+ mkdir(path, function(err) {
+ if (err) throw err;
+ writeFeatures(body, path, function() {
+ countFeatures(path, function(files) {
+ console.log('Saved ' + files.length + ' ' + (files.length > 1 ? 'features' : 'feature') + ' to ' + process.cwd() + '/' + path + '/');
+ });
+ if (callback) callback();
+ });
+ });
+ });
+ });
+}
+
+module.exports.fetchFeatures = fetchFeatures;
+
+function writeFeatures(body, path, callback) {
+ fs.writeFile(path + '.zip', body, function(err) {
+ if (err) throw err;
+ var stream = fs.createReadStream(path + '.zip').pipe(
+ unzip.Extract({
+ path: path
+ })
+ );
+
+ stream.on('close', function() {
+ removeZip(path + '.zip');
+ callback();
+ });
+ });
+}
+
+function ensureSettingsExist(id, userId, apiKey, callback) {
+ var err = null;
+ if (!id) {
+ err = new Error('Project id missing');
+ throw err;
+ }
+ if (!userId) {
+ err = new Error('User id missing');
+ throw err;
+ }
+ if (!apiKey) {
+ err = new Error('API key missing');
+ throw err;
+ }
+ if (callback) callback();
+}
+
+function countFeatures(path, callback) {
+ fs.readdir(path, function(err, files) {
+ callback(files);
+ });
+}
+
+function removeZip(file, callback) {
+ fs.unlink(file, function(err) {
+ if (err) throw err;
+ if (callback) callback();
+ });
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7cd9163
--- /dev/null
+++ b/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "behave-pro-js",
+ "version": "0.0.1",
+ "description": "Behave Pro JS exporter",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "Hindsight Software Ltd",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.1.1",
+ "mkdirp": "^0.5.1",
+ "request": "^2.58.0",
+ "underscore": "^1.8.3",
+ "unzip2": "^0.2.5"
+ },
+ "bin": {
+ "behavepro": "bin/cli.js"
+ }
+}