@beyondidentity/ai-cli 0.1.711

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,66 @@
1
+ # @beyondidentity/ai-cli
2
+
3
+ Beyond Identity AI CLI - unified command-line interface for AI agent operations.
4
+
5
+ ## Features
6
+
7
+ - **Proxy Management** (`byid proxy`): Start, stop, and manage the local proxy service
8
+ - **Auth Flow** (`byid auth`): Beyond Identity authentication helper
9
+ - **Launch** (`byid launch`): Launch programs with auth configured
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # Install from rolling channel (Cloudsmith)
15
+ npm install @beyondidentity/ai-cli@rolling
16
+
17
+ # Or use directly with npx
18
+ npx @beyondidentity/ai-cli@rolling --help
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```bash
24
+ # Show all commands
25
+ byid --help
26
+
27
+ # Proxy commands
28
+ byid proxy start # Start local proxy
29
+ byid proxy info # Show proxy status
30
+ byid proxy stop # Stop local proxy
31
+
32
+ # Auth flow
33
+ byid auth --help
34
+
35
+ # Launch programs
36
+ byid launch --help
37
+ ```
38
+
39
+ ## Private Registry Configuration
40
+
41
+ Configure `~/.npmrc` for Cloudsmith access:
42
+
43
+ ```
44
+ @beyondidentity:registry=https://npm.cloudsmith.io/beyond-identity/ai-agents-npm/
45
+ //npm.cloudsmith.io/beyond-identity/ai-agents-npm/:_authToken=YOUR_TOKEN
46
+ ```
47
+
48
+ ## Platform Support
49
+
50
+ Supports macOS (Intel/ARM), Linux (x64/ARM64), and Windows (x64).
51
+
52
+ ## Architecture
53
+
54
+ This shim package automatically installs the correct platform binary via npm's `optionalDependencies` mechanism. Platform-specific binaries are published as separate packages:
55
+
56
+ - `@beyondidentity/ai-cli-darwin-arm64`
57
+ - `@beyondidentity/ai-cli-darwin-x64`
58
+ - `@beyondidentity/ai-cli-linux-x64`
59
+ - `@beyondidentity/ai-cli-linux-arm64`
60
+ - `@beyondidentity/ai-cli-win32-x64`
61
+
62
+ If `optionalDependencies` installation fails, a postinstall script will attempt to download the binary as a fallback.
63
+
64
+ ## License
65
+
66
+ UNLICENSED - For internal use only.
package/bin/byid.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Execute the binary via index.js
4
+ const { getBinaryPath } = require('../index.js');
5
+
6
+ try {
7
+ const binaryPath = getBinaryPath();
8
+ const args = process.argv.slice(2);
9
+
10
+ // Execute binary directly - blocks until process exits
11
+ require('child_process').execFileSync(binaryPath, args, {
12
+ stdio: 'inherit'
13
+ });
14
+ } catch (error) {
15
+ // Print error message if it's not from execFileSync
16
+ if (!error.status) {
17
+ console.error(error.message);
18
+ }
19
+ process.exit(error.status || 1);
20
+ }
package/index.js ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ const { existsSync } = require('fs');
3
+ const path = require('path');
4
+
5
+ // Detect current platform
6
+ function getPlatform() {
7
+ const platform = process.platform;
8
+ const arch = process.arch;
9
+
10
+ const platformMap = {
11
+ 'darwin': 'darwin',
12
+ 'linux': 'linux',
13
+ 'win32': 'win32'
14
+ };
15
+
16
+ const archMap = {
17
+ 'x64': 'x64',
18
+ 'arm64': 'arm64',
19
+ 'arm': 'arm'
20
+ };
21
+
22
+ const mappedPlatform = platformMap[platform];
23
+ const mappedArch = archMap[arch];
24
+
25
+ if (!mappedPlatform || !mappedArch) {
26
+ throw new Error(`Unsupported platform: ${platform}-${arch}`);
27
+ }
28
+
29
+ return `${mappedPlatform}-${mappedArch}`;
30
+ }
31
+
32
+ // Get binary path
33
+ function getBinaryPath() {
34
+ const platform = getPlatform();
35
+ const binaryName = process.platform === 'win32' ? 'byid.exe' : 'byid';
36
+
37
+ // Strategy 1: Try platform-specific package (installed as optionalDependency)
38
+ const platformPackage = `@beyondidentity/ai-cli-${platform}`;
39
+ try {
40
+ const platformPath = require.resolve(`${platformPackage}/bin/${binaryName}`);
41
+ if (existsSync(platformPath)) {
42
+ return platformPath;
43
+ }
44
+ } catch (e) {
45
+ // Platform package not found, try fallback
46
+ }
47
+
48
+ // Strategy 2: Try fallback binary (downloaded by postinstall script)
49
+ const fallbackPath = path.join(__dirname, 'bin', binaryName);
50
+ if (existsSync(fallbackPath)) {
51
+ return fallbackPath;
52
+ }
53
+
54
+ // Neither strategy worked
55
+ throw new Error(
56
+ `Could not find binary for platform ${platform}.\n` +
57
+ `Tried:\n` +
58
+ ` 1. Platform package: ${platformPackage}\n` +
59
+ ` 2. Fallback download: ${fallbackPath}\n` +
60
+ `Make sure optionalDependencies are enabled or postinstall script ran successfully.\n` +
61
+ `For more information, contact Beyond Identity support.`
62
+ );
63
+ }
64
+
65
+ // Export for programmatic use
66
+ module.exports = { getBinaryPath, getPlatform };
67
+
68
+ // Execute if run directly
69
+ if (require.main === module) {
70
+ try {
71
+ const binaryPath = getBinaryPath();
72
+ const args = process.argv.slice(2);
73
+
74
+ // Execute binary directly - blocks until process exits
75
+ require('child_process').execFileSync(binaryPath, args, {
76
+ stdio: 'inherit'
77
+ });
78
+ } catch (error) {
79
+ // Print error message if it's not from execFileSync
80
+ if (!error.status) {
81
+ console.error(error.message);
82
+ }
83
+ process.exit(error.status || 1);
84
+ }
85
+ }
package/install.js ADDED
@@ -0,0 +1,418 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const https = require('https');
6
+ const http = require('http');
7
+ const zlib = require('zlib');
8
+ const { execSync } = require('child_process');
9
+
10
+ // Check if running in CI environment
11
+ const isCI = process.env.CI === 'true' || process.env.CI === '1';
12
+
13
+ // Logging helpers
14
+ function log(...args) {
15
+ if (!isCI) {
16
+ console.log(...args);
17
+ }
18
+ }
19
+
20
+ function logProgress(message) {
21
+ if (!isCI) {
22
+ process.stdout.write(`\r${message}`);
23
+ }
24
+ }
25
+
26
+ // Detect current platform
27
+ function getPlatform() {
28
+ const platform = process.platform;
29
+ const arch = process.arch;
30
+
31
+ const platformMap = {
32
+ 'darwin': 'darwin',
33
+ 'linux': 'linux',
34
+ 'win32': 'win32'
35
+ };
36
+
37
+ const archMap = {
38
+ 'x64': 'x64',
39
+ 'arm64': 'arm64',
40
+ 'arm': 'arm'
41
+ };
42
+
43
+ const mappedPlatform = platformMap[platform];
44
+ const mappedArch = archMap[arch];
45
+
46
+ if (!mappedPlatform || !mappedArch) {
47
+ throw new Error(`Unsupported platform: ${platform}-${arch}`);
48
+ }
49
+
50
+ return `${mappedPlatform}-${mappedArch}`;
51
+ }
52
+
53
+ // Check if optional dependency is already installed
54
+ function checkOptionalDependency(platformPackage, binaryName) {
55
+ try {
56
+ const platformPath = require.resolve(`${platformPackage}/bin/${binaryName}`);
57
+ if (fs.existsSync(platformPath)) {
58
+ log(`✓ Platform package ${platformPackage} already installed`);
59
+ return true;
60
+ }
61
+ } catch (e) {
62
+ // Platform package not found
63
+ }
64
+ return false;
65
+ }
66
+
67
+ // Check if fallback binary already exists and is valid
68
+ function checkFallbackBinary(binaryPath) {
69
+ if (fs.existsSync(binaryPath)) {
70
+ try {
71
+ fs.accessSync(binaryPath, fs.constants.X_OK);
72
+ log('✓ Fallback binary already exists and is executable');
73
+ return true;
74
+ } catch (e) {
75
+ // Binary exists but not executable, re-download
76
+ log('Existing fallback binary is invalid, re-downloading...');
77
+ fs.unlinkSync(binaryPath);
78
+ }
79
+ }
80
+ return false;
81
+ }
82
+
83
+ // Check write permissions for bin directory
84
+ function checkWritePermissions() {
85
+ const binDir = path.join(__dirname, 'bin');
86
+ try {
87
+ fs.mkdirSync(binDir, { recursive: true });
88
+ const testFile = path.join(binDir, '.write-test');
89
+ fs.writeFileSync(testFile, 'test');
90
+ fs.unlinkSync(testFile);
91
+ return true;
92
+ } catch (error) {
93
+ if (error.code === 'EACCES') {
94
+ console.warn('⚠ Warning: No write permissions for bin/ directory');
95
+ console.warn('Run with appropriate permissions or contact your system administrator');
96
+ return false;
97
+ }
98
+ throw error;
99
+ }
100
+ }
101
+
102
+
103
+ // Construct download URL based on registry
104
+ function constructDownloadUrl(packageName, version, registryUrl) {
105
+ // Extract package name without scope for tarball filename
106
+ const tarballName = packageName.split('/').pop();
107
+
108
+ return `${registryUrl}/${packageName}/-/${tarballName}-${version}.tgz`;
109
+ }
110
+
111
+ // Download file with progress indication
112
+ function downloadBinary(url, destPath, options = {}) {
113
+ return new Promise((resolve, reject) => {
114
+ const protocol = url.startsWith('https') ? https : http;
115
+
116
+ log(`Downloading from: ${url}`);
117
+
118
+ const requestOptions = {
119
+ headers: options.headers || {},
120
+ timeout: options.timeout || 30000
121
+ };
122
+
123
+ const request = protocol.get(url, requestOptions, (response) => {
124
+ // Handle redirects
125
+ if (response.statusCode === 302 || response.statusCode === 301) {
126
+ log(`Following redirect to: ${response.headers.location}`);
127
+ return downloadBinary(response.headers.location, destPath, options)
128
+ .then(resolve)
129
+ .catch(reject);
130
+ }
131
+
132
+ // Handle authentication errors
133
+ if (response.statusCode === 401 || response.statusCode === 403) {
134
+ return reject(new Error(
135
+ 'Authentication required. Package not found in public registry.\n' +
136
+ 'This package may be in a private registry. Use npm/pnpm/yarn for installation,\n' +
137
+ 'which will handle authentication automatically via your .npmrc configuration.'
138
+ ));
139
+ }
140
+
141
+ if (response.statusCode !== 200) {
142
+ return reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
143
+ }
144
+
145
+ const totalBytes = parseInt(response.headers['content-length'], 10);
146
+ let downloadedBytes = 0;
147
+
148
+ // Progress logging
149
+ response.on('data', (chunk) => {
150
+ downloadedBytes += chunk.length;
151
+ if (totalBytes) {
152
+ const percent = ((downloadedBytes / totalBytes) * 100).toFixed(1);
153
+ logProgress(`Downloading: ${percent}% (${downloadedBytes}/${totalBytes} bytes)`);
154
+ }
155
+ });
156
+
157
+ const fileStream = fs.createWriteStream(destPath);
158
+ response.pipe(fileStream);
159
+
160
+ fileStream.on('finish', () => {
161
+ fileStream.close();
162
+ if (!isCI) {
163
+ process.stdout.write('\n');
164
+ }
165
+
166
+ // Verify download completeness
167
+ if (totalBytes && downloadedBytes !== totalBytes) {
168
+ fs.unlinkSync(destPath);
169
+ return reject(new Error(`Incomplete download: ${downloadedBytes}/${totalBytes} bytes`));
170
+ }
171
+
172
+ log('✓ Download complete');
173
+ resolve();
174
+ });
175
+
176
+ fileStream.on('error', (err) => {
177
+ fs.unlinkSync(destPath);
178
+ reject(err);
179
+ });
180
+ });
181
+
182
+ request.on('error', reject);
183
+ request.on('timeout', () => {
184
+ request.destroy();
185
+ reject(new Error('Download timeout'));
186
+ });
187
+ });
188
+ }
189
+
190
+ // Download with retry logic
191
+ async function downloadWithRetry(url, destPath, options = {}, maxRetries = 3) {
192
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
193
+ try {
194
+ await downloadBinary(url, destPath, options);
195
+ return;
196
+ } catch (error) {
197
+ if (attempt === maxRetries) {
198
+ throw error;
199
+ }
200
+ const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s
201
+ console.warn(`\n⚠ Download failed (attempt ${attempt}/${maxRetries}): ${error.message}`);
202
+ console.warn(`Retrying in ${delay/1000}s...`);
203
+ await new Promise(resolve => setTimeout(resolve, delay));
204
+ }
205
+ }
206
+ }
207
+
208
+ // Extract a specific file from a tar.gz archive
209
+ // Implements manual tar parsing to avoid external dependencies
210
+ // Tar format: 512-byte blocks, alternating header and data blocks
211
+ function extractFileFromTarball(tarballBuffer, targetFilename) {
212
+ const BLOCK_SIZE = 512;
213
+ let offset = 0;
214
+
215
+ while (offset < tarballBuffer.length) {
216
+ // Read header block
217
+ const header = tarballBuffer.slice(offset, offset + BLOCK_SIZE);
218
+
219
+ // Check if we've reached the end (two zero blocks)
220
+ if (header.every(byte => byte === 0)) {
221
+ break;
222
+ }
223
+
224
+ // Extract filename (bytes 0-99, null-terminated)
225
+ const filenameBuffer = header.slice(0, 100);
226
+ const nullIndex = filenameBuffer.indexOf(0);
227
+ const filename = filenameBuffer.slice(0, nullIndex > 0 ? nullIndex : 100).toString('utf8');
228
+
229
+ // Extract file size (bytes 124-135, octal string)
230
+ const sizeStr = header.slice(124, 136).toString('utf8').trim().replace(/\0/g, '');
231
+ const fileSize = parseInt(sizeStr, 8) || 0;
232
+
233
+ // Move to data blocks
234
+ offset += BLOCK_SIZE;
235
+
236
+ // Check if this is the file we're looking for
237
+ if (filename === targetFilename || filename.endsWith('/' + targetFilename)) {
238
+ // Extract file data
239
+ const fileData = tarballBuffer.slice(offset, offset + fileSize);
240
+ return fileData;
241
+ }
242
+
243
+ // Skip to next header (file data is padded to 512-byte boundary)
244
+ const dataBlocks = Math.ceil(fileSize / BLOCK_SIZE);
245
+ offset += dataBlocks * BLOCK_SIZE;
246
+ }
247
+
248
+ return null;
249
+ }
250
+
251
+ // Download using npm pack (uses npm's authentication)
252
+ function downloadViaPackageManager(platformPackage, binaryName) {
253
+ log('Using package manager to download platform package...');
254
+
255
+ const npmExecPath = process.env.npm_execpath;
256
+ if (!npmExecPath) {
257
+ throw new Error('npm executable path not found');
258
+ }
259
+
260
+ try {
261
+ // Use npm pack to download the tarball
262
+ // npm pack automatically uses .npmrc authentication
263
+ log(`Running: npm pack ${platformPackage}`);
264
+
265
+ const output = execSync(`"${npmExecPath}" pack ${platformPackage}`, {
266
+ encoding: 'utf8',
267
+ cwd: __dirname,
268
+ stdio: ['pipe', 'pipe', 'pipe']
269
+ });
270
+
271
+ // npm pack outputs the tarball filename
272
+ const tarballFilename = output.trim().split('\n').pop();
273
+ const tarballPath = path.join(__dirname, tarballFilename);
274
+
275
+ if (!fs.existsSync(tarballPath)) {
276
+ throw new Error(`Tarball not found: ${tarballPath}`);
277
+ }
278
+
279
+ log(`✓ Downloaded: ${tarballFilename}`);
280
+
281
+ // Extract the binary
282
+ extractBinary(tarballPath, binaryName);
283
+
284
+ return true;
285
+ } catch (error) {
286
+ throw new Error(`npm pack failed: ${error.message}`);
287
+ }
288
+ }
289
+
290
+ // Extract binary from tarball
291
+ function extractBinary(tarballPath, binaryName) {
292
+ const extractDir = path.join(__dirname, 'bin');
293
+
294
+ try {
295
+ // Create bin directory
296
+ fs.mkdirSync(extractDir, { recursive: true });
297
+
298
+ log('Extracting tarball...');
299
+
300
+ // Read and decompress the .tgz file
301
+ const compressedData = fs.readFileSync(tarballPath);
302
+ const tarData = zlib.gunzipSync(compressedData);
303
+
304
+ // Platform packages have structure: package/bin/{binary-name}
305
+ const targetPath = `package/bin/${binaryName}`;
306
+
307
+ // Extract the binary from the tar archive
308
+ const binaryData = extractFileFromTarball(tarData, targetPath);
309
+
310
+ if (!binaryData) {
311
+ throw new Error(
312
+ `Binary '${binaryName}' not found in downloaded package.\n` +
313
+ `Expected at: ${targetPath}\n` +
314
+ `This may indicate a packaging issue.`
315
+ );
316
+ }
317
+
318
+ // Write binary to final location
319
+ const destBinary = path.join(extractDir, binaryName);
320
+ fs.writeFileSync(destBinary, binaryData);
321
+
322
+ // Set executable permissions
323
+ fs.chmodSync(destBinary, 0o755);
324
+
325
+ log(`✓ Binary extracted to: ${destBinary}`);
326
+
327
+ // Cleanup tarball
328
+ fs.unlinkSync(tarballPath);
329
+
330
+ } catch (error) {
331
+ // Cleanup on error
332
+ if (fs.existsSync(tarballPath)) {
333
+ fs.unlinkSync(tarballPath);
334
+ }
335
+ throw error;
336
+ }
337
+ }
338
+
339
+ // Main installation logic
340
+ async function main() {
341
+ try {
342
+ const platform = getPlatform();
343
+ const binaryName = process.platform === 'win32' ? 'byid.exe' : 'byid';
344
+ const platformPackage = `@beyondidentity/ai-cli-${platform}`;
345
+
346
+ // Check if optionalDependency already installed
347
+ if (checkOptionalDependency(platformPackage, binaryName)) {
348
+ process.exit(0);
349
+ }
350
+
351
+ // Check if fallback binary already exists
352
+ const fallbackBinaryPath = path.join(__dirname, 'bin', binaryName);
353
+ if (checkFallbackBinary(fallbackBinaryPath)) {
354
+ process.exit(0);
355
+ }
356
+
357
+ log(`Platform package ${platformPackage} not found, attempting fallback download...`);
358
+
359
+ // Check write permissions
360
+ if (!checkWritePermissions()) {
361
+ process.exit(0);
362
+ }
363
+
364
+ // Strategy 1: If npm is available, use npm pack (handles auth automatically)
365
+ if (process.env.npm_execpath) {
366
+ log('Detected npm package manager');
367
+ try {
368
+ downloadViaPackageManager(platformPackage, binaryName);
369
+ log('✓ Fallback installation complete via npm');
370
+ process.exit(0);
371
+ } catch (npmError) {
372
+ console.warn(`\n⚠ npm pack failed: ${npmError.message}`);
373
+ console.warn('Falling back to direct HTTPS download...');
374
+ }
375
+ } else {
376
+ log('npm not detected, using direct HTTPS download');
377
+ }
378
+
379
+ // Strategy 2: Direct HTTPS download (for non-npm package managers)
380
+ const pkgJson = require('./package.json');
381
+ const version = pkgJson.version;
382
+ const registryUrl = pkgJson.registryUrl || process.env.NPM_REGISTRY_URL || 'https://registry.npmjs.org';
383
+
384
+ log(`Registry: ${registryUrl}`);
385
+ log(`Version: ${version}`);
386
+
387
+ // Construct download URL
388
+ const downloadUrl = constructDownloadUrl(platformPackage, version, registryUrl);
389
+
390
+ // Download tarball (assumes public registry, no auth needed)
391
+ const tarballPath = path.join(__dirname, `.temp-${platform}.tgz`);
392
+ await downloadWithRetry(downloadUrl, tarballPath);
393
+
394
+ // Extract binary (synchronous)
395
+ extractBinary(tarballPath, binaryName);
396
+
397
+ log('✓ Fallback installation complete via HTTPS');
398
+ process.exit(0);
399
+
400
+ } catch (error) {
401
+ console.warn('\n⚠ Warning: Fallback binary download failed');
402
+ console.warn(`Error: ${error.message}`);
403
+ console.warn('\nThe package may not work correctly on this platform.');
404
+ console.warn('Please ensure optionalDependencies are enabled in your package manager.');
405
+ console.warn('For more information, see the README or visit:');
406
+ console.warn('https://gitlab.byndid.com/ai/ai-agents');
407
+
408
+ // Don't fail the install - just warn
409
+ process.exit(0);
410
+ }
411
+ }
412
+
413
+ // Run if executed directly
414
+ if (require.main === module) {
415
+ main();
416
+ }
417
+
418
+ module.exports = { getPlatform, constructDownloadUrl, extractFileFromTarball };
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@beyondidentity/ai-cli",
3
+ "version": "0.1.711+28e733c",
4
+ "description": "Beyond Identity AI CLI - unified command interface with proxy, auth, and launch commands",
5
+ "keywords": ["beyondidentity", "ai", "cli", "byid"],
6
+ "license": "UNLICENSED",
7
+ "bin": {
8
+ "byid": "./bin/byid.js"
9
+ },
10
+ "main": "./index.js",
11
+ "scripts": {
12
+ "postinstall": "node install.js"
13
+ },
14
+ "files": [
15
+ "index.js",
16
+ "install.js",
17
+ "bin/byid.js",
18
+ "THIRD_PARTY_LICENSES.txt"
19
+ ],
20
+ "optionalDependencies": {
21
+ "@beyondidentity/ai-cli-linux-x64": "0.1.711+28e733c"
22
+ },
23
+ "_commentedOutPlatforms": {
24
+ "_note": "These platforms are not yet supported but reserved for future use",
25
+ "_darwin-arm64": "@beyondidentity/ai-cli-darwin-arm64",
26
+ "_darwin-x64": "@beyondidentity/ai-cli-darwin-x64",
27
+ "_linux-arm64": "@beyondidentity/ai-cli-linux-arm64",
28
+ "_win32-x64": "@beyondidentity/ai-cli-win32-x64"
29
+ },
30
+ "registryUrl": "https://npm.cloudsmith.io/beyond-identity/ai-agents-npm",
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ }
34
+ }