@probelabs/probe 0.6.0-rc146 → 0.6.0-rc148
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/bin/binaries/probe-v0.6.0-rc148-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc148-aarch64-unknown-linux-gnu.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc148-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc148-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc148-x86_64-unknown-linux-gnu.tar.gz +0 -0
- package/bin/probe +12 -3
- package/build/agent/index.js +18 -404
- package/build/extractor.js +271 -0
- package/build/index.js +1 -7
- package/cjs/agent/ProbeAgent.cjs +659 -697
- package/cjs/index.cjs +610 -1274
- package/package.json +4 -12
- package/scripts/postinstall.js +75 -47
- package/src/extractor.js +271 -0
- package/src/index.js +1 -7
- package/build/agent/appTracer.js +0 -360
- package/build/agent/fileSpanExporter.js +0 -167
- package/build/agent/telemetry.js +0 -219
- package/cjs/agent/telemetry.cjs +0 -358
- package/src/agent/appTracer.js +0 -360
- package/src/agent/fileSpanExporter.js +0 -167
- package/src/agent/telemetry.js +0 -219
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary extractor for bundled probe binaries
|
|
3
|
+
* @module extractor
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import tar from 'tar';
|
|
9
|
+
import AdmZip from 'adm-zip';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
15
|
+
|
|
16
|
+
const BINARY_NAME = "probe";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Detects the current OS and architecture
|
|
20
|
+
* @returns {Object} Object containing OS and architecture information
|
|
21
|
+
*/
|
|
22
|
+
function detectPlatform() {
|
|
23
|
+
const osType = os.platform();
|
|
24
|
+
const archType = os.arch();
|
|
25
|
+
|
|
26
|
+
let platform;
|
|
27
|
+
let extension;
|
|
28
|
+
|
|
29
|
+
// Map to the same format used in release artifacts
|
|
30
|
+
if (osType === 'linux') {
|
|
31
|
+
if (archType === 'x64') {
|
|
32
|
+
platform = 'x86_64-unknown-linux-gnu';
|
|
33
|
+
extension = 'tar.gz';
|
|
34
|
+
} else if (archType === 'arm64') {
|
|
35
|
+
platform = 'aarch64-unknown-linux-gnu';
|
|
36
|
+
extension = 'tar.gz';
|
|
37
|
+
} else {
|
|
38
|
+
throw new Error(`Unsupported Linux architecture: ${archType}`);
|
|
39
|
+
}
|
|
40
|
+
} else if (osType === 'darwin') {
|
|
41
|
+
if (archType === 'x64') {
|
|
42
|
+
platform = 'x86_64-apple-darwin';
|
|
43
|
+
extension = 'tar.gz';
|
|
44
|
+
} else if (archType === 'arm64') {
|
|
45
|
+
platform = 'aarch64-apple-darwin';
|
|
46
|
+
extension = 'tar.gz';
|
|
47
|
+
} else {
|
|
48
|
+
throw new Error(`Unsupported macOS architecture: ${archType}`);
|
|
49
|
+
}
|
|
50
|
+
} else if (osType === 'win32') {
|
|
51
|
+
if (archType === 'x64') {
|
|
52
|
+
platform = 'x86_64-pc-windows-msvc';
|
|
53
|
+
extension = 'zip';
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error(`Unsupported Windows architecture: ${archType}`);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error(`Unsupported operating system: ${osType}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
62
|
+
console.log(`Detected platform: ${platform}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { platform, extension, osType, archType };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Validates that a path is within a base directory (prevents path traversal)
|
|
70
|
+
* @param {string} filePath - Path to validate
|
|
71
|
+
* @param {string} baseDir - Base directory that filePath must be within
|
|
72
|
+
* @returns {boolean} True if path is safe
|
|
73
|
+
*/
|
|
74
|
+
function isPathSafe(filePath, baseDir) {
|
|
75
|
+
const normalizedBase = path.normalize(baseDir);
|
|
76
|
+
const normalizedPath = path.normalize(filePath);
|
|
77
|
+
const relativePath = path.relative(normalizedBase, normalizedPath);
|
|
78
|
+
|
|
79
|
+
// Path is safe if it doesn't start with '..' and isn't absolute
|
|
80
|
+
return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Extracts a tar.gz archive using the tar library
|
|
85
|
+
* @param {string} archivePath - Path to the .tar.gz file
|
|
86
|
+
* @param {string} extractDir - Directory to extract to
|
|
87
|
+
*/
|
|
88
|
+
async function extractTarGz(archivePath, extractDir) {
|
|
89
|
+
await tar.extract({
|
|
90
|
+
file: archivePath,
|
|
91
|
+
cwd: extractDir,
|
|
92
|
+
// Security: Prevent path traversal attacks
|
|
93
|
+
onentry: (entry) => {
|
|
94
|
+
const fullPath = path.join(extractDir, entry.path);
|
|
95
|
+
if (!isPathSafe(fullPath, extractDir)) {
|
|
96
|
+
throw new Error(`Path traversal attempt detected: ${entry.path}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Extracts a zip archive using adm-zip library
|
|
104
|
+
* @param {string} archivePath - Path to the .zip file
|
|
105
|
+
* @param {string} extractDir - Directory to extract to
|
|
106
|
+
*/
|
|
107
|
+
async function extractZip(archivePath, extractDir) {
|
|
108
|
+
const zip = new AdmZip(archivePath);
|
|
109
|
+
const zipEntries = zip.getEntries();
|
|
110
|
+
|
|
111
|
+
// Extract each entry with path validation
|
|
112
|
+
for (const entry of zipEntries) {
|
|
113
|
+
const outputPath = path.join(extractDir, entry.entryName);
|
|
114
|
+
|
|
115
|
+
// Security: Validate path to prevent traversal attacks
|
|
116
|
+
if (!isPathSafe(outputPath, extractDir)) {
|
|
117
|
+
throw new Error(`Path traversal attempt detected: ${entry.entryName}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (entry.isDirectory) {
|
|
121
|
+
await fs.ensureDir(outputPath);
|
|
122
|
+
} else {
|
|
123
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
124
|
+
await fs.writeFile(outputPath, entry.getData());
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Finds the binary file in the extracted directory
|
|
131
|
+
* @param {string} dir - Directory to search
|
|
132
|
+
* @param {string} baseDir - Base directory for path validation
|
|
133
|
+
* @param {string} binaryName - Name of binary to find
|
|
134
|
+
* @param {boolean} isWindows - Whether running on Windows
|
|
135
|
+
* @returns {Promise<string|null>} Path to binary or null
|
|
136
|
+
*/
|
|
137
|
+
async function findBinary(dir, baseDir, binaryName, isWindows) {
|
|
138
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
139
|
+
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
const fullPath = path.join(dir, entry.name);
|
|
142
|
+
|
|
143
|
+
// Security: Validate path to prevent traversal
|
|
144
|
+
if (!isPathSafe(fullPath, baseDir)) {
|
|
145
|
+
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
146
|
+
console.log(`Skipping unsafe path: ${fullPath}`);
|
|
147
|
+
}
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (entry.isDirectory()) {
|
|
152
|
+
const result = await findBinary(fullPath, baseDir, binaryName, isWindows);
|
|
153
|
+
if (result) return result;
|
|
154
|
+
} else if (entry.isFile()) {
|
|
155
|
+
// Check if this is the binary we're looking for
|
|
156
|
+
if (entry.name === binaryName ||
|
|
157
|
+
entry.name === BINARY_NAME ||
|
|
158
|
+
(isWindows && entry.name.endsWith('.exe'))) {
|
|
159
|
+
return fullPath;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Extracts the bundled binary for the current platform
|
|
169
|
+
* @param {string} version - Version string (used for archive naming)
|
|
170
|
+
* @returns {Promise<string>} Path to the extracted binary
|
|
171
|
+
*/
|
|
172
|
+
export async function extractBundledBinary(version) {
|
|
173
|
+
const { platform, extension, osType } = detectPlatform();
|
|
174
|
+
|
|
175
|
+
// Construct the archive filename
|
|
176
|
+
const archiveName = `probe-v${version}-${platform}.${extension}`;
|
|
177
|
+
|
|
178
|
+
// Path to the bundled archive
|
|
179
|
+
const binariesDir = path.resolve(__dirname, '..', 'bin', 'binaries');
|
|
180
|
+
const archivePath = path.join(binariesDir, archiveName);
|
|
181
|
+
|
|
182
|
+
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
183
|
+
console.log(`Looking for bundled binary at: ${archivePath}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check if the archive exists
|
|
187
|
+
if (!(await fs.pathExists(archivePath))) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`Bundled binary not found for platform ${platform}.\n` +
|
|
190
|
+
`Expected archive: ${archiveName}\n` +
|
|
191
|
+
`Searched in: ${binariesDir}\n` +
|
|
192
|
+
`\n` +
|
|
193
|
+
`Supported platforms:\n` +
|
|
194
|
+
` - x86_64-unknown-linux-gnu (Linux x64)\n` +
|
|
195
|
+
` - aarch64-unknown-linux-gnu (Linux ARM64)\n` +
|
|
196
|
+
` - x86_64-apple-darwin (macOS Intel)\n` +
|
|
197
|
+
` - aarch64-apple-darwin (macOS Apple Silicon)\n` +
|
|
198
|
+
` - x86_64-pc-windows-msvc (Windows x64)\n` +
|
|
199
|
+
`\n` +
|
|
200
|
+
`Your platform: ${platform}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Determine output binary name and path
|
|
205
|
+
const binDir = path.resolve(__dirname, '..', 'bin');
|
|
206
|
+
const isWindows = osType === 'win32';
|
|
207
|
+
const binaryName = isWindows ? `${BINARY_NAME}.exe` : `${BINARY_NAME}-binary`;
|
|
208
|
+
const binaryPath = path.join(binDir, binaryName);
|
|
209
|
+
|
|
210
|
+
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
211
|
+
console.log(`Extracting ${archiveName} to ${binDir}...`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Create a temporary extraction directory
|
|
215
|
+
const extractDir = path.join(binDir, 'temp_extract');
|
|
216
|
+
await fs.ensureDir(extractDir);
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
// Extract based on file type using proper libraries (no shell commands!)
|
|
220
|
+
if (extension === 'tar.gz') {
|
|
221
|
+
await extractTarGz(archivePath, extractDir);
|
|
222
|
+
} else if (extension === 'zip') {
|
|
223
|
+
await extractZip(archivePath, extractDir);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Find the binary in the extracted files
|
|
227
|
+
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
228
|
+
console.log(`Searching for binary in extracted files...`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const binaryFilePath = await findBinary(extractDir, extractDir, binaryName, isWindows);
|
|
232
|
+
|
|
233
|
+
if (!binaryFilePath) {
|
|
234
|
+
const allFiles = await fs.readdir(extractDir, { recursive: true });
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Binary not found in the archive.\n` +
|
|
237
|
+
`Expected binary name: ${binaryName}\n` +
|
|
238
|
+
`Files in archive: ${allFiles.join(', ')}`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Copy the binary to the final location
|
|
243
|
+
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
244
|
+
console.log(`Found binary at ${binaryFilePath}`);
|
|
245
|
+
console.log(`Installing to ${binaryPath}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
await fs.copyFile(binaryFilePath, binaryPath);
|
|
249
|
+
|
|
250
|
+
// Make the binary executable on Unix-like systems
|
|
251
|
+
if (!isWindows) {
|
|
252
|
+
await fs.chmod(binaryPath, 0o755);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Clean up the temporary extraction directory
|
|
256
|
+
await fs.remove(extractDir);
|
|
257
|
+
|
|
258
|
+
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
259
|
+
console.log(`Binary successfully extracted to ${binaryPath}`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return binaryPath;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
// Clean up on error
|
|
265
|
+
try {
|
|
266
|
+
await fs.remove(extractDir);
|
|
267
|
+
} catch {}
|
|
268
|
+
|
|
269
|
+
throw new Error(`Failed to extract bundled binary: ${error.message}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
package/build/index.js
CHANGED
|
@@ -39,8 +39,6 @@ import { searchTool, queryTool, extractTool, delegateTool } from './tools/vercel
|
|
|
39
39
|
import { bashTool } from './tools/bash.js';
|
|
40
40
|
import { ProbeAgent } from './agent/ProbeAgent.js';
|
|
41
41
|
import { SimpleTelemetry, SimpleAppTracer, initializeSimpleTelemetryFromOptions } from './agent/simpleTelemetry.js';
|
|
42
|
-
import { TelemetryConfig, initializeTelemetryFromOptions } from './agent/telemetry.js';
|
|
43
|
-
import { AppTracer } from './agent/appTracer.js';
|
|
44
42
|
import { listFilesToolInstance, searchFilesToolInstance } from './agent/probeTool.js';
|
|
45
43
|
import { StorageAdapter, InMemoryStorageAdapter } from './agent/storage/index.js';
|
|
46
44
|
import { HookManager, HOOK_TYPES } from './agent/hooks/index.js';
|
|
@@ -64,14 +62,10 @@ export {
|
|
|
64
62
|
// Export hooks
|
|
65
63
|
HookManager,
|
|
66
64
|
HOOK_TYPES,
|
|
67
|
-
// Export simple telemetry classes (no
|
|
65
|
+
// Export simple telemetry classes (lightweight, no heavy dependencies)
|
|
68
66
|
SimpleTelemetry,
|
|
69
67
|
SimpleAppTracer,
|
|
70
68
|
initializeSimpleTelemetryFromOptions,
|
|
71
|
-
// Export full OpenTelemetry telemetry classes
|
|
72
|
-
TelemetryConfig,
|
|
73
|
-
AppTracer,
|
|
74
|
-
initializeTelemetryFromOptions,
|
|
75
69
|
// Export tool generators directly
|
|
76
70
|
searchTool,
|
|
77
71
|
queryTool,
|