From d5d011881993f7ee9522641d6be33a387c290da4 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Sun, 15 Feb 2026 08:39:04 -0500 Subject: [PATCH 1/9] feat: Add registry developer account registration command - Add 'flb register' command for creating Registry Developer Accounts - Interactive prompts for username, email, password, and name - Input validation for username format and password length - Calls /~registry/v1/developer-account/register API endpoint - Provides clear success/error messages - Guides users to login after successful registration --- index.js | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index ace79d8..60ed342 100755 --- a/index.js +++ b/index.js @@ -721,7 +721,102 @@ async function versionBump (options) { } } -// Command to handle login +// Command to handle registration +async function registerCommand(options) { + const registrationApi = 'https://api.fleetbase.io/~registry/v1/developer-account/register'; + + try { + // Collect registration information + const answers = await prompt([ + { + type: 'input', + name: 'username', + message: 'Username:', + initial: options.username, + skip: !!options.username, + validate: (value) => { + if (!value || value.length < 3) { + return 'Username must be at least 3 characters'; + } + if (!/^[a-zA-Z0-9_-]+$/.test(value)) { + return 'Username can only contain letters, numbers, hyphens, and underscores'; + } + return true; + } + }, + { + type: 'input', + name: 'email', + message: 'Email:', + initial: options.email, + skip: !!options.email, + validate: (value) => { + if (!value || !value.includes('@')) { + return 'Please enter a valid email address'; + } + return true; + } + }, + { + type: 'password', + name: 'password', + message: 'Password:', + skip: !!options.password, + validate: (value) => { + if (!value || value.length < 8) { + return 'Password must be at least 8 characters'; + } + return true; + } + }, + { + type: 'input', + name: 'name', + message: 'Full Name (optional):', + initial: options.name + } + ]); + + const registrationData = { + username: options.username || answers.username, + email: options.email || answers.email, + password: options.password || answers.password, + name: options.name || answers.name || undefined + }; + + console.log('\nRegistering account...'); + + // Make API call to register + const response = await axios.post(registrationApi, registrationData); + + if (response.data.status === 'success') { + console.log('\n✓ Account created successfully!'); + console.log('✓ Please check your email to verify your account.'); + console.log(`\n✓ Once verified, you can login with: flb login -u ${registrationData.username}`); + } else { + console.error('Registration failed:', response.data.message || 'Unknown error'); + process.exit(1); + } + } catch (error) { + if (error.response && error.response.data) { + const errorData = error.response.data; + if (errorData.errors) { + console.error('\nRegistration failed with the following errors:'); + Object.keys(errorData.errors).forEach(field => { + errorData.errors[field].forEach(message => { + console.error(` - ${field}: ${message}`); + }); + }); + } else { + console.error('Registration failed:', errorData.message || 'Unknown error'); + } + } else { + console.error('Registration failed:', error.message); + } + process.exit(1); + } +} + function loginCommand (options) { const npmLogin = require('npm-cli-login'); const username = options.username; @@ -875,6 +970,15 @@ program .option('--pre-release [identifier]', 'Add pre-release identifier') .action(versionBump); +program + .command('register') + .description('Register a new Registry Developer Account') + .option('-u, --username ', 'Username for the registry') + .option('-e, --email ', 'Email address') + .option('-p, --password ', 'Password') + .option('-n, --name ', 'Your full name (optional)') + .action(registerCommand); + program .command('login') .description('Log in to the Fleetbase registry') From 79a214867ac73a7872b63e989890fdaed2dcb4a8 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Mon, 23 Feb 2026 14:51:37 +0800 Subject: [PATCH 2/9] v0.0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84efe6e..963204a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fleetbase/cli", - "version": "0.0.3", + "version": "0.0.4", "description": "CLI tool for managing Fleetbase Extensions", "repository": "https://github.com/fleetbase/fleetbase", "license": "AGPL-3.0-or-later", From e47167ed97982aaf57f56bac9f90731fb5e14b88 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Mon, 23 Feb 2026 01:57:11 -0500 Subject: [PATCH 3/9] feat: Add install-fleetbase command (merged with register command) This commit adds the install-fleetbase command functionality on top of the dev-v0.0.4 branch which includes the register command. Both commands now coexist: - register: Register a new Registry Developer Account - install-fleetbase: Install Fleetbase using Docker The install command includes: - Interactive prompts for host, environment, and directory - Automatic APP_KEY generation - Docker compose configuration - Console environment file updates - Deployment automation --- index.js | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) mode change 100755 => 100644 index.js diff --git a/index.js b/index.js old mode 100755 new mode 100644 index 60ed342..a867c85 --- a/index.js +++ b/index.js @@ -817,6 +817,199 @@ async function registerCommand(options) { } } +// Command to install Fleetbase via Docker +async function installFleetbaseCommand(options) { + const crypto = require('crypto'); + const os = require('os'); + + console.log('\n🚀 Fleetbase Installation\n'); + + try { + // Collect installation parameters + const answers = await prompt([ + { + type: 'input', + name: 'host', + message: 'Enter host or IP address to bind to:', + initial: options.host || 'localhost', + validate: (value) => { + if (!value) { + return 'Host is required'; + } + return true; + } + }, + { + type: 'select', + name: 'environment', + message: 'Choose environment:', + initial: options.environment === 'production' ? 1 : 0, + choices: [ + { title: 'Development', value: 'development' }, + { title: 'Production', value: 'production' } + ] + }, + { + type: 'input', + name: 'directory', + message: 'Installation directory:', + initial: options.directory || process.cwd(), + validate: (value) => { + if (!value) { + return 'Directory is required'; + } + return true; + } + } + ]); + + const host = options.host || answers.host; + const environment = options.environment || answers.environment; + const directory = options.directory || answers.directory; + + // Determine configuration based on environment + const useHttps = environment === 'production'; + const appDebug = environment === 'development'; + const scSecure = environment === 'production'; + const schemeApi = useHttps ? 'https' : 'http'; + const schemeConsole = useHttps ? 'https' : 'http'; + + console.log(`\n📋 Configuration:`); + console.log(` Host: ${host}`); + console.log(` Environment: ${environment}`); + console.log(` Directory: ${directory}`); + console.log(` HTTPS: ${useHttps}`); + + // Check if directory exists and has Fleetbase files + if (!await fs.pathExists(directory)) { + console.error(`\n✖ Directory does not exist: ${directory}`); + console.log('\nℹ️ Please clone the Fleetbase repository first:'); + console.log(' git clone https://github.com/fleetbase/fleetbase.git'); + process.exit(1); + } + + const dockerComposePath = path.join(directory, 'docker-compose.yml'); + if (!await fs.pathExists(dockerComposePath)) { + console.error(`\n✖ docker-compose.yml not found in ${directory}`); + console.log('\nℹ️ Please ensure you are in the Fleetbase root directory.'); + process.exit(1); + } + + // Generate APP_KEY + console.log('\n⏳ Generating APP_KEY...'); + const appKey = 'base64:' + crypto.randomBytes(32).toString('base64'); + console.log('✔ APP_KEY generated'); + + // Create docker-compose.override.yml + console.log('⏳ Creating docker-compose.override.yml...'); + const overrideContent = `services: + application: + environment: + APP_KEY: "${appKey}" + CONSOLE_HOST: "${schemeConsole}://${host}:4200" + ENVIRONMENT: "${environment}" + APP_DEBUG: "${appDebug}" +`; + const overridePath = path.join(directory, 'docker-compose.override.yml'); + await fs.writeFile(overridePath, overrideContent); + console.log('✔ docker-compose.override.yml created'); + + // Create console/fleetbase.config.json (for development runtime config) + console.log('⏳ Creating console/fleetbase.config.json...'); + const configDir = path.join(directory, 'console'); + await fs.ensureDir(configDir); + const configContent = { + API_HOST: `${schemeApi}://${host}:8000`, + SOCKETCLUSTER_HOST: host, + SOCKETCLUSTER_PORT: '38000', + SOCKETCLUSTER_SECURE: scSecure + }; + const configPath = path.join(configDir, 'fleetbase.config.json'); + await fs.writeJson(configPath, configContent, { spaces: 2 }); + console.log('✔ console/fleetbase.config.json created'); + + // Update console environment files (.env.development and .env.production) + console.log('⏳ Updating console environment files...'); + const environmentsDir = path.join(configDir, 'environments'); + + // Update .env.development + const envDevelopmentContent = `API_HOST=http://${host}:8000 +API_NAMESPACE=int/v1 +SOCKETCLUSTER_PATH=/socketcluster/ +SOCKETCLUSTER_HOST=${host} +SOCKETCLUSTER_SECURE=false +SOCKETCLUSTER_PORT=38000 +OSRM_HOST=https://router.project-osrm.org +`; + const envDevelopmentPath = path.join(environmentsDir, '.env.development'); + await fs.writeFile(envDevelopmentPath, envDevelopmentContent); + + // Update .env.production + const envProductionContent = `API_HOST=https://${host}:8000 +API_NAMESPACE=int/v1 +API_SECURE=true +SOCKETCLUSTER_PATH=/socketcluster/ +SOCKETCLUSTER_HOST=${host} +SOCKETCLUSTER_SECURE=true +SOCKETCLUSTER_PORT=38000 +OSRM_HOST=https://router.project-osrm.org +`; + const envProductionPath = path.join(environmentsDir, '.env.production'); + await fs.writeFile(envProductionPath, envProductionContent); + + console.log('✔ Console environment files updated'); + + // Start Docker containers + console.log('\n⏳ Starting Fleetbase containers...'); + console.log(' This may take a few minutes on first run...\n'); + + exec('docker compose up -d', { cwd: directory, maxBuffer: maxBuffer }, async (error, stdout, stderr) => { + if (error) { + console.error(`\n✖ Error starting containers: ${error.message}`); + if (stderr) console.error(stderr); + process.exit(1); + } + + console.log(stdout); + console.log('✔ Containers started'); + + // Wait for database + console.log('\n⏳ Waiting for database to be ready...'); + await new Promise(resolve => setTimeout(resolve, 15000)); // Wait 15 seconds + console.log('✔ Database should be ready'); + + // Run deploy script + console.log('\n⏳ Running deployment script...'); + exec('docker compose exec -T application bash -c "./deploy.sh"', { cwd: directory, maxBuffer: maxBuffer }, (deployError, deployStdout, deployStderr) => { + if (deployError) { + console.error(`\n✖ Error during deployment: ${deployError.message}`); + if (deployStderr) console.error(deployStderr); + console.log('\nℹ️ You may need to run the deployment manually:'); + console.log(' docker compose exec application bash -c "./deploy.sh"'); + } else { + console.log(deployStdout); + console.log('✔ Deployment complete'); + } + + // Restart containers to ensure all changes are applied + exec('docker compose up -d', { cwd: directory }, () => { + console.log('\n🏁 Fleetbase is up!'); + console.log(` API → ${schemeApi}://${host}:8000`); + console.log(` Console → ${schemeConsole}://${host}:4200\n`); + console.log('ℹ️ Default credentials:'); + console.log(' Email: admin@fleetbase.io'); + console.log(' Password: password\n'); + }); + }); + }); + } catch (error) { + console.error('\n✖ Installation failed:', error.message); + process.exit(1); + } +} + + + function loginCommand (options) { const npmLogin = require('npm-cli-login'); const username = options.username; @@ -979,6 +1172,14 @@ program .option('-n, --name ', 'Your full name (optional)') .action(registerCommand); +program + .command('install-fleetbase') + .description('Install Fleetbase using Docker') + .option('--host ', 'Host or IP address to bind to (default: localhost)') + .option('--environment ', 'Environment: development or production (default: development)') + .option('--directory ', 'Installation directory (default: current directory)') + .action(installFleetbaseCommand); + program .command('login') .description('Log in to the Fleetbase registry') From 7d9233fbaf7ae3aafef6c4881c547caaa7f1d1d9 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Mon, 23 Feb 2026 02:17:10 -0500 Subject: [PATCH 4/9] fix: Restore executable permission on index.js --- index.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 index.js diff --git a/index.js b/index.js old mode 100644 new mode 100755 From e63a888cf2353456176a236a5a838aef26324e7e Mon Sep 17 00:00:00 2001 From: Manus AI Date: Mon, 23 Feb 2026 02:32:56 -0500 Subject: [PATCH 5/9] feat: Auto-clone Fleetbase repository if not present The install-fleetbase command now automatically clones the Fleetbase repository into the target directory if docker-compose.yml is not found. This improves the user experience by eliminating the need to manually clone the repository before running the install command. Changes: - Automatically detects if Fleetbase files are missing - Clones repository using 'git clone' if needed - Creates target directory if it doesn't exist - Provides clear feedback during the cloning process - Gracefully handles clone failures with helpful error messages --- index.js | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index a867c85..41b7d0f 100755 --- a/index.js +++ b/index.js @@ -881,18 +881,29 @@ async function installFleetbaseCommand(options) { console.log(` HTTPS: ${useHttps}`); // Check if directory exists and has Fleetbase files - if (!await fs.pathExists(directory)) { - console.error(`\n✖ Directory does not exist: ${directory}`); - console.log('\nℹ️ Please clone the Fleetbase repository first:'); - console.log(' git clone https://github.com/fleetbase/fleetbase.git'); - process.exit(1); - } - const dockerComposePath = path.join(directory, 'docker-compose.yml'); - if (!await fs.pathExists(dockerComposePath)) { - console.error(`\n✖ docker-compose.yml not found in ${directory}`); - console.log('\nℹ️ Please ensure you are in the Fleetbase root directory.'); - process.exit(1); + const needsClone = !await fs.pathExists(dockerComposePath); + + if (needsClone) { + console.log('\n⏳ Fleetbase repository not found, cloning...'); + + // Ensure parent directory exists + await fs.ensureDir(directory); + + // Clone the repository + const { execSync } = require('child_process'); + try { + execSync('git clone https://github.com/fleetbase/fleetbase.git .', { + cwd: directory, + stdio: 'inherit' + }); + console.log('✔ Repository cloned successfully'); + } catch (error) { + console.error('\n✖ Failed to clone repository:', error.message); + console.log('\nℹ️ You can manually clone with:'); + console.log(' git clone https://github.com/fleetbase/fleetbase.git'); + process.exit(1); + } } // Generate APP_KEY From 117da69c5fc6736f7f1ad9638af74ef9cf83bd87 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Mon, 23 Feb 2026 04:35:30 -0500 Subject: [PATCH 6/9] feat: Add --host parameter to register command The register command now accepts a --host parameter to allow users to register against self-hosted Fleetbase instances instead of only the default api.fleetbase.io. Usage: flb register --host myinstance.com flb register -h myinstance.com Changes: - Added --host/-h option to register command - Defaults to api.fleetbase.io if not specified - Dynamically builds registration API URL based on host - Updates login suggestion to include --host if used during registration --- index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 41b7d0f..b672f8b 100755 --- a/index.js +++ b/index.js @@ -723,7 +723,8 @@ async function versionBump (options) { // Command to handle registration async function registerCommand(options) { - const registrationApi = 'https://api.fleetbase.io/~registry/v1/developer-account/register'; + const host = options.host || 'api.fleetbase.io'; + const registrationApi = `https://${host}/~registry/v1/developer-account/register`; try { // Collect registration information @@ -792,7 +793,8 @@ async function registerCommand(options) { if (response.data.status === 'success') { console.log('\n✓ Account created successfully!'); console.log('✓ Please check your email to verify your account.'); - console.log(`\n✓ Once verified, you can login with: flb login -u ${registrationData.username}`); + const loginCmd = options.host ? `flb login -u ${registrationData.username} --host ${options.host}` : `flb login -u ${registrationData.username}`; + console.log(`\n✓ Once verified, you can login with: ${loginCmd}`); } else { console.error('Registration failed:', response.data.message || 'Unknown error'); process.exit(1); @@ -1181,6 +1183,7 @@ program .option('-e, --email ', 'Email address') .option('-p, --password ', 'Password') .option('-n, --name ', 'Your full name (optional)') + .option('-h, --host ', 'API host (default: api.fleetbase.io)') .action(registerCommand); program From d7e9e88e658298526b17474f73541d9d16f3ae13 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Mon, 23 Feb 2026 04:51:10 -0500 Subject: [PATCH 7/9] fix: Support full URL with protocol in --host parameter The --host parameter now accepts full URLs with protocol (http:// or https://) instead of hardcoding https. This allows users to register against local development instances using http://localhost:8000. Changes: - Accept full URL: https://api.fleetbase.io or http://localhost:8000 - Auto-add https:// if protocol is missing (backward compatible) - Updated option description to clarify full URL format Examples: flb register --host https://api.fleetbase.io flb register --host http://localhost:8000 flb register --host myinstance.com (defaults to https://) --- index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index b672f8b..b03a30c 100755 --- a/index.js +++ b/index.js @@ -723,8 +723,10 @@ async function versionBump (options) { // Command to handle registration async function registerCommand(options) { - const host = options.host || 'api.fleetbase.io'; - const registrationApi = `https://${host}/~registry/v1/developer-account/register`; + const host = options.host || 'https://api.fleetbase.io'; + // Ensure host has protocol, add https:// if missing + const apiHost = host.startsWith('http://') || host.startsWith('https://') ? host : `https://${host}`; + const registrationApi = `${apiHost}/~registry/v1/developer-account/register`; try { // Collect registration information @@ -1183,7 +1185,7 @@ program .option('-e, --email ', 'Email address') .option('-p, --password ', 'Password') .option('-n, --name ', 'Your full name (optional)') - .option('-h, --host ', 'API host (default: api.fleetbase.io)') + .option('-h, --host ', 'API host with protocol (default: https://api.fleetbase.io)') .action(registerCommand); program From 88f85643bee3e755f0e1a29e86bf6d20f5116932 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Mon, 23 Feb 2026 04:55:05 -0500 Subject: [PATCH 8/9] fix: Handle both array and string error formats in register command Fixed TypeError when API returns error messages as strings instead of arrays. The error handling now properly handles both formats: - Array: ['error message 1', 'error message 2'] - String: 'error message' This prevents crashes when displaying validation errors from the API. --- index.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index b03a30c..22470a4 100755 --- a/index.js +++ b/index.js @@ -807,9 +807,15 @@ async function registerCommand(options) { if (errorData.errors) { console.error('\nRegistration failed with the following errors:'); Object.keys(errorData.errors).forEach(field => { - errorData.errors[field].forEach(message => { - console.error(` - ${field}: ${message}`); - }); + const fieldErrors = errorData.errors[field]; + // Handle both array and string error formats + if (Array.isArray(fieldErrors)) { + fieldErrors.forEach(message => { + console.error(` - ${field}: ${message}`); + }); + } else { + console.error(` - ${field}: ${fieldErrors}`); + } }); } else { console.error('Registration failed:', errorData.message || 'Unknown error'); From 037434b79744d1588571c5705d7728a13ccd7539 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Mon, 23 Feb 2026 05:01:18 -0500 Subject: [PATCH 9/9] debug: Add detailed logging to register command Added debug logging to help diagnose network request issues: - Log the constructed API endpoint URL - Log the request data being sent - Log detailed error information including error codes - Log when no response is received from server This will help identify if: - The URL is being constructed correctly - The request is actually being made - There are network connectivity issues - The server is responding --- index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.js b/index.js index 22470a4..c56d5ed 100755 --- a/index.js +++ b/index.js @@ -788,6 +788,8 @@ async function registerCommand(options) { }; console.log('\nRegistering account...'); + console.log(`API Endpoint: ${registrationApi}`); + console.log(`Request Data:`, JSON.stringify(registrationData, null, 2)); // Make API call to register const response = await axios.post(registrationApi, registrationData); @@ -802,6 +804,12 @@ async function registerCommand(options) { process.exit(1); } } catch (error) { + console.error('\n[DEBUG] Error caught:', error.message); + if (error.code) console.error('[DEBUG] Error code:', error.code); + if (error.request && !error.response) { + console.error('[DEBUG] No response received from server'); + console.error('[DEBUG] Request was made to:', registrationApi); + } if (error.response && error.response.data) { const errorData = error.response.data; if (errorData.errors) {