@_xtribe/cli 2.0.7 → 2.1.0
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/install-tribe.js +89 -423
- package/package.json +2 -2
package/install-tribe.js
CHANGED
|
@@ -4,13 +4,9 @@ const os = require('os');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const https = require('https');
|
|
7
|
-
const { execSync
|
|
8
|
-
const readline = require('readline');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
9
8
|
const chalk = require('chalk');
|
|
10
9
|
const ora = require('ora');
|
|
11
|
-
const which = require('which');
|
|
12
|
-
const fetch = require('node-fetch');
|
|
13
|
-
const crypto = require('crypto');
|
|
14
10
|
|
|
15
11
|
// ASCII art for TRIBE
|
|
16
12
|
const asciiArt = `
|
|
@@ -23,20 +19,15 @@ const asciiArt = `
|
|
|
23
19
|
║ ██║ ██║ ██║██║██████╔╝███████╗ ║
|
|
24
20
|
║ ╚═╝ ╚═╝ ╚═╝╚═╝╚═════╝ ╚══════╝ ║
|
|
25
21
|
║ ║
|
|
26
|
-
║
|
|
22
|
+
║ Empower Your AI Agents • Become 10x Faster ║
|
|
27
23
|
║ ║
|
|
28
24
|
╚══════════════════════════════════════════════════════════════════╝`;
|
|
29
25
|
|
|
30
|
-
// Track shown warnings to prevent duplicates
|
|
31
|
-
const shownWarnings = new Set();
|
|
32
|
-
|
|
33
26
|
const platform = os.platform();
|
|
34
|
-
const
|
|
35
|
-
const arch = nodeArch === 'x64' ? 'amd64' : (nodeArch === 'arm64' || nodeArch === 'aarch64' ? 'arm64' : nodeArch);
|
|
27
|
+
const arch = os.arch() === 'x64' ? 'amd64' : (os.arch() === 'arm64' ? 'arm64' : os.arch());
|
|
36
28
|
const homeDir = os.homedir();
|
|
37
29
|
const tribeDir = path.join(homeDir, '.tribe');
|
|
38
30
|
const tribeBinDir = path.join(tribeDir, 'bin');
|
|
39
|
-
const binDir = tribeBinDir;
|
|
40
31
|
|
|
41
32
|
// Ensure directories exist
|
|
42
33
|
if (!fs.existsSync(tribeDir)) {
|
|
@@ -46,30 +37,17 @@ if (!fs.existsSync(tribeBinDir)) {
|
|
|
46
37
|
fs.mkdirSync(tribeBinDir, { recursive: true });
|
|
47
38
|
}
|
|
48
39
|
|
|
49
|
-
const log = {
|
|
50
|
-
success: (msg) => console.log(chalk.green('✓'), msg),
|
|
51
|
-
error: (msg) => console.log(chalk.red('✗'), msg),
|
|
52
|
-
warning: (msg) => {
|
|
53
|
-
// Check if we've already shown this warning
|
|
54
|
-
if (!shownWarnings.has(msg)) {
|
|
55
|
-
console.log(chalk.yellow('⚠'), msg);
|
|
56
|
-
shownWarnings.add(msg);
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
info: (msg) => console.log(chalk.blue('ℹ'), msg),
|
|
60
|
-
step: (msg) => console.log(chalk.cyan('→'), msg)
|
|
61
|
-
};
|
|
62
|
-
|
|
63
40
|
function showWelcome() {
|
|
64
41
|
console.clear();
|
|
65
42
|
console.log(chalk.cyan(asciiArt));
|
|
66
43
|
console.log(chalk.bold('\n🚀 Welcome to TRIBE\n'));
|
|
67
|
-
console.log('
|
|
68
|
-
|
|
69
|
-
console.log('
|
|
70
|
-
console.log('
|
|
71
|
-
console.log('
|
|
72
|
-
console.log('
|
|
44
|
+
console.log(chalk.bold('Track • Measure • Optimize Your AI Coding Agents\n'));
|
|
45
|
+
|
|
46
|
+
console.log('TRIBE empowers your AI development workflow by:');
|
|
47
|
+
console.log(' 📊 Tracking usage of Claude, Cursor, Copilot & more');
|
|
48
|
+
console.log(' 📈 Measuring productivity gains and patterns');
|
|
49
|
+
console.log(' ⚡ Optimizing how you work with AI agents');
|
|
50
|
+
console.log(' 🎯 Providing insights to make you 10x faster\n');
|
|
73
51
|
|
|
74
52
|
console.log(chalk.gray(`Platform: ${platform} (${arch})`));
|
|
75
53
|
console.log(chalk.gray(`Node: ${process.version}\n`));
|
|
@@ -77,79 +55,37 @@ function showWelcome() {
|
|
|
77
55
|
|
|
78
56
|
function showInstallationSummary() {
|
|
79
57
|
console.log('\n' + '═'.repeat(70));
|
|
80
|
-
console.log(chalk.green.bold('\n✨ TRIBE
|
|
81
|
-
|
|
82
|
-
console.log('📋
|
|
83
|
-
console.log(' ✓
|
|
84
|
-
console.log(' ✓
|
|
85
|
-
console.log(' ✓
|
|
86
|
-
|
|
87
|
-
console.log(chalk.bold('🎯
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
console.log('
|
|
104
|
-
console.log(
|
|
105
|
-
console.log(chalk.cyan(' tribe enable') + ' # Start telemetry');
|
|
106
|
-
console.log(chalk.cyan(' tribe status') + ' # Check your setup\n');
|
|
58
|
+
console.log(chalk.green.bold('\n✨ TRIBE Telemetry Ready!\n'));
|
|
59
|
+
|
|
60
|
+
console.log('📋 What We Installed:');
|
|
61
|
+
console.log(' ✓ TRIBE CLI for telemetry collection');
|
|
62
|
+
console.log(' ✓ Configuration in ~/.tribe directory');
|
|
63
|
+
console.log(' ✓ Automatic PATH setup\n');
|
|
64
|
+
|
|
65
|
+
console.log(chalk.bold('🎯 AI Agents We Track:'));
|
|
66
|
+
console.log(' 🤖 Claude (Anthropic)');
|
|
67
|
+
console.log(' ⚡ Cursor');
|
|
68
|
+
console.log(' 🐙 GitHub Copilot');
|
|
69
|
+
console.log(' 🧠 ChatGPT');
|
|
70
|
+
console.log(' 💻 Codeium');
|
|
71
|
+
console.log(' 🦾 And more...\n');
|
|
72
|
+
|
|
73
|
+
console.log(chalk.bold('🚀 Get Started in 3 Steps:'));
|
|
74
|
+
console.log(chalk.cyan(' 1. tribe login') + ' # Connect your account');
|
|
75
|
+
console.log(chalk.cyan(' 2. tribe enable') + ' # Start tracking');
|
|
76
|
+
console.log(chalk.cyan(' 3. tribe status') + ' # View your metrics\n');
|
|
77
|
+
|
|
78
|
+
console.log(chalk.bold('💡 What Happens Next:'));
|
|
79
|
+
console.log(' • TRIBE automatically tracks your AI agent usage');
|
|
80
|
+
console.log(' • View insights at https://tribecode.ai/dashboard');
|
|
81
|
+
console.log(' • Get weekly reports on your productivity gains');
|
|
82
|
+
console.log(' • Join the community of 10x developers\n');
|
|
107
83
|
|
|
108
84
|
console.log(chalk.gray('Documentation: https://tribecode.ai/docs'));
|
|
109
|
-
console.log(chalk.gray('Support:
|
|
85
|
+
console.log(chalk.gray('Support: hello@tribecode.ai'));
|
|
110
86
|
console.log('\n' + '═'.repeat(70) + '\n');
|
|
111
87
|
}
|
|
112
88
|
|
|
113
|
-
async function checkCommand(cmd) {
|
|
114
|
-
try {
|
|
115
|
-
await which(cmd);
|
|
116
|
-
return true;
|
|
117
|
-
} catch {
|
|
118
|
-
const cmdPath = path.join(tribeBinDir, cmd);
|
|
119
|
-
try {
|
|
120
|
-
await fs.promises.access(cmdPath, fs.constants.X_OK);
|
|
121
|
-
return true;
|
|
122
|
-
} catch {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function findCommand(cmd) {
|
|
129
|
-
const possiblePaths = [
|
|
130
|
-
path.join(binDir, cmd),
|
|
131
|
-
path.join('/opt/homebrew/bin', cmd),
|
|
132
|
-
path.join('/usr/local/bin', cmd),
|
|
133
|
-
cmd
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const cmdPath = await which(cmd);
|
|
138
|
-
return cmdPath;
|
|
139
|
-
} catch {
|
|
140
|
-
for (const cmdPath of possiblePaths) {
|
|
141
|
-
try {
|
|
142
|
-
await fs.promises.access(cmdPath, fs.constants.X_OK);
|
|
143
|
-
return cmdPath;
|
|
144
|
-
} catch {
|
|
145
|
-
// Continue searching
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
89
|
async function downloadFile(url, dest) {
|
|
154
90
|
return new Promise((resolve, reject) => {
|
|
155
91
|
const file = fs.createWriteStream(dest);
|
|
@@ -158,173 +94,39 @@ async function downloadFile(url, dest) {
|
|
|
158
94
|
return downloadFile(response.headers.location, dest).then(resolve, reject);
|
|
159
95
|
}
|
|
160
96
|
if (response.statusCode !== 200) {
|
|
161
|
-
reject(new Error(`HTTP ${response.statusCode}
|
|
97
|
+
reject(new Error(`HTTP ${response.statusCode}`));
|
|
162
98
|
return;
|
|
163
99
|
}
|
|
164
100
|
response.pipe(file);
|
|
165
|
-
file.on('finish',
|
|
101
|
+
file.on('finish', () => {
|
|
166
102
|
file.close();
|
|
167
|
-
|
|
168
|
-
// Check for pointer files
|
|
169
|
-
const stats = fs.statSync(dest);
|
|
170
|
-
if (stats.size < 500) {
|
|
171
|
-
const content = fs.readFileSync(dest, 'utf8').trim();
|
|
172
|
-
if (content.match(/^[\w\-\/]+$/) && !content.includes('<!DOCTYPE') && !content.includes('<html')) {
|
|
173
|
-
let actualBinaryUrl;
|
|
174
|
-
|
|
175
|
-
if (content.startsWith('http')) {
|
|
176
|
-
actualBinaryUrl = content;
|
|
177
|
-
} else if (content.includes('/')) {
|
|
178
|
-
const baseUrl = url.substring(0, url.lastIndexOf('/'));
|
|
179
|
-
actualBinaryUrl = `${baseUrl}/${content}`;
|
|
180
|
-
} else {
|
|
181
|
-
const baseUrl = url.substring(0, url.lastIndexOf('/'));
|
|
182
|
-
actualBinaryUrl = `${baseUrl}/${content}`;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
fs.unlinkSync(dest);
|
|
186
|
-
await downloadFile(actualBinaryUrl, dest);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
103
|
resolve();
|
|
191
104
|
});
|
|
192
105
|
}).on('error', reject);
|
|
193
106
|
});
|
|
194
107
|
}
|
|
195
108
|
|
|
196
|
-
async function installColima() {
|
|
197
|
-
if (platform !== 'darwin') {
|
|
198
|
-
return true;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const existingColima = await findCommand('colima');
|
|
202
|
-
if (existingColima) {
|
|
203
|
-
console.log(`🐳 Colima ${chalk.gray('(already installed)')}`);
|
|
204
|
-
return true;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const spinner = ora('🐳 Installing Colima...').start();
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
// Try Homebrew first
|
|
211
|
-
try {
|
|
212
|
-
execSync('brew --version', { stdio: 'ignore' });
|
|
213
|
-
execSync('brew install colima', { stdio: 'ignore' });
|
|
214
|
-
spinner.succeed('Colima installed');
|
|
215
|
-
return true;
|
|
216
|
-
} catch {
|
|
217
|
-
// Continue with direct download
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Direct download
|
|
221
|
-
const colimaUrl = `https://github.com/abiosoft/colima/releases/latest/download/colima-${platform}-${arch}`;
|
|
222
|
-
const colimaDest = path.join(binDir, 'colima');
|
|
223
|
-
|
|
224
|
-
await downloadFile(colimaUrl, colimaDest);
|
|
225
|
-
fs.chmodSync(colimaDest, '755');
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
execSync(`xattr -d com.apple.quarantine ${colimaDest}`, { stdio: 'ignore' });
|
|
229
|
-
} catch {
|
|
230
|
-
// Quarantine attribute may not exist
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
spinner.succeed('Colima installed');
|
|
234
|
-
return true;
|
|
235
|
-
} catch (error) {
|
|
236
|
-
spinner.fail(`Colima installation failed: ${error.message}`);
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function installKubectl() {
|
|
242
|
-
if (await checkCommand('kubectl')) {
|
|
243
|
-
console.log(`☸️ kubectl ${chalk.gray('(already installed)')}`);
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const spinner = ora('☸️ Installing kubectl...').start();
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
const versionResponse = await fetch('https://dl.k8s.io/release/stable.txt');
|
|
251
|
-
const version = await versionResponse.text();
|
|
252
|
-
const kubectlUrl = `https://dl.k8s.io/release/${version.trim()}/bin/${platform}/${arch}/kubectl`;
|
|
253
|
-
const kubectlDest = path.join(binDir, 'kubectl');
|
|
254
|
-
|
|
255
|
-
await downloadFile(kubectlUrl, kubectlDest);
|
|
256
|
-
fs.chmodSync(kubectlDest, '755');
|
|
257
|
-
|
|
258
|
-
spinner.succeed('kubectl installed');
|
|
259
|
-
return true;
|
|
260
|
-
} catch (error) {
|
|
261
|
-
spinner.fail(`kubectl installation failed: ${error.message}`);
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
109
|
async function installTribeCLI() {
|
|
267
110
|
const tribeDest = path.join(tribeBinDir, 'tribe');
|
|
268
111
|
|
|
269
|
-
// Check if
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
const spinner = ora(isUpdate ? '🚀 Updating TRIBE CLI...' : '🚀 Installing TRIBE CLI...').start();
|
|
112
|
+
// Check if update needed
|
|
113
|
+
const exists = fs.existsSync(tribeDest);
|
|
114
|
+
const spinner = ora(exists ? '🔄 Updating TRIBE CLI...' : '📥 Installing TRIBE CLI...').start();
|
|
274
115
|
|
|
275
116
|
try {
|
|
276
117
|
// Remove existing if present
|
|
277
|
-
if (
|
|
118
|
+
if (exists) {
|
|
278
119
|
fs.unlinkSync(tribeDest);
|
|
279
120
|
}
|
|
280
121
|
|
|
281
|
-
// Check for local binary first
|
|
282
|
-
const localBinary = path.join(__dirname, 'tribe');
|
|
283
|
-
if (fs.existsSync(localBinary)) {
|
|
284
|
-
fs.copyFileSync(localBinary, tribeDest);
|
|
285
|
-
fs.chmodSync(tribeDest, '755');
|
|
286
|
-
spinner.succeed(isUpdate ? 'TRIBE CLI updated' : 'TRIBE CLI installed');
|
|
287
|
-
return true;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
122
|
// Download from GitHub
|
|
291
|
-
const githubRepo =
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
let downloadUrl = '';
|
|
295
|
-
|
|
296
|
-
try {
|
|
297
|
-
const response = await fetch(`https://api.github.com/repos/${githubRepo}/releases`, {
|
|
298
|
-
headers: {
|
|
299
|
-
'User-Agent': 'TRIBE-Installer',
|
|
300
|
-
...(process.env.GITHUB_TOKEN ? { 'Authorization': `token ${process.env.GITHUB_TOKEN}` } : {})
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
if (response.ok) {
|
|
305
|
-
const releases = await response.json();
|
|
306
|
-
if (releases && releases.length > 0) {
|
|
307
|
-
const asset = releases[0].assets?.find(a =>
|
|
308
|
-
a.name === `tribe-${platform}-${arch}` ||
|
|
309
|
-
a.name === `tribe-${platform}-${arch}.exe`
|
|
310
|
-
);
|
|
311
|
-
if (asset) {
|
|
312
|
-
downloadUrl = asset.browser_download_url;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
} catch {
|
|
317
|
-
// Fallback to direct URL
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (!downloadUrl) {
|
|
321
|
-
downloadUrl = `https://github.com/${githubRepo}/releases/latest/download/tribe-${platform}-${arch}`;
|
|
322
|
-
}
|
|
123
|
+
const githubRepo = 'TRIBE-INC/releases';
|
|
124
|
+
const downloadUrl = `https://github.com/${githubRepo}/releases/latest/download/tribe-${platform}-${arch}`;
|
|
323
125
|
|
|
324
126
|
await downloadFile(downloadUrl, tribeDest);
|
|
325
127
|
fs.chmodSync(tribeDest, '755');
|
|
326
128
|
|
|
327
|
-
// Remove macOS quarantine
|
|
129
|
+
// Remove macOS quarantine if needed
|
|
328
130
|
if (platform === 'darwin') {
|
|
329
131
|
try {
|
|
330
132
|
execSync(`xattr -d com.apple.quarantine "${tribeDest}"`, { stdio: 'ignore' });
|
|
@@ -333,160 +135,48 @@ async function installTribeCLI() {
|
|
|
333
135
|
}
|
|
334
136
|
}
|
|
335
137
|
|
|
336
|
-
spinner.succeed(
|
|
138
|
+
spinner.succeed(exists ? 'TRIBE CLI updated' : 'TRIBE CLI installed');
|
|
337
139
|
return true;
|
|
338
140
|
} catch (error) {
|
|
339
|
-
spinner.fail(`
|
|
141
|
+
spinner.fail(`Installation failed: ${error.message}`);
|
|
340
142
|
return false;
|
|
341
143
|
}
|
|
342
144
|
}
|
|
343
145
|
|
|
344
|
-
async function
|
|
345
|
-
const
|
|
146
|
+
async function setupPath() {
|
|
147
|
+
const spinner = ora('🔧 Setting up PATH...').start();
|
|
346
148
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
149
|
+
try {
|
|
150
|
+
// Create PATH script
|
|
151
|
+
const envScript = `#!/bin/bash
|
|
152
|
+
# TRIBE CLI Environment
|
|
350
153
|
TRIBE_BIN_DIR="$HOME/.tribe/bin"
|
|
351
|
-
|
|
352
154
|
if [[ -d "$TRIBE_BIN_DIR" ]] && [[ ":$PATH:" != *":$TRIBE_BIN_DIR:"* ]]; then
|
|
353
155
|
export PATH="$TRIBE_BIN_DIR:$PATH"
|
|
354
|
-
fi
|
|
355
|
-
|
|
356
|
-
command -v tribe &> /dev/null || true
|
|
357
|
-
`;
|
|
358
|
-
|
|
359
|
-
fs.writeFileSync(envScriptDest, envScriptContent);
|
|
360
|
-
fs.chmodSync(envScriptDest, '755');
|
|
361
|
-
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
async function setupGlobalNpmCommand() {
|
|
366
|
-
try {
|
|
367
|
-
const tempDir = path.join(os.tmpdir(), 'tribe-global-install-' + Date.now());
|
|
368
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
156
|
+
fi`;
|
|
369
157
|
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
description: 'TRIBE CLI global command',
|
|
374
|
-
bin: {
|
|
375
|
-
tribe: './tribe-wrapper.js'
|
|
376
|
-
},
|
|
377
|
-
files: ['tribe-wrapper.js'],
|
|
378
|
-
private: true
|
|
379
|
-
};
|
|
158
|
+
const envScriptPath = path.join(tribeDir, 'tribe-env.sh');
|
|
159
|
+
fs.writeFileSync(envScriptPath, envScript);
|
|
160
|
+
fs.chmodSync(envScriptPath, '755');
|
|
380
161
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
162
|
+
// Try to add to shell config
|
|
163
|
+
const shellConfig = process.env.SHELL?.includes('zsh') ? '.zshrc' : '.bashrc';
|
|
164
|
+
const rcPath = path.join(homeDir, shellConfig);
|
|
165
|
+
const sourceLine = 'source ~/.tribe/tribe-env.sh';
|
|
385
166
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const path = require('path');
|
|
391
|
-
const os = require('os');
|
|
392
|
-
|
|
393
|
-
const tribeBinaryPath = path.join(os.homedir(), '.tribe', 'bin', 'tribe');
|
|
394
|
-
|
|
395
|
-
if (!fs.existsSync(tribeBinaryPath)) {
|
|
396
|
-
console.error('Error: TRIBE CLI binary not found.');
|
|
397
|
-
console.error('Please reinstall using: npx @_xtribe/cli@latest');
|
|
398
|
-
process.exit(1);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
try {
|
|
402
|
-
fs.accessSync(tribeBinaryPath, fs.constants.X_OK);
|
|
403
|
-
} catch (err) {
|
|
404
|
-
console.error('Error: TRIBE CLI binary is not executable.');
|
|
405
|
-
console.error('Please reinstall using: npx @_xtribe/cli@latest');
|
|
406
|
-
process.exit(1);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const child = spawn(tribeBinaryPath, process.argv.slice(2), {
|
|
410
|
-
stdio: 'inherit',
|
|
411
|
-
env: process.env
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
child.on('exit', (code) => {
|
|
415
|
-
process.exit(code || 0);
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
child.on('error', (err) => {
|
|
419
|
-
if (err.code === 'ENOENT') {
|
|
420
|
-
console.error('Error: TRIBE CLI binary not found at expected location.');
|
|
421
|
-
console.error('Please reinstall using: npx @_xtribe/cli@latest');
|
|
422
|
-
} else {
|
|
423
|
-
console.error('Failed to execute tribe:', err.message);
|
|
424
|
-
}
|
|
425
|
-
process.exit(1);
|
|
426
|
-
});`;
|
|
427
|
-
|
|
428
|
-
const wrapperPath = path.join(tempDir, 'tribe-wrapper.js');
|
|
429
|
-
fs.writeFileSync(wrapperPath, wrapperScript);
|
|
430
|
-
fs.chmodSync(wrapperPath, '755');
|
|
431
|
-
|
|
432
|
-
try {
|
|
433
|
-
execSync('npm install -g . --force', {
|
|
434
|
-
cwd: tempDir,
|
|
435
|
-
stdio: 'pipe'
|
|
436
|
-
});
|
|
437
|
-
} catch (error) {
|
|
438
|
-
if (error.message.includes('EACCES') || error.message.includes('permission')) {
|
|
439
|
-
try {
|
|
440
|
-
execSync('sudo npm install -g . --force', {
|
|
441
|
-
cwd: tempDir,
|
|
442
|
-
stdio: 'inherit'
|
|
443
|
-
});
|
|
444
|
-
} catch {
|
|
445
|
-
// Ignore errors
|
|
446
|
-
}
|
|
167
|
+
if (fs.existsSync(rcPath)) {
|
|
168
|
+
const content = fs.readFileSync(rcPath, 'utf8');
|
|
169
|
+
if (!content.includes(sourceLine)) {
|
|
170
|
+
fs.appendFileSync(rcPath, `\n# TRIBE CLI\n${sourceLine}\n`);
|
|
447
171
|
}
|
|
448
172
|
}
|
|
449
173
|
|
|
450
|
-
|
|
451
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
452
|
-
} catch {
|
|
453
|
-
// Ignore cleanup errors
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
return true;
|
|
457
|
-
} catch {
|
|
458
|
-
return false;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
async function startColimaWithKubernetes() {
|
|
463
|
-
const spinner = ora('🌟 Starting container runtime...').start();
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
const colimaPath = await findCommand('colima') || path.join(binDir, 'colima');
|
|
467
|
-
|
|
468
|
-
// Check if running
|
|
469
|
-
try {
|
|
470
|
-
const status = execSync(`${colimaPath} status 2>&1`, { encoding: 'utf8' });
|
|
471
|
-
if (status.includes('is running')) {
|
|
472
|
-
spinner.succeed('Container runtime ready');
|
|
473
|
-
return true;
|
|
474
|
-
}
|
|
475
|
-
} catch {
|
|
476
|
-
// Not running, start it
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
spinner.text = 'Starting Colima with Kubernetes...';
|
|
480
|
-
execSync(`${colimaPath} start --kubernetes --cpu 4 --memory 8 --disk 20`, {
|
|
481
|
-
stdio: 'pipe',
|
|
482
|
-
env: { ...process.env, PATH: `${binDir}:${process.env.PATH}` },
|
|
483
|
-
timeout: 300000
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
spinner.succeed('Container runtime started');
|
|
174
|
+
spinner.succeed('PATH configured');
|
|
487
175
|
return true;
|
|
488
176
|
} catch (error) {
|
|
489
|
-
spinner.
|
|
177
|
+
spinner.warn('PATH setup needs manual configuration');
|
|
178
|
+
console.log(chalk.yellow('\nTo use tribe command, run:'));
|
|
179
|
+
console.log(chalk.cyan(' source ~/.tribe/tribe-env.sh\n'));
|
|
490
180
|
return false;
|
|
491
181
|
}
|
|
492
182
|
}
|
|
@@ -496,64 +186,40 @@ async function main() {
|
|
|
496
186
|
|
|
497
187
|
// Handle help
|
|
498
188
|
if (args.includes('--help') || args.includes('-h')) {
|
|
499
|
-
console.log(chalk.bold
|
|
189
|
+
console.log(chalk.bold('TRIBE Telemetry Installer\n'));
|
|
190
|
+
console.log('Empower your AI coding agents and become 10x faster\n');
|
|
500
191
|
console.log('Usage: npx @_xtribe/cli [options]\n');
|
|
501
192
|
console.log('Options:');
|
|
502
|
-
console.log(' --help, -h
|
|
503
|
-
console.log(' --
|
|
504
|
-
console.log(' --dry-run Show what would be installed');
|
|
193
|
+
console.log(' --help, -h Show this help message');
|
|
194
|
+
console.log(' --version Show version');
|
|
505
195
|
process.exit(0);
|
|
506
196
|
}
|
|
507
197
|
|
|
508
198
|
// Show welcome
|
|
509
199
|
showWelcome();
|
|
510
200
|
|
|
511
|
-
//
|
|
512
|
-
console.log(chalk.bold('
|
|
513
|
-
|
|
514
|
-
const existingTools = {
|
|
515
|
-
kubectl: await checkCommand('kubectl'),
|
|
516
|
-
colima: platform === 'darwin' ? await checkCommand('colima') : true,
|
|
517
|
-
tribe: await checkCommand('tribe')
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
const toolsFound = Object.values(existingTools).filter(v => v).length;
|
|
521
|
-
if (toolsFound > 0) {
|
|
522
|
-
console.log(chalk.green(`📦 Found ${toolsFound} existing tool${toolsFound > 1 ? 's' : ''}:`));
|
|
523
|
-
if (existingTools.kubectl) console.log(' ✓ kubectl');
|
|
524
|
-
if (existingTools.colima && platform === 'darwin') console.log(' ✓ colima');
|
|
525
|
-
if (existingTools.tribe) console.log(' ✓ tribe');
|
|
526
|
-
console.log('');
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// Installation
|
|
530
|
-
console.log(chalk.bold('📥 Installing components...\n'));
|
|
201
|
+
// Simple installation flow
|
|
202
|
+
console.log(chalk.bold('📦 Setting up TRIBE Telemetry...\n'));
|
|
531
203
|
|
|
532
|
-
// Install
|
|
533
|
-
|
|
534
|
-
|
|
204
|
+
// Install TRIBE CLI
|
|
205
|
+
const success = await installTribeCLI();
|
|
206
|
+
if (!success) {
|
|
207
|
+
console.error(chalk.red('\n❌ Installation failed'));
|
|
208
|
+
console.log(chalk.yellow('Please check your internet connection and try again'));
|
|
209
|
+
process.exit(1);
|
|
535
210
|
}
|
|
536
|
-
await installKubectl();
|
|
537
|
-
await installTribeCLI();
|
|
538
|
-
|
|
539
|
-
console.log();
|
|
540
211
|
|
|
541
|
-
//
|
|
542
|
-
|
|
543
|
-
const configSpinner = ora('Setting up PATH...').start();
|
|
544
|
-
await setupPathEnvironment();
|
|
545
|
-
await setupGlobalNpmCommand();
|
|
546
|
-
configSpinner.succeed('Environment configured');
|
|
547
|
-
|
|
548
|
-
// Start container runtime if needed
|
|
549
|
-
if (platform === 'darwin' && !args.includes('--skip-cluster')) {
|
|
550
|
-
console.log();
|
|
551
|
-
await startColimaWithKubernetes();
|
|
552
|
-
}
|
|
212
|
+
// Setup PATH
|
|
213
|
+
await setupPath();
|
|
553
214
|
|
|
554
215
|
// Show summary
|
|
555
216
|
showInstallationSummary();
|
|
556
217
|
|
|
218
|
+
// Final message
|
|
219
|
+
console.log(chalk.green.bold('🎉 Ready to track your AI agents!\n'));
|
|
220
|
+
console.log('Start now with: ' + chalk.cyan.bold('tribe login'));
|
|
221
|
+
console.log();
|
|
222
|
+
|
|
557
223
|
process.exit(0);
|
|
558
224
|
}
|
|
559
225
|
|
|
@@ -563,7 +229,7 @@ module.exports = { main };
|
|
|
563
229
|
// Run if executed directly
|
|
564
230
|
if (require.main === module) {
|
|
565
231
|
main().catch(error => {
|
|
566
|
-
console.error(chalk.red('
|
|
232
|
+
console.error(chalk.red('Error:'), error.message);
|
|
567
233
|
process.exit(1);
|
|
568
234
|
});
|
|
569
235
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@_xtribe/cli",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "TRIBE
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "TRIBE - Track, measure and optimize your AI coding agents to become 10x faster",
|
|
5
5
|
"main": "install-tribe.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cli": "./index.js",
|