@telara-cli/cli 0.1.0

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/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @telera/cli
2
+
3
+ Install the Telara CLI via npm.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ npm install -g @telera/cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```
14
+ telara login
15
+ telara setup
16
+ telara --help
17
+ ```
18
+
19
+ ## Alternative installation
20
+
21
+ ```
22
+ macOS/Linux: curl -fsSL https://get.telara.ai/install.sh | sh
23
+ Windows: irm https://get.telara.ai/windows | iex
24
+ Homebrew: brew install telera-ai/tap/telara
25
+ ```
package/bin/telara ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ // This stub is replaced by the actual binary during postinstall (npm scripts/install.js).
3
+ // If this script is still running, the postinstall step did not complete successfully.
4
+ console.error('telara binary not found.');
5
+ console.error('The postinstall step may have failed. Try reinstalling:');
6
+ console.error(' npm install -g @telera/cli');
7
+ console.error('');
8
+ console.error('Or install manually:');
9
+ console.error(' macOS/Linux: curl -fsSL https://get.telara.ai/install.sh | sh');
10
+ console.error(' Windows: irm https://get.telara.ai/windows | iex');
11
+ process.exit(1);
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@telara-cli/cli",
3
+ "version": "0.1.0",
4
+ "description": "Telara CLI — manage your MCP configurations",
5
+ "homepage": "https://telara.ai",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/Telara-Labs/Telara-CLI"
9
+ },
10
+ "license": "MIT",
11
+ "bin": {
12
+ "telara": "./bin/telara"
13
+ },
14
+ "scripts": {
15
+ "postinstall": "node scripts/install.js"
16
+ },
17
+ "engines": {
18
+ "node": ">=14"
19
+ },
20
+ "files": [
21
+ "bin/",
22
+ "scripts/install.js",
23
+ "README.md"
24
+ ]
25
+ }
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const https = require('https');
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const os = require('os');
9
+ const { execSync } = require('child_process');
10
+
11
+ // Read version from package.json, allow override via env var
12
+ const pkg = require('../package.json');
13
+ const version = process.env.TELARA_VERSION || pkg.version;
14
+
15
+ const PRIMARY_BASE_URL = 'https://get.telara.ai/download';
16
+ const FALLBACK_BASE_URL = 'https://github.com/Telara-Labs/Telara-CLI/releases/download';
17
+ const MANUAL_INSTALL_URL = 'https://telara.ai/docs/cli/install';
18
+
19
+ function getPlatformInfo() {
20
+ const platform = process.platform;
21
+ const arch = process.arch;
22
+
23
+ let os_name;
24
+ switch (platform) {
25
+ case 'darwin':
26
+ os_name = 'darwin';
27
+ break;
28
+ case 'linux':
29
+ os_name = 'linux';
30
+ break;
31
+ case 'win32':
32
+ os_name = 'windows';
33
+ break;
34
+ default:
35
+ throw new Error(
36
+ `Unsupported platform: ${platform}\n` +
37
+ `Please install manually: ${MANUAL_INSTALL_URL}`
38
+ );
39
+ }
40
+
41
+ let arch_name;
42
+ switch (arch) {
43
+ case 'x64':
44
+ arch_name = 'amd64';
45
+ break;
46
+ case 'arm64':
47
+ arch_name = 'arm64';
48
+ break;
49
+ default:
50
+ throw new Error(
51
+ `Unsupported architecture: ${arch}\n` +
52
+ `Please install manually: ${MANUAL_INSTALL_URL}`
53
+ );
54
+ }
55
+
56
+ return { os_name, arch_name };
57
+ }
58
+
59
+ function getArchiveFilename(version, os_name, arch_name) {
60
+ // version field in package.json does not include the "v" prefix
61
+ // archive filenames use the bare version number (e.g. telara_0.1.0_darwin_amd64.tar.gz)
62
+ const bare_version = version.replace(/^v/, '');
63
+
64
+ if (os_name === 'windows') {
65
+ return `telara_${bare_version}_windows_${arch_name}.zip`;
66
+ }
67
+ return `telara_${bare_version}_${os_name}_${arch_name}.tar.gz`;
68
+ }
69
+
70
+ function getBinPath() {
71
+ const bin_dir = path.join(__dirname, '..', 'bin');
72
+ const bin_name = process.platform === 'win32' ? 'telara.exe' : 'telara';
73
+ return { bin_dir, bin_path: path.join(bin_dir, bin_name) };
74
+ }
75
+
76
+ function isCorrectVersionInstalled(bin_path) {
77
+ if (!fs.existsSync(bin_path)) {
78
+ return false;
79
+ }
80
+ try {
81
+ const output = execSync(`"${bin_path}" version`, {
82
+ timeout: 5000,
83
+ stdio: ['ignore', 'pipe', 'ignore'],
84
+ }).toString().trim();
85
+ const bare_version = version.replace(/^v/, '');
86
+ return output.includes(bare_version);
87
+ } catch (_) {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ function download(url, dest) {
93
+ return new Promise((resolve, reject) => {
94
+ const file = fs.createWriteStream(dest);
95
+
96
+ const request = (target_url) => {
97
+ https.get(target_url, (res) => {
98
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
99
+ // Follow redirect
100
+ file.close();
101
+ request(res.headers.location);
102
+ return;
103
+ }
104
+
105
+ if (res.statusCode !== 200) {
106
+ file.close();
107
+ fs.unlink(dest, () => {});
108
+ reject(new Error(`Download failed with HTTP ${res.statusCode} from ${target_url}`));
109
+ return;
110
+ }
111
+
112
+ res.pipe(file);
113
+ file.on('finish', () => {
114
+ file.close(resolve);
115
+ });
116
+ }).on('error', (err) => {
117
+ file.close();
118
+ fs.unlink(dest, () => {});
119
+ reject(err);
120
+ });
121
+ };
122
+
123
+ request(url);
124
+ });
125
+ }
126
+
127
+ function extractTarGz(archive_path, extract_dir) {
128
+ execSync(`tar -xzf "${archive_path}" -C "${extract_dir}"`, { stdio: 'inherit' });
129
+ }
130
+
131
+ function extractZip(archive_path, extract_dir) {
132
+ // Use PowerShell Expand-Archive on Windows
133
+ execSync(
134
+ `powershell -NoProfile -NonInteractive -Command "Expand-Archive -Force -Path '${archive_path}' -DestinationPath '${extract_dir}'"`,
135
+ { stdio: 'inherit' }
136
+ );
137
+ }
138
+
139
+ async function downloadWithFallback(filename, version, dest) {
140
+ const tag = `v${version.replace(/^v/, '')}`;
141
+ const primary_url = `${PRIMARY_BASE_URL}/${tag}/${filename}`;
142
+ const fallback_url = `${FALLBACK_BASE_URL}/${tag}/${filename}`;
143
+
144
+ console.log(`Downloading telara v${version.replace(/^v/, '')}...`);
145
+
146
+ try {
147
+ await download(primary_url, dest);
148
+ return;
149
+ } catch (primary_err) {
150
+ console.log(`Primary download failed (${primary_err.message}), trying fallback...`);
151
+ }
152
+
153
+ try {
154
+ await download(fallback_url, dest);
155
+ } catch (fallback_err) {
156
+ throw new Error(
157
+ `Both download sources failed.\n` +
158
+ ` Primary: ${primary_url}\n` +
159
+ ` Fallback: ${fallback_url}\n` +
160
+ ` Last error: ${fallback_err.message}`
161
+ );
162
+ }
163
+ }
164
+
165
+ async function main() {
166
+ const { os_name, arch_name } = getPlatformInfo();
167
+ const filename = getArchiveFilename(version, os_name, arch_name);
168
+ const { bin_dir, bin_path } = getBinPath();
169
+
170
+ // Skip download if correct version is already installed
171
+ if (isCorrectVersionInstalled(bin_path)) {
172
+ console.log(`telara v${version.replace(/^v/, '')} is already installed.`);
173
+ return;
174
+ }
175
+
176
+ // Ensure bin directory exists
177
+ if (!fs.existsSync(bin_dir)) {
178
+ fs.mkdirSync(bin_dir, { recursive: true });
179
+ }
180
+
181
+ const tmp_dir = fs.mkdtempSync(path.join(os.tmpdir(), 'telara-install-'));
182
+ const archive_path = path.join(tmp_dir, filename);
183
+
184
+ try {
185
+ await downloadWithFallback(filename, version, archive_path);
186
+
187
+ console.log('Extracting...');
188
+ if (os_name === 'windows') {
189
+ extractZip(archive_path, tmp_dir);
190
+ } else {
191
+ extractTarGz(archive_path, tmp_dir);
192
+ }
193
+
194
+ const extracted_bin_name = os_name === 'windows' ? 'telara.exe' : 'telara';
195
+ const extracted_bin = path.join(tmp_dir, extracted_bin_name);
196
+
197
+ if (!fs.existsSync(extracted_bin)) {
198
+ throw new Error(`Expected binary not found after extraction: ${extracted_bin}`);
199
+ }
200
+
201
+ // Move binary into place — use copy+delete to handle cross-filesystem moves
202
+ try {
203
+ fs.renameSync(extracted_bin, bin_path);
204
+ } catch (_) {
205
+ fs.copyFileSync(extracted_bin, bin_path);
206
+ fs.unlinkSync(extracted_bin);
207
+ }
208
+
209
+ // Make executable on unix
210
+ if (os_name !== 'windows') {
211
+ fs.chmodSync(bin_path, 0o755);
212
+ }
213
+
214
+ console.log(`telara installed successfully.`);
215
+ console.log('');
216
+ console.log('Get started:');
217
+ console.log(' 1. Generate a token at https://app.telara.ai/settings?tab=developer');
218
+ console.log(' 2. telara login --token <your-token>');
219
+ console.log(' 3. telara setup claude-code');
220
+ } finally {
221
+ // Clean up temp directory
222
+ try {
223
+ fs.rmSync(tmp_dir, { recursive: true, force: true });
224
+ } catch (_) {
225
+ // Non-critical cleanup failure — ignore
226
+ }
227
+ }
228
+ }
229
+
230
+ main().catch((err) => {
231
+ console.error('');
232
+ console.error('telara install failed: ' + err.message);
233
+ console.error('');
234
+ console.error('Install manually:');
235
+ console.error(' macOS/Linux: curl -fsSL https://get.telara.ai/install.sh | sh');
236
+ console.error(' Windows: irm https://get.telara.ai/windows | iex');
237
+ console.error(' More options: ' + MANUAL_INSTALL_URL);
238
+ console.error('');
239
+ process.exit(1);
240
+ });