@_xtribe/cli 2.0.3 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Default entry point for npx @_xtribe/cli
5
+ * This runs the full installation process
6
+ */
7
+
8
+ // Execute the installer in a way that preserves require.main
9
+ const { spawn } = require('child_process');
10
+ const path = require('path');
11
+
12
+ const installerPath = path.join(__dirname, 'install-tribe.js');
13
+ const child = spawn(process.execPath, [installerPath, ...process.argv.slice(2)], {
14
+ stdio: 'inherit',
15
+ env: process.env
16
+ });
17
+
18
+ child.on('exit', (code) => {
19
+ process.exit(code || 0);
20
+ });
@@ -0,0 +1,272 @@
1
+ #!/usr/bin/env node
2
+
3
+ const os = require('os');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { spawn, execSync } = require('child_process');
7
+
8
+ // Import the existing installer
9
+ const originalInstaller = require('./install-tribe.js');
10
+
11
+ // Auto-launch specific functionality
12
+ const platform = os.platform();
13
+ const homeDir = os.homedir();
14
+ const tribeDir = path.join(homeDir, '.tribe');
15
+ const firstTimeMarker = path.join(tribeDir, '.first-install-complete');
16
+
17
+ // Color codes for output
18
+ const colors = {
19
+ reset: '\x1b[0m',
20
+ bright: '\x1b[1m',
21
+ green: '\x1b[32m',
22
+ yellow: '\x1b[33m',
23
+ blue: '\x1b[34m',
24
+ cyan: '\x1b[36m'
25
+ };
26
+
27
+ function log(message, color = '') {
28
+ console.log(color + message + colors.reset);
29
+ }
30
+
31
+ function sleep(ms) {
32
+ return new Promise(resolve => setTimeout(resolve, ms));
33
+ }
34
+
35
+ /**
36
+ * Check if we should auto-launch the interactive UI
37
+ */
38
+ function shouldAutoLaunch() {
39
+ // Check for command line flags
40
+ const args = process.argv.slice(2);
41
+ const noLaunchFlag = args.includes('--no-launch') || args.includes('--no-auto');
42
+ const launchFlag = args.includes('--launch') || args.includes('--auto');
43
+ const simpleFlag = args.includes('--simple');
44
+
45
+ if (noLaunchFlag || simpleFlag) {
46
+ return false;
47
+ }
48
+
49
+ if (launchFlag) {
50
+ return true;
51
+ }
52
+
53
+ // Auto-launch conditions:
54
+ // 1. Interactive terminal (TTY)
55
+ const isTTY = process.stdout.isTTY && process.stdin.isTTY;
56
+ if (!isTTY) {
57
+ return false;
58
+ }
59
+
60
+ // 2. Not in CI environment
61
+ const isCI = process.env.CI === 'true' ||
62
+ process.env.CONTINUOUS_INTEGRATION === 'true' ||
63
+ process.env.GITHUB_ACTIONS === 'true';
64
+ if (isCI) {
65
+ return false;
66
+ }
67
+
68
+ // 3. First time install (no marker file exists)
69
+ const isFirstTime = !fs.existsSync(firstTimeMarker);
70
+
71
+ return isFirstTime;
72
+ }
73
+
74
+ /**
75
+ * Get the path to the tribe binary
76
+ */
77
+ function getTribeBinaryPath() {
78
+ const tribeBinDir = path.join(homeDir, '.tribe', 'bin');
79
+ const tribePath = path.join(tribeBinDir, 'tribe');
80
+
81
+ if (fs.existsSync(tribePath)) {
82
+ return tribePath;
83
+ }
84
+
85
+ // Try global install
86
+ try {
87
+ return execSync('which tribe', { encoding: 'utf8' }).trim();
88
+ } catch {
89
+ throw new Error('Tribe binary not found');
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Check if the Tribe cluster is running
95
+ */
96
+ async function isClusterRunning() {
97
+ try {
98
+ const tribePath = getTribeBinaryPath();
99
+ const result = execSync(`${tribePath} --simple status`, { encoding: 'utf8' });
100
+ return result.includes('Cluster is running');
101
+ } catch {
102
+ return false;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Start the Tribe cluster
108
+ */
109
+ async function startCluster() {
110
+ const tribePath = getTribeBinaryPath();
111
+ log('\nStarting Tribe cluster...', colors.cyan);
112
+
113
+ try {
114
+ execSync(`${tribePath} --simple start`, { stdio: 'inherit' });
115
+
116
+ // Wait for cluster to be ready
117
+ log('Waiting for services to be ready...', colors.yellow);
118
+ let attempts = 0;
119
+ while (attempts < 30) {
120
+ await sleep(2000);
121
+ if (await isClusterRunning()) {
122
+ log('✅ Cluster is ready!', colors.green);
123
+ return true;
124
+ }
125
+ attempts++;
126
+ }
127
+
128
+ throw new Error('Cluster failed to start in time');
129
+ } catch (error) {
130
+ log('Failed to start cluster: ' + error.message, colors.reset);
131
+ return false;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Display the first-time welcome experience
137
+ */
138
+ async function showFirstTimeWelcome() {
139
+ console.log('\n' + colors.bright + colors.cyan + '🎉 Welcome to TRIBE!' + colors.reset);
140
+ console.log('\nYour AI development team is ready to help you build amazing software!\n');
141
+
142
+ console.log('Meet your AI agents:');
143
+ console.log(' 🎨 ' + colors.bright + 'Pixel' + colors.reset + ' - Creative Design & UI/UX');
144
+ console.log(' ⚡ ' + colors.bright + 'Spark' + colors.reset + ' - Implementation & Performance');
145
+ console.log(' 🌟 ' + colors.bright + 'Nova' + colors.reset + ' - Architecture & Strategy');
146
+ console.log(' 🧘 ' + colors.bright + 'Zen' + colors.reset + ' - Testing & Quality');
147
+ console.log(' 🔥 ' + colors.bright + 'Blaze' + colors.reset + ' - DevOps & Infrastructure');
148
+ console.log(' 🌌 ' + colors.bright + 'Cosmos' + colors.reset + ' - Data & Analytics');
149
+ console.log(' 🔊 ' + colors.bright + 'Echo' + colors.reset + ' - API & Integration');
150
+ console.log(' ⚛️ ' + colors.bright + 'Quantum' + colors.reset + ' - Security & Cryptography');
151
+
152
+ console.log('\n' + colors.yellow + 'Launching interactive mode...' + colors.reset);
153
+ await sleep(2000);
154
+ }
155
+
156
+ /**
157
+ * Launch the Tribe interactive UI
158
+ */
159
+ async function launchTribeInteractive() {
160
+ const tribePath = getTribeBinaryPath();
161
+
162
+ // Clear the screen for a clean start
163
+ if (platform !== 'win32') {
164
+ process.stdout.write('\x1Bc');
165
+ }
166
+
167
+ // Launch tribe in interactive mode (default when no args)
168
+ const child = spawn(tribePath, [], {
169
+ stdio: 'inherit',
170
+ env: {
171
+ ...process.env,
172
+ TERM: process.env.TERM || 'xterm-256color'
173
+ }
174
+ });
175
+
176
+ // Handle child process exit
177
+ child.on('exit', (code) => {
178
+ if (code !== 0) {
179
+ console.error(`\nTribe exited with code ${code}`);
180
+ }
181
+ process.exit(code || 0);
182
+ });
183
+
184
+ // Handle errors
185
+ child.on('error', (err) => {
186
+ console.error('Failed to launch Tribe:', err.message);
187
+ showManualInstructions();
188
+ process.exit(1);
189
+ });
190
+ }
191
+
192
+ /**
193
+ * Show manual launch instructions
194
+ */
195
+ function showManualInstructions() {
196
+ console.log('\n' + colors.yellow + 'To start Tribe manually:' + colors.reset);
197
+ console.log(' ' + colors.green + 'tribe' + colors.reset + ' # Interactive mode');
198
+ console.log(' ' + colors.green + 'tribe --simple' + colors.reset + ' # Simple CLI mode');
199
+ console.log(' ' + colors.green + 'tribe --help' + colors.reset + ' # Show all options\n');
200
+ }
201
+
202
+ /**
203
+ * Mark first install as complete
204
+ */
205
+ function markFirstInstallComplete() {
206
+ if (!fs.existsSync(tribeDir)) {
207
+ fs.mkdirSync(tribeDir, { recursive: true });
208
+ }
209
+ fs.writeFileSync(firstTimeMarker, new Date().toISOString());
210
+ }
211
+
212
+ /**
213
+ * Main auto-launch handler
214
+ */
215
+ async function handleAutoLaunch() {
216
+ // Only proceed if we should auto-launch
217
+ if (!shouldAutoLaunch()) {
218
+ showManualInstructions();
219
+ return;
220
+ }
221
+
222
+ try {
223
+ // Check if this is first time
224
+ const isFirstTime = !fs.existsSync(firstTimeMarker);
225
+
226
+ // Show welcome for first-time users
227
+ if (isFirstTime) {
228
+ await showFirstTimeWelcome();
229
+ } else {
230
+ log('\nLaunching TRIBE interactive mode...', colors.cyan);
231
+ await sleep(1000);
232
+ }
233
+
234
+ // Check and start cluster if needed (skip if --no-start was used)
235
+ const args = process.argv.slice(2);
236
+ const skipCluster = args.includes('--skip-cluster') || args.includes('--no-start');
237
+
238
+ if (!skipCluster && !await isClusterRunning()) {
239
+ const started = await startCluster();
240
+ if (!started) {
241
+ showManualInstructions();
242
+ return;
243
+ }
244
+ }
245
+
246
+ // Mark first install complete before launching
247
+ if (isFirstTime) {
248
+ markFirstInstallComplete();
249
+ }
250
+
251
+ // Launch the interactive UI
252
+ await launchTribeInteractive();
253
+
254
+ } catch (error) {
255
+ console.error('\n' + colors.reset + 'Could not launch Tribe automatically.');
256
+ console.error('Error:', error.message);
257
+ showManualInstructions();
258
+ }
259
+ }
260
+
261
+ // Export for use in main installer
262
+ module.exports = {
263
+ shouldAutoLaunch,
264
+ handleAutoLaunch,
265
+ showManualInstructions,
266
+ markFirstInstallComplete
267
+ };
268
+
269
+ // If run directly (for testing)
270
+ if (require.main === module) {
271
+ handleAutoLaunch();
272
+ }
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const { execSync } = require('child_process');
7
+ const https = require('https');
8
+ const http = require('http');
9
+
10
+ const platform = os.platform();
11
+ const arch = process.arch === 'x64' ? 'amd64' : process.arch;
12
+ const homeDir = os.homedir();
13
+ const tribeDir = path.join(homeDir, '.tribe');
14
+ const binDir = path.join(tribeDir, 'bin');
15
+
16
+ console.log(`TRIBE Minimal Installer - Linux MVP`);
17
+ console.log(`Platform: ${platform} (${arch})`);
18
+ console.log(`Installing to: ${binDir}`);
19
+
20
+ // Create bin directory
21
+ if (!fs.existsSync(binDir)) {
22
+ fs.mkdirSync(binDir, { recursive: true });
23
+ }
24
+
25
+ // Download function
26
+ async function downloadFile(url, dest) {
27
+ return new Promise((resolve, reject) => {
28
+ const file = fs.createWriteStream(dest);
29
+ const protocol = url.startsWith('https') ? https : http;
30
+
31
+ console.log(`Downloading from: ${url}`);
32
+
33
+ const request = protocol.get(url, (response) => {
34
+ if (response.statusCode === 302 || response.statusCode === 301) {
35
+ file.close();
36
+ fs.unlinkSync(dest);
37
+ return downloadFile(response.headers.location, dest).then(resolve).catch(reject);
38
+ }
39
+
40
+ if (response.statusCode !== 200) {
41
+ file.close();
42
+ fs.unlinkSync(dest);
43
+ reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
44
+ return;
45
+ }
46
+
47
+ response.pipe(file);
48
+
49
+ file.on('finish', () => {
50
+ file.close();
51
+ resolve();
52
+ });
53
+ }).on('error', (err) => {
54
+ fs.unlinkSync(dest);
55
+ reject(err);
56
+ });
57
+ });
58
+ }
59
+
60
+ async function installTribe() {
61
+ const tribeDest = path.join(binDir, 'tribe');
62
+
63
+ // If TRIBE_TEST_BINARY is set, copy it instead of downloading
64
+ if (process.env.TRIBE_TEST_BINARY && fs.existsSync(process.env.TRIBE_TEST_BINARY)) {
65
+ console.log('Using test binary from:', process.env.TRIBE_TEST_BINARY);
66
+ fs.copyFileSync(process.env.TRIBE_TEST_BINARY, tribeDest);
67
+ fs.chmodSync(tribeDest, '755');
68
+ console.log('✓ TRIBE CLI installed from test binary');
69
+ return true;
70
+ }
71
+
72
+ // Download from GitHub releases
73
+ const url = `https://github.com/TRIBE-INC/releases/releases/latest/download/tribe-${platform}-${arch}`;
74
+
75
+ try {
76
+ await downloadFile(url, tribeDest);
77
+
78
+ const stats = fs.statSync(tribeDest);
79
+ console.log(`Downloaded file size: ${stats.size} bytes`);
80
+
81
+ if (stats.size < 1000000) { // Less than 1MB is suspiciously small
82
+ throw new Error('Downloaded file is too small, likely not a valid binary');
83
+ }
84
+
85
+ fs.chmodSync(tribeDest, '755');
86
+
87
+ // Try to run version
88
+ try {
89
+ const version = execSync(`${tribeDest} version`, { encoding: 'utf8' });
90
+ console.log(`✓ TRIBE CLI installed successfully: ${version.trim()}`);
91
+ } catch (e) {
92
+ console.log('✓ TRIBE CLI installed (version check failed - may need different architecture)');
93
+ }
94
+
95
+ return true;
96
+ } catch (error) {
97
+ console.error(`✗ Failed to install TRIBE CLI: ${error.message}`);
98
+ if (fs.existsSync(tribeDest)) {
99
+ fs.unlinkSync(tribeDest);
100
+ }
101
+ return false;
102
+ }
103
+ }
104
+
105
+ // Update PATH
106
+ function updatePath() {
107
+ // Create tribe-env.sh script
108
+ const tribeEnvPath = path.join(tribeDir, 'tribe-env.sh');
109
+ const envScriptContent = `#!/bin/bash
110
+ # TRIBE CLI Environment Setup
111
+ # Auto-generated by TRIBE installer
112
+
113
+ # Add TRIBE bin directory to PATH if not already present
114
+ TRIBE_BIN_DIR="$HOME/.tribe/bin"
115
+
116
+ if [[ -d "$TRIBE_BIN_DIR" ]] && [[ ":$PATH:" != *":$TRIBE_BIN_DIR:"* ]]; then
117
+ export PATH="$TRIBE_BIN_DIR:$PATH"
118
+ fi
119
+ `;
120
+
121
+ try {
122
+ fs.writeFileSync(tribeEnvPath, envScriptContent);
123
+ fs.chmodSync(tribeEnvPath, '755');
124
+ console.log('✓ Created tribe-env.sh environment script');
125
+ } catch (error) {
126
+ console.log(`⚠ Failed to create tribe-env.sh: ${error.message}`);
127
+ return;
128
+ }
129
+
130
+ // Update shell config
131
+ const shell = process.env.SHELL || '/bin/bash';
132
+ const rcFile = shell.includes('zsh') ? '.zshrc' : '.bashrc';
133
+ const rcPath = path.join(homeDir, rcFile);
134
+ const sourceCommand = 'source ~/.tribe/tribe-env.sh';
135
+
136
+ try {
137
+ const rcContent = fs.existsSync(rcPath) ? fs.readFileSync(rcPath, 'utf8') : '';
138
+ if (!rcContent.includes(sourceCommand)) {
139
+ fs.appendFileSync(rcPath, `\n# TRIBE CLI\n${sourceCommand}\n`);
140
+ console.log(`✓ Updated ${rcFile} to source tribe-env.sh`);
141
+ } else {
142
+ console.log(`✓ ${rcFile} already configured`);
143
+ }
144
+ } catch (error) {
145
+ console.log(`⚠ Failed to update ${rcFile}: ${error.message}`);
146
+ console.log('Please manually add this line to your shell config:');
147
+ console.log(` ${sourceCommand}`);
148
+ }
149
+ }
150
+
151
+ // Main
152
+ async function main() {
153
+ updatePath();
154
+ const success = await installTribe();
155
+
156
+ if (success) {
157
+ console.log('\n✓ Installation complete!');
158
+ console.log(`\nNext steps:`);
159
+ console.log(`1. Run: source ~/.${process.env.SHELL?.includes('zsh') ? 'zshrc' : 'bashrc'}`);
160
+ console.log(`2. Run: tribe version`);
161
+ process.exit(0);
162
+ } else {
163
+ console.error('\n✗ Installation failed');
164
+ process.exit(1);
165
+ }
166
+ }
167
+
168
+ main().catch(err => {
169
+ console.error('Installation error:', err);
170
+ process.exit(1);
171
+ });