@_xtribe/cli 2.2.50 → 2.2.52
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 +119 -23
- package/package.json +1 -1
- package/tribe-deployment.yaml +143 -0
package/install-tribe.js
CHANGED
|
@@ -182,17 +182,6 @@ async function installTribeCLIQuiet() {
|
|
|
182
182
|
}
|
|
183
183
|
fs.chmodSync(tutorCollectorDest, '755');
|
|
184
184
|
|
|
185
|
-
// Also download tutor-server binary for self-hosting capability
|
|
186
|
-
const tutorServerDest = path.join(tribeBinDir, 'tutor-server');
|
|
187
|
-
const tutorServerUrl = `https://github.com/TRIBE-INC/tutor-server-community-release/releases/latest/download/tutor-server-${platform}-${arch}`;
|
|
188
|
-
try {
|
|
189
|
-
await downloadFile(tutorServerUrl, tutorServerDest);
|
|
190
|
-
fs.chmodSync(tutorServerDest, '755');
|
|
191
|
-
} catch (error) {
|
|
192
|
-
// Server binary is optional - don't fail installation if unavailable
|
|
193
|
-
console.warn('Warning: Could not download tutor-server binary (optional for self-hosting)');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
185
|
// Remove macOS quarantine if needed
|
|
197
186
|
if (platform === 'darwin') {
|
|
198
187
|
try {
|
|
@@ -200,9 +189,6 @@ async function installTribeCLIQuiet() {
|
|
|
200
189
|
if (fs.existsSync(tutorCollectorDest)) {
|
|
201
190
|
execSync(`xattr -d com.apple.quarantine "${tutorCollectorDest}"`, { stdio: 'ignore' });
|
|
202
191
|
}
|
|
203
|
-
if (fs.existsSync(tutorServerDest)) {
|
|
204
|
-
execSync(`xattr -d com.apple.quarantine "${tutorServerDest}"`, { stdio: 'ignore' });
|
|
205
|
-
}
|
|
206
192
|
} catch {
|
|
207
193
|
// Not critical
|
|
208
194
|
}
|
|
@@ -233,6 +219,98 @@ async function setupPathQuiet() {
|
|
|
233
219
|
}
|
|
234
220
|
}
|
|
235
221
|
|
|
222
|
+
async function autoEnableTelemetry() {
|
|
223
|
+
const homeDir = os.homedir();
|
|
224
|
+
const tribeBin = path.join(homeDir, '.tribe', 'bin', 'tribe');
|
|
225
|
+
const tutorCollector = path.join(homeDir, '.tribe', 'bin', 'tutor-collector');
|
|
226
|
+
|
|
227
|
+
// Check if binaries exist
|
|
228
|
+
if (!fs.existsSync(tribeBin) || !fs.existsSync(tutorCollector)) {
|
|
229
|
+
return; // Binaries not installed yet
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// On macOS, create launchd agent for auto-start on boot
|
|
233
|
+
if (process.platform === 'darwin') {
|
|
234
|
+
const launchAgentsDir = path.join(homeDir, 'Library', 'LaunchAgents');
|
|
235
|
+
const logsDir = path.join(homeDir, '.tribe', 'logs');
|
|
236
|
+
const plistPath = path.join(launchAgentsDir, 'ai.tribe.tutor-collector.plist');
|
|
237
|
+
|
|
238
|
+
// Ensure directories exist
|
|
239
|
+
fs.mkdirSync(launchAgentsDir, { recursive: true });
|
|
240
|
+
fs.mkdirSync(logsDir, { recursive: true });
|
|
241
|
+
|
|
242
|
+
const serverURL = process.env.TRIBE_TUTOR_SERVER_URL || 'https://tutor.tribecode.ai';
|
|
243
|
+
|
|
244
|
+
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
245
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
246
|
+
<plist version="1.0">
|
|
247
|
+
<dict>
|
|
248
|
+
<key>Label</key>
|
|
249
|
+
<string>ai.tribe.tutor-collector</string>
|
|
250
|
+
<key>ProgramArguments</key>
|
|
251
|
+
<array>
|
|
252
|
+
<string>${tutorCollector}</string>
|
|
253
|
+
<string>-server</string>
|
|
254
|
+
<string>${serverURL}</string>
|
|
255
|
+
<string>-interval</string>
|
|
256
|
+
<string>10s</string>
|
|
257
|
+
<string>-buffer</string>
|
|
258
|
+
<string>50</string>
|
|
259
|
+
</array>
|
|
260
|
+
<key>RunAtLoad</key>
|
|
261
|
+
<true/>
|
|
262
|
+
<key>KeepAlive</key>
|
|
263
|
+
<dict>
|
|
264
|
+
<key>SuccessfulExit</key>
|
|
265
|
+
<false/>
|
|
266
|
+
</dict>
|
|
267
|
+
<key>StandardOutPath</key>
|
|
268
|
+
<string>${logsDir}/tutor-collector.log</string>
|
|
269
|
+
<key>StandardErrorPath</key>
|
|
270
|
+
<string>${logsDir}/tutor-collector.error.log</string>
|
|
271
|
+
<key>WorkingDirectory</key>
|
|
272
|
+
<string>${homeDir}</string>
|
|
273
|
+
<key>EnvironmentVariables</key>
|
|
274
|
+
<dict>
|
|
275
|
+
<key>HOME</key>
|
|
276
|
+
<string>${homeDir}</string>
|
|
277
|
+
<key>PATH</key>
|
|
278
|
+
<string>/usr/local/bin:/usr/bin:/bin:${homeDir}/.tribe/bin</string>
|
|
279
|
+
</dict>
|
|
280
|
+
</dict>
|
|
281
|
+
</plist>
|
|
282
|
+
`;
|
|
283
|
+
|
|
284
|
+
// Unload old agents first
|
|
285
|
+
for (const oldLabel of ['ai.tribe.tutor', 'ai.tribecode.tutor', 'ai.tribe.tutor-collector']) {
|
|
286
|
+
try {
|
|
287
|
+
execSync(`launchctl unload "${path.join(launchAgentsDir, oldLabel + '.plist')}"`, { stdio: 'ignore' });
|
|
288
|
+
} catch {
|
|
289
|
+
// Ignore errors
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Write and load new plist
|
|
294
|
+
fs.writeFileSync(plistPath, plistContent);
|
|
295
|
+
try {
|
|
296
|
+
execSync(`launchctl load "${plistPath}"`, { stdio: 'ignore' });
|
|
297
|
+
} catch {
|
|
298
|
+
// If launchctl fails, try starting directly
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Also try to start via tribe enable for immediate startup
|
|
303
|
+
try {
|
|
304
|
+
execSync(`"${tribeBin}" enable`, {
|
|
305
|
+
stdio: 'ignore',
|
|
306
|
+
timeout: 10000,
|
|
307
|
+
env: { ...process.env, HOME: homeDir }
|
|
308
|
+
});
|
|
309
|
+
} catch {
|
|
310
|
+
// Ignore - launchd will handle it on next boot
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
236
314
|
async function main() {
|
|
237
315
|
const args = process.argv.slice(2);
|
|
238
316
|
|
|
@@ -270,22 +348,40 @@ async function main() {
|
|
|
270
348
|
// Silently ignore update failures
|
|
271
349
|
});
|
|
272
350
|
|
|
351
|
+
// Auto-enable telemetry collection (critical for data gathering)
|
|
352
|
+
try {
|
|
353
|
+
await autoEnableTelemetry();
|
|
354
|
+
} catch (error) {
|
|
355
|
+
// Log but don't fail installation
|
|
356
|
+
console.warn(chalk.dim('Note: Run "tribe enable" to start telemetry'));
|
|
357
|
+
}
|
|
358
|
+
|
|
273
359
|
spinner.succeed('Ready!');
|
|
274
360
|
|
|
275
|
-
//
|
|
361
|
+
// Check if ~/.tribe/bin is already in the user's actual PATH
|
|
362
|
+
// Note: 'which tribe' may work in subprocess even when parent shell doesn't have it
|
|
363
|
+
const userPath = process.env.PATH || '';
|
|
364
|
+
const tribeBinInPath = userPath.includes('.tribe/bin');
|
|
365
|
+
|
|
366
|
+
// Also verify the binary actually exists and is executable
|
|
276
367
|
let commandWorks = false;
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
368
|
+
if (tribeBinInPath) {
|
|
369
|
+
try {
|
|
370
|
+
execSync('which tribe', { stdio: 'ignore', timeout: 2000 });
|
|
371
|
+
commandWorks = true;
|
|
372
|
+
} catch (error) {
|
|
373
|
+
commandWorks = false;
|
|
374
|
+
}
|
|
282
375
|
}
|
|
283
376
|
|
|
284
|
-
// Show
|
|
285
|
-
if (commandWorks) {
|
|
377
|
+
// Show completion message - always provide activation command for fresh installs
|
|
378
|
+
if (commandWorks && tribeBinInPath) {
|
|
286
379
|
console.log(chalk.green('\n✅ Ready! Type ' + chalk.cyan.bold('tribe') + ' to get started'));
|
|
287
380
|
} else {
|
|
288
|
-
|
|
381
|
+
// Provide explicit activation command since PATH isn't set up yet
|
|
382
|
+
console.log(chalk.yellow('\n📍 To activate TRIBE in this terminal:'));
|
|
383
|
+
console.log(chalk.cyan(' source ~/.tribe/tribe-env.sh'));
|
|
384
|
+
console.log(chalk.dim('\n Or restart your terminal, then type ') + chalk.cyan.bold('tribe'));
|
|
289
385
|
}
|
|
290
386
|
|
|
291
387
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@_xtribe/cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.52",
|
|
4
4
|
"description": "TRIBE - Privacy-first AI development analytics. Self-host your telemetry, skip authentication, or run completely offline. Your data stays on your machine.",
|
|
5
5
|
"main": "install-tribe.js",
|
|
6
6
|
"bin": {
|
package/tribe-deployment.yaml
CHANGED
|
@@ -457,6 +457,149 @@ spec:
|
|
|
457
457
|
name: claude-config
|
|
458
458
|
optional: true
|
|
459
459
|
---
|
|
460
|
+
# Gemini Worker Deployment
|
|
461
|
+
apiVersion: apps/v1
|
|
462
|
+
kind: Deployment
|
|
463
|
+
metadata:
|
|
464
|
+
name: gemini-worker-deployment
|
|
465
|
+
namespace: tribe-system
|
|
466
|
+
spec:
|
|
467
|
+
replicas: 1
|
|
468
|
+
selector:
|
|
469
|
+
matchLabels:
|
|
470
|
+
app: gemini-worker
|
|
471
|
+
template:
|
|
472
|
+
metadata:
|
|
473
|
+
labels:
|
|
474
|
+
app: gemini-worker
|
|
475
|
+
app.kubernetes.io/name: gemini-agent
|
|
476
|
+
spec:
|
|
477
|
+
containers:
|
|
478
|
+
- name: gemini-agent
|
|
479
|
+
image: tribexal/tribe:latest-gemini-agent
|
|
480
|
+
imagePullPolicy: IfNotPresent
|
|
481
|
+
ports:
|
|
482
|
+
- containerPort: 7781
|
|
483
|
+
name: ttyd
|
|
484
|
+
resources:
|
|
485
|
+
requests:
|
|
486
|
+
memory: "512Mi"
|
|
487
|
+
cpu: "500m"
|
|
488
|
+
limits:
|
|
489
|
+
memory: "2Gi"
|
|
490
|
+
cpu: "2"
|
|
491
|
+
env:
|
|
492
|
+
- name: AGENT_TYPE
|
|
493
|
+
value: "gemini"
|
|
494
|
+
- name: AGENT_CAPABILITIES
|
|
495
|
+
value: "gemini,api,code-review"
|
|
496
|
+
- name: ROLE
|
|
497
|
+
value: worker
|
|
498
|
+
- name: TASKMASTER_URL
|
|
499
|
+
value: http://taskmaster:8080
|
|
500
|
+
- name: GITEA_URL
|
|
501
|
+
value: http://gitea:3000
|
|
502
|
+
- name: GITEA_USER
|
|
503
|
+
value: gitea_admin
|
|
504
|
+
- name: GITEA_PASS
|
|
505
|
+
value: admin123
|
|
506
|
+
- name: GITEA_TOKEN
|
|
507
|
+
valueFrom:
|
|
508
|
+
secretKeyRef:
|
|
509
|
+
name: gitea-token
|
|
510
|
+
key: token
|
|
511
|
+
optional: true
|
|
512
|
+
- name: NAMESPACE
|
|
513
|
+
value: tribe-system
|
|
514
|
+
- name: GOOGLE_API_KEY
|
|
515
|
+
valueFrom:
|
|
516
|
+
secretKeyRef:
|
|
517
|
+
name: gemini-api-key
|
|
518
|
+
key: GOOGLE_API_KEY
|
|
519
|
+
optional: true
|
|
520
|
+
- name: GEMINI_MODEL
|
|
521
|
+
value: "gemini-2.0-flash-exp"
|
|
522
|
+
- name: GH_HOST
|
|
523
|
+
value: gitea:3000
|
|
524
|
+
- name: GH_ENTERPRISE_TOKEN
|
|
525
|
+
valueFrom:
|
|
526
|
+
secretKeyRef:
|
|
527
|
+
name: gitea-token
|
|
528
|
+
key: token
|
|
529
|
+
optional: true
|
|
530
|
+
volumeMounts:
|
|
531
|
+
- name: workspace
|
|
532
|
+
mountPath: /workspace
|
|
533
|
+
volumes:
|
|
534
|
+
- name: workspace
|
|
535
|
+
emptyDir: {}
|
|
536
|
+
---
|
|
537
|
+
# Gemini Review Agents
|
|
538
|
+
apiVersion: apps/v1
|
|
539
|
+
kind: Deployment
|
|
540
|
+
metadata:
|
|
541
|
+
name: gemini-review-agents
|
|
542
|
+
namespace: tribe-system
|
|
543
|
+
spec:
|
|
544
|
+
replicas: 0
|
|
545
|
+
selector:
|
|
546
|
+
matchLabels:
|
|
547
|
+
app: gemini-review-agent
|
|
548
|
+
worker-type: review
|
|
549
|
+
template:
|
|
550
|
+
metadata:
|
|
551
|
+
labels:
|
|
552
|
+
app: gemini-review-agent
|
|
553
|
+
worker-type: review
|
|
554
|
+
spec:
|
|
555
|
+
containers:
|
|
556
|
+
- name: gemini-agent
|
|
557
|
+
image: tribexal/tribe:latest-gemini-agent
|
|
558
|
+
imagePullPolicy: IfNotPresent
|
|
559
|
+
ports:
|
|
560
|
+
- containerPort: 7781
|
|
561
|
+
name: ttyd
|
|
562
|
+
resources:
|
|
563
|
+
requests:
|
|
564
|
+
memory: "512Mi"
|
|
565
|
+
cpu: "500m"
|
|
566
|
+
limits:
|
|
567
|
+
memory: "2Gi"
|
|
568
|
+
cpu: "2"
|
|
569
|
+
env:
|
|
570
|
+
- name: AGENT_TYPE
|
|
571
|
+
value: "gemini-reviewer"
|
|
572
|
+
- name: AGENT_CAPABILITIES
|
|
573
|
+
value: "gemini,code-review"
|
|
574
|
+
- name: ROLE
|
|
575
|
+
value: reviewer
|
|
576
|
+
- name: TASKMASTER_URL
|
|
577
|
+
value: http://taskmaster:8080
|
|
578
|
+
- name: GITEA_URL
|
|
579
|
+
value: http://gitea:3000
|
|
580
|
+
- name: GITEA_USER
|
|
581
|
+
value: gitea_admin
|
|
582
|
+
- name: GITEA_TOKEN
|
|
583
|
+
valueFrom:
|
|
584
|
+
secretKeyRef:
|
|
585
|
+
name: gitea-token
|
|
586
|
+
key: token
|
|
587
|
+
optional: true
|
|
588
|
+
- name: GOOGLE_API_KEY
|
|
589
|
+
valueFrom:
|
|
590
|
+
secretKeyRef:
|
|
591
|
+
name: gemini-api-key
|
|
592
|
+
key: GOOGLE_API_KEY
|
|
593
|
+
optional: true
|
|
594
|
+
- name: GEMINI_MODEL
|
|
595
|
+
value: "gemini-2.0-flash-exp"
|
|
596
|
+
volumeMounts:
|
|
597
|
+
- name: workspace
|
|
598
|
+
mountPath: /workspace
|
|
599
|
+
volumes:
|
|
600
|
+
- name: workspace
|
|
601
|
+
emptyDir: {}
|
|
602
|
+
---
|
|
460
603
|
# NodePort service for easy access
|
|
461
604
|
apiVersion: v1
|
|
462
605
|
kind: Service
|