@_xtribe/cli 1.0.0-beta.18 → 1.0.0-beta.22

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 CHANGED
@@ -93,6 +93,60 @@ async function downloadFile(url, dest) {
93
93
 
94
94
  // Docker installation removed - Colima provides Docker runtime
95
95
 
96
+ async function installK3s() {
97
+ if (platform !== 'linux') {
98
+ return true; // K3s is Linux only
99
+ }
100
+
101
+ const spinner = ora('Installing K3s (lightweight Kubernetes)...').start();
102
+
103
+ try {
104
+ // Check if already installed
105
+ try {
106
+ execSync('k3s --version', { stdio: 'ignore' });
107
+ spinner.succeed('K3s already installed');
108
+ return true;
109
+ } catch {
110
+ // Not installed, continue
111
+ }
112
+
113
+ // One-line K3s installation
114
+ spinner.text = 'Installing K3s (this may take a few minutes)...';
115
+ console.log(chalk.yellow('\nšŸ“¦ Installing K3s - Lightweight Kubernetes'));
116
+ console.log(chalk.gray('This is a one-line installation that will:'));
117
+ console.log(chalk.gray(' • Download and install K3s'));
118
+ console.log(chalk.gray(' • Configure systemd service'));
119
+ console.log(chalk.gray(' • Set up kubectl access'));
120
+ console.log(chalk.gray(' • Disable Traefik (we use our own ingress)\n'));
121
+
122
+ execSync('curl -sfL https://get.k3s.io | sh -s - --disable traefik --write-kubeconfig-mode 644', {
123
+ stdio: 'inherit',
124
+ shell: '/bin/bash'
125
+ });
126
+
127
+ // Wait for K3s to be ready
128
+ spinner.text = 'Waiting for K3s to be ready...';
129
+ await new Promise(resolve => setTimeout(resolve, 10000));
130
+
131
+ // Make kubectl available
132
+ try {
133
+ execSync('sudo ln -sf /usr/local/bin/k3s /usr/local/bin/kubectl', { stdio: 'ignore' });
134
+ } catch {
135
+ // Link might already exist
136
+ }
137
+
138
+ // Set KUBECONFIG for current process
139
+ process.env.KUBECONFIG = '/etc/rancher/k3s/k3s.yaml';
140
+
141
+ spinner.succeed('K3s installed successfully');
142
+ return true;
143
+ } catch (error) {
144
+ spinner.fail(`K3s installation failed: ${error.message}`);
145
+ log.info('You can install K3s manually with: curl -sfL https://get.k3s.io | sh -');
146
+ return false;
147
+ }
148
+ }
149
+
96
150
  async function installColima() {
97
151
  if (platform !== 'darwin') {
98
152
  log.info('Colima is only needed on macOS - skipping');
@@ -149,6 +203,23 @@ async function installColima() {
149
203
  // KIND installation removed - using Colima's built-in Kubernetes
150
204
 
151
205
  async function installKubectl() {
206
+ // Linux with K3s already has kubectl
207
+ if (platform === 'linux') {
208
+ try {
209
+ execSync('k3s kubectl version --client', { stdio: 'ignore' });
210
+ log.success('kubectl available via k3s');
211
+ // Create a symlink for convenience
212
+ try {
213
+ execSync('sudo ln -sf /usr/local/bin/k3s /usr/local/bin/kubectl', { stdio: 'ignore' });
214
+ } catch {
215
+ // Link might already exist
216
+ }
217
+ return true;
218
+ } catch {
219
+ // Continue with regular kubectl installation
220
+ }
221
+ }
222
+
152
223
  if (await checkCommand('kubectl')) {
153
224
  log.success('kubectl already installed');
154
225
  return true;
@@ -174,65 +245,63 @@ async function installKubectl() {
174
245
  }
175
246
  }
176
247
 
177
- async function installTribeCli() {
248
+ async function installTribeCLI() {
178
249
  const spinner = ora('Installing TRIBE CLI...').start();
179
250
 
180
251
  try {
181
252
  const tribeDest = path.join(binDir, 'tribe');
182
253
 
183
- // First check if we have a bundled binary
184
- const bundledBinary = path.join(__dirname, 'tribe');
185
- if (fs.existsSync(bundledBinary)) {
186
- fs.copyFileSync(bundledBinary, tribeDest);
187
- fs.chmodSync(tribeDest, '755');
188
- spinner.succeed('TRIBE CLI installed from bundled binary');
189
- return true;
190
- }
191
-
192
- // Check if we have local source
193
- const sourceFile = path.join(__dirname, 'cluster-cli.go');
194
- if (fs.existsSync(sourceFile)) {
195
- // Build from source
254
+ // Skip if already installed and working
255
+ if (fs.existsSync(tribeDest)) {
196
256
  try {
197
- execSync('go version', { stdio: 'ignore' });
198
- execSync(`cd ${__dirname} && go build -o tribe cluster-cli.go client.go`);
199
- fs.copyFileSync(path.join(__dirname, 'tribe'), tribeDest);
200
- fs.chmodSync(tribeDest, '755');
201
- spinner.succeed('TRIBE CLI built from source');
257
+ execSync(`${tribeDest} version`, { stdio: 'ignore' });
258
+ spinner.succeed('TRIBE CLI already installed');
202
259
  return true;
203
260
  } catch {
204
- spinner.warn('Go not available, trying pre-built binary...');
261
+ // Binary exists but doesn't work, remove it
262
+ fs.unlinkSync(tribeDest);
205
263
  }
206
264
  }
207
265
 
208
- // Try pre-built binary from GitHub
209
- const tribeUrl = `https://github.com/0zen/0zen/releases/latest/download/tribe-${platform}-${arch}`;
210
-
211
- try {
212
- await downloadFile(tribeUrl, tribeDest);
213
- fs.chmodSync(tribeDest, '755');
214
- spinner.succeed('TRIBE CLI installed');
215
- return true;
216
- } catch {
217
- // Fallback: look for any existing tribe binary
218
- const possiblePaths = [
219
- path.join(__dirname, '..', 'tribe-cli'),
220
- path.join(__dirname, '..', 'tribe'),
221
- './tribe-cli',
222
- './tribe'
223
- ];
224
-
225
- for (const possiblePath of possiblePaths) {
226
- if (fs.existsSync(possiblePath)) {
227
- fs.copyFileSync(possiblePath, tribeDest);
228
- fs.chmodSync(tribeDest, '755');
229
- spinner.succeed('TRIBE CLI installed from local binary');
230
- return true;
231
- }
266
+ // Download pre-built binary from GitHub
267
+ const arch = process.arch === 'x64' ? 'amd64' : 'arm64';
268
+ const platform = os.platform();
269
+
270
+ // Multiple sources for reliability
271
+ const sources = [
272
+ // GitHub releases (primary source)
273
+ `https://github.com/TRIBE-INC/0zen/releases/latest/download/tribe-${platform}-${arch}`,
274
+ // Try jsDelivr CDN as fallback
275
+ `https://cdn.jsdelivr.net/gh/TRIBE-INC/0zen@latest/releases/tribe-${platform}-${arch}`,
276
+ // Direct raw GitHub as last resort
277
+ `https://raw.githubusercontent.com/TRIBE-INC/0zen/main/releases/tribe-${platform}-${arch}`
278
+ ];
279
+
280
+ let downloaded = false;
281
+ let lastError;
282
+
283
+ for (const url of sources) {
284
+ spinner.text = `Downloading TRIBE CLI from ${url.includes('jsdelivr') ? 'CDN' : 'GitHub'}...`;
285
+ try {
286
+ await downloadFile(url, tribeDest);
287
+ fs.chmodSync(tribeDest, '755');
288
+
289
+ // Verify the binary works
290
+ execSync(`${tribeDest} version`, { stdio: 'ignore' });
291
+ spinner.succeed('TRIBE CLI installed successfully');
292
+ downloaded = true;
293
+ break;
294
+ } catch (error) {
295
+ lastError = error;
296
+ log.warning(`Failed to download from ${url.split('/').slice(2, 3).join('/')}, trying next source...`);
232
297
  }
233
-
234
- throw new Error('No TRIBE CLI binary available');
235
298
  }
299
+
300
+ if (!downloaded) {
301
+ throw new Error(`Failed to download TRIBE CLI: ${lastError?.message || 'All sources failed'}`);
302
+ }
303
+
304
+ return true;
236
305
  } catch (error) {
237
306
  spinner.fail(`TRIBE CLI installation failed: ${error.message}`);
238
307
  return false;
@@ -240,17 +309,18 @@ async function installTribeCli() {
240
309
  }
241
310
 
242
311
  async function startContainerRuntime() {
243
- if (platform !== 'darwin') {
244
- return true; // Linux uses Docker daemon directly
245
- }
246
-
247
- // Check if container runtime is already working
312
+ const spinner = ora('Starting container runtime...').start();
313
+
248
314
  try {
249
- execSync('docker info', { stdio: 'ignore' });
250
- log.success('Container runtime is already working');
251
- return true;
252
- } catch {
253
- // Try to start Colima with different approaches
315
+ // Platform-specific container runtime handling
316
+ if (platform === 'darwin') {
317
+ // macOS - Check if container runtime is already working via Colima
318
+ try {
319
+ execSync('docker info', { stdio: 'ignore' });
320
+ log.success('Container runtime is already working');
321
+ return true;
322
+ } catch {
323
+ // Try to start Colima with different approaches
254
324
  if (await checkCommand('colima')) {
255
325
  const spinner = ora('Starting Colima container runtime...').start();
256
326
 
@@ -307,8 +377,40 @@ async function startContainerRuntime() {
307
377
  }
308
378
  }
309
379
  }
380
+ }
381
+ } else if (platform === 'linux') {
382
+ // Linux - K3s should already be running
383
+ spinner.text = 'Checking K3s status...';
384
+ try {
385
+ execSync('sudo systemctl is-active --quiet k3s', { stdio: 'ignore' });
386
+ spinner.succeed('K3s is running');
387
+ return true;
388
+ } catch {
389
+ // Try to start K3s
390
+ spinner.text = 'Starting K3s...';
391
+ try {
392
+ execSync('sudo systemctl start k3s', { stdio: 'ignore' });
393
+ await new Promise(resolve => setTimeout(resolve, 5000));
394
+ spinner.succeed('K3s started');
395
+ return true;
396
+ } catch (error) {
397
+ spinner.fail('Failed to start K3s');
398
+ log.error('Please ensure K3s is installed and you have sudo access');
399
+ return false;
400
+ }
401
+ }
402
+ } else if (platform === 'win32') {
403
+ spinner.fail('Windows support coming soon!');
404
+ log.info('For Windows, please use WSL2 with Ubuntu and run this installer inside WSL2');
405
+ return false;
406
+ } else {
407
+ spinner.fail(`Unsupported platform: ${platform}`);
408
+ return false;
409
+ }
410
+ } catch (error) {
411
+ spinner.fail(`Container runtime error: ${error.message}`);
412
+ return false;
310
413
  }
311
- return false;
312
414
  }
313
415
 
314
416
  async function updatePath() {
@@ -488,6 +590,32 @@ async function deployTribeCluster() {
488
590
  if (fs.existsSync(sourceYaml)) {
489
591
  fs.copyFileSync(sourceYaml, destYaml);
490
592
  log.info('Copied deployment configuration');
593
+ } else {
594
+ // Download deployment YAML if not bundled
595
+ spinner.text = 'Downloading deployment configuration...';
596
+ const yamlSources = [
597
+ // Direct from GitHub (primary)
598
+ 'https://raw.githubusercontent.com/TRIBE-INC/0zen/main/sdk/cmd/cli-gui/package/tribe-deployment.yaml',
599
+ // jsDelivr CDN as fallback
600
+ 'https://cdn.jsdelivr.net/gh/TRIBE-INC/0zen@main/sdk/cmd/cli-gui/package/tribe-deployment.yaml'
601
+ ];
602
+
603
+ let yamlDownloaded = false;
604
+ for (const yamlUrl of yamlSources) {
605
+ try {
606
+ await downloadFile(yamlUrl, destYaml);
607
+ log.info('Downloaded deployment configuration');
608
+ yamlDownloaded = true;
609
+ break;
610
+ } catch (downloadError) {
611
+ // Try next source
612
+ }
613
+ }
614
+
615
+ if (!yamlDownloaded) {
616
+ spinner.fail('Failed to get deployment configuration');
617
+ throw new Error('Could not download deployment YAML from any source');
618
+ }
491
619
  }
492
620
 
493
621
  // Run tribe start command with deployment YAML path
@@ -558,20 +686,36 @@ async function deployTribeCluster() {
558
686
  let nodeReady = false;
559
687
  for (let i = 0; i < 20; i++) {
560
688
  try {
561
- const nodeStatus = execSync(`${kubectlPath} get nodes -o jsonpath='{.items[0].status.conditions[?(@.type=="Ready")].status}'`, {
689
+ // First check if any nodes exist
690
+ const nodeList = execSync(`${kubectlPath} get nodes -o json`, {
562
691
  encoding: 'utf8',
563
- env: env
564
- }).trim();
692
+ env: env,
693
+ stdio: 'pipe'
694
+ });
565
695
 
566
- if (nodeStatus === 'True') {
567
- nodeReady = true;
568
- spinner.text = 'Kubernetes node is ready';
569
- break;
696
+ const nodes = JSON.parse(nodeList);
697
+ if (nodes.items && nodes.items.length > 0) {
698
+ // Now check if the node is ready
699
+ const nodeStatus = execSync(`${kubectlPath} get nodes -o jsonpath='{.items[0].status.conditions[?(@.type=="Ready")].status}'`, {
700
+ encoding: 'utf8',
701
+ env: env,
702
+ stdio: 'pipe'
703
+ }).trim();
704
+
705
+ if (nodeStatus === 'True') {
706
+ nodeReady = true;
707
+ spinner.text = 'Kubernetes node is ready';
708
+ break;
709
+ }
710
+ }
711
+ } catch (error) {
712
+ // Ignore errors - node might not be registered yet or connection issues
713
+ if (error.message && error.message.includes('connection reset')) {
714
+ spinner.text = `Waiting for Kubernetes node... (${i+1}/20) - reconnecting...`;
715
+ } else {
716
+ spinner.text = `Waiting for Kubernetes node... (${i+1}/20)`;
570
717
  }
571
- } catch {
572
- // Node might not be registered yet
573
718
  }
574
- spinner.text = `Waiting for Kubernetes node... (${i+1}/20)`;
575
719
  await new Promise(resolve => setTimeout(resolve, 3000));
576
720
  }
577
721
 
@@ -642,17 +786,40 @@ async function promptForClusterSetup() {
642
786
  async function main() {
643
787
  console.log(chalk.bold.blue('\nšŸš€ TRIBE CLI Complete Installer\n'));
644
788
 
789
+ // Detect and display platform info
790
+ const arch = process.arch === 'x64' ? 'amd64' : process.arch;
791
+ console.log(chalk.cyan(`Platform: ${platform} (${arch})`));
792
+ console.log(chalk.cyan(`Node: ${process.version}`));
793
+ console.log('');
794
+
795
+ // Check for unsupported platforms early
796
+ if (platform === 'win32') {
797
+ console.log(chalk.yellow('\nāš ļø Windows is not yet supported'));
798
+ console.log(chalk.yellow('Please use WSL2 with Ubuntu and run this installer inside WSL2'));
799
+ console.log(chalk.yellow('Instructions: https://docs.microsoft.com/en-us/windows/wsl/install\n'));
800
+ process.exit(1);
801
+ }
802
+
645
803
  log.info(`Detected: ${platform} (${arch})`);
646
804
  log.info(`Installing to: ${binDir}`);
647
805
 
648
806
  // Update PATH first
649
807
  await updatePath();
650
808
 
651
- const tasks = [
652
- { name: 'Colima', fn: installColima },
809
+ const tasks = [];
810
+
811
+ // Platform-specific Kubernetes installation
812
+ if (platform === 'darwin') {
813
+ tasks.push({ name: 'Colima', fn: installColima });
814
+ } else if (platform === 'linux') {
815
+ tasks.push({ name: 'K3s', fn: installK3s });
816
+ }
817
+
818
+ // Common tools for all platforms
819
+ tasks.push(
653
820
  { name: 'kubectl', fn: installKubectl },
654
- { name: 'TRIBE CLI', fn: installTribeCli }
655
- ];
821
+ { name: 'TRIBE CLI', fn: installTribeCLI }
822
+ );
656
823
 
657
824
  let allSuccess = true;
658
825
 
@@ -672,7 +839,7 @@ async function main() {
672
839
  // Check if cluster already exists
673
840
  const clusterExists = await checkClusterExists();
674
841
 
675
- if (!clusterExists) {
842
+ if (!clusterExists && !global.skipCluster) {
676
843
  // Prompt for cluster setup
677
844
  const shouldSetup = await promptForClusterSetup();
678
845
 
@@ -776,13 +943,24 @@ if (require.main === module) {
776
943
 
777
944
  if (args.includes('--help') || args.includes('-h')) {
778
945
  console.log(chalk.bold.blue('TRIBE CLI Installer\n'));
779
- console.log('Usage: npx tribe-cli-local [options]\n');
946
+ console.log('Usage: npx @_xtribe/cli [options]\n');
780
947
  console.log('Options:');
781
948
  console.log(' --help, -h Show this help message');
782
949
  console.log(' --verify Only verify existing installation');
783
950
  console.log(' --dry-run Show what would be installed');
951
+ console.log(' --skip-cluster Skip cluster deployment (for testing)');
784
952
  console.log('\nThis installer sets up the complete TRIBE development environment:');
785
- console.log('• Colima (Container runtime with Kubernetes)');
953
+
954
+ if (platform === 'darwin') {
955
+ console.log('• Colima (Container runtime with Kubernetes)');
956
+ } else if (platform === 'linux') {
957
+ console.log('• K3s (Lightweight Kubernetes, one-line install)');
958
+ } else if (platform === 'win32') {
959
+ console.log('\nāš ļø Windows support coming soon!');
960
+ console.log('Please use WSL2 with Ubuntu and run this installer inside WSL2');
961
+ process.exit(1);
962
+ }
963
+
786
964
  console.log('• kubectl (Kubernetes CLI)');
787
965
  console.log('• TRIBE CLI (Multi-agent orchestration)');
788
966
  console.log('\nAfter installation:');
@@ -810,6 +988,9 @@ if (require.main === module) {
810
988
  process.exit(0);
811
989
  }
812
990
 
991
+ // Store skip-cluster flag
992
+ global.skipCluster = args.includes('--skip-cluster');
993
+
813
994
  main().catch(error => {
814
995
  console.error(chalk.red('Installation failed:'), error.message);
815
996
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_xtribe/cli",
3
- "version": "1.0.0-beta.18",
3
+ "version": "1.0.0-beta.22",
4
4
  "description": "TRIBE multi-agent development system - Zero to productive with one command",
5
5
  "main": "install-tribe.js",
6
6
  "bin": {
@@ -35,9 +35,6 @@
35
35
  },
36
36
  "files": [
37
37
  "install-tribe.js",
38
- "lima-guestagent.Linux-aarch64.gz",
39
- "tribe-deployment.yaml",
40
- "tribe",
41
38
  "README.md",
42
39
  "package.json"
43
40
  ],
Binary file
package/tribe DELETED
Binary file
@@ -1,455 +0,0 @@
1
- ---
2
- # TRIBE Complete Deployment - Bundled with NPM Package
3
- # This file is automatically deployed by 'npx @_xtribe/cli'
4
- #
5
- # IMPORTANT: This deployment uses PUBLIC Docker Hub images from tribexal/tribe
6
- # - tribexal/tribe:latest-taskmaster
7
- # - tribexal/tribe:latest-bridge
8
- # - tribexal/tribe:latest-claude-agent
9
- #
10
- # DO NOT change these to local image names for the npm package!
11
- ---
12
- apiVersion: v1
13
- kind: Namespace
14
- metadata:
15
- name: tribe-system
16
- ---
17
- # ServiceAccount for Bridge
18
- apiVersion: v1
19
- kind: ServiceAccount
20
- metadata:
21
- name: bridge
22
- namespace: tribe-system
23
- ---
24
- # Role for Bridge
25
- apiVersion: rbac.authorization.k8s.io/v1
26
- kind: Role
27
- metadata:
28
- name: bridge-role
29
- namespace: tribe-system
30
- rules:
31
- - apiGroups: [""]
32
- resources: ["pods", "services", "pods/exec", "pods/log", "configmaps", "secrets", "namespaces"]
33
- verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
34
- - apiGroups: ["apps"]
35
- resources: ["deployments", "replicasets"]
36
- verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
37
- - apiGroups: ["batch"]
38
- resources: ["jobs"]
39
- verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
40
- ---
41
- # RoleBinding for Bridge
42
- apiVersion: rbac.authorization.k8s.io/v1
43
- kind: RoleBinding
44
- metadata:
45
- name: bridge-rolebinding
46
- namespace: tribe-system
47
- subjects:
48
- - kind: ServiceAccount
49
- name: bridge
50
- namespace: tribe-system
51
- roleRef:
52
- kind: Role
53
- name: bridge-role
54
- apiGroup: rbac.authorization.k8s.io
55
- ---
56
- # PostgreSQL
57
- apiVersion: apps/v1
58
- kind: Deployment
59
- metadata:
60
- name: postgres
61
- namespace: tribe-system
62
- spec:
63
- replicas: 1
64
- selector:
65
- matchLabels:
66
- app: postgres
67
- template:
68
- metadata:
69
- labels:
70
- app: postgres
71
- spec:
72
- containers:
73
- - name: postgres
74
- image: postgres:15
75
- env:
76
- - name: POSTGRES_DB
77
- value: gitea
78
- - name: POSTGRES_USER
79
- value: gitea
80
- - name: POSTGRES_PASSWORD
81
- value: gitea
82
- ports:
83
- - containerPort: 5432
84
- readinessProbe:
85
- exec:
86
- command:
87
- - pg_isready
88
- - -U
89
- - gitea
90
- initialDelaySeconds: 5
91
- periodSeconds: 5
92
- ---
93
- apiVersion: v1
94
- kind: Service
95
- metadata:
96
- name: postgres
97
- namespace: tribe-system
98
- spec:
99
- selector:
100
- app: postgres
101
- ports:
102
- - port: 5432
103
- ---
104
- # Gitea
105
- apiVersion: apps/v1
106
- kind: Deployment
107
- metadata:
108
- name: gitea
109
- namespace: tribe-system
110
- spec:
111
- replicas: 1
112
- selector:
113
- matchLabels:
114
- app: gitea
115
- template:
116
- metadata:
117
- labels:
118
- app: gitea
119
- spec:
120
- initContainers:
121
- - name: wait-for-db
122
- image: busybox:1.35
123
- command: ['sh', '-c', 'until nc -z postgres 5432; do echo waiting for db; sleep 2; done']
124
- - name: init-gitea
125
- image: gitea/gitea:1.20.5
126
- command: ['/bin/bash', '-c']
127
- args:
128
- - |
129
- # Create app.ini
130
- mkdir -p /data/gitea/conf
131
- cat > /data/gitea/conf/app.ini << 'EOF'
132
- APP_NAME = Gitea
133
- RUN_MODE = prod
134
-
135
- [database]
136
- DB_TYPE = postgres
137
- HOST = postgres:5432
138
- NAME = gitea
139
- USER = gitea
140
- PASSWD = gitea
141
-
142
- [server]
143
- DOMAIN = gitea
144
- ROOT_URL = http://gitea:3000/
145
- HTTP_PORT = 3000
146
-
147
- [service]
148
- DISABLE_REGISTRATION = true
149
-
150
- [security]
151
- INSTALL_LOCK = true
152
- SECRET_KEY = changeme
153
- EOF
154
-
155
- # Run migrations
156
- gitea migrate
157
-
158
- # Create admin user
159
- gitea admin user create --admin --username gitea_admin --password admin123 --email admin@example.com || true
160
- env:
161
- - name: GITEA_WORK_DIR
162
- value: /data
163
- - name: GITEA_CUSTOM
164
- value: /data/gitea
165
- volumeMounts:
166
- - name: gitea-data
167
- mountPath: /data
168
- containers:
169
- - name: gitea
170
- image: gitea/gitea:1.20.5
171
- ports:
172
- - containerPort: 3000
173
- env:
174
- - name: GITEA_WORK_DIR
175
- value: /data
176
- - name: GITEA_CUSTOM
177
- value: /data/gitea
178
- volumeMounts:
179
- - name: gitea-data
180
- mountPath: /data
181
- readinessProbe:
182
- httpGet:
183
- path: /
184
- port: 3000
185
- initialDelaySeconds: 30
186
- periodSeconds: 10
187
- volumes:
188
- - name: gitea-data
189
- emptyDir: {}
190
- ---
191
- apiVersion: v1
192
- kind: Service
193
- metadata:
194
- name: gitea
195
- namespace: tribe-system
196
- spec:
197
- selector:
198
- app: gitea
199
- ports:
200
- - port: 3000
201
- ---
202
- # TaskMaster
203
- apiVersion: apps/v1
204
- kind: Deployment
205
- metadata:
206
- name: taskmaster
207
- namespace: tribe-system
208
- spec:
209
- replicas: 1
210
- selector:
211
- matchLabels:
212
- app: taskmaster
213
- template:
214
- metadata:
215
- labels:
216
- app: taskmaster
217
- spec:
218
- initContainers:
219
- - name: wait-for-db
220
- image: busybox:1.35
221
- command: ['sh', '-c', 'until nc -z postgres 5432; do echo waiting for db; sleep 2; done']
222
- containers:
223
- - name: taskmaster
224
- image: tribexal/tribe:latest-taskmaster
225
- imagePullPolicy: IfNotPresent
226
- ports:
227
- - containerPort: 5000
228
- env:
229
- - name: FLASK_ENV
230
- value: development
231
- - name: DATABASE_URL
232
- value: postgresql://gitea:gitea@postgres:5432/gitea
233
- - name: GITEA_URL
234
- value: http://gitea:3000
235
- - name: GITEA_TOKEN
236
- value: will-be-set-by-init-job
237
- readinessProbe:
238
- httpGet:
239
- path: /
240
- port: 5000
241
- initialDelaySeconds: 10
242
- periodSeconds: 5
243
- ---
244
- apiVersion: v1
245
- kind: Service
246
- metadata:
247
- name: taskmaster
248
- namespace: tribe-system
249
- spec:
250
- selector:
251
- app: taskmaster
252
- ports:
253
- - port: 5000
254
- ---
255
- # Bridge
256
- apiVersion: apps/v1
257
- kind: Deployment
258
- metadata:
259
- name: bridge
260
- namespace: tribe-system
261
- spec:
262
- replicas: 1
263
- selector:
264
- matchLabels:
265
- app: bridge
266
- template:
267
- metadata:
268
- labels:
269
- app: bridge
270
- spec:
271
- serviceAccountName: bridge
272
- initContainers:
273
- - name: wait-for-services
274
- image: busybox:1.35
275
- command: ['sh', '-c']
276
- args:
277
- - |
278
- echo "Waiting for services..."
279
- until nc -z taskmaster 5000; do echo waiting for taskmaster; sleep 2; done
280
- until nc -z gitea 3000; do echo waiting for gitea; sleep 2; done
281
- echo "All services ready!"
282
- containers:
283
- - name: bridge
284
- image: tribexal/tribe:latest-bridge
285
- imagePullPolicy: IfNotPresent
286
- ports:
287
- - containerPort: 8080
288
- - containerPort: 3456
289
- env:
290
- - name: TASKMASTER_URL
291
- value: http://taskmaster:5000
292
- - name: GITEA_URL
293
- value: http://gitea:3000
294
- - name: GITEA_ADMIN_USER
295
- value: gitea_admin
296
- - name: GITEA_ADMIN_PASSWORD
297
- value: admin123
298
- - name: NAMESPACE
299
- value: tribe-system
300
- readinessProbe:
301
- httpGet:
302
- path: /health
303
- port: 8080
304
- initialDelaySeconds: 10
305
- periodSeconds: 5
306
- ---
307
- apiVersion: v1
308
- kind: Service
309
- metadata:
310
- name: bridge
311
- namespace: tribe-system
312
- spec:
313
- selector:
314
- app: bridge
315
- ports:
316
- - name: http
317
- port: 8080
318
- - name: websocket
319
- port: 3456
320
- ---
321
- # Claude Worker Deployment (starts with 0 replicas)
322
- apiVersion: apps/v1
323
- kind: Deployment
324
- metadata:
325
- name: claude-worker-deployment
326
- namespace: tribe-system
327
- spec:
328
- replicas: 0
329
- selector:
330
- matchLabels:
331
- app: claude-worker
332
- template:
333
- metadata:
334
- labels:
335
- app: claude-worker
336
- spec:
337
- containers:
338
- - name: claude-agent
339
- image: tribexal/tribe:latest-claude-agent
340
- imagePullPolicy: IfNotPresent
341
- env:
342
- - name: ROLE
343
- value: worker
344
- - name: TASKMASTER_URL
345
- value: http://taskmaster:5000
346
- - name: GITEA_URL
347
- value: http://gitea:3000
348
- - name: NAMESPACE
349
- value: tribe-system
350
- - name: ANTHROPIC_API_KEY
351
- valueFrom:
352
- secretKeyRef:
353
- name: claude-api-key
354
- key: api-key
355
- optional: true
356
- volumeMounts:
357
- - name: workspace
358
- mountPath: /workspace
359
- - name: config
360
- mountPath: /app/minimal-config
361
- readinessProbe:
362
- exec:
363
- command:
364
- - /bin/sh
365
- - -c
366
- - test -f /tmp/worker-ready
367
- initialDelaySeconds: 30
368
- periodSeconds: 10
369
- volumes:
370
- - name: workspace
371
- emptyDir: {}
372
- - name: config
373
- configMap:
374
- name: claude-config
375
- optional: true
376
- ---
377
- # NodePort service for easy access
378
- apiVersion: v1
379
- kind: Service
380
- metadata:
381
- name: bridge-nodeport
382
- namespace: tribe-system
383
- spec:
384
- type: NodePort
385
- selector:
386
- app: bridge
387
- ports:
388
- - name: http
389
- port: 8080
390
- nodePort: 30080
391
- - name: websocket
392
- port: 3456
393
- nodePort: 30456
394
- ---
395
- # ConfigMap for Claude agent configuration
396
- apiVersion: v1
397
- kind: ConfigMap
398
- metadata:
399
- name: claude-config
400
- namespace: tribe-system
401
- data:
402
- config.yaml: |
403
- mcp_servers:
404
- filesystem:
405
- command: npx
406
- args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
407
- git:
408
- command: npx
409
- args: ["-y", "@modelcontextprotocol/server-git"]
410
- env:
411
- PATH: /usr/local/bin:/usr/bin:/bin
412
- ---
413
- # Initialization Job
414
- apiVersion: batch/v1
415
- kind: Job
416
- metadata:
417
- name: tribe-init
418
- namespace: tribe-system
419
- spec:
420
- template:
421
- spec:
422
- restartPolicy: OnFailure
423
- containers:
424
- - name: init
425
- image: curlimages/curl:8.4.0
426
- command: ['/bin/sh', '-c']
427
- args:
428
- - |
429
- echo "Waiting for Gitea to be ready..."
430
- until curl -s http://gitea:3000 > /dev/null; do
431
- echo "Waiting for Gitea..."
432
- sleep 5
433
- done
434
-
435
- echo "Creating Gitea access token..."
436
- TOKEN=$(curl -s -X POST http://gitea:3000/api/v1/users/gitea_admin/tokens \
437
- -u gitea_admin:admin123 \
438
- -H "Content-Type: application/json" \
439
- -d '{"name":"taskmaster-'$(date +%s)'","scopes":["write:repository","write:user","write:issue","write:organization","read:repository"]}' \
440
- | grep -o '"sha1":"[^"]*' | cut -d'"' -f4)
441
-
442
- if [ -z "$TOKEN" ]; then
443
- echo "Failed to create token!"
444
- exit 1
445
- fi
446
-
447
- echo "Token created successfully"
448
-
449
- # Update TaskMaster with the token
450
- echo "Updating TaskMaster configuration..."
451
- curl -X POST http://taskmaster:5000/api/config \
452
- -H "Content-Type: application/json" \
453
- -d "{\"gitea_token\":\"$TOKEN\"}"
454
-
455
- echo "Initialization complete!"