@_xtribe/cli 1.0.0-beta.11 → 1.0.0-beta.14

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.
Files changed (2) hide show
  1. package/install-tribe.js +141 -5
  2. package/package.json +1 -1
package/install-tribe.js CHANGED
@@ -392,14 +392,43 @@ async function checkColimaRunning() {
392
392
  }
393
393
  }
394
394
 
395
+ async function checkColimaHasKubernetes() {
396
+ try {
397
+ const colimaPath = await findCommand('colima') || path.join(binDir, 'colima');
398
+ const status = execSync(`${colimaPath} status`, { encoding: 'utf8' });
399
+ // Check if kubernetes is mentioned in the status
400
+ return status.toLowerCase().includes('kubernetes');
401
+ } catch {
402
+ return false;
403
+ }
404
+ }
405
+
395
406
  async function startColimaWithKubernetes() {
396
407
  const spinner = ora('Starting Colima with Kubernetes...').start();
397
408
 
398
409
  try {
399
410
  // Check if already running
400
411
  if (await checkColimaRunning()) {
401
- spinner.succeed('Colima is already running');
402
- return true;
412
+ // Check if it has Kubernetes enabled
413
+ if (await checkColimaHasKubernetes()) {
414
+ spinner.succeed('Colima is already running with Kubernetes');
415
+ return true;
416
+ } else {
417
+ spinner.text = 'Colima is running without Kubernetes. Restarting with Kubernetes...';
418
+
419
+ // Stop existing Colima
420
+ const colimaPath = await findCommand('colima') || path.join(binDir, 'colima');
421
+ try {
422
+ execSync(`${colimaPath} stop`, {
423
+ stdio: 'pipe',
424
+ timeout: 30000
425
+ });
426
+ // Wait for it to fully stop
427
+ await new Promise(resolve => setTimeout(resolve, 5000));
428
+ } catch (stopError) {
429
+ log.warning('Failed to stop Colima, attempting to start anyway...');
430
+ }
431
+ }
403
432
  }
404
433
 
405
434
  // Start Colima with Kubernetes enabled
@@ -407,12 +436,24 @@ async function startColimaWithKubernetes() {
407
436
  const colimaPath = await findCommand('colima') || path.join(binDir, 'colima');
408
437
  execSync(`${colimaPath} start --kubernetes --cpu 4 --memory 8 --disk 20`, {
409
438
  stdio: 'pipe',
410
- env: { ...process.env, PATH: `${binDir}:${process.env.PATH}` }
439
+ env: { ...process.env, PATH: `${binDir}:${process.env.PATH}` },
440
+ timeout: 300000 // 5 minute timeout for first start
411
441
  });
412
442
 
413
- // Verify it's working
443
+ // Give Colima a moment to stabilize after starting
444
+ spinner.text = 'Waiting for Colima to stabilize...';
445
+ await new Promise(resolve => setTimeout(resolve, 5000));
446
+
447
+ // Verify it's working and set context
414
448
  const kubectlPath = await findCommand('kubectl') || 'kubectl';
415
449
  execSync(`${kubectlPath} version --client`, { stdio: 'ignore' });
450
+
451
+ // Set kubectl context to colima
452
+ try {
453
+ execSync(`${kubectlPath} config use-context colima`, { stdio: 'ignore' });
454
+ } catch {
455
+ // Context might not exist yet, that's OK
456
+ }
416
457
  spinner.succeed('Colima started with Kubernetes');
417
458
  return true;
418
459
  } catch (error) {
@@ -460,6 +501,89 @@ async function deployTribeCluster() {
460
501
  TRIBE_DEPLOYMENT_YAML: destYaml
461
502
  };
462
503
 
504
+ // Wait for Kubernetes to be fully ready
505
+ spinner.text = 'Waiting for Kubernetes to be ready...';
506
+ const kubectlPath = await findCommand('kubectl') || 'kubectl';
507
+ let apiReady = false;
508
+ let contextSet = false;
509
+
510
+ // First, wait for the API server to be accessible
511
+ for (let i = 0; i < 30; i++) {
512
+ try {
513
+ // Try to get cluster info - this will work regardless of port
514
+ const clusterInfo = execSync(`${kubectlPath} cluster-info`, {
515
+ encoding: 'utf8',
516
+ env: env,
517
+ stdio: 'pipe'
518
+ });
519
+
520
+ // Check if we got valid cluster info
521
+ if (clusterInfo && clusterInfo.includes('is running at')) {
522
+ apiReady = true;
523
+ spinner.text = 'Kubernetes API server is ready';
524
+
525
+ // Extract the actual API server URL for logging
526
+ const urlMatch = clusterInfo.match(/is running at (https?:\/\/[^\s]+)/);
527
+ if (urlMatch) {
528
+ log.info(`Kubernetes API server: ${urlMatch[1]}`);
529
+ }
530
+ break;
531
+ }
532
+ } catch (error) {
533
+ spinner.text = `Waiting for Kubernetes API server... (${i+1}/30)`;
534
+ await new Promise(resolve => setTimeout(resolve, 2000));
535
+ }
536
+ }
537
+
538
+ if (!apiReady) {
539
+ spinner.warn('Kubernetes API server not ready after 60 seconds');
540
+ log.info('Deployment may fail. You can try running "tribe start" manually later.');
541
+ return false;
542
+ }
543
+
544
+ // Set the kubectl context to colima
545
+ spinner.text = 'Setting kubectl context...';
546
+ try {
547
+ execSync(`${kubectlPath} config use-context colima`, {
548
+ stdio: 'ignore',
549
+ env: env
550
+ });
551
+ contextSet = true;
552
+ } catch {
553
+ log.warning('Could not set kubectl context to colima');
554
+ }
555
+
556
+ // Wait for the node to be ready
557
+ spinner.text = 'Waiting for Kubernetes node to be ready...';
558
+ let nodeReady = false;
559
+ for (let i = 0; i < 20; i++) {
560
+ try {
561
+ const nodeStatus = execSync(`${kubectlPath} get nodes -o jsonpath='{.items[0].status.conditions[?(@.type=="Ready")].status}'`, {
562
+ encoding: 'utf8',
563
+ env: env
564
+ }).trim();
565
+
566
+ if (nodeStatus === 'True') {
567
+ nodeReady = true;
568
+ spinner.text = 'Kubernetes node is ready';
569
+ break;
570
+ }
571
+ } catch {
572
+ // Node might not be registered yet
573
+ }
574
+ spinner.text = `Waiting for Kubernetes node... (${i+1}/20)`;
575
+ await new Promise(resolve => setTimeout(resolve, 3000));
576
+ }
577
+
578
+ if (!nodeReady) {
579
+ spinner.warn('Kubernetes node not ready after 60 seconds');
580
+ log.info('The cluster may still be initializing. Proceeding with deployment...');
581
+ }
582
+
583
+ // Small delay to let everything stabilize
584
+ spinner.text = 'Starting TRIBE deployment...';
585
+ await new Promise(resolve => setTimeout(resolve, 2000));
586
+
463
587
  // Execute tribe start
464
588
  execSync(`${tribePath} start`, {
465
589
  stdio: 'pipe',
@@ -475,7 +599,19 @@ async function deployTribeCluster() {
475
599
  } catch (error) {
476
600
  spinner.fail('Failed to deploy TRIBE cluster');
477
601
  log.error(error.message);
478
- log.info('You can manually deploy later with: tribe start');
602
+
603
+ // Check if this is a Kubernetes connectivity issue
604
+ if (error.message && error.message.includes('connection refused')) {
605
+ log.warning('\nIt appears Kubernetes is not ready or not enabled.');
606
+ log.info('Troubleshooting steps:');
607
+ log.info('1. Check Colima status: colima status');
608
+ log.info('2. If running without Kubernetes, restart it:');
609
+ log.info(' colima stop');
610
+ log.info(' colima start --kubernetes');
611
+ log.info('3. Then run: tribe start');
612
+ } else {
613
+ log.info('You can manually deploy later with: tribe start');
614
+ }
479
615
  return false;
480
616
  }
481
617
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_xtribe/cli",
3
- "version": "1.0.0-beta.11",
3
+ "version": "1.0.0-beta.14",
4
4
  "description": "TRIBE multi-agent development system - Zero to productive with one command",
5
5
  "main": "install-tribe.js",
6
6
  "bin": {