@probelabs/probe 0.6.0-rc142 → 0.6.0-rc144
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/build/agent/index.js +233 -44
- package/build/downloader.js +343 -55
- package/build/mcp/index.js +9 -2
- package/build/mcp/index.ts +9 -2
- package/build/tools/common.js +25 -1
- package/build/tools/langchain.js +3 -2
- package/build/tools/vercel.js +3 -2
- package/build/utils.js +9 -7
- package/cjs/agent/ProbeAgent.cjs +233 -44
- package/cjs/index.cjs +234 -45
- package/package.json +1 -1
- package/src/downloader.js +343 -55
- package/src/mcp/index.ts +9 -2
- package/src/tools/common.js +25 -1
- package/src/tools/langchain.js +3 -2
- package/src/tools/vercel.js +3 -2
- package/src/utils.js +9 -7
package/cjs/index.cjs
CHANGED
|
@@ -206,6 +206,145 @@ var init_directory_resolver = __esm({
|
|
|
206
206
|
});
|
|
207
207
|
|
|
208
208
|
// src/downloader.js
|
|
209
|
+
async function acquireFileLock(lockPath, version) {
|
|
210
|
+
const lockData = {
|
|
211
|
+
version,
|
|
212
|
+
pid: process.pid,
|
|
213
|
+
timestamp: Date.now()
|
|
214
|
+
};
|
|
215
|
+
try {
|
|
216
|
+
await import_fs_extra2.default.writeFile(lockPath, JSON.stringify(lockData), { flag: "wx" });
|
|
217
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
218
|
+
console.log(`Acquired file lock: ${lockPath}`);
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
} catch (error2) {
|
|
222
|
+
if (error2.code === "EEXIST") {
|
|
223
|
+
try {
|
|
224
|
+
const existingLock = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
|
|
225
|
+
const lockAge = Date.now() - existingLock.timestamp;
|
|
226
|
+
if (lockAge > LOCK_TIMEOUT_MS) {
|
|
227
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
228
|
+
console.log(`Removing stale lock file (age: ${Math.round(lockAge / 1e3)}s, pid: ${existingLock.pid})`);
|
|
229
|
+
}
|
|
230
|
+
await import_fs_extra2.default.remove(lockPath);
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
234
|
+
console.log(`Download in progress by process ${existingLock.pid}, waiting...`);
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
} catch (readError) {
|
|
238
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
239
|
+
console.log(`Lock file corrupted, removing: ${readError.message}`);
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
await import_fs_extra2.default.remove(lockPath);
|
|
243
|
+
} catch {
|
|
244
|
+
}
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (error2.code === "EACCES" || error2.code === "EPERM" || error2.code === "EROFS") {
|
|
249
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
250
|
+
console.log(`Cannot create lock file (${error2.code}): ${lockPath}`);
|
|
251
|
+
console.log(`File-based locking unavailable, will proceed without cross-process coordination`);
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
256
|
+
console.log(`Unexpected error creating lock file: ${error2.message}`);
|
|
257
|
+
console.log(`Proceeding without file-based lock`);
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function releaseFileLock(lockPath) {
|
|
263
|
+
try {
|
|
264
|
+
await import_fs_extra2.default.remove(lockPath);
|
|
265
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
266
|
+
console.log(`Released file lock: ${lockPath}`);
|
|
267
|
+
}
|
|
268
|
+
} catch (error2) {
|
|
269
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
270
|
+
console.log(`Warning: Could not release lock file: ${error2.message}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async function waitForFileLock(lockPath, binaryPath) {
|
|
275
|
+
const startTime = Date.now();
|
|
276
|
+
while (Date.now() - startTime < MAX_LOCK_WAIT_MS) {
|
|
277
|
+
if (await import_fs_extra2.default.pathExists(binaryPath)) {
|
|
278
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
279
|
+
console.log(`Binary now available at ${binaryPath}, download completed by another process`);
|
|
280
|
+
}
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
const lockExists = await import_fs_extra2.default.pathExists(lockPath);
|
|
284
|
+
if (!lockExists) {
|
|
285
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
286
|
+
console.log(`Lock file removed but binary not found - download may have failed`);
|
|
287
|
+
}
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const lockData = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
|
|
292
|
+
const lockAge = Date.now() - lockData.timestamp;
|
|
293
|
+
if (lockAge > LOCK_TIMEOUT_MS) {
|
|
294
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
295
|
+
console.log(`Lock expired (age: ${Math.round(lockAge / 1e3)}s), will retry download`);
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
await new Promise((resolve4) => setTimeout(resolve4, LOCK_POLL_INTERVAL_MS));
|
|
302
|
+
}
|
|
303
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
304
|
+
console.log(`Timeout waiting for file lock`);
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
async function withDownloadLock(version, downloadFn) {
|
|
309
|
+
const lockKey = version || "latest";
|
|
310
|
+
if (downloadLocks.has(lockKey)) {
|
|
311
|
+
const lock = downloadLocks.get(lockKey);
|
|
312
|
+
const lockAge = Date.now() - lock.timestamp;
|
|
313
|
+
if (lockAge > LOCK_TIMEOUT_MS) {
|
|
314
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
315
|
+
console.log(`In-memory lock for version ${lockKey} expired (age: ${Math.round(lockAge / 1e3)}s), removing stale lock`);
|
|
316
|
+
}
|
|
317
|
+
downloadLocks.delete(lockKey);
|
|
318
|
+
} else {
|
|
319
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
320
|
+
console.log(`Download already in progress in this process for version ${lockKey}, waiting...`);
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
return await lock.promise;
|
|
324
|
+
} catch (error2) {
|
|
325
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
326
|
+
console.log(`In-memory locked download failed, will retry: ${error2.message}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const downloadPromise = Promise.race([
|
|
332
|
+
downloadFn(),
|
|
333
|
+
new Promise(
|
|
334
|
+
(_2, reject2) => setTimeout(() => reject2(new Error(`Download timeout after ${LOCK_TIMEOUT_MS / 1e3}s`)), LOCK_TIMEOUT_MS)
|
|
335
|
+
)
|
|
336
|
+
]);
|
|
337
|
+
downloadLocks.set(lockKey, {
|
|
338
|
+
promise: downloadPromise,
|
|
339
|
+
timestamp: Date.now()
|
|
340
|
+
});
|
|
341
|
+
try {
|
|
342
|
+
const result = await downloadPromise;
|
|
343
|
+
return result;
|
|
344
|
+
} finally {
|
|
345
|
+
downloadLocks.delete(lockKey);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
209
348
|
function detectOsArch() {
|
|
210
349
|
const osType = import_os2.default.platform();
|
|
211
350
|
const archType = import_os2.default.arch();
|
|
@@ -649,16 +788,64 @@ async function getPackageVersion() {
|
|
|
649
788
|
return "0.0.0";
|
|
650
789
|
}
|
|
651
790
|
}
|
|
791
|
+
async function doDownload(version) {
|
|
792
|
+
const localDir = await getPackageBinDir();
|
|
793
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
794
|
+
console.log(`Downloading probe binary (version: ${version || "latest"})...`);
|
|
795
|
+
console.log(`Using binary directory: ${localDir}`);
|
|
796
|
+
}
|
|
797
|
+
const isWindows = import_os2.default.platform() === "win32";
|
|
798
|
+
const binaryName = isWindows ? `${BINARY_NAME}.exe` : `${BINARY_NAME}-binary`;
|
|
799
|
+
const binaryPath = import_path2.default.join(localDir, binaryName);
|
|
800
|
+
const { os: osInfo, arch: archInfo } = detectOsArch();
|
|
801
|
+
let versionToUse = version;
|
|
802
|
+
let bestAsset;
|
|
803
|
+
let tagVersion;
|
|
804
|
+
if (!versionToUse || versionToUse === "0.0.0") {
|
|
805
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
806
|
+
console.log("No specific version requested, will use the latest release");
|
|
807
|
+
}
|
|
808
|
+
const { tag: tag2, assets } = await getLatestRelease(void 0);
|
|
809
|
+
tagVersion = tag2.startsWith("v") ? tag2.substring(1) : tag2;
|
|
810
|
+
bestAsset = findBestAsset(assets, osInfo, archInfo);
|
|
811
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
812
|
+
console.log(`Found release version: ${tagVersion}`);
|
|
813
|
+
}
|
|
814
|
+
} else {
|
|
815
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
816
|
+
console.log(`Direct download for version: ${versionToUse}`);
|
|
817
|
+
}
|
|
818
|
+
tagVersion = versionToUse;
|
|
819
|
+
bestAsset = constructAssetInfo(versionToUse, osInfo, archInfo);
|
|
820
|
+
}
|
|
821
|
+
const { assetPath, checksumPath } = await downloadAsset(bestAsset, localDir);
|
|
822
|
+
const checksumValid = await verifyChecksum(assetPath, checksumPath);
|
|
823
|
+
if (!checksumValid) {
|
|
824
|
+
throw new Error("Checksum verification failed");
|
|
825
|
+
}
|
|
826
|
+
const extractedBinaryPath = await extractBinary(assetPath, localDir);
|
|
827
|
+
await saveVersionInfo(tagVersion, localDir);
|
|
828
|
+
try {
|
|
829
|
+
await import_fs_extra2.default.remove(assetPath);
|
|
830
|
+
if (checksumPath) {
|
|
831
|
+
await import_fs_extra2.default.remove(checksumPath);
|
|
832
|
+
}
|
|
833
|
+
} catch (err) {
|
|
834
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
835
|
+
console.log(`Warning: Could not clean up temporary files: ${err}`);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
839
|
+
console.log(`Binary successfully installed at ${extractedBinaryPath} (version: ${tagVersion})`);
|
|
840
|
+
}
|
|
841
|
+
return extractedBinaryPath;
|
|
842
|
+
}
|
|
652
843
|
async function downloadProbeBinary(version) {
|
|
653
844
|
try {
|
|
654
845
|
const localDir = await getPackageBinDir();
|
|
655
846
|
if (!version || version === "0.0.0") {
|
|
656
847
|
version = await getPackageVersion();
|
|
657
848
|
}
|
|
658
|
-
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
659
|
-
console.log(`Downloading probe binary (version: ${version || "latest"})...`);
|
|
660
|
-
console.log(`Using binary directory: ${localDir}`);
|
|
661
|
-
}
|
|
662
849
|
const isWindows = import_os2.default.platform() === "win32";
|
|
663
850
|
const binaryName = isWindows ? `${BINARY_NAME}.exe` : `${BINARY_NAME}-binary`;
|
|
664
851
|
const binaryPath = import_path2.default.join(localDir, binaryName);
|
|
@@ -674,54 +861,44 @@ async function downloadProbeBinary(version) {
|
|
|
674
861
|
console.log(`Existing binary version (${versionInfo?.version || "unknown"}) doesn't match requested version (${version}). Downloading new version...`);
|
|
675
862
|
}
|
|
676
863
|
}
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
let
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
689
|
-
console.log(`Found release version: ${tagVersion}`);
|
|
864
|
+
const lockPath = import_path2.default.join(localDir, `.probe-download-${version}.lock`);
|
|
865
|
+
const maxRetries = 3;
|
|
866
|
+
for (let retry = 0; retry < maxRetries; retry++) {
|
|
867
|
+
const lockAcquired = await acquireFileLock(lockPath, version);
|
|
868
|
+
if (lockAcquired === true) {
|
|
869
|
+
try {
|
|
870
|
+
const result = await withDownloadLock(version, () => doDownload(version));
|
|
871
|
+
return result;
|
|
872
|
+
} finally {
|
|
873
|
+
await releaseFileLock(lockPath);
|
|
874
|
+
}
|
|
690
875
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
876
|
+
if (lockAcquired === null) {
|
|
877
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
878
|
+
console.log(`File-based locking unavailable, downloading without cross-process coordination`);
|
|
879
|
+
}
|
|
880
|
+
return await withDownloadLock(version, () => doDownload(version));
|
|
694
881
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
const { assetPath, checksumPath } = await downloadAsset(bestAsset, localDir);
|
|
699
|
-
const checksumValid = await verifyChecksum(assetPath, checksumPath);
|
|
700
|
-
if (!checksumValid) {
|
|
701
|
-
throw new Error("Checksum verification failed");
|
|
702
|
-
}
|
|
703
|
-
const extractedBinaryPath = await extractBinary(assetPath, localDir);
|
|
704
|
-
await saveVersionInfo(tagVersion, localDir);
|
|
705
|
-
try {
|
|
706
|
-
await import_fs_extra2.default.remove(assetPath);
|
|
707
|
-
if (checksumPath) {
|
|
708
|
-
await import_fs_extra2.default.remove(checksumPath);
|
|
882
|
+
const downloadCompleted = await waitForFileLock(lockPath, binaryPath);
|
|
883
|
+
if (downloadCompleted) {
|
|
884
|
+
return binaryPath;
|
|
709
885
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
886
|
+
if (retry < maxRetries - 1) {
|
|
887
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
888
|
+
console.log(`Retrying download (attempt ${retry + 2}/${maxRetries})...`);
|
|
889
|
+
}
|
|
713
890
|
}
|
|
714
891
|
}
|
|
715
892
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
716
|
-
console.log(`
|
|
893
|
+
console.log(`All lock attempts exhausted, attempting direct download`);
|
|
717
894
|
}
|
|
718
|
-
return
|
|
895
|
+
return await withDownloadLock(version, () => doDownload(version));
|
|
719
896
|
} catch (error2) {
|
|
720
897
|
console.error("Error downloading probe binary:", error2);
|
|
721
898
|
throw error2;
|
|
722
899
|
}
|
|
723
900
|
}
|
|
724
|
-
var import_axios, import_fs_extra2, import_path2, import_crypto, import_util, import_child_process, import_tar, import_os2, import_url2, exec, REPO_OWNER, REPO_NAME, BINARY_NAME, __filename2, __dirname2;
|
|
901
|
+
var import_axios, import_fs_extra2, import_path2, import_crypto, import_util, import_child_process, import_tar, import_os2, import_url2, exec, REPO_OWNER, REPO_NAME, BINARY_NAME, __filename2, __dirname2, downloadLocks, LOCK_TIMEOUT_MS, LOCK_POLL_INTERVAL_MS, MAX_LOCK_WAIT_MS;
|
|
725
902
|
var init_downloader = __esm({
|
|
726
903
|
"src/downloader.js"() {
|
|
727
904
|
"use strict";
|
|
@@ -742,19 +919,25 @@ var init_downloader = __esm({
|
|
|
742
919
|
BINARY_NAME = "probe";
|
|
743
920
|
__filename2 = (0, import_url2.fileURLToPath)("file:///");
|
|
744
921
|
__dirname2 = import_path2.default.dirname(__filename2);
|
|
922
|
+
downloadLocks = /* @__PURE__ */ new Map();
|
|
923
|
+
LOCK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
924
|
+
LOCK_POLL_INTERVAL_MS = 1e3;
|
|
925
|
+
MAX_LOCK_WAIT_MS = 5 * 60 * 1e3;
|
|
745
926
|
}
|
|
746
927
|
});
|
|
747
928
|
|
|
748
929
|
// src/utils.js
|
|
749
930
|
async function getBinaryPath(options = {}) {
|
|
750
931
|
const { forceDownload = false, version } = options;
|
|
751
|
-
if (probeBinaryPath && !forceDownload && import_fs_extra3.default.existsSync(probeBinaryPath)) {
|
|
752
|
-
return probeBinaryPath;
|
|
753
|
-
}
|
|
754
932
|
if (process.env.PROBE_PATH && import_fs_extra3.default.existsSync(process.env.PROBE_PATH) && !forceDownload) {
|
|
755
933
|
probeBinaryPath = process.env.PROBE_PATH;
|
|
756
934
|
return probeBinaryPath;
|
|
757
935
|
}
|
|
936
|
+
if (version && !forceDownload) {
|
|
937
|
+
console.log(`Specific version ${version} requested. Downloading...`);
|
|
938
|
+
probeBinaryPath = await downloadProbeBinary(version);
|
|
939
|
+
return probeBinaryPath;
|
|
940
|
+
}
|
|
758
941
|
const binDir = await getPackageBinDir();
|
|
759
942
|
const isWindows = process.platform === "win32";
|
|
760
943
|
const binaryName = isWindows ? "probe.exe" : "probe-binary";
|
|
@@ -5477,6 +5660,12 @@ function createMessagePreview(message, charsPerSide = 200) {
|
|
|
5477
5660
|
const end = message.substring(message.length - charsPerSide);
|
|
5478
5661
|
return `${start}...${end}`;
|
|
5479
5662
|
}
|
|
5663
|
+
function parseTargets(targets) {
|
|
5664
|
+
if (!targets || typeof targets !== "string") {
|
|
5665
|
+
return [];
|
|
5666
|
+
}
|
|
5667
|
+
return targets.split(/\s+/).filter((f3) => f3.length > 0);
|
|
5668
|
+
}
|
|
5480
5669
|
var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, bashDescription, DEFAULT_VALID_TOOLS;
|
|
5481
5670
|
var init_common = __esm({
|
|
5482
5671
|
"src/tools/common.js"() {
|
|
@@ -6131,7 +6320,7 @@ var init_vercel = __esm({
|
|
|
6131
6320
|
format: effectiveFormat
|
|
6132
6321
|
};
|
|
6133
6322
|
} else if (targets) {
|
|
6134
|
-
const files =
|
|
6323
|
+
const files = parseTargets(targets);
|
|
6135
6324
|
let effectiveFormat = format2;
|
|
6136
6325
|
if (outline && format2 === "outline-xml") {
|
|
6137
6326
|
effectiveFormat = "xml";
|
|
@@ -7489,7 +7678,7 @@ function createExtractTool() {
|
|
|
7489
7678
|
schema: extractSchema,
|
|
7490
7679
|
func: async ({ targets, line, end_line, allow_tests, context_lines, format: format2 }) => {
|
|
7491
7680
|
try {
|
|
7492
|
-
const files =
|
|
7681
|
+
const files = parseTargets(targets);
|
|
7493
7682
|
const results = await extract({
|
|
7494
7683
|
files,
|
|
7495
7684
|
allowTests: allow_tests,
|