fss-link 1.5.7 → 1.6.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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/bundle/fss-link.js +4785 -3183
  3. package/package.json +4 -1
  4. package/scripts/analyze-session-logs.sh +279 -0
  5. package/scripts/build.js +55 -0
  6. package/scripts/build_package.js +37 -0
  7. package/scripts/build_sandbox.js +195 -0
  8. package/scripts/build_vscode_companion.js +30 -0
  9. package/scripts/check-build-status.js +148 -0
  10. package/scripts/check-publish.js +101 -0
  11. package/scripts/clean.js +55 -0
  12. package/scripts/copy_bundle_assets.js +40 -0
  13. package/scripts/copy_files.js +56 -0
  14. package/scripts/create_alias.sh +39 -0
  15. package/scripts/emergency-kill-all-tests.sh +95 -0
  16. package/scripts/emergency-kill-vitest.sh +95 -0
  17. package/scripts/extract-session-logs.sh +202 -0
  18. package/scripts/generate-git-commit-info.js +71 -0
  19. package/scripts/get-previous-tag.js +213 -0
  20. package/scripts/get-release-version.js +119 -0
  21. package/scripts/index-session-logs.sh +173 -0
  22. package/scripts/install-linux.sh +294 -0
  23. package/scripts/install-macos.sh +343 -0
  24. package/scripts/install-windows.ps1 +427 -0
  25. package/scripts/local_telemetry.js +219 -0
  26. package/scripts/memory-monitor.sh +165 -0
  27. package/scripts/postinstall-message.js +31 -0
  28. package/scripts/prepare-package.js +51 -0
  29. package/scripts/process-session-log.py +302 -0
  30. package/scripts/quick-install.sh +195 -0
  31. package/scripts/sandbox_command.js +126 -0
  32. package/scripts/start.js +76 -0
  33. package/scripts/telemetry.js +85 -0
  34. package/scripts/telemetry_gcp.js +188 -0
  35. package/scripts/telemetry_utils.js +421 -0
  36. package/scripts/test-windows-paths.js +51 -0
  37. package/scripts/tests/get-release-version.test.js +110 -0
  38. package/scripts/tests/test-setup.ts +12 -0
  39. package/scripts/tests/vitest.config.ts +20 -0
  40. package/scripts/version.js +83 -0
@@ -0,0 +1,427 @@
1
+ # FSS Link Windows Installation Script
2
+ # Supports Windows 10+ with automatic dependency management
3
+
4
+ param(
5
+ [switch]$Help,
6
+ [switch]$Version,
7
+ [switch]$Force,
8
+ [switch]$NoChocolatey
9
+ )
10
+
11
+ # Color output functions
12
+ function Write-Info {
13
+ param([string]$Message)
14
+ Write-Host "[INFO] $Message" -ForegroundColor Blue
15
+ }
16
+
17
+ function Write-Success {
18
+ param([string]$Message)
19
+ Write-Host "[SUCCESS] $Message" -ForegroundColor Green
20
+ }
21
+
22
+ function Write-Warning {
23
+ param([string]$Message)
24
+ Write-Host "[WARNING] $Message" -ForegroundColor Yellow
25
+ }
26
+
27
+ function Write-Error {
28
+ param([string]$Message)
29
+ Write-Host "[ERROR] $Message" -ForegroundColor Red
30
+ }
31
+
32
+ # Check if running as Administrator
33
+ function Test-Administrator {
34
+ $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
35
+ $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
36
+ return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
37
+ }
38
+
39
+ # Check Windows version
40
+ function Test-WindowsVersion {
41
+ Write-Info "Checking Windows version..."
42
+
43
+ $version = [System.Environment]::OSVersion.Version
44
+ $buildNumber = (Get-ItemProperty "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion").ReleaseId
45
+
46
+ Write-Info "Windows version: $($version.Major).$($version.Minor) Build $buildNumber"
47
+
48
+ if ($version.Major -ge 10) {
49
+ Write-Success "Windows version supported"
50
+ return $true
51
+ } else {
52
+ Write-Error "Windows 10+ required, found Windows $($version.Major).$($version.Minor)"
53
+ return $false
54
+ }
55
+ }
56
+
57
+ # Check for Node.js
58
+ function Test-NodeJS {
59
+ Write-Info "Checking Node.js installation..."
60
+
61
+ try {
62
+ $nodeVersion = & node --version 2>$null
63
+ if ($nodeVersion) {
64
+ $version = $nodeVersion.TrimStart('v')
65
+ $majorVersion = [int]($version.Split('.')[0])
66
+
67
+ if ($majorVersion -ge 20) {
68
+ Write-Success "Node.js $nodeVersion detected (>= 20.0.0 required)"
69
+ return $true
70
+ } else {
71
+ Write-Warning "Node.js $nodeVersion detected, but 20.0.0+ required"
72
+ return $false
73
+ }
74
+ }
75
+ } catch {
76
+ Write-Warning "Node.js not found"
77
+ return $false
78
+ }
79
+
80
+ return $false
81
+ }
82
+
83
+ # Check for Chocolatey
84
+ function Test-Chocolatey {
85
+ Write-Info "Checking for Chocolatey package manager..."
86
+
87
+ try {
88
+ $chocoVersion = & choco --version 2>$null
89
+ if ($chocoVersion) {
90
+ Write-Success "Chocolatey $chocoVersion found"
91
+ return $true
92
+ }
93
+ } catch {
94
+ Write-Warning "Chocolatey not found"
95
+ return $false
96
+ }
97
+
98
+ return $false
99
+ }
100
+
101
+ # Install Chocolatey
102
+ function Install-Chocolatey {
103
+ Write-Info "Installing Chocolatey package manager..."
104
+
105
+ Set-ExecutionPolicy Bypass -Scope Process -Force
106
+ [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
107
+
108
+ try {
109
+ Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
110
+
111
+ # Refresh environment variables
112
+ $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User")
113
+
114
+ if (Test-Chocolatey) {
115
+ Write-Success "Chocolatey installed successfully"
116
+ return $true
117
+ } else {
118
+ Write-Error "Chocolatey installation verification failed"
119
+ return $false
120
+ }
121
+ } catch {
122
+ Write-Error "Chocolatey installation failed: $($_.Exception.Message)"
123
+ return $false
124
+ }
125
+ }
126
+
127
+ # Install Node.js
128
+ function Install-NodeJS {
129
+ Write-Info "Installing Node.js 20..."
130
+
131
+ if ($NoChocolatey) {
132
+ Write-Info "Manual Node.js installation selected"
133
+ Write-Info "Please download and install Node.js 20+ from https://nodejs.org/"
134
+ Write-Info "Press Enter when installation is complete..."
135
+ Read-Host
136
+
137
+ if (Test-NodeJS) {
138
+ Write-Success "Node.js installed successfully"
139
+ return $true
140
+ } else {
141
+ Write-Error "Node.js installation verification failed"
142
+ return $false
143
+ }
144
+ } else {
145
+ try {
146
+ # Install Node.js via Chocolatey
147
+ & choco install nodejs --version=20.11.0 -y
148
+
149
+ # Refresh environment variables
150
+ $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User")
151
+
152
+ if (Test-NodeJS) {
153
+ Write-Success "Node.js installed successfully"
154
+ return $true
155
+ } else {
156
+ Write-Error "Node.js installation verification failed"
157
+ return $false
158
+ }
159
+ } catch {
160
+ Write-Error "Node.js installation failed: $($_.Exception.Message)"
161
+ return $false
162
+ }
163
+ }
164
+ }
165
+
166
+ # Install Visual Studio Build Tools
167
+ function Install-BuildTools {
168
+ Write-Info "Installing Visual Studio Build Tools..."
169
+
170
+ if ($NoChocolatey) {
171
+ Write-Info "Please install Visual Studio Build Tools 2019 or later manually"
172
+ Write-Info "Download from: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019"
173
+ Write-Info "Press Enter when installation is complete..."
174
+ Read-Host
175
+ return $true
176
+ } else {
177
+ try {
178
+ & choco install visualstudio2019buildtools -y
179
+ Write-Success "Visual Studio Build Tools installed"
180
+ return $true
181
+ } catch {
182
+ Write-Warning "Build tools installation may have failed: $($_.Exception.Message)"
183
+ Write-Info "FSS Link installation will continue, but native modules may not compile"
184
+ return $true
185
+ }
186
+ }
187
+ }
188
+
189
+ # Install Python
190
+ function Install-Python {
191
+ Write-Info "Installing Python 3..."
192
+
193
+ if ($NoChocolatey) {
194
+ Write-Info "Please install Python 3.8+ manually from https://python.org/"
195
+ Write-Info "Press Enter when installation is complete..."
196
+ Read-Host
197
+ return $true
198
+ } else {
199
+ try {
200
+ & choco install python3 -y
201
+
202
+ # Refresh PATH
203
+ $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User")
204
+
205
+ Write-Success "Python 3 installed"
206
+ return $true
207
+ } catch {
208
+ Write-Warning "Python installation may have failed: $($_.Exception.Message)"
209
+ return $true
210
+ }
211
+ }
212
+ }
213
+
214
+ # Install FSS Link
215
+ function Install-FSSLink {
216
+ Write-Info "Installing FSS Link..."
217
+
218
+ try {
219
+ # Try global installation first
220
+ & npm install -g fss-link
221
+
222
+ if (Test-FSSLink) {
223
+ Write-Success "FSS Link installed globally"
224
+ return $true
225
+ } else {
226
+ throw "Global installation verification failed"
227
+ }
228
+ } catch {
229
+ Write-Warning "Global installation failed, trying alternative approach: $($_.Exception.Message)"
230
+
231
+ try {
232
+ # Create local npm directory
233
+ $npmGlobalPath = "$env:USERPROFILE\.npm-global"
234
+ New-Item -ItemType Directory -Path $npmGlobalPath -Force | Out-Null
235
+
236
+ & npm config set prefix $npmGlobalPath
237
+
238
+ # Add to PATH
239
+ $userPath = [System.Environment]::GetEnvironmentVariable("PATH", "User")
240
+ $npmBinPath = "$npmGlobalPath\bin"
241
+
242
+ if ($userPath -notlike "*$npmBinPath*") {
243
+ [System.Environment]::SetEnvironmentVariable("PATH", "$userPath;$npmBinPath", "User")
244
+ $env:PATH = "$env:PATH;$npmBinPath"
245
+ }
246
+
247
+ # Install locally
248
+ & npm install -g fss-link
249
+
250
+ Write-Success "FSS Link installed locally"
251
+ return $true
252
+ } catch {
253
+ Write-Error "FSS Link installation failed: $($_.Exception.Message)"
254
+ return $false
255
+ }
256
+ }
257
+ }
258
+
259
+ # Test FSS Link installation
260
+ function Test-FSSLink {
261
+ try {
262
+ $fssVersion = & fss-link --version 2>$null
263
+ if ($fssVersion) {
264
+ Write-Success "FSS Link installed successfully: $fssVersion"
265
+ return $true
266
+ }
267
+ } catch {
268
+ return $false
269
+ }
270
+
271
+ return $false
272
+ }
273
+
274
+ # Verify FSS Link functionality
275
+ function Test-FSSLinkFunctionality {
276
+ Write-Info "Running FSS Link functionality tests..."
277
+
278
+ try {
279
+ # Test help command
280
+ $helpOutput = & fss-link --help 2>$null
281
+ if ($helpOutput) {
282
+ Write-Success "✅ Help command working"
283
+ } else {
284
+ Write-Warning "⚠️ Help command failed"
285
+ }
286
+
287
+ # Test parsers
288
+ $parsersOutput = & fss-link test-parsers 2>$null
289
+ if ($parsersOutput) {
290
+ Write-Success "✅ Document parsers working"
291
+ } else {
292
+ Write-Warning "⚠️ Document parsers test failed"
293
+ }
294
+
295
+ return $true
296
+ } catch {
297
+ Write-Warning "Some functionality tests failed: $($_.Exception.Message)"
298
+ return $false
299
+ }
300
+ }
301
+
302
+ # Print usage information
303
+ function Show-Usage {
304
+ Write-Host @"
305
+
306
+ 🚀 FSS Link Installation Complete!
307
+
308
+ 📋 Quick Start:
309
+ fss-link --version # Check version
310
+ fss-link --help # Show help
311
+ fss-link test-parsers # Test document processing
312
+
313
+ 🔧 Configuration:
314
+ fss-link init # Initialize configuration
315
+ fss-link models setup # Set up model profiles
316
+
317
+ 📚 Documentation:
318
+ https://github.com/FSSCoding/fss-link/blob/main/INSTALLATION.md
319
+ https://github.com/FSSCoding/fss-link/blob/main/fss-docs/README.md
320
+
321
+ 🎯 Example Usage:
322
+ fss-link -p "analyze this project"
323
+ fss-link --tools excel-parser -p "parse spreadsheet.xlsx"
324
+ fss-link --tools web-scraper -p "scrape https://example.com"
325
+
326
+ 💻 Windows Specific:
327
+ - FSS Link is now in your PATH
328
+ - Restart PowerShell/Command Prompt to ensure PATH changes take effect
329
+ - Use Windows Terminal for the best experience
330
+
331
+ "@ -ForegroundColor Cyan
332
+ }
333
+
334
+ # Main installation flow
335
+ function Main {
336
+ Write-Host "🚀 FSS Link Windows Installation Script" -ForegroundColor Cyan
337
+ Write-Host "=======================================" -ForegroundColor Cyan
338
+ Write-Host ""
339
+
340
+ # Check if running as administrator
341
+ if (Test-Administrator) {
342
+ Write-Warning "Running as Administrator. FSS Link will be installed globally."
343
+ }
344
+
345
+ # Check Windows version
346
+ if (-not (Test-WindowsVersion)) {
347
+ exit 1
348
+ }
349
+
350
+ # Install Chocolatey if needed (unless disabled)
351
+ if (-not $NoChocolatey -and -not (Test-Chocolatey)) {
352
+ Write-Info "Installing Chocolatey for automated dependency management..."
353
+ if (-not (Install-Chocolatey)) {
354
+ Write-Error "Chocolatey installation failed"
355
+ Write-Info "Re-run with -NoChocolatey flag for manual installation"
356
+ exit 1
357
+ }
358
+ }
359
+
360
+ # Install Node.js if needed
361
+ if (-not (Test-NodeJS)) {
362
+ if (-not (Install-NodeJS)) {
363
+ Write-Error "Node.js installation failed"
364
+ exit 1
365
+ }
366
+ }
367
+
368
+ # Install build tools
369
+ Install-BuildTools | Out-Null
370
+
371
+ # Install Python
372
+ Install-Python | Out-Null
373
+
374
+ # Install FSS Link
375
+ if (-not (Install-FSSLink)) {
376
+ Write-Error "FSS Link installation failed"
377
+ Write-Info "Please check the installation manually or report issues at:"
378
+ Write-Info "https://github.com/FSSCoding/fss-link/issues"
379
+ exit 1
380
+ }
381
+
382
+ # Verify installation
383
+ Test-FSSLinkFunctionality | Out-Null
384
+
385
+ Show-Usage
386
+ Write-Success "🎉 FSS Link installation successful!"
387
+ }
388
+
389
+ # Handle script parameters
390
+ if ($Help) {
391
+ Write-Host @"
392
+ FSS Link Windows Installation Script
393
+
394
+ Usage: .\install-windows.ps1 [options]
395
+
396
+ Options:
397
+ -Help Show this help message
398
+ -Version Show script version
399
+ -Force Force reinstallation
400
+ -NoChocolatey Skip Chocolatey installation (manual mode)
401
+
402
+ This script will:
403
+ 1. Check Windows version compatibility
404
+ 2. Install Chocolatey package manager (unless -NoChocolatey)
405
+ 3. Install Node.js 20+ and dependencies
406
+ 4. Install Visual Studio Build Tools
407
+ 5. Install FSS Link from npm
408
+ 6. Verify the installation
409
+
410
+ Examples:
411
+ .\install-windows.ps1 # Standard installation
412
+ .\install-windows.ps1 -NoChocolatey # Manual installation mode
413
+ .\install-windows.ps1 -Force # Force reinstallation
414
+ "@
415
+ exit 0
416
+ }
417
+
418
+ if ($Version) {
419
+ Write-Host "FSS Link Windows Installation Script v1.0.0"
420
+ exit 0
421
+ }
422
+
423
+ # Set execution policy for this session
424
+ Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
425
+
426
+ # Run main installation
427
+ Main
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import path from 'path';
10
+ import fs from 'fs';
11
+ import { spawn, execSync } from 'child_process';
12
+ import { fileURLToPath } from 'url';
13
+ import {
14
+ BIN_DIR,
15
+ OTEL_DIR,
16
+ ensureBinary,
17
+ fileExists,
18
+ manageTelemetrySettings,
19
+ registerCleanup,
20
+ waitForPort,
21
+ } from './telemetry_utils.js';
22
+
23
+ const __filename = fileURLToPath(import.meta.url);
24
+ const __dirname = path.dirname(__filename);
25
+
26
+ const OTEL_CONFIG_FILE = path.join(OTEL_DIR, 'collector-local.yaml');
27
+ const OTEL_LOG_FILE = path.join(OTEL_DIR, 'collector.log');
28
+ const JAEGER_LOG_FILE = path.join(OTEL_DIR, 'jaeger.log');
29
+ const JAEGER_PORT = 16686;
30
+
31
+ // This configuration is for the primary otelcol-contrib instance.
32
+ // It receives from the CLI on 4317, exports traces to Jaeger on 14317,
33
+ // and sends metrics/logs to the debug log.
34
+ const OTEL_CONFIG_CONTENT = `
35
+ receivers:
36
+ otlp:
37
+ protocols:
38
+ grpc:
39
+ endpoint: "localhost:4317"
40
+ processors:
41
+ batch:
42
+ timeout: 1s
43
+ exporters:
44
+ otlp:
45
+ endpoint: "localhost:14317"
46
+ tls:
47
+ insecure: true
48
+ debug:
49
+ verbosity: detailed
50
+ service:
51
+ telemetry:
52
+ logs:
53
+ level: "debug"
54
+ metrics:
55
+ level: "none"
56
+ pipelines:
57
+ traces:
58
+ receivers: [otlp]
59
+ processors: [batch]
60
+ exporters: [otlp]
61
+ metrics:
62
+ receivers: [otlp]
63
+ processors: [batch]
64
+ exporters: [debug]
65
+ logs:
66
+ receivers: [otlp]
67
+ processors: [batch]
68
+ exporters: [debug]
69
+ `;
70
+
71
+ async function main() {
72
+ // 1. Ensure binaries are available, downloading if necessary.
73
+ // Binaries are stored in the project's .fss-link/otel/bin directory
74
+ // to avoid modifying the user's system.
75
+ if (!fileExists(BIN_DIR)) fs.mkdirSync(BIN_DIR, { recursive: true });
76
+
77
+ const otelcolPath = await ensureBinary(
78
+ 'otelcol-contrib',
79
+ 'open-telemetry/opentelemetry-collector-releases',
80
+ (version, platform, arch, ext) =>
81
+ `otelcol-contrib_${version}_${platform}_${arch}.${ext}`,
82
+ 'otelcol-contrib',
83
+ false, // isJaeger = false
84
+ ).catch((e) => {
85
+ console.error(`��� Error getting otelcol-contrib: ${e.message}`);
86
+ return null;
87
+ });
88
+ if (!otelcolPath) process.exit(1);
89
+
90
+ const jaegerPath = await ensureBinary(
91
+ 'jaeger',
92
+ 'jaegertracing/jaeger',
93
+ (version, platform, arch, ext) =>
94
+ `jaeger-${version}-${platform}-${arch}.${ext}`,
95
+ 'jaeger',
96
+ true, // isJaeger = true
97
+ ).catch((e) => {
98
+ console.error(`🛑 Error getting jaeger: ${e.message}`);
99
+ return null;
100
+ });
101
+ if (!jaegerPath) process.exit(1);
102
+
103
+ // 2. Kill any existing processes to ensure a clean start.
104
+ console.log('🧹 Cleaning up old processes and logs...');
105
+ try {
106
+ execSync('pkill -f "otelcol-contrib"');
107
+ console.log('✅ Stopped existing otelcol-contrib process.');
108
+ } catch (_e) {} // eslint-disable-line no-empty
109
+ try {
110
+ execSync('pkill -f "jaeger"');
111
+ console.log('✅ Stopped existing jaeger process.');
112
+ } catch (_e) {} // eslint-disable-line no-empty
113
+ try {
114
+ if (fileExists(OTEL_LOG_FILE)) fs.unlinkSync(OTEL_LOG_FILE);
115
+ console.log('✅ Deleted old collector log.');
116
+ } catch (e) {
117
+ if (e.code !== 'ENOENT') console.error(e);
118
+ }
119
+ try {
120
+ if (fileExists(JAEGER_LOG_FILE)) fs.unlinkSync(JAEGER_LOG_FILE);
121
+ console.log('✅ Deleted old jaeger log.');
122
+ } catch (e) {
123
+ if (e.code !== 'ENOENT') console.error(e);
124
+ }
125
+
126
+ let jaegerProcess, collectorProcess;
127
+ let jaegerLogFd, collectorLogFd;
128
+
129
+ const originalSandboxSetting = manageTelemetrySettings(
130
+ true,
131
+ 'http://localhost:4317',
132
+ 'local',
133
+ );
134
+
135
+ registerCleanup(
136
+ () => [jaegerProcess, collectorProcess],
137
+ () => [jaegerLogFd, collectorLogFd],
138
+ originalSandboxSetting,
139
+ );
140
+
141
+ if (!fileExists(OTEL_DIR)) fs.mkdirSync(OTEL_DIR, { recursive: true });
142
+ fs.writeFileSync(OTEL_CONFIG_FILE, OTEL_CONFIG_CONTENT);
143
+ console.log('📄 Wrote OTEL collector config.');
144
+
145
+ // Start Jaeger
146
+ console.log(`🚀 Starting Jaeger service... Logs: ${JAEGER_LOG_FILE}`);
147
+ jaegerLogFd = fs.openSync(JAEGER_LOG_FILE, 'a');
148
+ jaegerProcess = spawn(
149
+ jaegerPath,
150
+ ['--set=receivers.otlp.protocols.grpc.endpoint=localhost:14317'],
151
+ { stdio: ['ignore', jaegerLogFd, jaegerLogFd] },
152
+ );
153
+ console.log(`⏳ Waiting for Jaeger to start (PID: ${jaegerProcess.pid})...`);
154
+
155
+ try {
156
+ await waitForPort(JAEGER_PORT);
157
+ console.log(`✅ Jaeger started successfully.`);
158
+ } catch (_) {
159
+ console.error(`🛑 Error: Jaeger failed to start on port ${JAEGER_PORT}.`);
160
+ if (jaegerProcess && jaegerProcess.pid) {
161
+ process.kill(jaegerProcess.pid, 'SIGKILL');
162
+ }
163
+ if (fileExists(JAEGER_LOG_FILE)) {
164
+ console.error('📄 Jaeger Log Output:');
165
+ console.error(fs.readFileSync(JAEGER_LOG_FILE, 'utf-8'));
166
+ }
167
+ process.exit(1);
168
+ }
169
+
170
+ // Start the primary OTEL collector
171
+ console.log(`🚀 Starting OTEL collector... Logs: ${OTEL_LOG_FILE}`);
172
+ collectorLogFd = fs.openSync(OTEL_LOG_FILE, 'a');
173
+ collectorProcess = spawn(otelcolPath, ['--config', OTEL_CONFIG_FILE], {
174
+ stdio: ['ignore', collectorLogFd, collectorLogFd],
175
+ });
176
+ console.log(
177
+ `⏳ Waiting for OTEL collector to start (PID: ${collectorProcess.pid})...`,
178
+ );
179
+
180
+ try {
181
+ await waitForPort(4317);
182
+ console.log(`✅ OTEL collector started successfully.`);
183
+ } catch (_) {
184
+ console.error(`🛑 Error: OTEL collector failed to start on port 4317.`);
185
+ if (collectorProcess && collectorProcess.pid) {
186
+ process.kill(collectorProcess.pid, 'SIGKILL');
187
+ }
188
+ if (fileExists(OTEL_LOG_FILE)) {
189
+ console.error('📄 OTEL Collector Log Output:');
190
+ console.error(fs.readFileSync(OTEL_LOG_FILE, 'utf-8'));
191
+ }
192
+ process.exit(1);
193
+ }
194
+
195
+ [jaegerProcess, collectorProcess].forEach((proc) => {
196
+ if (proc) {
197
+ proc.on('error', (err) => {
198
+ console.error(`${proc.spawnargs[0]} process error:`, err);
199
+ process.exit(1);
200
+ });
201
+ }
202
+ });
203
+
204
+ console.log(`
205
+ ✨ Local telemetry environment is running.`);
206
+ console.log(
207
+ `
208
+ 🔎 View traces in the Jaeger UI: http://localhost:${JAEGER_PORT}`,
209
+ );
210
+ console.log(`📊 View metrics in the logs and metrics: ${OTEL_LOG_FILE}`);
211
+ console.log(
212
+ `
213
+ 📄 Tail logs and metrics in another terminal: tail -f ${OTEL_LOG_FILE}`,
214
+ );
215
+ console.log(`
216
+ Press Ctrl+C to exit.`);
217
+ }
218
+
219
+ main();