@_xtribe/cli 1.0.0-beta.19 ā 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 +229 -64
- package/package.json +1 -4
- package/lima-guestagent.Linux-aarch64.gz +0 -0
- package/tribe +0 -0
- package/tribe-deployment.yaml +0 -455
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
|
|
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
|
-
//
|
|
184
|
-
|
|
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(
|
|
198
|
-
|
|
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
|
-
|
|
261
|
+
// Binary exists but doesn't work, remove it
|
|
262
|
+
fs.unlinkSync(tribeDest);
|
|
205
263
|
}
|
|
206
264
|
}
|
|
207
265
|
|
|
208
|
-
//
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Check if container runtime is already working
|
|
312
|
+
const spinner = ora('Starting container runtime...').start();
|
|
313
|
+
|
|
248
314
|
try {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
|
@@ -658,17 +786,40 @@ async function promptForClusterSetup() {
|
|
|
658
786
|
async function main() {
|
|
659
787
|
console.log(chalk.bold.blue('\nš TRIBE CLI Complete Installer\n'));
|
|
660
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
|
+
|
|
661
803
|
log.info(`Detected: ${platform} (${arch})`);
|
|
662
804
|
log.info(`Installing to: ${binDir}`);
|
|
663
805
|
|
|
664
806
|
// Update PATH first
|
|
665
807
|
await updatePath();
|
|
666
808
|
|
|
667
|
-
const tasks = [
|
|
668
|
-
|
|
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(
|
|
669
820
|
{ name: 'kubectl', fn: installKubectl },
|
|
670
|
-
{ name: 'TRIBE CLI', fn:
|
|
671
|
-
|
|
821
|
+
{ name: 'TRIBE CLI', fn: installTribeCLI }
|
|
822
|
+
);
|
|
672
823
|
|
|
673
824
|
let allSuccess = true;
|
|
674
825
|
|
|
@@ -688,7 +839,7 @@ async function main() {
|
|
|
688
839
|
// Check if cluster already exists
|
|
689
840
|
const clusterExists = await checkClusterExists();
|
|
690
841
|
|
|
691
|
-
if (!clusterExists) {
|
|
842
|
+
if (!clusterExists && !global.skipCluster) {
|
|
692
843
|
// Prompt for cluster setup
|
|
693
844
|
const shouldSetup = await promptForClusterSetup();
|
|
694
845
|
|
|
@@ -792,13 +943,24 @@ if (require.main === module) {
|
|
|
792
943
|
|
|
793
944
|
if (args.includes('--help') || args.includes('-h')) {
|
|
794
945
|
console.log(chalk.bold.blue('TRIBE CLI Installer\n'));
|
|
795
|
-
console.log('Usage: npx
|
|
946
|
+
console.log('Usage: npx @_xtribe/cli [options]\n');
|
|
796
947
|
console.log('Options:');
|
|
797
948
|
console.log(' --help, -h Show this help message');
|
|
798
949
|
console.log(' --verify Only verify existing installation');
|
|
799
950
|
console.log(' --dry-run Show what would be installed');
|
|
951
|
+
console.log(' --skip-cluster Skip cluster deployment (for testing)');
|
|
800
952
|
console.log('\nThis installer sets up the complete TRIBE development environment:');
|
|
801
|
-
|
|
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
|
+
|
|
802
964
|
console.log('⢠kubectl (Kubernetes CLI)');
|
|
803
965
|
console.log('⢠TRIBE CLI (Multi-agent orchestration)');
|
|
804
966
|
console.log('\nAfter installation:');
|
|
@@ -826,6 +988,9 @@ if (require.main === module) {
|
|
|
826
988
|
process.exit(0);
|
|
827
989
|
}
|
|
828
990
|
|
|
991
|
+
// Store skip-cluster flag
|
|
992
|
+
global.skipCluster = args.includes('--skip-cluster');
|
|
993
|
+
|
|
829
994
|
main().catch(error => {
|
|
830
995
|
console.error(chalk.red('Installation failed:'), error.message);
|
|
831
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.
|
|
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
|
package/tribe-deployment.yaml
DELETED
|
@@ -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!"
|