@_xtribe/cli 1.0.9 → 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 +212 -82
- 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
|
}
|
|
@@ -156,7 +183,7 @@ async function installK3s() {
|
|
|
156
183
|
if (isContainer) {
|
|
157
184
|
spinner.warn('Running in container/CI - K3s installation skipped');
|
|
158
185
|
log.info('K3s requires systemd and privileged access');
|
|
159
|
-
log.info('For containers, consider using
|
|
186
|
+
log.info('For containers, consider using an external cluster');
|
|
160
187
|
return true; // Don't fail in containers
|
|
161
188
|
}
|
|
162
189
|
|
|
@@ -274,7 +301,6 @@ async function installColima() {
|
|
|
274
301
|
|
|
275
302
|
// Lima installation removed - Colima handles virtualization
|
|
276
303
|
|
|
277
|
-
// KIND installation removed - using Colima's built-in Kubernetes
|
|
278
304
|
|
|
279
305
|
async function installKubectl() {
|
|
280
306
|
// Linux with K3s already has kubectl
|
|
@@ -319,6 +345,53 @@ async function installKubectl() {
|
|
|
319
345
|
}
|
|
320
346
|
}
|
|
321
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
|
+
|
|
322
395
|
async function setupGlobalNpmCommand() {
|
|
323
396
|
const spinner = ora('Setting up global tribe command...').start();
|
|
324
397
|
|
|
@@ -546,7 +619,7 @@ async function installTribeCLI() {
|
|
|
546
619
|
// Multiple sources for reliability
|
|
547
620
|
// For testing, use a direct URL to our releases folder
|
|
548
621
|
const isTestEnv = process.env.TRIBE_TEST_BINARY_URL;
|
|
549
|
-
const githubRepo = process.env.TRIBE_INSTALLER_REPO || 'TRIBE-INC/
|
|
622
|
+
const githubRepo = process.env.TRIBE_INSTALLER_REPO || 'TRIBE-INC/0zen';
|
|
550
623
|
|
|
551
624
|
let downloadUrl = '';
|
|
552
625
|
|
|
@@ -583,6 +656,10 @@ async function installTribeCLI() {
|
|
|
583
656
|
downloadUrl,
|
|
584
657
|
// GitHub releases direct download (fallback if API fails)
|
|
585
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}`,
|
|
586
663
|
// Local build if available
|
|
587
664
|
...(hasLocalBuild ? [`file://${localBuildPath}`] : [])
|
|
588
665
|
].filter(Boolean); // Filter out empty downloadUrl if API failed
|
|
@@ -642,6 +719,16 @@ async function installTribeCLI() {
|
|
|
642
719
|
|
|
643
720
|
fs.chmodSync(tribeDest, '755');
|
|
644
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
|
+
|
|
645
732
|
// Verify the binary works
|
|
646
733
|
try {
|
|
647
734
|
// Try version command first
|
|
@@ -724,58 +811,22 @@ async function startContainerRuntime() {
|
|
|
724
811
|
// Colima not running, need to start it
|
|
725
812
|
}
|
|
726
813
|
|
|
727
|
-
//
|
|
814
|
+
// Don't try to start Colima automatically - it takes too long
|
|
728
815
|
if (await checkCommand('colima')) {
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
spinner.succeed('Colima started successfully');
|
|
741
|
-
return true;
|
|
742
|
-
|
|
743
|
-
} catch (error) {
|
|
744
|
-
// Strategy 2: Start in background with Kubernetes
|
|
745
|
-
try {
|
|
746
|
-
spinner.text = 'Starting Colima with Kubernetes in background...';
|
|
747
|
-
const colimaPath = await findCommand('colima') || path.join(binDir, 'colima');
|
|
748
|
-
const child = spawn(colimaPath, ['start', '--cpu', '2', '--memory', '4', '--disk', '10', '--kubernetes'], {
|
|
749
|
-
detached: true,
|
|
750
|
-
stdio: 'ignore',
|
|
751
|
-
env: { ...process.env, PATH: `${binDir}:${process.env.PATH}` }
|
|
752
|
-
});
|
|
753
|
-
child.unref(); // Don't wait for completion
|
|
754
|
-
|
|
755
|
-
spinner.succeed('Colima startup initiated (background)');
|
|
756
|
-
log.info('Colima is starting in the background');
|
|
757
|
-
log.info('Run "colima status" to check progress');
|
|
758
|
-
return true;
|
|
759
|
-
|
|
760
|
-
} catch (bgError) {
|
|
761
|
-
spinner.fail('Failed to start Colima');
|
|
762
|
-
log.warning('Container runtime startup failed (likely due to macOS system restrictions)');
|
|
763
|
-
log.info('Options to fix:');
|
|
764
|
-
log.info('');
|
|
765
|
-
log.info('Option 1 - Manual Colima start:');
|
|
766
|
-
log.info(' colima start --cpu 2 --memory 4 --kubernetes');
|
|
767
|
-
log.info(' # This downloads a 344MB disk image (may take time)');
|
|
768
|
-
log.info('');
|
|
769
|
-
log.info('Option 2 - Use Homebrew (recommended):');
|
|
770
|
-
log.info(' brew install colima');
|
|
771
|
-
log.info(' colima start --kubernetes');
|
|
772
|
-
log.info('');
|
|
773
|
-
return false;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
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;
|
|
776
827
|
}
|
|
777
828
|
} else if (platform === 'linux') {
|
|
778
|
-
// Linux - K3s
|
|
829
|
+
// Linux - Check K3s status but don't try to start it
|
|
779
830
|
spinner.text = 'Checking K3s status...';
|
|
780
831
|
|
|
781
832
|
// Check if we're in a container (no systemd)
|
|
@@ -783,27 +834,23 @@ async function startContainerRuntime() {
|
|
|
783
834
|
|
|
784
835
|
if (isContainer) {
|
|
785
836
|
spinner.info('Running in container - K3s requires systemd');
|
|
786
|
-
log.info('For containers,
|
|
837
|
+
log.info('For containers, connect to an external cluster');
|
|
787
838
|
return true; // Don't fail
|
|
788
839
|
}
|
|
789
840
|
|
|
790
841
|
try {
|
|
791
|
-
execSync('sudo systemctl is-active --quiet k3s', { stdio: 'ignore' });
|
|
842
|
+
execSync('sudo systemctl is-active --quiet k3s', { stdio: 'ignore', timeout: 5000 });
|
|
792
843
|
spinner.succeed('K3s is running');
|
|
793
844
|
return true;
|
|
794
845
|
} catch {
|
|
795
|
-
//
|
|
796
|
-
spinner.
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
spinner.warn('K3s not available - requires systemd');
|
|
804
|
-
log.info('K3s requires systemd. Install K3s manually or use KIND/external cluster');
|
|
805
|
-
return true; // Don't fail
|
|
806
|
-
}
|
|
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
|
|
807
854
|
}
|
|
808
855
|
} else if (platform === 'win32') {
|
|
809
856
|
spinner.fail('Windows support coming soon!');
|
|
@@ -863,10 +910,26 @@ async function verifyInstallation() {
|
|
|
863
910
|
spinner.stop();
|
|
864
911
|
|
|
865
912
|
console.log('\n' + chalk.bold('Installation Summary:'));
|
|
866
|
-
|
|
913
|
+
for (const tool of tools) {
|
|
867
914
|
const status = results[tool] ? chalk.green('✓') : chalk.red('✗');
|
|
868
|
-
|
|
869
|
-
|
|
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
|
+
}
|
|
870
933
|
|
|
871
934
|
const extraStatus = containerWorking ? chalk.green('✓') : chalk.yellow('⚠');
|
|
872
935
|
console.log(`${extraStatus} Container runtime`);
|
|
@@ -1174,6 +1237,21 @@ async function deployTribeCluster() {
|
|
|
1174
1237
|
}
|
|
1175
1238
|
}
|
|
1176
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
|
+
|
|
1177
1255
|
async function promptForClusterSetup() {
|
|
1178
1256
|
// Check for auto-approve in CI environments
|
|
1179
1257
|
if (process.env.CI === 'true' || process.env.TRIBE_AUTO_APPROVE === 'true') {
|
|
@@ -1378,7 +1456,7 @@ async function main() {
|
|
|
1378
1456
|
|
|
1379
1457
|
// 4. Check for existing Kubernetes installations
|
|
1380
1458
|
const k8sTools = [];
|
|
1381
|
-
const checkTools = ['minikube', 'microk8s', '
|
|
1459
|
+
const checkTools = ['minikube', 'microk8s', 'k3d', 'kubectl'];
|
|
1382
1460
|
for (const tool of checkTools) {
|
|
1383
1461
|
try {
|
|
1384
1462
|
execSync(`which ${tool}`, { stdio: 'ignore' });
|
|
@@ -1422,7 +1500,8 @@ async function main() {
|
|
|
1422
1500
|
tasks.push(
|
|
1423
1501
|
{ name: 'kubectl', fn: installKubectl },
|
|
1424
1502
|
{ name: 'TRIBE CLI', fn: installTribeCLI },
|
|
1425
|
-
{ name: '
|
|
1503
|
+
{ name: 'PATH environment', fn: setupPathEnvironment }
|
|
1504
|
+
// We'll try npm global as a fallback, but not as primary method
|
|
1426
1505
|
);
|
|
1427
1506
|
|
|
1428
1507
|
let allSuccess = true;
|
|
@@ -1430,15 +1509,20 @@ async function main() {
|
|
|
1430
1509
|
for (const task of tasks) {
|
|
1431
1510
|
log.step(`Installing ${task.name}...`);
|
|
1432
1511
|
const success = await task.fn();
|
|
1433
|
-
if (!success)
|
|
1512
|
+
if (!success) {
|
|
1513
|
+
allSuccess = false;
|
|
1514
|
+
if (task.name === 'PATH environment') {
|
|
1515
|
+
global.envScriptCreated = false;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1434
1518
|
}
|
|
1435
1519
|
|
|
1436
|
-
//
|
|
1437
|
-
await startContainerRuntime();
|
|
1438
|
-
|
|
1439
|
-
// Verify everything
|
|
1520
|
+
// Verify everything first
|
|
1440
1521
|
const verified = await verifyInstallation();
|
|
1441
1522
|
|
|
1523
|
+
// Try to start container runtime (after showing results)
|
|
1524
|
+
await startContainerRuntime();
|
|
1525
|
+
|
|
1442
1526
|
if (verified) {
|
|
1443
1527
|
// Check if cluster already exists
|
|
1444
1528
|
const clusterExists = await checkClusterExists();
|
|
@@ -1468,11 +1552,47 @@ async function main() {
|
|
|
1468
1552
|
console.log('\n' + chalk.bold.green('✨ TRIBE is ready!'));
|
|
1469
1553
|
console.log('');
|
|
1470
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
|
+
|
|
1471
1572
|
// Provide immediate access to tribe command
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
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
|
+
}
|
|
1476
1596
|
console.log('');
|
|
1477
1597
|
|
|
1478
1598
|
log.info('Quick start:');
|
|
@@ -1496,8 +1616,18 @@ async function main() {
|
|
|
1496
1616
|
console.log('');
|
|
1497
1617
|
|
|
1498
1618
|
// Provide immediate access to tribe command
|
|
1499
|
-
|
|
1500
|
-
|
|
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
|
+
}
|
|
1501
1631
|
console.log('');
|
|
1502
1632
|
|
|
1503
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
|
+
}
|