@_xtribe/cli 2.2.15 → 2.2.17

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.
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env node
2
+
3
+ const os = require('os');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const https = require('https');
7
+ const { execSync } = require('child_process');
8
+ const chalk = require('chalk');
9
+
10
+ class TribeAutoUpdater {
11
+ constructor() {
12
+ this.homeDir = os.homedir();
13
+ this.tribeDir = path.join(this.homeDir, '.tribe');
14
+ this.tribeBinDir = path.join(this.tribeDir, 'bin');
15
+ this.versionFile = path.join(this.tribeDir, 'version.json');
16
+ this.platform = os.platform();
17
+ this.arch = os.arch() === 'x64' ? 'amd64' : (os.arch() === 'arm64' ? 'arm64' : os.arch());
18
+ this.githubRepo = 'TRIBE-INC/releases';
19
+ }
20
+
21
+ async fetchLatestVersion() {
22
+ return new Promise((resolve, reject) => {
23
+ const url = `https://api.github.com/repos/${this.githubRepo}/releases/latest`;
24
+ https.get(url, {
25
+ headers: {
26
+ 'User-Agent': 'TRIBE-CLI-Updater'
27
+ }
28
+ }, (response) => {
29
+ let data = '';
30
+ response.on('data', chunk => data += chunk);
31
+ response.on('end', () => {
32
+ try {
33
+ const release = JSON.parse(data);
34
+ resolve({
35
+ version: release.tag_name,
36
+ publishedAt: release.published_at,
37
+ downloadUrl: `https://github.com/${this.githubRepo}/releases/latest/download/tribe-${this.platform}-${this.arch}`
38
+ });
39
+ } catch (error) {
40
+ reject(error);
41
+ }
42
+ });
43
+ }).on('error', reject);
44
+ });
45
+ }
46
+
47
+ getCurrentVersion() {
48
+ try {
49
+ if (fs.existsSync(this.versionFile)) {
50
+ const versionData = JSON.parse(fs.readFileSync(this.versionFile, 'utf8'));
51
+ return versionData;
52
+ }
53
+ } catch (error) {
54
+ // Ignore errors, return null for fresh install
55
+ }
56
+ return null;
57
+ }
58
+
59
+ saveVersionInfo(versionInfo) {
60
+ try {
61
+ fs.writeFileSync(this.versionFile, JSON.stringify({
62
+ version: versionInfo.version,
63
+ publishedAt: versionInfo.publishedAt,
64
+ lastChecked: new Date().toISOString(),
65
+ installedAt: new Date().toISOString()
66
+ }, null, 2));
67
+ } catch (error) {
68
+ console.warn(chalk.yellow(`Warning: Could not save version info: ${error.message}`));
69
+ }
70
+ }
71
+
72
+ shouldCheckForUpdates() {
73
+ const current = this.getCurrentVersion();
74
+ if (!current || !current.lastChecked) return true;
75
+
76
+ const lastChecked = new Date(current.lastChecked);
77
+ const now = new Date();
78
+ const hoursSinceLastCheck = (now - lastChecked) / (1000 * 60 * 60);
79
+
80
+ // Check for updates every 24 hours
81
+ return hoursSinceLastCheck >= 24;
82
+ }
83
+
84
+ isUpdateAvailable(currentVersion, latestVersion) {
85
+ if (!currentVersion) return true; // No version installed
86
+
87
+ // Simple version comparison (assumes semver-like tags)
88
+ const current = currentVersion.version?.replace('v', '') || '0.0.0';
89
+ const latest = latestVersion.version?.replace('v', '') || '0.0.0';
90
+
91
+ return current !== latest;
92
+ }
93
+
94
+ async downloadFile(url, dest) {
95
+ return new Promise((resolve, reject) => {
96
+ const file = fs.createWriteStream(dest);
97
+ https.get(url, (response) => {
98
+ if (response.statusCode === 302 || response.statusCode === 301) {
99
+ return this.downloadFile(response.headers.location, dest).then(resolve, reject);
100
+ }
101
+ if (response.statusCode !== 200) {
102
+ reject(new Error(`HTTP ${response.statusCode}`));
103
+ return;
104
+ }
105
+ response.pipe(file);
106
+ file.on('finish', () => {
107
+ file.close();
108
+ resolve();
109
+ });
110
+ }).on('error', reject);
111
+ });
112
+ }
113
+
114
+ async performUpdate(latestVersion, options = {}) {
115
+ const { silent = false, force = false } = options;
116
+ const tribeBinary = path.join(this.tribeBinDir, 'tribe');
117
+
118
+ if (!silent) {
119
+ console.log(chalk.blue(`šŸ”„ Updating TRIBE CLI to ${latestVersion.version}...`));
120
+ }
121
+
122
+ try {
123
+ // Backup existing binary if it exists
124
+ const backupPath = tribeBinary + '.backup';
125
+ if (fs.existsSync(tribeBinary)) {
126
+ fs.copyFileSync(tribeBinary, backupPath);
127
+ }
128
+
129
+ // Download new version
130
+ await this.downloadFile(latestVersion.downloadUrl, tribeBinary);
131
+ fs.chmodSync(tribeBinary, '755');
132
+
133
+ // Remove macOS quarantine if needed
134
+ if (this.platform === 'darwin') {
135
+ try {
136
+ execSync(`xattr -d com.apple.quarantine "${tribeBinary}"`, { stdio: 'ignore' });
137
+ } catch {
138
+ // Not critical
139
+ }
140
+ }
141
+
142
+ // Verify the update worked
143
+ try {
144
+ execSync(`"${tribeBinary}" --version`, { stdio: 'ignore', timeout: 5000 });
145
+
146
+ // Remove backup on success
147
+ if (fs.existsSync(backupPath)) {
148
+ fs.unlinkSync(backupPath);
149
+ }
150
+
151
+ // Save version info
152
+ this.saveVersionInfo(latestVersion);
153
+
154
+ if (!silent) {
155
+ console.log(chalk.green(`āœ… Updated to TRIBE CLI ${latestVersion.version}`));
156
+ }
157
+ return true;
158
+ } catch (error) {
159
+ // Restore backup on verification failure
160
+ if (fs.existsSync(backupPath)) {
161
+ fs.copyFileSync(backupPath, tribeBinary);
162
+ fs.unlinkSync(backupPath);
163
+ }
164
+ throw new Error(`Update verification failed: ${error.message}`);
165
+ }
166
+
167
+ } catch (error) {
168
+ if (!silent) {
169
+ console.error(chalk.red(`āŒ Update failed: ${error.message}`));
170
+ }
171
+ return false;
172
+ }
173
+ }
174
+
175
+ async checkForUpdates(options = {}) {
176
+ const { silent = false, force = false } = options;
177
+
178
+ try {
179
+ if (!force && !this.shouldCheckForUpdates()) {
180
+ return { hasUpdate: false, reason: 'Recently checked' };
181
+ }
182
+
183
+ const latestVersion = await this.fetchLatestVersion();
184
+ const currentVersion = this.getCurrentVersion();
185
+
186
+ // Update last checked time
187
+ if (currentVersion) {
188
+ currentVersion.lastChecked = new Date().toISOString();
189
+ this.saveVersionInfo(currentVersion);
190
+ }
191
+
192
+ const hasUpdate = this.isUpdateAvailable(currentVersion, latestVersion);
193
+
194
+ if (hasUpdate) {
195
+ if (!silent) {
196
+ console.log(chalk.yellow(`šŸ“¦ New version available: ${latestVersion.version}`));
197
+ if (currentVersion?.version) {
198
+ console.log(chalk.gray(` Current: ${currentVersion.version}`));
199
+ }
200
+ }
201
+ return {
202
+ hasUpdate: true,
203
+ currentVersion: currentVersion?.version || 'unknown',
204
+ latestVersion: latestVersion.version,
205
+ latestVersionInfo: latestVersion
206
+ };
207
+ } else {
208
+ if (!silent) {
209
+ console.log(chalk.green('āœ… TRIBE CLI is up to date'));
210
+ }
211
+ return { hasUpdate: false, reason: 'Up to date' };
212
+ }
213
+
214
+ } catch (error) {
215
+ if (!silent) {
216
+ console.warn(chalk.yellow(`āš ļø Could not check for updates: ${error.message}`));
217
+ }
218
+ return { hasUpdate: false, reason: 'Check failed', error: error.message };
219
+ }
220
+ }
221
+
222
+ async autoUpdate(options = {}) {
223
+ const { silent = false, force = false } = options;
224
+
225
+ const updateCheck = await this.checkForUpdates({ silent, force });
226
+
227
+ if (updateCheck.hasUpdate) {
228
+ return await this.performUpdate(updateCheck.latestVersionInfo, { silent, force });
229
+ }
230
+
231
+ return false; // No update needed
232
+ }
233
+
234
+ // Check if binary exists and is functional
235
+ isInstalled() {
236
+ const tribeBinary = path.join(this.tribeBinDir, 'tribe');
237
+ if (!fs.existsSync(tribeBinary)) return false;
238
+
239
+ try {
240
+ execSync(`"${tribeBinary}" --version`, { stdio: 'ignore', timeout: 5000 });
241
+ return true;
242
+ } catch {
243
+ return false;
244
+ }
245
+ }
246
+
247
+ async promptForUpdate(updateInfo) {
248
+ const readline = require('readline');
249
+ const rl = readline.createInterface({
250
+ input: process.stdin,
251
+ output: process.stdout
252
+ });
253
+
254
+ return new Promise((resolve) => {
255
+ console.log(chalk.yellow(`\nšŸ“¦ TRIBE CLI update available!`));
256
+ console.log(chalk.gray(` Current: ${updateInfo.currentVersion}`));
257
+ console.log(chalk.cyan(` Latest: ${updateInfo.latestVersion}`));
258
+
259
+ rl.question('\nWould you like to update now? (Y/n): ', (answer) => {
260
+ rl.close();
261
+ const shouldUpdate = answer.toLowerCase() !== 'n' && answer.toLowerCase() !== 'no';
262
+ resolve(shouldUpdate);
263
+ });
264
+ });
265
+ }
266
+ }
267
+
268
+ module.exports = { TribeAutoUpdater };
package/index.js CHANGED
@@ -2,15 +2,22 @@
2
2
 
3
3
  /**
4
4
  * Default entry point for npx @_xtribe/cli
5
- * This runs the full installation process
5
+ * This runs the installation process with optional auto-update support
6
6
  */
7
7
 
8
- // Execute the installer in a way that preserves require.main
9
8
  const { spawn } = require('child_process');
10
9
  const path = require('path');
11
10
 
12
- const installerPath = path.join(__dirname, 'install-tribe.js');
13
- const child = spawn(process.execPath, [installerPath, ...process.argv.slice(2)], {
11
+ // Check if user wants auto-update features
12
+ const args = process.argv.slice(2);
13
+ const useAutoUpdate = args.includes('--check-updates') || args.includes('--auto-update');
14
+
15
+ // Choose installer based on features requested
16
+ const installerPath = useAutoUpdate
17
+ ? path.join(__dirname, 'install-tribe-with-autoupdate.js')
18
+ : path.join(__dirname, 'install-tribe.js');
19
+
20
+ const child = spawn(process.execPath, [installerPath, ...args], {
14
21
  stdio: 'inherit',
15
22
  env: process.env
16
23
  });
@@ -0,0 +1,328 @@
1
+ #!/usr/bin/env node
2
+
3
+ const os = require('os');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const https = require('https');
7
+ const { execSync } = require('child_process');
8
+ const chalk = require('chalk');
9
+ const ora = require('ora');
10
+ const { EnhancedPathSetup } = require('./enhanced-path-setup');
11
+ const { TribeAutoUpdater } = require('./auto-updater');
12
+
13
+ // ASCII art for TRIBE
14
+ const asciiArt = `
15
+ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—
16
+ ā•šā•ā•ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā•ā•ā•ā•
17
+ ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā–ˆā–ˆā–ˆā•—
18
+ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•”ā•ā•ā•
19
+ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—
20
+ ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•šā•ā•ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā•ā•
21
+
22
+ Learn AI Engineering • Maximum Impact • It Doesn't Have to Be Hard`;
23
+
24
+ const platform = os.platform();
25
+ const arch = os.arch() === 'x64' ? 'amd64' : (os.arch() === 'arm64' ? 'arm64' : os.arch());
26
+ const homeDir = os.homedir();
27
+ const tribeDir = path.join(homeDir, '.tribe');
28
+ const tribeBinDir = path.join(tribeDir, 'bin');
29
+ const tutorDir = path.join(tribeDir, 'tutor');
30
+ const logsDir = path.join(tribeDir, 'logs');
31
+
32
+ // Ensure all directories exist with proper permissions (700)
33
+ const directories = [
34
+ { path: tribeDir, name: 'base' },
35
+ { path: tribeBinDir, name: 'bin' },
36
+ { path: tutorDir, name: 'tutor' },
37
+ { path: logsDir, name: 'logs' }
38
+ ];
39
+
40
+ directories.forEach(({ path: dirPath, name }) => {
41
+ if (!fs.existsSync(dirPath)) {
42
+ fs.mkdirSync(dirPath, { recursive: true, mode: 0o700 });
43
+ } else {
44
+ // Fix permissions if directory already exists
45
+ try {
46
+ fs.chmodSync(dirPath, 0o700);
47
+ } catch (err) {
48
+ // Ignore permission errors on some systems
49
+ }
50
+ }
51
+ });
52
+
53
+ function showWelcome() {
54
+ console.clear();
55
+ console.log(chalk.cyan(asciiArt));
56
+ console.log(chalk.gray('Master AI Engineering Through Practice\n'));
57
+ }
58
+
59
+ async function downloadFile(url, dest) {
60
+ return new Promise((resolve, reject) => {
61
+ const file = fs.createWriteStream(dest);
62
+ https.get(url, (response) => {
63
+ if (response.statusCode === 302 || response.statusCode === 301) {
64
+ return downloadFile(response.headers.location, dest).then(resolve, reject);
65
+ }
66
+ if (response.statusCode !== 200) {
67
+ reject(new Error(`HTTP ${response.statusCode}`));
68
+ return;
69
+ }
70
+ response.pipe(file);
71
+ file.on('finish', () => {
72
+ file.close();
73
+ resolve();
74
+ });
75
+ }).on('error', reject);
76
+ });
77
+ }
78
+
79
+ async function installOrUpdateTribeCLI() {
80
+ const updater = new TribeAutoUpdater();
81
+ const tribeDest = path.join(tribeBinDir, 'tribe');
82
+
83
+ // Check if it's an installation or update
84
+ const isInstalled = updater.isInstalled();
85
+ const action = isInstalled ? 'Updating' : 'Installing';
86
+
87
+ const spinner = ora(`${action} CLI...`).start();
88
+
89
+ try {
90
+ if (isInstalled) {
91
+ // Use auto-updater for existing installations
92
+ const updated = await updater.autoUpdate({ silent: true, force: true });
93
+ if (updated) {
94
+ spinner.succeed('CLI updated to latest version');
95
+ } else {
96
+ spinner.succeed('CLI already up to date');
97
+ }
98
+ } else {
99
+ // Fresh installation - download latest version
100
+ const latestVersion = await updater.fetchLatestVersion();
101
+
102
+ await downloadFile(latestVersion.downloadUrl, tribeDest);
103
+ fs.chmodSync(tribeDest, '755');
104
+
105
+ // Remove macOS quarantine if needed
106
+ if (platform === 'darwin') {
107
+ try {
108
+ execSync(`xattr -d com.apple.quarantine "${tribeDest}"`, { stdio: 'ignore' });
109
+ } catch {
110
+ // Not critical
111
+ }
112
+ }
113
+
114
+ // Save version info for future updates
115
+ updater.saveVersionInfo(latestVersion);
116
+
117
+ spinner.succeed('CLI installed successfully');
118
+ }
119
+
120
+ return true;
121
+ } catch (error) {
122
+ spinner.fail(`${action} failed: ${error.message}`);
123
+ return false;
124
+ }
125
+ }
126
+
127
+ async function installTutorCollector() {
128
+ const tutorCollectorDest = path.join(tribeBinDir, 'tutor-collector');
129
+ const githubRepo = 'TRIBE-INC/releases';
130
+ const tutorCollectorUrl = `https://github.com/${githubRepo}/releases/latest/download/tutor-collector-${platform}-${arch}`;
131
+
132
+ try {
133
+ await downloadFile(tutorCollectorUrl, tutorCollectorDest);
134
+ fs.chmodSync(tutorCollectorDest, '755');
135
+
136
+ // Remove macOS quarantine if needed
137
+ if (platform === 'darwin') {
138
+ try {
139
+ execSync(`xattr -d com.apple.quarantine "${tutorCollectorDest}"`, { stdio: 'ignore' });
140
+ } catch {
141
+ // Not critical
142
+ }
143
+ }
144
+ return true;
145
+ } catch (tutorError) {
146
+ // Tutor collector is optional for basic CLI functionality
147
+ console.warn(chalk.yellow('Warning: Could not download tutor-collector binary'));
148
+ return false;
149
+ }
150
+ }
151
+
152
+ async function setupAutoUpdate() {
153
+ // Create a simple update script that users can run manually or add to cron
154
+ const updateScript = `#!/bin/bash
155
+ # TRIBE CLI Auto-Update Script
156
+ # Run this periodically to keep TRIBE CLI up to date
157
+
158
+ echo "šŸ” Checking for TRIBE CLI updates..."
159
+ npx @_xtribe/cli --check-updates --auto-update
160
+
161
+ # Optional: Add to cron by running:
162
+ # echo "0 12 * * * $HOME/.tribe/update-tribe.sh" | crontab -
163
+ `;
164
+
165
+ const updateScriptPath = path.join(tribeDir, 'update-tribe.sh');
166
+
167
+ try {
168
+ fs.writeFileSync(updateScriptPath, updateScript);
169
+ fs.chmodSync(updateScriptPath, '755');
170
+ return updateScriptPath;
171
+ } catch (error) {
172
+ console.warn(chalk.yellow(`Warning: Could not create update script: ${error.message}`));
173
+ return null;
174
+ }
175
+ }
176
+
177
+ async function setupPath() {
178
+ const pathSetup = new EnhancedPathSetup();
179
+ const result = await pathSetup.setup();
180
+ return result.success;
181
+ }
182
+
183
+ async function main() {
184
+ const args = process.argv.slice(2);
185
+
186
+ // Handle version check and auto-update
187
+ if (args.includes('--check-updates') || args.includes('--auto-update')) {
188
+ const updater = new TribeAutoUpdater();
189
+
190
+ if (args.includes('--auto-update')) {
191
+ console.log(chalk.blue('šŸ”„ Checking for updates...'));
192
+ const updated = await updater.autoUpdate({ silent: false, force: true });
193
+ if (updated) {
194
+ console.log(chalk.green('āœ… TRIBE CLI updated successfully'));
195
+ } else {
196
+ console.log(chalk.blue('šŸ“¦ TRIBE CLI is already up to date'));
197
+ }
198
+ } else {
199
+ const updateCheck = await updater.checkForUpdates({ silent: false, force: true });
200
+ if (updateCheck.hasUpdate) {
201
+ console.log(chalk.yellow(`\nšŸ“¦ Update available: ${updateCheck.latestVersion}`));
202
+ console.log(chalk.gray(`Run 'npx @_xtribe/cli --auto-update' to update`));
203
+ }
204
+ }
205
+ process.exit(0);
206
+ }
207
+
208
+ // Handle help
209
+ if (args.includes('--help') || args.includes('-h')) {
210
+ console.log(chalk.bold('TRIBE CLI Installer with Auto-Update\n'));
211
+ console.log('Empower your AI coding agents and become 10x faster\n');
212
+ console.log('Usage: npx @_xtribe/cli [options]\n');
213
+ console.log('Options:');
214
+ console.log(' --help, -h Show this help message');
215
+ console.log(' --version Show version');
216
+ console.log(' --check-updates Check for CLI updates');
217
+ console.log(' --auto-update Update CLI to latest version');
218
+ process.exit(0);
219
+ }
220
+
221
+ // Show welcome
222
+ showWelcome();
223
+
224
+ // Check for updates first (if CLI is already installed)
225
+ const updater = new TribeAutoUpdater();
226
+ if (updater.isInstalled()) {
227
+ console.log(chalk.blue('šŸ” Checking for updates...'));
228
+ const updateCheck = await updater.checkForUpdates({ silent: true });
229
+
230
+ if (updateCheck.hasUpdate) {
231
+ console.log(chalk.yellow(`šŸ“¦ New version available: ${updateCheck.latestVersion}`));
232
+
233
+ // Prompt user for update
234
+ const shouldUpdate = await updater.promptForUpdate(updateCheck);
235
+ if (shouldUpdate) {
236
+ const spinner = ora('Updating TRIBE CLI...').start();
237
+ const updated = await updater.performUpdate(updateCheck.latestVersionInfo, { silent: true });
238
+ if (updated) {
239
+ spinner.succeed(`Updated to ${updateCheck.latestVersion}`);
240
+ } else {
241
+ spinner.fail('Update failed');
242
+ }
243
+ } else {
244
+ console.log(chalk.gray('Skipping update. You can update later with: npx @_xtribe/cli --auto-update'));
245
+ }
246
+ }
247
+ }
248
+
249
+ // Single spinner for entire installation
250
+ const spinner = ora('Installing...').start();
251
+
252
+ try {
253
+ // Install or update TRIBE CLI
254
+ spinner.text = 'Installing CLI...';
255
+ const cliSuccess = await installOrUpdateTribeCLI();
256
+ if (!cliSuccess) {
257
+ spinner.fail('Installation failed');
258
+ console.log(chalk.yellow('Please check your internet connection and try again'));
259
+ process.exit(1);
260
+ }
261
+
262
+ // Install tutor collector
263
+ spinner.text = 'Installing tutor collector...';
264
+ await installTutorCollector();
265
+
266
+ // Setup PATH
267
+ spinner.text = 'Setting up environment...';
268
+ try {
269
+ await setupPath();
270
+ } catch (error) {
271
+ // PATH setup had issues but continue with installation
272
+ console.log(chalk.yellow('āš ļø PATH setup had warnings, but installation completed'));
273
+ }
274
+
275
+ // Setup auto-update script
276
+ spinner.text = 'Setting up auto-update...';
277
+ const updateScriptPath = await setupAutoUpdate();
278
+
279
+ spinner.succeed('Ready!');
280
+
281
+ // Test if tribe command works immediately
282
+ let commandWorks = false;
283
+ try {
284
+ execSync('which tribe', { stdio: 'ignore', timeout: 2000 });
285
+ commandWorks = true;
286
+ } catch (error) {
287
+ commandWorks = false;
288
+ }
289
+
290
+ // Show appropriate completion message
291
+ if (commandWorks) {
292
+ console.log(chalk.green('\nāœ… TRIBE CLI is ready to use!'));
293
+ console.log('Type ' + chalk.cyan.bold('tribe') + ' to get started');
294
+ } else {
295
+ console.log(chalk.yellow('\nāš ļø TRIBE CLI installed successfully!'));
296
+ console.log(chalk.blue('To use the tribe command, please restart your terminal'));
297
+ console.log(chalk.gray('or run: ') + chalk.cyan.bold('source ~/.tribe/tribe-env.sh'));
298
+ console.log(chalk.gray('\nThen type: ') + chalk.cyan.bold('tribe') + chalk.gray(' to get started'));
299
+ }
300
+
301
+ // Show auto-update info
302
+ console.log(chalk.blue('\nšŸ”„ Auto-Update:'));
303
+ console.log(chalk.gray(' Check for updates: ') + chalk.cyan('npx @_xtribe/cli --check-updates'));
304
+ console.log(chalk.gray(' Auto-update: ') + chalk.cyan('npx @_xtribe/cli --auto-update'));
305
+
306
+ if (updateScriptPath) {
307
+ console.log(chalk.gray(' Update script: ') + chalk.cyan(updateScriptPath));
308
+ }
309
+
310
+ } catch (error) {
311
+ spinner.fail('Installation failed');
312
+ console.error(chalk.red(error.message));
313
+ process.exit(1);
314
+ }
315
+
316
+ process.exit(0);
317
+ }
318
+
319
+ // Export for use from index.js
320
+ module.exports = { main };
321
+
322
+ // Run if executed directly
323
+ if (require.main === module) {
324
+ main().catch(error => {
325
+ console.error(chalk.red('Error:'), error.message);
326
+ process.exit(1);
327
+ });
328
+ }
package/install-tribe.js CHANGED
@@ -186,12 +186,18 @@ async function main() {
186
186
 
187
187
  // Handle help
188
188
  if (args.includes('--help') || args.includes('-h')) {
189
- console.log(chalk.bold('TRIBE Telemetry Installer\n'));
189
+ console.log(chalk.bold('TRIBE CLI Installer\n'));
190
190
  console.log('Empower your AI coding agents and become 10x faster\n');
191
191
  console.log('Usage: npx @_xtribe/cli [options]\n');
192
192
  console.log('Options:');
193
- console.log(' --help, -h Show this help message');
194
- console.log(' --version Show version');
193
+ console.log(' --help, -h Show this help message');
194
+ console.log(' --version Show version');
195
+ console.log(' --check-updates Check for CLI updates');
196
+ console.log(' --auto-update Update CLI to latest version');
197
+ console.log('\nAuto-Update Features:');
198
+ console.log(' The CLI can automatically check for and install updates');
199
+ console.log(' Use --check-updates to see if a newer version is available');
200
+ console.log(' Use --auto-update to download and install the latest version');
195
201
  process.exit(0);
196
202
  }
197
203
 
@@ -242,6 +248,11 @@ async function main() {
242
248
  console.log(chalk.gray('\nThen type: ') + chalk.cyan.bold('tribe') + chalk.gray(' to get started'));
243
249
  }
244
250
 
251
+ // Show auto-update information
252
+ console.log(chalk.blue('\nšŸ’” Keep your TRIBE CLI up to date:'));
253
+ console.log(chalk.gray(' Check for updates: ') + chalk.cyan('npx @_xtribe/cli --check-updates'));
254
+ console.log(chalk.gray(' Auto-update: ') + chalk.cyan('npx @_xtribe/cli --auto-update'));
255
+
245
256
  } catch (error) {
246
257
  spinner.fail('Installation failed');
247
258
  console.error(chalk.red(error.message));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_xtribe/cli",
3
- "version": "2.2.15",
3
+ "version": "2.2.17",
4
4
  "description": "TRIBE - Track, measure and optimize your AI coding agents to become 10x faster",
5
5
  "main": "install-tribe.js",
6
6
  "bin": {
@@ -42,6 +42,8 @@
42
42
  "install-tribe.js",
43
43
  "install-tribe-minimal.js",
44
44
  "install-tribe-autolaunch.js",
45
+ "install-tribe-with-autoupdate.js",
46
+ "auto-updater.js",
45
47
  "setup-path.js",
46
48
  "enhanced-path-setup.js",
47
49
  "install.sh",