@_xtribe/cli 1.0.10 → 1.0.11
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 +209 -78
- package/package.json +4 -2
- package/setup-path.js +105 -0
package/install-tribe.js
CHANGED
|
@@ -5,6 +5,7 @@ const fs = require('fs');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const https = require('https');
|
|
7
7
|
const { execSync, spawn } = require('child_process');
|
|
8
|
+
const readline = require('readline');
|
|
8
9
|
const chalk = require('chalk');
|
|
9
10
|
const ora = require('ora');
|
|
10
11
|
const which = require('which');
|
|
@@ -46,6 +47,32 @@ async function checkCommand(cmd) {
|
|
|
46
47
|
await which(cmd);
|
|
47
48
|
return true;
|
|
48
49
|
} catch {
|
|
50
|
+
// If not in PATH, check our install locations
|
|
51
|
+
if (cmd === 'tribe') {
|
|
52
|
+
const tribePath = path.join(tribeBinDir, 'tribe');
|
|
53
|
+
try {
|
|
54
|
+
await fs.promises.access(tribePath, fs.constants.X_OK);
|
|
55
|
+
return true;
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
} else if (cmd === 'kubectl') {
|
|
60
|
+
const kubectlPath = path.join(binDir, 'kubectl');
|
|
61
|
+
try {
|
|
62
|
+
await fs.promises.access(kubectlPath, fs.constants.X_OK);
|
|
63
|
+
return true;
|
|
64
|
+
} catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
} else if (cmd === 'colima') {
|
|
68
|
+
const colimaPath = path.join(binDir, 'colima');
|
|
69
|
+
try {
|
|
70
|
+
await fs.promises.access(colimaPath, fs.constants.X_OK);
|
|
71
|
+
return true;
|
|
72
|
+
} catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
49
76
|
return false;
|
|
50
77
|
}
|
|
51
78
|
}
|
|
@@ -318,6 +345,53 @@ async function installKubectl() {
|
|
|
318
345
|
}
|
|
319
346
|
}
|
|
320
347
|
|
|
348
|
+
async function setupPathEnvironment() {
|
|
349
|
+
const spinner = ora('Setting up PATH environment...').start();
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
// Copy the tribe-env.sh script to ~/.tribe/
|
|
353
|
+
const envScriptSource = path.join(__dirname, 'tribe-env.sh');
|
|
354
|
+
const envScriptDest = path.join(tribeBinDir, '..', 'tribe-env.sh');
|
|
355
|
+
|
|
356
|
+
// Create the environment script content
|
|
357
|
+
const envScriptContent = `#!/bin/bash
|
|
358
|
+
# TRIBE CLI Environment Setup
|
|
359
|
+
#
|
|
360
|
+
# To use this, add the following line to your shell config:
|
|
361
|
+
# source ~/.tribe/tribe-env.sh
|
|
362
|
+
#
|
|
363
|
+
# Or run it manually in your current session:
|
|
364
|
+
# source ~/.tribe/tribe-env.sh
|
|
365
|
+
|
|
366
|
+
# Add TRIBE bin directory to PATH if not already present
|
|
367
|
+
TRIBE_BIN_DIR="$HOME/.tribe/bin"
|
|
368
|
+
|
|
369
|
+
if [[ -d "$TRIBE_BIN_DIR" ]] && [[ ":$PATH:" != *":$TRIBE_BIN_DIR:"* ]]; then
|
|
370
|
+
export PATH="$TRIBE_BIN_DIR:$PATH"
|
|
371
|
+
fi
|
|
372
|
+
|
|
373
|
+
# Optional: Add helpful aliases
|
|
374
|
+
alias tribe-logs="$TRIBE_BIN_DIR/tribe-logs" 2>/dev/null || true
|
|
375
|
+
|
|
376
|
+
# Verify tribe is available (silent check)
|
|
377
|
+
command -v tribe &> /dev/null || true
|
|
378
|
+
`;
|
|
379
|
+
|
|
380
|
+
fs.writeFileSync(envScriptDest, envScriptContent);
|
|
381
|
+
fs.chmodSync(envScriptDest, '755');
|
|
382
|
+
|
|
383
|
+
spinner.succeed('PATH environment script created');
|
|
384
|
+
|
|
385
|
+
// Store that we created the env script
|
|
386
|
+
global.envScriptCreated = true;
|
|
387
|
+
|
|
388
|
+
return true;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
spinner.fail(`Failed to create PATH environment script: ${error.message}`);
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
321
395
|
async function setupGlobalNpmCommand() {
|
|
322
396
|
const spinner = ora('Setting up global tribe command...').start();
|
|
323
397
|
|
|
@@ -545,7 +619,7 @@ async function installTribeCLI() {
|
|
|
545
619
|
// Multiple sources for reliability
|
|
546
620
|
// For testing, use a direct URL to our releases folder
|
|
547
621
|
const isTestEnv = process.env.TRIBE_TEST_BINARY_URL;
|
|
548
|
-
const githubRepo = process.env.TRIBE_INSTALLER_REPO || 'TRIBE-INC/
|
|
622
|
+
const githubRepo = process.env.TRIBE_INSTALLER_REPO || 'TRIBE-INC/0zen';
|
|
549
623
|
|
|
550
624
|
let downloadUrl = '';
|
|
551
625
|
|
|
@@ -582,6 +656,10 @@ async function installTribeCLI() {
|
|
|
582
656
|
downloadUrl,
|
|
583
657
|
// GitHub releases direct download (fallback if API fails)
|
|
584
658
|
`https://github.com/${githubRepo}/releases/latest/download/tribe-${platform}-${arch}`,
|
|
659
|
+
// GitHub raw content as emergency fallback
|
|
660
|
+
`https://raw.githubusercontent.com/${githubRepo}/main/releases/tribe-${platform}-${arch}`,
|
|
661
|
+
// jsdelivr CDN (mirrors GitHub)
|
|
662
|
+
`https://cdn.jsdelivr.net/gh/${githubRepo}@latest/releases/tribe-${platform}-${arch}`,
|
|
585
663
|
// Local build if available
|
|
586
664
|
...(hasLocalBuild ? [`file://${localBuildPath}`] : [])
|
|
587
665
|
].filter(Boolean); // Filter out empty downloadUrl if API failed
|
|
@@ -641,6 +719,16 @@ async function installTribeCLI() {
|
|
|
641
719
|
|
|
642
720
|
fs.chmodSync(tribeDest, '755');
|
|
643
721
|
|
|
722
|
+
// Remove macOS quarantine attribute
|
|
723
|
+
if (platform === 'darwin') {
|
|
724
|
+
try {
|
|
725
|
+
execSync(`xattr -d com.apple.quarantine "${tribeDest}" 2>/dev/null`, { stdio: 'ignore' });
|
|
726
|
+
log.info('Removed macOS quarantine attribute');
|
|
727
|
+
} catch {
|
|
728
|
+
// Not critical if this fails
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
644
732
|
// Verify the binary works
|
|
645
733
|
try {
|
|
646
734
|
// Try version command first
|
|
@@ -723,58 +811,22 @@ async function startContainerRuntime() {
|
|
|
723
811
|
// Colima not running, need to start it
|
|
724
812
|
}
|
|
725
813
|
|
|
726
|
-
//
|
|
814
|
+
// Don't try to start Colima automatically - it takes too long
|
|
727
815
|
if (await checkCommand('colima')) {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
spinner.succeed('Colima started successfully');
|
|
740
|
-
return true;
|
|
741
|
-
|
|
742
|
-
} catch (error) {
|
|
743
|
-
// Strategy 2: Start in background with Kubernetes
|
|
744
|
-
try {
|
|
745
|
-
spinner.text = 'Starting Colima with Kubernetes in background...';
|
|
746
|
-
const colimaPath = await findCommand('colima') || path.join(binDir, 'colima');
|
|
747
|
-
const child = spawn(colimaPath, ['start', '--cpu', '2', '--memory', '4', '--disk', '10', '--kubernetes'], {
|
|
748
|
-
detached: true,
|
|
749
|
-
stdio: 'ignore',
|
|
750
|
-
env: { ...process.env, PATH: `${binDir}:${process.env.PATH}` }
|
|
751
|
-
});
|
|
752
|
-
child.unref(); // Don't wait for completion
|
|
753
|
-
|
|
754
|
-
spinner.succeed('Colima startup initiated (background)');
|
|
755
|
-
log.info('Colima is starting in the background');
|
|
756
|
-
log.info('Run "colima status" to check progress');
|
|
757
|
-
return true;
|
|
758
|
-
|
|
759
|
-
} catch (bgError) {
|
|
760
|
-
spinner.fail('Failed to start Colima');
|
|
761
|
-
log.warning('Container runtime startup failed (likely due to macOS system restrictions)');
|
|
762
|
-
log.info('Options to fix:');
|
|
763
|
-
log.info('');
|
|
764
|
-
log.info('Option 1 - Manual Colima start:');
|
|
765
|
-
log.info(' colima start --cpu 2 --memory 4 --kubernetes');
|
|
766
|
-
log.info(' # This downloads a 344MB disk image (may take time)');
|
|
767
|
-
log.info('');
|
|
768
|
-
log.info('Option 2 - Use Homebrew (recommended):');
|
|
769
|
-
log.info(' brew install colima');
|
|
770
|
-
log.info(' colima start --kubernetes');
|
|
771
|
-
log.info('');
|
|
772
|
-
return false;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
816
|
+
spinner.stop(); // Stop the spinner before showing info
|
|
817
|
+
console.log('');
|
|
818
|
+
console.log(chalk.yellow(' ⚠️ Colima needs to be started before using TRIBE'));
|
|
819
|
+
console.log(chalk.gray(' To start Colima with Kubernetes:'));
|
|
820
|
+
console.log(chalk.cyan(' colima start --kubernetes'));
|
|
821
|
+
console.log(chalk.gray(' This may take 2-5 minutes on first run'));
|
|
822
|
+
console.log('');
|
|
823
|
+
return true; // Return true since it's installed
|
|
824
|
+
} else {
|
|
825
|
+
spinner.warn('Colima not found');
|
|
826
|
+
return false;
|
|
775
827
|
}
|
|
776
828
|
} else if (platform === 'linux') {
|
|
777
|
-
// Linux - K3s
|
|
829
|
+
// Linux - Check K3s status but don't try to start it
|
|
778
830
|
spinner.text = 'Checking K3s status...';
|
|
779
831
|
|
|
780
832
|
// Check if we're in a container (no systemd)
|
|
@@ -787,22 +839,18 @@ async function startContainerRuntime() {
|
|
|
787
839
|
}
|
|
788
840
|
|
|
789
841
|
try {
|
|
790
|
-
execSync('sudo systemctl is-active --quiet k3s', { stdio: 'ignore' });
|
|
842
|
+
execSync('sudo systemctl is-active --quiet k3s', { stdio: 'ignore', timeout: 5000 });
|
|
791
843
|
spinner.succeed('K3s is running');
|
|
792
844
|
return true;
|
|
793
845
|
} catch {
|
|
794
|
-
//
|
|
795
|
-
spinner.
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
spinner.warn('K3s not available - requires systemd');
|
|
803
|
-
log.info('K3s requires systemd. Install K3s manually or connect to external cluster');
|
|
804
|
-
return true; // Don't fail
|
|
805
|
-
}
|
|
846
|
+
// Don't try to start K3s - just inform the user
|
|
847
|
+
spinner.info('K3s is not running');
|
|
848
|
+
console.log('');
|
|
849
|
+
console.log(chalk.yellow(' ⚠️ K3s needs to be started'));
|
|
850
|
+
console.log(chalk.gray(' To start K3s:'));
|
|
851
|
+
console.log(chalk.cyan(' sudo systemctl start k3s'));
|
|
852
|
+
console.log('');
|
|
853
|
+
return true; // Don't fail
|
|
806
854
|
}
|
|
807
855
|
} else if (platform === 'win32') {
|
|
808
856
|
spinner.fail('Windows support coming soon!');
|
|
@@ -862,10 +910,26 @@ async function verifyInstallation() {
|
|
|
862
910
|
spinner.stop();
|
|
863
911
|
|
|
864
912
|
console.log('\n' + chalk.bold('Installation Summary:'));
|
|
865
|
-
|
|
913
|
+
for (const tool of tools) {
|
|
866
914
|
const status = results[tool] ? chalk.green('✓') : chalk.red('✗');
|
|
867
|
-
|
|
868
|
-
|
|
915
|
+
let message = `${status} ${tool}`;
|
|
916
|
+
|
|
917
|
+
// Add additional info for tribe if it's installed but not in PATH
|
|
918
|
+
if (tool === 'tribe' && results[tool]) {
|
|
919
|
+
try {
|
|
920
|
+
await which('tribe');
|
|
921
|
+
// It's in PATH, no extra message needed
|
|
922
|
+
} catch {
|
|
923
|
+
// It's installed but not in PATH
|
|
924
|
+
message += chalk.gray(' (installed at ~/.tribe/bin/tribe)');
|
|
925
|
+
if (global.envScriptCreated) {
|
|
926
|
+
message += chalk.yellow('\n Run: source ~/.tribe/tribe-env.sh');
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
console.log(message);
|
|
932
|
+
}
|
|
869
933
|
|
|
870
934
|
const extraStatus = containerWorking ? chalk.green('✓') : chalk.yellow('⚠');
|
|
871
935
|
console.log(`${extraStatus} Container runtime`);
|
|
@@ -1173,6 +1237,21 @@ async function deployTribeCluster() {
|
|
|
1173
1237
|
}
|
|
1174
1238
|
}
|
|
1175
1239
|
|
|
1240
|
+
async function promptForPathSetup() {
|
|
1241
|
+
return new Promise((resolve) => {
|
|
1242
|
+
const rl = readline.createInterface({
|
|
1243
|
+
input: process.stdin,
|
|
1244
|
+
output: process.stdout
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
console.log('');
|
|
1248
|
+
rl.question(chalk.yellow('Would you like to add "tribe" to your PATH? (y/n) '), (answer) => {
|
|
1249
|
+
rl.close();
|
|
1250
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
1251
|
+
});
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1176
1255
|
async function promptForClusterSetup() {
|
|
1177
1256
|
// Check for auto-approve in CI environments
|
|
1178
1257
|
if (process.env.CI === 'true' || process.env.TRIBE_AUTO_APPROVE === 'true') {
|
|
@@ -1421,7 +1500,8 @@ async function main() {
|
|
|
1421
1500
|
tasks.push(
|
|
1422
1501
|
{ name: 'kubectl', fn: installKubectl },
|
|
1423
1502
|
{ name: 'TRIBE CLI', fn: installTribeCLI },
|
|
1424
|
-
{ name: '
|
|
1503
|
+
{ name: 'PATH environment', fn: setupPathEnvironment }
|
|
1504
|
+
// We'll try npm global as a fallback, but not as primary method
|
|
1425
1505
|
);
|
|
1426
1506
|
|
|
1427
1507
|
let allSuccess = true;
|
|
@@ -1429,15 +1509,20 @@ async function main() {
|
|
|
1429
1509
|
for (const task of tasks) {
|
|
1430
1510
|
log.step(`Installing ${task.name}...`);
|
|
1431
1511
|
const success = await task.fn();
|
|
1432
|
-
if (!success)
|
|
1512
|
+
if (!success) {
|
|
1513
|
+
allSuccess = false;
|
|
1514
|
+
if (task.name === 'PATH environment') {
|
|
1515
|
+
global.envScriptCreated = false;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1433
1518
|
}
|
|
1434
1519
|
|
|
1435
|
-
//
|
|
1436
|
-
await startContainerRuntime();
|
|
1437
|
-
|
|
1438
|
-
// Verify everything
|
|
1520
|
+
// Verify everything first
|
|
1439
1521
|
const verified = await verifyInstallation();
|
|
1440
1522
|
|
|
1523
|
+
// Try to start container runtime (after showing results)
|
|
1524
|
+
await startContainerRuntime();
|
|
1525
|
+
|
|
1441
1526
|
if (verified) {
|
|
1442
1527
|
// Check if cluster already exists
|
|
1443
1528
|
const clusterExists = await checkClusterExists();
|
|
@@ -1467,11 +1552,47 @@ async function main() {
|
|
|
1467
1552
|
console.log('\n' + chalk.bold.green('✨ TRIBE is ready!'));
|
|
1468
1553
|
console.log('');
|
|
1469
1554
|
|
|
1555
|
+
// Offer to set up PATH
|
|
1556
|
+
if (global.envScriptCreated && !process.env.CI && !process.env.TRIBE_SKIP_PATH_PROMPT) {
|
|
1557
|
+
const shouldSetupPath = await promptForPathSetup();
|
|
1558
|
+
if (shouldSetupPath) {
|
|
1559
|
+
// Run the setup-path logic inline
|
|
1560
|
+
try {
|
|
1561
|
+
const setupPath = require('./setup-path.js');
|
|
1562
|
+
setupPath();
|
|
1563
|
+
console.log('');
|
|
1564
|
+
// PATH is now set up, update instructions
|
|
1565
|
+
global.pathSetupComplete = true;
|
|
1566
|
+
} catch (error) {
|
|
1567
|
+
log.warning('Could not automatically set up PATH');
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1470
1572
|
// Provide immediate access to tribe command
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1573
|
+
if (global.pathSetupComplete) {
|
|
1574
|
+
log.info('TRIBE is now in your PATH!');
|
|
1575
|
+
console.log('');
|
|
1576
|
+
console.log(chalk.bold('To start using tribe:'));
|
|
1577
|
+
console.log(chalk.green(' source ~/.tribe/tribe-env.sh # For current session'));
|
|
1578
|
+
console.log(chalk.green(' tribe # In new terminal'));
|
|
1579
|
+
} else if (global.envScriptCreated) {
|
|
1580
|
+
log.info('TRIBE command is installed!');
|
|
1581
|
+
console.log('');
|
|
1582
|
+
console.log(chalk.bold('To add "tribe" to your PATH:'));
|
|
1583
|
+
console.log(chalk.green(' npx @_xtribe/cli setup-path'));
|
|
1584
|
+
console.log('');
|
|
1585
|
+
console.log(chalk.bold('Or for this session only:'));
|
|
1586
|
+
console.log(chalk.green(' source ~/.tribe/tribe-env.sh'));
|
|
1587
|
+
console.log('');
|
|
1588
|
+
console.log(chalk.bold('Or use the full path:'));
|
|
1589
|
+
console.log(chalk.green(' ~/.tribe/bin/tribe'));
|
|
1590
|
+
} else {
|
|
1591
|
+
log.info('TRIBE command is installed!');
|
|
1592
|
+
console.log(chalk.green(' ~/.tribe/bin/tribe # Run TRIBE'));
|
|
1593
|
+
console.log(chalk.gray(' ~/.tribe/bin/tribe --help # View available commands'));
|
|
1594
|
+
console.log(chalk.gray(' ~/.tribe/bin/tribe status # Check cluster status'));
|
|
1595
|
+
}
|
|
1475
1596
|
console.log('');
|
|
1476
1597
|
|
|
1477
1598
|
log.info('Quick start:');
|
|
@@ -1495,8 +1616,18 @@ async function main() {
|
|
|
1495
1616
|
console.log('');
|
|
1496
1617
|
|
|
1497
1618
|
// Provide immediate access to tribe command
|
|
1498
|
-
|
|
1499
|
-
|
|
1619
|
+
if (global.envScriptCreated) {
|
|
1620
|
+
log.info('TRIBE command is installed!');
|
|
1621
|
+
console.log('');
|
|
1622
|
+
console.log(chalk.bold('To use "tribe" command from anywhere:'));
|
|
1623
|
+
console.log(chalk.green(' source ~/.tribe/tribe-env.sh'));
|
|
1624
|
+
console.log('');
|
|
1625
|
+
console.log(chalk.bold('Or you can use the full path:'));
|
|
1626
|
+
console.log(chalk.green(' ~/.tribe/bin/tribe # Run TRIBE'));
|
|
1627
|
+
} else {
|
|
1628
|
+
log.info('TRIBE command is installed!');
|
|
1629
|
+
console.log(chalk.green(' ~/.tribe/bin/tribe # Run TRIBE'));
|
|
1630
|
+
}
|
|
1500
1631
|
console.log('');
|
|
1501
1632
|
|
|
1502
1633
|
log.info('Commands:');
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@_xtribe/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "TRIBE multi-agent development system - Zero to productive with one command",
|
|
5
5
|
"main": "install-tribe.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"install-tribe": "./install-tribe.js"
|
|
7
|
+
"install-tribe": "./install-tribe.js",
|
|
8
|
+
"setup-path": "./setup-path.js"
|
|
8
9
|
},
|
|
9
10
|
"scripts": {
|
|
10
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
},
|
|
36
37
|
"files": [
|
|
37
38
|
"install-tribe.js",
|
|
39
|
+
"setup-path.js",
|
|
38
40
|
"README.md",
|
|
39
41
|
"package.json"
|
|
40
42
|
],
|
package/setup-path.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
|
|
8
|
+
const homeDir = os.homedir();
|
|
9
|
+
const tribeEnvPath = path.join(homeDir, '.tribe', 'tribe-env.sh');
|
|
10
|
+
|
|
11
|
+
// Detect user's shell
|
|
12
|
+
function detectShell() {
|
|
13
|
+
const shell = process.env.SHELL || '';
|
|
14
|
+
if (shell.includes('zsh')) return 'zsh';
|
|
15
|
+
if (shell.includes('bash')) return 'bash';
|
|
16
|
+
if (shell.includes('fish')) return 'fish';
|
|
17
|
+
return 'unknown';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Get shell config file
|
|
21
|
+
function getShellConfigFile() {
|
|
22
|
+
const shell = detectShell();
|
|
23
|
+
const configFiles = {
|
|
24
|
+
'zsh': ['.zshrc', '.zprofile'],
|
|
25
|
+
'bash': ['.bashrc', '.bash_profile', '.profile'],
|
|
26
|
+
'fish': ['.config/fish/config.fish']
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const candidates = configFiles[shell] || [];
|
|
30
|
+
|
|
31
|
+
// Check which config file exists
|
|
32
|
+
for (const file of candidates) {
|
|
33
|
+
const fullPath = path.join(homeDir, file);
|
|
34
|
+
if (fs.existsSync(fullPath)) {
|
|
35
|
+
return fullPath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// If none exist, use the first candidate
|
|
40
|
+
if (candidates.length > 0) {
|
|
41
|
+
return path.join(homeDir, candidates[0]);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function setupPath() {
|
|
48
|
+
console.log(chalk.bold('🔧 TRIBE PATH Setup\n'));
|
|
49
|
+
|
|
50
|
+
// Check if tribe-env.sh exists
|
|
51
|
+
if (!fs.existsSync(tribeEnvPath)) {
|
|
52
|
+
console.log(chalk.red('Error: TRIBE environment script not found.'));
|
|
53
|
+
console.log('Please run the installer first: npx @_xtribe/cli');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const shellConfig = getShellConfigFile();
|
|
58
|
+
const shell = detectShell();
|
|
59
|
+
|
|
60
|
+
if (!shellConfig) {
|
|
61
|
+
console.log(chalk.yellow('Could not detect shell configuration file.'));
|
|
62
|
+
console.log('\nPlease manually add this line to your shell config:');
|
|
63
|
+
console.log(chalk.green(` source ~/.tribe/tribe-env.sh`));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check if already added
|
|
68
|
+
try {
|
|
69
|
+
const content = fs.readFileSync(shellConfig, 'utf8');
|
|
70
|
+
if (content.includes('source ~/.tribe/tribe-env.sh') ||
|
|
71
|
+
content.includes('source $HOME/.tribe/tribe-env.sh') ||
|
|
72
|
+
content.includes('. ~/.tribe/tribe-env.sh')) {
|
|
73
|
+
console.log(chalk.green('✓ PATH already configured!'));
|
|
74
|
+
console.log('\nTo use tribe in your current session:');
|
|
75
|
+
console.log(chalk.green(` source ~/.tribe/tribe-env.sh`));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
// File doesn't exist yet, that's ok
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Add to shell config
|
|
83
|
+
const sourceCommand = '\n# TRIBE CLI\nsource ~/.tribe/tribe-env.sh\n';
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
fs.appendFileSync(shellConfig, sourceCommand);
|
|
87
|
+
console.log(chalk.green(`✓ Added TRIBE to your ${shell} configuration!`));
|
|
88
|
+
console.log(` Configuration file: ${shellConfig}`);
|
|
89
|
+
console.log('\nTo use tribe in your current session:');
|
|
90
|
+
console.log(chalk.green(` source ~/.tribe/tribe-env.sh`));
|
|
91
|
+
console.log('\nOr open a new terminal window.');
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.log(chalk.red(`Error updating ${shellConfig}: ${error.message}`));
|
|
94
|
+
console.log('\nPlease manually add this line to your shell config:');
|
|
95
|
+
console.log(chalk.green(` source ~/.tribe/tribe-env.sh`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Export for use by other modules
|
|
100
|
+
module.exports = setupPath;
|
|
101
|
+
|
|
102
|
+
// Add to package.json bin entry
|
|
103
|
+
if (require.main === module) {
|
|
104
|
+
setupPath();
|
|
105
|
+
}
|