@_xtribe/cli 2.2.73 → 2.2.76
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 +96 -8
- package/package.json +1 -1
package/install-tribe.js
CHANGED
|
@@ -64,9 +64,49 @@ function showWelcome() {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
// Fetch latest release version from GitHub
|
|
68
|
+
async function getLatestVersion() {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
const url = 'https://api.github.com/repos/TRIBE-INC/releases/releases/latest';
|
|
71
|
+
https.get(url, {
|
|
72
|
+
headers: { 'User-Agent': 'TRIBE-CLI-Installer' }
|
|
73
|
+
}, (response) => {
|
|
74
|
+
let data = '';
|
|
75
|
+
response.on('data', chunk => data += chunk);
|
|
76
|
+
response.on('end', () => {
|
|
77
|
+
try {
|
|
78
|
+
const release = JSON.parse(data);
|
|
79
|
+
resolve(release.tag_name); // e.g., "v2.2.74"
|
|
80
|
+
} catch (error) {
|
|
81
|
+
resolve(null); // Ignore errors, proceed with install
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}).on('error', () => resolve(null));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Get installed version by running tribe --version
|
|
89
|
+
function getInstalledVersion() {
|
|
90
|
+
const tribeDest = path.join(tribeBinDir, 'tribe');
|
|
91
|
+
if (!fs.existsSync(tribeDest)) return null;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const output = execSync(`"${tribeDest}" --version 2>/dev/null || true`, {
|
|
95
|
+
encoding: 'utf8',
|
|
96
|
+
timeout: 5000
|
|
97
|
+
});
|
|
98
|
+
// Extract version like "v2.2.74" or "2.2.74"
|
|
99
|
+
const match = output.match(/v?(\d+\.\d+\.\d+)/);
|
|
100
|
+
return match ? `v${match[1]}` : null;
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
67
106
|
async function downloadFile(url, dest) {
|
|
68
107
|
return new Promise((resolve, reject) => {
|
|
69
|
-
|
|
108
|
+
// Create file with execute permissions from the start (0755)
|
|
109
|
+
const file = fs.createWriteStream(dest, { mode: 0o755 });
|
|
70
110
|
https.get(url, (response) => {
|
|
71
111
|
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
72
112
|
return downloadFile(response.headers.location, dest).then(resolve, reject);
|
|
@@ -78,6 +118,12 @@ async function downloadFile(url, dest) {
|
|
|
78
118
|
response.pipe(file);
|
|
79
119
|
file.on('finish', () => {
|
|
80
120
|
file.close();
|
|
121
|
+
// Ensure execute permissions are set after download completes
|
|
122
|
+
try {
|
|
123
|
+
fs.chmodSync(dest, 0o755);
|
|
124
|
+
} catch (e) {
|
|
125
|
+
// Ignore chmod errors - permissions were set during creation
|
|
126
|
+
}
|
|
81
127
|
resolve();
|
|
82
128
|
});
|
|
83
129
|
}).on('error', reject);
|
|
@@ -87,9 +133,38 @@ async function downloadFile(url, dest) {
|
|
|
87
133
|
async function installTribeCLI() {
|
|
88
134
|
const tribeDest = path.join(tribeBinDir, 'tribe');
|
|
89
135
|
|
|
90
|
-
// Check if update needed
|
|
136
|
+
// Check if update needed by comparing versions
|
|
91
137
|
const exists = fs.existsSync(tribeDest);
|
|
92
|
-
const
|
|
138
|
+
const installedVersion = getInstalledVersion();
|
|
139
|
+
const latestVersion = await getLatestVersion();
|
|
140
|
+
|
|
141
|
+
// Determine if we need to download
|
|
142
|
+
let needsDownload = !exists;
|
|
143
|
+
let statusMsg = 'Installing CLI...';
|
|
144
|
+
|
|
145
|
+
if (exists && latestVersion && installedVersion) {
|
|
146
|
+
// Compare versions (strip 'v' prefix for comparison)
|
|
147
|
+
const installed = installedVersion.replace(/^v/, '');
|
|
148
|
+
const latest = latestVersion.replace(/^v/, '');
|
|
149
|
+
if (installed !== latest) {
|
|
150
|
+
needsDownload = true;
|
|
151
|
+
statusMsg = `Updating CLI (${installedVersion} → ${latestVersion})...`;
|
|
152
|
+
} else {
|
|
153
|
+
statusMsg = `CLI is up to date (${latestVersion})`;
|
|
154
|
+
}
|
|
155
|
+
} else if (exists) {
|
|
156
|
+
// Can't determine versions, force update to be safe
|
|
157
|
+
needsDownload = true;
|
|
158
|
+
statusMsg = 'Updating CLI...';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const spinner = ora(statusMsg).start();
|
|
162
|
+
|
|
163
|
+
// Skip download if already up to date
|
|
164
|
+
if (exists && !needsDownload) {
|
|
165
|
+
spinner.succeed(`CLI is up to date (${latestVersion || 'latest'})`);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
93
168
|
|
|
94
169
|
try {
|
|
95
170
|
// Clean up any existing tribe binaries first
|
|
@@ -105,7 +180,7 @@ async function installTribeCLI() {
|
|
|
105
180
|
const downloadUrl = `https://github.com/${githubRepo}/releases/latest/download/tribe-${platform}-${arch}`;
|
|
106
181
|
|
|
107
182
|
await downloadFile(downloadUrl, tribeDest);
|
|
108
|
-
fs.chmodSync(tribeDest,
|
|
183
|
+
fs.chmodSync(tribeDest, 0o755);
|
|
109
184
|
|
|
110
185
|
// Remove macOS quarantine if needed
|
|
111
186
|
if (platform === 'darwin') {
|
|
@@ -116,7 +191,20 @@ async function installTribeCLI() {
|
|
|
116
191
|
}
|
|
117
192
|
}
|
|
118
193
|
|
|
119
|
-
|
|
194
|
+
// Save version info for future update checks
|
|
195
|
+
if (latestVersion) {
|
|
196
|
+
try {
|
|
197
|
+
const versionFile = path.join(tribeDir, 'version.json');
|
|
198
|
+
fs.writeFileSync(versionFile, JSON.stringify({
|
|
199
|
+
version: latestVersion,
|
|
200
|
+
installedAt: new Date().toISOString()
|
|
201
|
+
}, null, 2));
|
|
202
|
+
} catch {
|
|
203
|
+
// Not critical
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
spinner.succeed(`CLI ready (${latestVersion || 'latest'})`);
|
|
120
208
|
return true;
|
|
121
209
|
} catch (error) {
|
|
122
210
|
spinner.fail(`Installation failed: ${error.message}`);
|
|
@@ -166,7 +254,7 @@ async function installTribeCLIQuiet() {
|
|
|
166
254
|
const downloadUrl = `https://github.com/${githubRepo}/releases/latest/download/tribe-${platform}-${arch}`;
|
|
167
255
|
|
|
168
256
|
await downloadFile(downloadUrl, tribeDest);
|
|
169
|
-
fs.chmodSync(tribeDest,
|
|
257
|
+
fs.chmodSync(tribeDest, 0o755);
|
|
170
258
|
|
|
171
259
|
// Also download tutor-collector binary (CRITICAL - this is the core product!)
|
|
172
260
|
const tutorCollectorDest = path.join(tribeBinDir, 'tutor-collector');
|
|
@@ -180,7 +268,7 @@ async function installTribeCLIQuiet() {
|
|
|
180
268
|
const communityUrl = `https://github.com/TRIBE-INC/tutor-server-community-release/releases/latest/download/tutor-collector-${platform}-${arch}`;
|
|
181
269
|
await downloadFile(communityUrl, tutorCollectorDest);
|
|
182
270
|
}
|
|
183
|
-
fs.chmodSync(tutorCollectorDest,
|
|
271
|
+
fs.chmodSync(tutorCollectorDest, 0o755);
|
|
184
272
|
|
|
185
273
|
// Download realtime-sync binary (for tribe realtime command)
|
|
186
274
|
const realtimeSyncDest = path.join(tribeBinDir, 'realtime-sync');
|
|
@@ -188,7 +276,7 @@ async function installTribeCLIQuiet() {
|
|
|
188
276
|
|
|
189
277
|
try {
|
|
190
278
|
await downloadFile(realtimeSyncUrl, realtimeSyncDest);
|
|
191
|
-
fs.chmodSync(realtimeSyncDest,
|
|
279
|
+
fs.chmodSync(realtimeSyncDest, 0o755);
|
|
192
280
|
} catch (error) {
|
|
193
281
|
// realtime-sync is optional, don't fail install if missing
|
|
194
282
|
console.log('Note: realtime-sync not available in this release');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@_xtribe/cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.76",
|
|
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": {
|