@_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 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
- // Test if tribe command works immediately
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
- try {
278
- execSync('which tribe', { stdio: 'ignore', timeout: 2000 });
279
- commandWorks = true;
280
- } catch (error) {
281
- commandWorks = false;
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 minimal completion message
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
- console.log(chalk.yellow('\n⚠️ Restart your terminal, then type ' + chalk.cyan.bold('tribe')));
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.50",
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": {
@@ -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