@lincoln504/pi-research 1.3.3 → 1.3.5
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 +7 -2
- package/dist/cli.mjs +242 -95
- package/dist/thread-worker.mjs +122 -50
- package/docs/CHANGELOG.md +76 -0
- package/package.json +1 -1
- package/skills/pi-research/SKILL.md +1 -1
- package/src/core/service-registry.ts +37 -3
- package/src/healthcheck/index.ts +9 -7
- package/src/infrastructure/browser/browser-client.ts +5 -2
- package/src/infrastructure/browser/task-execution-service.ts +21 -5
- package/src/infrastructure/browser/thread-worker-browser.ts +49 -1
- package/src/infrastructure/browser/thread-worker-messaging.ts +70 -25
- package/src/infrastructure/browser/thread-worker.mjs +122 -50
- package/src/infrastructure/knowledge-store-service.ts +27 -2
- package/src/knowledge/chunker.ts +14 -1
- package/src/orchestration/quick-research-orchestrator.ts +13 -2
- package/src/orchestration/research-orchestration-service.ts +16 -3
- package/src/sdk.ts +11 -2
- package/src/security/github-advisories.ts +13 -4
- package/src/security/osv-types.ts +1 -1
- package/src/skill-install/skill-installer.ts +69 -6
- package/src/stackexchange/index.ts +15 -0
- package/src/stackexchange/rest-client.ts +13 -24
- package/src/tools/research-tool-definition.ts +3 -2
- package/src/tools/scrape.ts +6 -4
- package/src/tools/security.ts +13 -4
- package/src/utils/input-validation.ts +0 -10
- package/src/utils/json-utils.ts +0 -78
- package/src/utils/log-rotation.ts +21 -6
- package/src/utils/log-utils.ts +43 -33
- package/src/utils/metrics.ts +0 -8
- package/src/utils/shared-links.ts +0 -14
- package/src/utils/stdio-capture.ts +44 -7
- package/src/utils/text-utils.ts +6 -2
- package/src/utils/url-utils.ts +7 -1
- package/src/web-research/scraper-utils.ts +8 -3
- package/src/web-research/web-scraper.ts +33 -1
- package/src/youtube/potoken.ts +26 -2
- package/src/youtube/transcript-client.ts +5 -2
package/dist/cli.mjs
CHANGED
|
@@ -215,12 +215,8 @@ function formatArg(arg) {
|
|
|
215
215
|
return String(arg);
|
|
216
216
|
}
|
|
217
217
|
function redactSecrets(message) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const lastKeptUnit = message.charCodeAt(keep - 1);
|
|
221
|
-
if (lastKeptUnit >= 55296 && lastKeptUnit <= 56319) keep -= 1;
|
|
222
|
-
}
|
|
223
|
-
let out = message.length > MAX_LOG_MESSAGE_LENGTH ? `${message.slice(0, keep)}\u2026[truncated ${message.length - keep} chars]` : message;
|
|
218
|
+
const rawLength = message.length;
|
|
219
|
+
let out = rawLength > REDACT_SCAN_LENGTH ? message.slice(0, REDACT_SCAN_LENGTH) : message;
|
|
224
220
|
out = out.replace(ANSI_PATTERN, "");
|
|
225
221
|
out = out.replace(URL_CREDENTIALS_PATTERN, "$1[REDACTED]@");
|
|
226
222
|
out = out.replace(JWT_PATTERN, "[REDACTED]");
|
|
@@ -231,12 +227,20 @@ function redactSecrets(message) {
|
|
|
231
227
|
out = out.replace(KNOWN_TOKEN_PATTERN, "[REDACTED]");
|
|
232
228
|
out = out.replace(PROVIDER_TOKEN_PATTERN, "[REDACTED]");
|
|
233
229
|
out = out.replace(LONG_HEX_SECRET_PATTERN, "[REDACTED]");
|
|
230
|
+
let keep = MAX_LOG_MESSAGE_LENGTH;
|
|
231
|
+
if (out.length > keep) {
|
|
232
|
+
const lastKeptUnit = out.charCodeAt(keep - 1);
|
|
233
|
+
if (lastKeptUnit >= 55296 && lastKeptUnit <= 56319) keep -= 1;
|
|
234
|
+
}
|
|
235
|
+
if (out.length > MAX_LOG_MESSAGE_LENGTH) {
|
|
236
|
+
out = `${out.slice(0, keep)}\u2026[truncated ${rawLength - keep} chars]`;
|
|
237
|
+
}
|
|
234
238
|
return out;
|
|
235
239
|
}
|
|
236
240
|
function stripTerminalEscapes(message) {
|
|
237
241
|
return message.replace(TERMINAL_ESCAPE_PATTERN, "").replace(CONTROL_CHARS_PATTERN, " ");
|
|
238
242
|
}
|
|
239
|
-
var logContextStorage, MAX_LOG_MESSAGE_LENGTH, ANSI_PATTERN, URL_CREDENTIALS_PATTERN, COOKIE_HEADER_PATTERN, SENSITIVE_KV_PATTERN, KNOWN_TOKEN_PATTERN, JWT_PATTERN, BASIC_AUTH_PATTERN, BEARER_AUTH_PATTERN, PROVIDER_TOKEN_PATTERN, LONG_HEX_SECRET_PATTERN, CONTROL_CHARS_PATTERN, TERMINAL_ESCAPE_PATTERN;
|
|
243
|
+
var logContextStorage, MAX_LOG_MESSAGE_LENGTH, ANSI_PATTERN, URL_CREDENTIALS_PATTERN, COOKIE_HEADER_PATTERN, SENSITIVE_KV_PATTERN, KNOWN_TOKEN_PATTERN, JWT_PATTERN, BASIC_AUTH_PATTERN, BEARER_AUTH_PATTERN, PROVIDER_TOKEN_PATTERN, LONG_HEX_SECRET_PATTERN, CONTROL_CHARS_PATTERN, REDACT_SCAN_LENGTH, TERMINAL_ESCAPE_PATTERN;
|
|
240
244
|
var init_log_utils = __esm({
|
|
241
245
|
"src/utils/log-utils.ts"() {
|
|
242
246
|
"use strict";
|
|
@@ -245,7 +249,7 @@ var init_log_utils = __esm({
|
|
|
245
249
|
ANSI_PATTERN = /\x1b\[[0-9;]*[A-Za-z]/g;
|
|
246
250
|
URL_CREDENTIALS_PATTERN = /([a-z][a-z0-9+.-]*:\/\/)[^/\s:@]+:[^/\s:@]+@/gi;
|
|
247
251
|
COOKIE_HEADER_PATTERN = /\b(set[_-]?cookie|cookie)\b(["']?\s*[:=]\s*["']?)([^\r\n]+)/gi;
|
|
248
|
-
SENSITIVE_KV_PATTERN = /\b(api[_-]?key|apikey|access[_-]?token|auth[_-]?token|refresh[_-]?token|secret|client[_-]?secret|password|passwd|pwd|authorization|bearer|set[_-]?cookie|cookie|session[_-]?id|session|csrf[_-]?token|xsrf[_-]?token|private[_-]?key)\b(["']?\s*[:=]\s*["']?)([^\s"',&)]+)/gi;
|
|
252
|
+
SENSITIVE_KV_PATTERN = /\b(api[_-]?key|apikey|access[_-]?token|auth[_-]?token|refresh[_-]?token|secret|client[_-]?secret|password|passwd|pwd|authorization|bearer|set[_-]?cookie|cookie|session[_-]?id|session|csrf[_-]?token|xsrf[_-]?token|private[_-]?key|key)\b(["']?\s*[:=]\s*["']?)([^\s"',&)]+)/gi;
|
|
249
253
|
KNOWN_TOKEN_PATTERN = /\b(sk-[A-Za-z0-9_-]{16,}|gh[posru]_[A-Za-z0-9]{16,}|github_pat_[A-Za-z0-9_]{20,}|AKIA[0-9A-Z]{16}|xox[baprs]-[A-Za-z0-9-]{10,})\b/g;
|
|
250
254
|
JWT_PATTERN = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
|
|
251
255
|
BASIC_AUTH_PATTERN = /\bBasic\s+[A-Za-z0-9+/]{16,}={0,2}/gi;
|
|
@@ -253,6 +257,7 @@ var init_log_utils = __esm({
|
|
|
253
257
|
PROVIDER_TOKEN_PATTERN = /\b(AIza[0-9A-Za-z_-]{35}|ya29\.[0-9A-Za-z_-]{20,}|[sp]k_(?:live|test)_[0-9A-Za-z]{16,})\b/g;
|
|
254
258
|
LONG_HEX_SECRET_PATTERN = /\b[0-9a-fA-F]{32,}\b/g;
|
|
255
259
|
CONTROL_CHARS_PATTERN = /[\x00-\x1f\x7f]/g;
|
|
260
|
+
REDACT_SCAN_LENGTH = MAX_LOG_MESSAGE_LENGTH * 4;
|
|
256
261
|
TERMINAL_ESCAPE_PATTERN = new RegExp(
|
|
257
262
|
"\\x1b\\[[0-?]*[ -/]*[@-~]?|\\x1b\\][^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)?|\\x1b[PX^_][^\\x1b]*(?:\\x1b\\\\)?|\\x1b.?",
|
|
258
263
|
"g"
|
|
@@ -263,10 +268,17 @@ var init_log_utils = __esm({
|
|
|
263
268
|
// src/utils/log-rotation.ts
|
|
264
269
|
import * as fs from "node:fs";
|
|
265
270
|
import * as path2 from "node:path";
|
|
266
|
-
|
|
271
|
+
function touchOwnerOnly(filePath, mode) {
|
|
272
|
+
try {
|
|
273
|
+
fs.closeSync(fs.openSync(filePath, APPEND_CREATE_NOFOLLOW_FLAGS, mode));
|
|
274
|
+
} catch {
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
var APPEND_CREATE_NOFOLLOW_FLAGS, LogRotation;
|
|
267
278
|
var init_log_rotation = __esm({
|
|
268
279
|
"src/utils/log-rotation.ts"() {
|
|
269
280
|
"use strict";
|
|
281
|
+
APPEND_CREATE_NOFOLLOW_FLAGS = fs.constants.O_WRONLY | fs.constants.O_APPEND | fs.constants.O_CREAT | (typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0);
|
|
270
282
|
LogRotation = class {
|
|
271
283
|
MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
272
284
|
// 10MB max file size
|
|
@@ -284,10 +296,7 @@ var init_log_rotation = __esm({
|
|
|
284
296
|
try {
|
|
285
297
|
if (fs.existsSync(logFile)) {
|
|
286
298
|
fs.unlinkSync(logFile);
|
|
287
|
-
|
|
288
|
-
fs.closeSync(fs.openSync(logFile, "a", 384));
|
|
289
|
-
} catch {
|
|
290
|
-
}
|
|
299
|
+
touchOwnerOnly(logFile, 384);
|
|
291
300
|
try {
|
|
292
301
|
fs.chmodSync(logFile, 384);
|
|
293
302
|
} catch {
|
|
@@ -327,10 +336,7 @@ var init_log_rotation = __esm({
|
|
|
327
336
|
this.logger.log("[Logger] Log rotation skipped (rename failed; file likely in use):", renameErr);
|
|
328
337
|
return;
|
|
329
338
|
}
|
|
330
|
-
|
|
331
|
-
fs.closeSync(fs.openSync(logFile, "a", 384));
|
|
332
|
-
} catch {
|
|
333
|
-
}
|
|
339
|
+
touchOwnerOnly(logFile, 384);
|
|
334
340
|
try {
|
|
335
341
|
fs.chmodSync(logFile, 384);
|
|
336
342
|
} catch {
|
|
@@ -497,7 +503,10 @@ async function captureStdio(logFile, hasSufficientDiskSpace, task, sessionId) {
|
|
|
497
503
|
unkeyedCaptureDepth++;
|
|
498
504
|
isAnyLoggerCapturingOutput = true;
|
|
499
505
|
}
|
|
500
|
-
const
|
|
506
|
+
const stderrDecoder = new TextDecoder2();
|
|
507
|
+
const stdoutDecoder = new TextDecoder2();
|
|
508
|
+
const fd1SyncDecoder = new TextDecoder2();
|
|
509
|
+
const fd2SyncDecoder = new TextDecoder2();
|
|
501
510
|
const originalStderrWrite = process.stderr.write;
|
|
502
511
|
const originalStdoutWrite = process.stdout.write;
|
|
503
512
|
const originalFsWriteSync = fs3.writeSync;
|
|
@@ -543,7 +552,11 @@ async function captureStdio(logFile, hasSufficientDiskSpace, task, sessionId) {
|
|
|
543
552
|
console.debug = createConsolePatch("debug", logFile, hasSufficientDiskSpace);
|
|
544
553
|
process.stderr.write = (chunk, encodingOrCb, callback) => {
|
|
545
554
|
const cb = typeof encodingOrCb === "function" ? encodingOrCb : callback;
|
|
546
|
-
const message = typeof chunk === "string" ? chunk :
|
|
555
|
+
const message = typeof chunk === "string" ? chunk : stderrDecoder.decode(chunk, { stream: true });
|
|
556
|
+
if (message.length === 0) {
|
|
557
|
+
if (typeof cb === "function") cb();
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
547
560
|
if (!hasSufficientDiskSpace()) {
|
|
548
561
|
if (typeof cb === "function") cb();
|
|
549
562
|
return true;
|
|
@@ -564,7 +577,7 @@ async function captureStdio(logFile, hasSufficientDiskSpace, task, sessionId) {
|
|
|
564
577
|
return true;
|
|
565
578
|
};
|
|
566
579
|
process.stdout.write = (chunk, encodingOrCb, callback) => {
|
|
567
|
-
const message = typeof chunk === "string" ? chunk :
|
|
580
|
+
const message = typeof chunk === "string" ? chunk : stdoutDecoder.decode(chunk, { stream: true });
|
|
568
581
|
const isNative = isNativeLog(message);
|
|
569
582
|
const complexTui = isComplexTui(message);
|
|
570
583
|
const boxDrawing = isBoxDrawing(message);
|
|
@@ -618,7 +631,11 @@ async function captureStdio(logFile, hasSufficientDiskSpace, task, sessionId) {
|
|
|
618
631
|
if (!descriptor || (descriptor.writable || descriptor.set)) {
|
|
619
632
|
fs3.writeSync = (fd, chunk, ...args) => {
|
|
620
633
|
if (fd === 1 || fd === 2) {
|
|
621
|
-
const
|
|
634
|
+
const fdDecoder = fd === 1 ? fd1SyncDecoder : fd2SyncDecoder;
|
|
635
|
+
const message = typeof chunk === "string" ? chunk : fdDecoder.decode(chunk, { stream: true });
|
|
636
|
+
if (fd === 2 && message.length === 0) {
|
|
637
|
+
return typeof chunk === "string" ? Buffer.from(chunk).length : chunk.length;
|
|
638
|
+
}
|
|
622
639
|
const isNative = isNativeLog(message);
|
|
623
640
|
const boxDrawing = isBoxDrawing(message);
|
|
624
641
|
const complexTui = isComplexTui(message);
|
|
@@ -1349,6 +1366,24 @@ var init_service_registry = __esm({
|
|
|
1349
1366
|
]);
|
|
1350
1367
|
if (settleTimer) clearTimeout(settleTimer);
|
|
1351
1368
|
}
|
|
1369
|
+
const inFlightDisposals = Array.from(this.services.values()).map((r) => r.disposalPromise).filter((p) => p != null);
|
|
1370
|
+
if (inFlightDisposals.length > 0) {
|
|
1371
|
+
if (this.defaultOptions.enableLogging) {
|
|
1372
|
+
logger.debug(`[ServiceContainer] Waiting for ${inFlightDisposals.length} in-flight disposal(s) before teardown`);
|
|
1373
|
+
}
|
|
1374
|
+
let disposalSettleTimer;
|
|
1375
|
+
await Promise.race([
|
|
1376
|
+
Promise.allSettled(inFlightDisposals),
|
|
1377
|
+
new Promise((resolve9) => {
|
|
1378
|
+
disposalSettleTimer = setTimeout(() => {
|
|
1379
|
+
logger.warn("[ServiceContainer] Timed out waiting for in-flight service disposal; proceeding with teardown");
|
|
1380
|
+
resolve9();
|
|
1381
|
+
}, DISPOSE_INFLIGHT_INIT_TIMEOUT_MS);
|
|
1382
|
+
disposalSettleTimer.unref?.();
|
|
1383
|
+
})
|
|
1384
|
+
]);
|
|
1385
|
+
if (disposalSettleTimer) clearTimeout(disposalSettleTimer);
|
|
1386
|
+
}
|
|
1352
1387
|
const activeServices = Array.from(this.services.keys()).filter(
|
|
1353
1388
|
(name) => this.services.get(name)?.instance !== null
|
|
1354
1389
|
);
|
|
@@ -1932,7 +1967,7 @@ function normalizeUrl(url) {
|
|
|
1932
1967
|
}
|
|
1933
1968
|
return result;
|
|
1934
1969
|
} catch (_err) {
|
|
1935
|
-
logger.debug(`[url-utils] normalizing unparseable URL (${url.slice(0, 200)}): ${_err instanceof Error ? _err.message : String(_err)}`);
|
|
1970
|
+
logger.debug(`[url-utils] normalizing unparseable URL (${redactSecrets(url).slice(0, 200)}): ${_err instanceof Error ? _err.message : String(_err)}`);
|
|
1936
1971
|
let cleaned = url.trim().replace(/^[*_~`"']{1,20}/, "").replace(/[*_~`"',.)}\]]{1,20}$/, "");
|
|
1937
1972
|
const hashIdx = cleaned.indexOf("#");
|
|
1938
1973
|
if (hashIdx >= 0) cleaned = cleaned.substring(0, hashIdx);
|
|
@@ -1996,6 +2031,7 @@ var init_url_utils = __esm({
|
|
|
1996
2031
|
"src/utils/url-utils.ts"() {
|
|
1997
2032
|
"use strict";
|
|
1998
2033
|
init_logger();
|
|
2034
|
+
init_log_utils();
|
|
1999
2035
|
MAX_INITIAL_LINKS = 20;
|
|
2000
2036
|
MAX_INITIAL_LINK_CHARS = 2048;
|
|
2001
2037
|
}
|
|
@@ -6434,7 +6470,7 @@ var init_chunker = __esm({
|
|
|
6434
6470
|
if (code >= 56320 && code <= 57343) {
|
|
6435
6471
|
if (start - 1 > iterationStart) {
|
|
6436
6472
|
start -= 1;
|
|
6437
|
-
} else if (start + 1
|
|
6473
|
+
} else if (start + 1 <= end) {
|
|
6438
6474
|
start += 1;
|
|
6439
6475
|
}
|
|
6440
6476
|
}
|
|
@@ -8663,6 +8699,9 @@ var init_knowledge_store_service = __esm({
|
|
|
8663
8699
|
await this._initializationPromise;
|
|
8664
8700
|
} catch {
|
|
8665
8701
|
}
|
|
8702
|
+
if (this._disposalPromise) {
|
|
8703
|
+
return this._disposalPromise;
|
|
8704
|
+
}
|
|
8666
8705
|
}
|
|
8667
8706
|
this.lifecycle = "disposing" /* DISPOSING */;
|
|
8668
8707
|
logger.debug("[KnowledgeStoreService] Disposing...");
|
|
@@ -8670,7 +8709,8 @@ var init_knowledge_store_service = __esm({
|
|
|
8670
8709
|
const store = this._store;
|
|
8671
8710
|
const writerQueue = this._writerQueue;
|
|
8672
8711
|
const initLock = this._initLock;
|
|
8673
|
-
|
|
8712
|
+
let disposePromise = null;
|
|
8713
|
+
disposePromise = (async () => {
|
|
8674
8714
|
try {
|
|
8675
8715
|
if (writerQueue) {
|
|
8676
8716
|
await writerQueue.dispose?.();
|
|
@@ -8694,9 +8734,12 @@ var init_knowledge_store_service = __esm({
|
|
|
8694
8734
|
logger.error("[KnowledgeStoreService] Error during disposal:", err);
|
|
8695
8735
|
} finally {
|
|
8696
8736
|
this.lifecycle = "disposed" /* DISPOSED */;
|
|
8697
|
-
this._disposalPromise
|
|
8737
|
+
if (this._disposalPromise === disposePromise) {
|
|
8738
|
+
this._disposalPromise = null;
|
|
8739
|
+
}
|
|
8698
8740
|
}
|
|
8699
8741
|
})();
|
|
8742
|
+
this._disposalPromise = disposePromise;
|
|
8700
8743
|
return this._disposalPromise;
|
|
8701
8744
|
}
|
|
8702
8745
|
/**
|
|
@@ -9740,16 +9783,31 @@ function installSkill(toolIds, opts = {}) {
|
|
|
9740
9783
|
continue;
|
|
9741
9784
|
}
|
|
9742
9785
|
fs16.unlinkSync(absSkillPath);
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9786
|
+
try {
|
|
9787
|
+
fs16.symlinkSync(source, absSkillPath, process.platform === "win32" ? "junction" : "dir");
|
|
9788
|
+
upsertEntry(manifest, { tool: id, path: absSkillPath, type: "symlink", source, createdAt: now, ...skillVersion ? { version: skillVersion } : {} });
|
|
9789
|
+
results.push({ tool: id, path: absSkillPath, type: "symlink", status: "installed", message: "re-pointed stale symlink to current source" });
|
|
9790
|
+
} catch (relinkErr) {
|
|
9791
|
+
try {
|
|
9792
|
+
copyDir(source, absSkillPath);
|
|
9793
|
+
upsertEntry(manifest, { tool: id, path: absSkillPath, type: "copy", source, createdAt: now, ...skillVersion ? { version: skillVersion } : {} });
|
|
9794
|
+
results.push({ tool: id, path: absSkillPath, type: "copy", status: "installed", message: `symlink re-point unavailable (${relinkErr?.code ?? relinkErr?.message}); copied instead` });
|
|
9795
|
+
} catch (copyErr) {
|
|
9796
|
+
results.push({ tool: id, path: absSkillPath, type: "symlink", status: "error", message: `symlink re-point failed (${relinkErr?.code ?? relinkErr?.message}) and the copy fallback also failed: ${copyErr?.message ?? String(copyErr)}` });
|
|
9797
|
+
}
|
|
9798
|
+
}
|
|
9746
9799
|
continue;
|
|
9747
9800
|
}
|
|
9748
9801
|
}
|
|
9749
9802
|
} catch {
|
|
9750
9803
|
}
|
|
9751
9804
|
results.push({ tool: id, path: absSkillPath, type, status: "already-installed" });
|
|
9752
|
-
|
|
9805
|
+
{
|
|
9806
|
+
const isSymlinkNow = isSymlinkPresent(absSkillPath);
|
|
9807
|
+
const existingEntry = manifest.entries.find((e) => e.path === absSkillPath);
|
|
9808
|
+
const versionField = isSymlinkNow ? skillVersion ? { version: skillVersion } : {} : existingEntry?.version ? { version: existingEntry.version } : {};
|
|
9809
|
+
upsertEntry(manifest, { tool: id, path: absSkillPath, type: isSymlinkNow ? "symlink" : "copy", source, createdAt: now, ...versionField });
|
|
9810
|
+
}
|
|
9753
9811
|
continue;
|
|
9754
9812
|
}
|
|
9755
9813
|
if (fs16.existsSync(absSkillPath) || isSymlinkPresent(absSkillPath)) {
|
|
@@ -9933,11 +9991,31 @@ function reconcileSkillInstalls(opts = {}) {
|
|
|
9933
9991
|
if (source !== null) {
|
|
9934
9992
|
try {
|
|
9935
9993
|
fs16.unlinkSync(e.path);
|
|
9994
|
+
} catch {
|
|
9995
|
+
keep.push(e);
|
|
9996
|
+
continue;
|
|
9997
|
+
}
|
|
9998
|
+
try {
|
|
9936
9999
|
fs16.symlinkSync(source, e.path, process.platform === "win32" ? "junction" : "dir");
|
|
9937
10000
|
keep.push({ ...e, type: "symlink", source });
|
|
9938
10001
|
result.repointed.push(e.path);
|
|
9939
10002
|
} catch {
|
|
9940
|
-
|
|
10003
|
+
const dir = path17.dirname(e.path);
|
|
10004
|
+
const base = path17.basename(e.path);
|
|
10005
|
+
const suffix = crypto10.randomBytes(4).toString("hex");
|
|
10006
|
+
const fresh = path17.join(dir, `.${base}.new-${suffix}`);
|
|
10007
|
+
try {
|
|
10008
|
+
copyDir(source, fresh);
|
|
10009
|
+
fs16.renameSync(fresh, e.path);
|
|
10010
|
+
keep.push({ ...e, type: "copy", source });
|
|
10011
|
+
result.repointed.push(e.path);
|
|
10012
|
+
} catch {
|
|
10013
|
+
try {
|
|
10014
|
+
fs16.rmSync(fresh, { recursive: true, force: true });
|
|
10015
|
+
} catch {
|
|
10016
|
+
}
|
|
10017
|
+
result.pruned.push(e.path);
|
|
10018
|
+
}
|
|
9941
10019
|
}
|
|
9942
10020
|
} else if (!targetLive) {
|
|
9943
10021
|
try {
|
|
@@ -11384,6 +11462,7 @@ function isFullMockMode() {
|
|
|
11384
11462
|
init_config();
|
|
11385
11463
|
init_logger();
|
|
11386
11464
|
init_error_tracker();
|
|
11465
|
+
init_log_utils();
|
|
11387
11466
|
init_http_body();
|
|
11388
11467
|
import * as http2 from "node:http";
|
|
11389
11468
|
|
|
@@ -11519,7 +11598,7 @@ var BrowserClient = class {
|
|
|
11519
11598
|
resolve9(parsed);
|
|
11520
11599
|
}
|
|
11521
11600
|
} catch (_e) {
|
|
11522
|
-
const raw = collected.toString();
|
|
11601
|
+
const raw = redactSecrets(collected.toString());
|
|
11523
11602
|
const preview = raw.length > 200 ? raw.slice(0, 200) + "..." : raw;
|
|
11524
11603
|
const error = new Error(`Failed to parse response (status ${res.statusCode}): ${preview}`);
|
|
11525
11604
|
errorTracker.trackError(error, {
|
|
@@ -15867,6 +15946,7 @@ init_logger();
|
|
|
15867
15946
|
|
|
15868
15947
|
// src/infrastructure/browser/task-execution-service.ts
|
|
15869
15948
|
init_logger();
|
|
15949
|
+
init_log_utils();
|
|
15870
15950
|
init_error_tracker();
|
|
15871
15951
|
|
|
15872
15952
|
// src/infrastructure/browser/browser-lifecycle.ts
|
|
@@ -15914,6 +15994,10 @@ var lastRestartTime = 0;
|
|
|
15914
15994
|
var RESTART_COOLDOWN_MS = 1e4;
|
|
15915
15995
|
var LEADER_HANDOVER_RETRIES = 3;
|
|
15916
15996
|
var HANDOVER_BACKOFF_MS = 1200;
|
|
15997
|
+
function briefErrorMessage(error) {
|
|
15998
|
+
const msg2 = error instanceof Error ? error.message : String(error);
|
|
15999
|
+
return redactSecrets(msg2).substring(0, 100);
|
|
16000
|
+
}
|
|
15917
16001
|
async function recoverFromLeaderHandover(container) {
|
|
15918
16002
|
logger.warn("[BrowserManager] Leader handover detected (pool draining) \u2014 dropping stale scheduler handle and re-resolving...");
|
|
15919
16003
|
await forceSchedulerRestart2(false, container).catch(
|
|
@@ -16003,7 +16087,7 @@ async function runBrowserTask(taskOrUrl, type = "scrape", config, signal, retrie
|
|
|
16003
16087
|
taskType: type,
|
|
16004
16088
|
errorType: "leader_handover"
|
|
16005
16089
|
});
|
|
16006
|
-
logger.warn(`[BrowserManager] Leader handover during ${type} task (handover attempts left: ${handoverRetries}): ${(error
|
|
16090
|
+
logger.warn(`[BrowserManager] Leader handover during ${type} task (handover attempts left: ${handoverRetries}): ${briefErrorMessage(error)}...`);
|
|
16007
16091
|
await recoverFromLeaderHandover(container);
|
|
16008
16092
|
await new Promise((resolve9) => setTimeout(resolve9, HANDOVER_BACKOFF_MS + Math.floor(Math.random() * 400)));
|
|
16009
16093
|
return runBrowserTask(taskOrUrl, type, config, signal, retries, container, handoverRetries - 1);
|
|
@@ -16015,7 +16099,7 @@ async function runBrowserTask(taskOrUrl, type = "scrape", config, signal, retrie
|
|
|
16015
16099
|
taskType: type,
|
|
16016
16100
|
errorType: "transient_socket_error"
|
|
16017
16101
|
});
|
|
16018
|
-
logger.warn(`[BrowserManager] Transient socket error during ${type} task (retries left: ${retries}): ${(error
|
|
16102
|
+
logger.warn(`[BrowserManager] Transient socket error during ${type} task (retries left: ${retries}): ${briefErrorMessage(error)}...`);
|
|
16019
16103
|
if (isPoolShutdownError(error)) {
|
|
16020
16104
|
logger.warn(`[BrowserManager] Pool is draining \u2014 waiting for pool idle before retry...`);
|
|
16021
16105
|
await waitForBrowserPoolIdle(15e3).catch((err) => logger.debug("Wait for browser idle timed out or failed:", err));
|
|
@@ -16042,7 +16126,7 @@ async function runBrowserHealthCheck(config, retries = 1, signal, container = ge
|
|
|
16042
16126
|
operation: "healthcheck",
|
|
16043
16127
|
errorType: "transient_socket_error"
|
|
16044
16128
|
});
|
|
16045
|
-
logger.warn(`[BrowserManager] Transient socket error during healthcheck (retries left: ${retries}): ${(error
|
|
16129
|
+
logger.warn(`[BrowserManager] Transient socket error during healthcheck (retries left: ${retries}): ${briefErrorMessage(error)}...`);
|
|
16046
16130
|
if (isPoolShutdownError(error)) {
|
|
16047
16131
|
await recoverFromLeaderHandover(container);
|
|
16048
16132
|
} else {
|
|
@@ -16074,7 +16158,7 @@ async function runWorkerSearch(query, config, signal, retries = 1, sessionId, co
|
|
|
16074
16158
|
query,
|
|
16075
16159
|
errorType: "leader_handover"
|
|
16076
16160
|
});
|
|
16077
|
-
logger.warn(`[BrowserManager] Leader handover during search (handover attempts left: ${handoverRetries}): ${(error
|
|
16161
|
+
logger.warn(`[BrowserManager] Leader handover during search (handover attempts left: ${handoverRetries}): ${briefErrorMessage(error)}...`);
|
|
16078
16162
|
await recoverFromLeaderHandover(container);
|
|
16079
16163
|
await new Promise((resolve9) => setTimeout(resolve9, HANDOVER_BACKOFF_MS + Math.floor(Math.random() * 400)));
|
|
16080
16164
|
return runWorkerSearch(query, config, signal, retries, sessionId, container, handoverRetries - 1);
|
|
@@ -16086,7 +16170,7 @@ async function runWorkerSearch(query, config, signal, retries = 1, sessionId, co
|
|
|
16086
16170
|
query,
|
|
16087
16171
|
errorType: "transient_socket_error"
|
|
16088
16172
|
});
|
|
16089
|
-
logger.warn(`[BrowserManager] Transient socket error during search (retries left: ${retries}): ${(error
|
|
16173
|
+
logger.warn(`[BrowserManager] Transient socket error during search (retries left: ${retries}): ${briefErrorMessage(error)}...`);
|
|
16090
16174
|
if (isPoolShutdownError(error)) {
|
|
16091
16175
|
await waitForBrowserPoolIdle(15e3).catch((err) => logger.debug("Wait for browser idle timed out or failed:", err));
|
|
16092
16176
|
} else {
|
|
@@ -16513,13 +16597,11 @@ function registerHealthChecks(registry, container = getServiceContainer()) {
|
|
|
16513
16597
|
registry.register("StateManager", async () => {
|
|
16514
16598
|
try {
|
|
16515
16599
|
const stateManager = await getService(ServiceNames.STATE_MANAGER, { container }, container);
|
|
16516
|
-
const stats = await stateManager.getMetrics();
|
|
16517
16600
|
const gpuOwner = await stateManager.getGpuOwner();
|
|
16518
16601
|
return {
|
|
16519
16602
|
healthy: true,
|
|
16520
16603
|
diagnostic: {
|
|
16521
16604
|
status: "operational",
|
|
16522
|
-
sessions: stats.activeSessions,
|
|
16523
16605
|
gpuLocked: !!gpuOwner,
|
|
16524
16606
|
gpuOwner: gpuOwner?.sessionId || "none"
|
|
16525
16607
|
}
|
|
@@ -16805,6 +16887,7 @@ function isBenignScrapeFailure(error) {
|
|
|
16805
16887
|
return msg2.startsWith("Fetch blocked:") || // bot-protection interstitial (Cloudflare, DDoS-Guard, …)
|
|
16806
16888
|
msg2.startsWith("Fetch returned stub:") || // nav-only / near-empty page
|
|
16807
16889
|
msg2.startsWith("Could not extract content from PDF") || // malformed/encrypted/scanned-only PDF
|
|
16890
|
+
msg2.startsWith("PDF too large") || // exceeds the deliberate 100MB policy cap
|
|
16808
16891
|
/^HTTP \d{3}\b/.test(msg2) || // remote 4xx/5xx status
|
|
16809
16892
|
isCloudflareBlockError(error) || isTaskTimeoutError(error) || isPoolShutdownError(error);
|
|
16810
16893
|
}
|
|
@@ -17097,8 +17180,22 @@ async function extractPdfToMarkdown(bytes) {
|
|
|
17097
17180
|
throw new Error(`PDF too large (${sizeMB}MB, max 100MB)`);
|
|
17098
17181
|
}
|
|
17099
17182
|
const pdfExtractionStart = Date.now();
|
|
17183
|
+
let WasmPdfDocument;
|
|
17184
|
+
try {
|
|
17185
|
+
({ WasmPdfDocument } = await import("pdf-oxide-wasm"));
|
|
17186
|
+
} catch (e) {
|
|
17187
|
+
const msg2 = e instanceof Error ? e.message : String(e);
|
|
17188
|
+
logger.error(`[Scrapers] pdf-oxide-wasm failed to load \u2014 PDF extraction is unavailable (not just for this URL): ${msg2}`);
|
|
17189
|
+
metrics.increment("scrape_pdf_errors_total", 1, { error_type: "native_module_unavailable" });
|
|
17190
|
+
errorTracker.trackError(e instanceof Error ? e : String(e), {
|
|
17191
|
+
component: "scrapers",
|
|
17192
|
+
operation: "pdf-extract",
|
|
17193
|
+
contentType: "pdf",
|
|
17194
|
+
errorType: "native_module_unavailable"
|
|
17195
|
+
});
|
|
17196
|
+
throw new Error(`PDF extraction unavailable (pdf-oxide-wasm failed to load: ${msg2})`, { cause: e });
|
|
17197
|
+
}
|
|
17100
17198
|
try {
|
|
17101
|
-
const { WasmPdfDocument } = await import("pdf-oxide-wasm");
|
|
17102
17199
|
const doc = new WasmPdfDocument(bytes);
|
|
17103
17200
|
const pageCount = doc.pageCount();
|
|
17104
17201
|
let markdown = `# PDF Document
|
|
@@ -17472,6 +17569,7 @@ async function scrape(urls, maxConcurrency = 5, signal, config, sessionId, onUrl
|
|
|
17472
17569
|
// src/tools/scrape.ts
|
|
17473
17570
|
init_constants();
|
|
17474
17571
|
init_text_utils();
|
|
17572
|
+
init_log_utils();
|
|
17475
17573
|
init_config();
|
|
17476
17574
|
init_service_registry();
|
|
17477
17575
|
init_service_interfaces();
|
|
@@ -17643,18 +17741,19 @@ ${evictedDuplicates.map((u) => `- ${u}`).join("\n")}
|
|
|
17643
17741
|
let freshResults;
|
|
17644
17742
|
const concurrency = p.maxConcurrency || defaultConcurrency;
|
|
17645
17743
|
try {
|
|
17646
|
-
const results = await scrape(urlsToFetch, concurrency, signal,
|
|
17744
|
+
const results = await scrape(urlsToFetch, concurrency, signal, config, getGlobalState().researchId, (result) => {
|
|
17647
17745
|
options.onUrlScrapeResult?.(result.url, result.success);
|
|
17648
17746
|
}, container);
|
|
17649
17747
|
freshResults = Array.isArray(results) ? results : [];
|
|
17650
17748
|
} catch (error) {
|
|
17651
|
-
|
|
17749
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17750
|
+
logger.error(`[scrape tool] Scrape failed: ${message}`);
|
|
17652
17751
|
metrics.increment("tool_scrape_calls_total", 1, { status: "error" });
|
|
17653
17752
|
return {
|
|
17654
17753
|
content: [{ type: "text", text: `# Scrape Failed
|
|
17655
17754
|
|
|
17656
|
-
${
|
|
17657
|
-
details: { error: String(error) }
|
|
17755
|
+
${redactSecrets(message)}` }],
|
|
17756
|
+
details: { error: redactSecrets(String(error)) }
|
|
17658
17757
|
};
|
|
17659
17758
|
}
|
|
17660
17759
|
const successfulFresh = freshResults.filter((r) => r.success);
|
|
@@ -18548,9 +18647,9 @@ async function searchGitHubAdvisories(terms, options) {
|
|
|
18548
18647
|
throw new Error(`Invalid repo format: "${options.repo}". Expected "owner/name".`);
|
|
18549
18648
|
}
|
|
18550
18649
|
const [owner, name] = repoParts;
|
|
18551
|
-
const repoNameRe = /^[A-Za-z0-9._-]+$/;
|
|
18650
|
+
const repoNameRe = /^(?!\.+$)[A-Za-z0-9._-]+$/;
|
|
18552
18651
|
if (!repoNameRe.test(owner) || !repoNameRe.test(name)) {
|
|
18553
|
-
throw new Error(`Invalid repo format: "${options.repo}". Owner and name may only contain letters, digits, '.', '_' and '-'.`);
|
|
18652
|
+
throw new Error(`Invalid repo format: "${options.repo}". Owner and name may only contain letters, digits, '.', '_' and '-', and cannot be all dots.`);
|
|
18554
18653
|
}
|
|
18555
18654
|
const url = `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/security-advisories?per_page=${perPage}`;
|
|
18556
18655
|
const response = await githubCircuitBreaker.execute(() => retryWithBackoff(async () => {
|
|
@@ -18901,7 +19000,7 @@ function mapOsvItemToVulnerability(item) {
|
|
|
18901
19000
|
for (const cwe of item.database_specific.cwe) {
|
|
18902
19001
|
if (typeof cwe === "string") {
|
|
18903
19002
|
cwes.push(cwe);
|
|
18904
|
-
} else if (typeof cwe === "object" && typeof cwe.id === "string") {
|
|
19003
|
+
} else if (typeof cwe === "object" && cwe !== null && typeof cwe.id === "string") {
|
|
18905
19004
|
cwes.push(cwe.id);
|
|
18906
19005
|
}
|
|
18907
19006
|
}
|
|
@@ -19282,6 +19381,10 @@ async function searchSecurityDatabases(params, signal) {
|
|
|
19282
19381
|
// src/tools/security.ts
|
|
19283
19382
|
init_constants();
|
|
19284
19383
|
init_metrics();
|
|
19384
|
+
var MAX_DESCRIPTION_CHARS = 300;
|
|
19385
|
+
function truncateDescription(description) {
|
|
19386
|
+
return description.length > MAX_DESCRIPTION_CHARS ? `${description.substring(0, MAX_DESCRIPTION_CHARS)}...` : description;
|
|
19387
|
+
}
|
|
19285
19388
|
function createSecuritySearchTool(options) {
|
|
19286
19389
|
const SecuritySearchParamsSchema = Type6.Object({
|
|
19287
19390
|
databases: Type6.Optional(Type6.Array(Type6.String({
|
|
@@ -19484,7 +19587,7 @@ Unable to search security databases. This may be a temporary issue - try again l
|
|
|
19484
19587
|
}
|
|
19485
19588
|
}
|
|
19486
19589
|
const description = vuln.description;
|
|
19487
|
-
markdown += `- **Description:** ${description
|
|
19590
|
+
markdown += `- **Description:** ${truncateDescription(description)}
|
|
19488
19591
|
`;
|
|
19489
19592
|
if (vuln.knownExploited === true) {
|
|
19490
19593
|
markdown += "- **[Actively Exploited]**\n";
|
|
@@ -19536,7 +19639,7 @@ Unable to search security databases. This may be a temporary issue - try again l
|
|
|
19536
19639
|
`;
|
|
19537
19640
|
}
|
|
19538
19641
|
const description = vuln.description;
|
|
19539
|
-
markdown += `- **Description:** ${description
|
|
19642
|
+
markdown += `- **Description:** ${truncateDescription(description)}
|
|
19540
19643
|
`;
|
|
19541
19644
|
if (vuln.dueDate !== void 0) {
|
|
19542
19645
|
markdown += `- **Due Date:** ${vuln.dueDate}
|
|
@@ -19584,7 +19687,7 @@ Unable to search security databases. This may be a temporary issue - try again l
|
|
|
19584
19687
|
markdown += `- **Summary:** ${adv.summary}
|
|
19585
19688
|
`;
|
|
19586
19689
|
const description = adv.description ?? "";
|
|
19587
|
-
markdown += `- **Description:** ${description
|
|
19690
|
+
markdown += `- **Description:** ${truncateDescription(description)}
|
|
19588
19691
|
`;
|
|
19589
19692
|
if (adv.published) {
|
|
19590
19693
|
markdown += `- **Published:** ${adv.published}
|
|
@@ -19626,7 +19729,7 @@ Unable to search security databases. This may be a temporary issue - try again l
|
|
|
19626
19729
|
markdown += `- **Severity:** ${vuln.severity}
|
|
19627
19730
|
`;
|
|
19628
19731
|
const description = vuln.description;
|
|
19629
|
-
markdown += `- **Description:** ${description
|
|
19732
|
+
markdown += `- **Description:** ${truncateDescription(description)}
|
|
19630
19733
|
`;
|
|
19631
19734
|
if (vuln.affectedProducts && vuln.affectedProducts.length > 0) {
|
|
19632
19735
|
markdown += `- **Affected:** ${vuln.affectedProducts.join(", ")}
|
|
@@ -19674,6 +19777,7 @@ init_logger();
|
|
|
19674
19777
|
init_circuit_breaker();
|
|
19675
19778
|
init_metrics();
|
|
19676
19779
|
init_http_body();
|
|
19780
|
+
init_retry_utils();
|
|
19677
19781
|
var API_BASE = "https://api.stackexchange.com/2.3";
|
|
19678
19782
|
var QUOTA_PROBE_COOLDOWN_MS = 10 * 60 * 1e3;
|
|
19679
19783
|
var StackExchangeClient = class {
|
|
@@ -19721,21 +19825,11 @@ var StackExchangeClient = class {
|
|
|
19721
19825
|
if (!url.searchParams.has("site") && !options.endpoint.startsWith("/sites")) {
|
|
19722
19826
|
url.searchParams.set("site", "stackoverflow.com");
|
|
19723
19827
|
}
|
|
19724
|
-
const
|
|
19725
|
-
const timeoutId = setTimeout(() => {
|
|
19726
|
-
controller.abort();
|
|
19727
|
-
}, this._timeout);
|
|
19728
|
-
const abortHandler = () => {
|
|
19729
|
-
clearTimeout(timeoutId);
|
|
19730
|
-
controller.abort();
|
|
19731
|
-
};
|
|
19732
|
-
if (signal) {
|
|
19733
|
-
signal.addEventListener("abort", abortHandler, { once: true });
|
|
19734
|
-
}
|
|
19828
|
+
const requestSignal = createTimeoutSignal(this._timeout, signal);
|
|
19735
19829
|
try {
|
|
19736
19830
|
const response = await fetch(url.toString(), {
|
|
19737
19831
|
method: options.method,
|
|
19738
|
-
signal:
|
|
19832
|
+
signal: requestSignal,
|
|
19739
19833
|
headers: {
|
|
19740
19834
|
"Accept": "application/json"
|
|
19741
19835
|
}
|
|
@@ -19790,11 +19884,6 @@ var StackExchangeClient = class {
|
|
|
19790
19884
|
throw new Error(`Request timeout after ${this._timeout}ms`, { cause: error });
|
|
19791
19885
|
}
|
|
19792
19886
|
throw error;
|
|
19793
|
-
} finally {
|
|
19794
|
-
clearTimeout(timeoutId);
|
|
19795
|
-
if (signal) {
|
|
19796
|
-
signal.removeEventListener("abort", abortHandler);
|
|
19797
|
-
}
|
|
19798
19887
|
}
|
|
19799
19888
|
});
|
|
19800
19889
|
}
|
|
@@ -20035,6 +20124,33 @@ function formatCompactQuestions(questions) {
|
|
|
20035
20124
|
}
|
|
20036
20125
|
|
|
20037
20126
|
// src/stackexchange/output/compact.ts
|
|
20127
|
+
function formatQuestionsCompact(questions) {
|
|
20128
|
+
if (questions.length === 0) {
|
|
20129
|
+
return "No questions found.";
|
|
20130
|
+
}
|
|
20131
|
+
const lines = [];
|
|
20132
|
+
let index = 1;
|
|
20133
|
+
for (const q of questions) {
|
|
20134
|
+
const accepted = q.accepted_answer_id ? "[accepted]" : " ";
|
|
20135
|
+
lines.push(`${index}. ${accepted} [${q.title}](${q.link}) (${q.score} pts, ${q.answer_count} ans, ${q.view_count} views)`);
|
|
20136
|
+
index++;
|
|
20137
|
+
}
|
|
20138
|
+
return lines.join("\n");
|
|
20139
|
+
}
|
|
20140
|
+
function formatAnswersCompact(answers) {
|
|
20141
|
+
if (answers.length === 0) {
|
|
20142
|
+
return "No answers found.";
|
|
20143
|
+
}
|
|
20144
|
+
const lines = [];
|
|
20145
|
+
let index = 1;
|
|
20146
|
+
for (const a of answers) {
|
|
20147
|
+
const accepted = a.is_accepted ? "[accepted]" : " ";
|
|
20148
|
+
const displayName = a.owner?.display_name ?? "Unknown";
|
|
20149
|
+
lines.push(`${index}. ${accepted} by ${displayName} (${a.score} pts)`);
|
|
20150
|
+
index++;
|
|
20151
|
+
}
|
|
20152
|
+
return lines.join("\n");
|
|
20153
|
+
}
|
|
20038
20154
|
function formatUsersCompact(users) {
|
|
20039
20155
|
if (users.length === 0) {
|
|
20040
20156
|
return "No users found.";
|
|
@@ -20318,6 +20434,16 @@ function formatCompact(result) {
|
|
|
20318
20434
|
return formatCompactQuestions(result);
|
|
20319
20435
|
}
|
|
20320
20436
|
}
|
|
20437
|
+
} else if (typeof result === "object" && result !== null) {
|
|
20438
|
+
if ("question" in result && "answers" in result) {
|
|
20439
|
+
const r = result;
|
|
20440
|
+
let output = formatQuestionsCompact([r.question]);
|
|
20441
|
+
if (r.answers.length > 0) {
|
|
20442
|
+
output += `
|
|
20443
|
+
${formatAnswersCompact(r.answers)}`;
|
|
20444
|
+
}
|
|
20445
|
+
return output;
|
|
20446
|
+
}
|
|
20321
20447
|
}
|
|
20322
20448
|
return JSON.stringify(result);
|
|
20323
20449
|
}
|
|
@@ -20532,11 +20658,13 @@ function watchUrl(videoId) {
|
|
|
20532
20658
|
init_retry_utils();
|
|
20533
20659
|
init_circuit_breaker();
|
|
20534
20660
|
init_logger();
|
|
20661
|
+
init_log_utils();
|
|
20535
20662
|
init_metrics();
|
|
20536
20663
|
init_http_body();
|
|
20537
20664
|
|
|
20538
20665
|
// src/youtube/potoken.ts
|
|
20539
20666
|
init_logger();
|
|
20667
|
+
init_safe_unref();
|
|
20540
20668
|
init_metrics();
|
|
20541
20669
|
var DEFAULT_REQUEST_KEY = "O43z0dpjhgX20SCx4KAo";
|
|
20542
20670
|
var BRIDGED_GLOBALS = ["window", "document", "location", "navigator", "origin"];
|
|
@@ -20549,9 +20677,19 @@ function describeError(error) {
|
|
|
20549
20677
|
return String(error);
|
|
20550
20678
|
}
|
|
20551
20679
|
var mintChain = Promise.resolve();
|
|
20680
|
+
var MINT_HARD_RELEASE_MS = 5 * 60 * 1e3;
|
|
20552
20681
|
async function mintPoTokens(identifiers, opts = {}) {
|
|
20553
20682
|
const run = mintChain.then(() => doMint(identifiers, opts), () => doMint(identifiers, opts));
|
|
20554
|
-
|
|
20683
|
+
const settled = run.then(() => void 0, () => void 0);
|
|
20684
|
+
let hardTimer;
|
|
20685
|
+
const hardRelease = new Promise((resolve9) => {
|
|
20686
|
+
hardTimer = setTimeout(() => {
|
|
20687
|
+
logger.warn("[youtube] potoken mint mutex force-released \u2014 doMint() did not settle within the hard timeout");
|
|
20688
|
+
resolve9();
|
|
20689
|
+
}, MINT_HARD_RELEASE_MS);
|
|
20690
|
+
safeUnref(hardTimer);
|
|
20691
|
+
});
|
|
20692
|
+
mintChain = Promise.race([settled, hardRelease]).finally(() => clearTimeout(hardTimer));
|
|
20555
20693
|
return run;
|
|
20556
20694
|
}
|
|
20557
20695
|
async function doMint(identifiers, opts) {
|
|
@@ -20833,7 +20971,7 @@ function parseJson3(body) {
|
|
|
20833
20971
|
try {
|
|
20834
20972
|
parsed = JSON.parse(body);
|
|
20835
20973
|
} catch {
|
|
20836
|
-
logger.debug(`[youtube] timedtext body was not valid json3 (first 120 chars): ${body.slice(0, 120)}`);
|
|
20974
|
+
logger.debug(`[youtube] timedtext body was not valid json3 (first 120 chars): ${redactSecrets(body).slice(0, 120)}`);
|
|
20837
20975
|
return "";
|
|
20838
20976
|
}
|
|
20839
20977
|
const events = parsed.events;
|
|
@@ -22362,32 +22500,36 @@ ${result}`);
|
|
|
22362
22500
|
if (this.config.KNOWLEDGE_STORE_MODE !== "none") {
|
|
22363
22501
|
const ksService = await getService(ServiceNames.KNOWLEDGE_STORE, ctx, container);
|
|
22364
22502
|
if (ksService.isReady()) {
|
|
22365
|
-
const writer = await
|
|
22366
|
-
|
|
22367
|
-
|
|
22368
|
-
|
|
22369
|
-
|
|
22370
|
-
|
|
22371
|
-
|
|
22372
|
-
if (cit.url) {
|
|
22373
|
-
const fullContent = getCachedScrapedContent(this.options.researchId, cit.url);
|
|
22374
|
-
const markdown = cit.description || `(source: ${cit.url})`;
|
|
22375
|
-
writer.enqueue({
|
|
22376
|
-
url: normalizeUrl(cit.url),
|
|
22377
|
-
markdown,
|
|
22378
|
-
content: fullContent,
|
|
22379
|
-
metadata: {
|
|
22380
|
-
ingestionType: "synthesis-description",
|
|
22381
|
-
source: "researcher",
|
|
22382
|
-
synthesizedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22383
|
-
description: cit.description || "",
|
|
22384
|
-
fullContentSnippet: fullContent?.substring(0, 5e3)
|
|
22385
|
-
}
|
|
22386
|
-
});
|
|
22387
|
-
enqueued++;
|
|
22503
|
+
const writer = await ksService.getWriterQueue();
|
|
22504
|
+
if (!writer) {
|
|
22505
|
+
logger.debug("[QuickOrchestrator] Writer queue unavailable, skipping link descriptions");
|
|
22506
|
+
} else {
|
|
22507
|
+
const citations = parseCitations(result);
|
|
22508
|
+
if (citations.length === 0) {
|
|
22509
|
+
logger.warn("[QuickOrchestrator] Researcher produced no parseable CITED LINKS \u2014 no descriptions stored for this session");
|
|
22388
22510
|
}
|
|
22511
|
+
let enqueued = 0;
|
|
22512
|
+
for (const cit of citations) {
|
|
22513
|
+
if (cit.url) {
|
|
22514
|
+
const fullContent = getCachedScrapedContent(this.options.researchId, cit.url);
|
|
22515
|
+
const markdown = cit.description || `(source: ${cit.url})`;
|
|
22516
|
+
writer.enqueue({
|
|
22517
|
+
url: normalizeUrl(cit.url),
|
|
22518
|
+
markdown,
|
|
22519
|
+
content: fullContent,
|
|
22520
|
+
metadata: {
|
|
22521
|
+
ingestionType: "synthesis-description",
|
|
22522
|
+
source: "researcher",
|
|
22523
|
+
synthesizedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22524
|
+
description: cit.description || "",
|
|
22525
|
+
fullContentSnippet: fullContent?.substring(0, 5e3)
|
|
22526
|
+
}
|
|
22527
|
+
});
|
|
22528
|
+
enqueued++;
|
|
22529
|
+
}
|
|
22530
|
+
}
|
|
22531
|
+
if (enqueued > 0) await writer.drain();
|
|
22389
22532
|
}
|
|
22390
|
-
if (enqueued > 0) await writer.drain();
|
|
22391
22533
|
}
|
|
22392
22534
|
}
|
|
22393
22535
|
} catch (err) {
|
|
@@ -23180,7 +23322,11 @@ var ResearchOrchestrationService = class {
|
|
|
23180
23322
|
return;
|
|
23181
23323
|
}
|
|
23182
23324
|
const synthesisService = await getService(ServiceNames.RESEARCH_SYNTHESIS_SERVICE, ctx, container);
|
|
23183
|
-
const writer = await
|
|
23325
|
+
const writer = await ksService.getWriterQueue();
|
|
23326
|
+
if (!writer) {
|
|
23327
|
+
logger.debug("[ResearchOrchestrationService] Writer queue unavailable, skipping link descriptions");
|
|
23328
|
+
return;
|
|
23329
|
+
}
|
|
23184
23330
|
const roundPrefix = `${round}.`;
|
|
23185
23331
|
let enqueued = 0;
|
|
23186
23332
|
let researcherCount = 0;
|
|
@@ -23833,6 +23979,7 @@ async function initializeOrchestrationServices(ctx, container = getServiceContai
|
|
|
23833
23979
|
init_service_registry();
|
|
23834
23980
|
init_service_interfaces();
|
|
23835
23981
|
init_logger();
|
|
23982
|
+
init_log_utils();
|
|
23836
23983
|
init_config();
|
|
23837
23984
|
init_metrics();
|
|
23838
23985
|
|
|
@@ -24175,7 +24322,7 @@ function getLastResearcherOutcome() {
|
|
|
24175
24322
|
}
|
|
24176
24323
|
function logRunErrorSummary(report, depthLabel, status) {
|
|
24177
24324
|
if (!report || report.totalErrors === 0) return;
|
|
24178
|
-
const top = report.patterns.slice(0, 3).map((p) => `"${String(p.message ?? p.signature ?? "error").slice(0, 48)}" \xD7${p.count}`).join(", ");
|
|
24325
|
+
const top = report.patterns.slice(0, 3).map((p) => `"${redactSecrets(String(p.message ?? p.signature ?? "error")).slice(0, 48)}" \xD7${p.count}`).join(", ");
|
|
24179
24326
|
logger.warn(`[SDK] run ${status} with ${report.totalErrors} tracked error(s) across ${report.uniquePatterns} pattern(s) [${depthLabel}]${top ? ` \u2014 top: ${top}` : ""}`);
|
|
24180
24327
|
}
|
|
24181
24328
|
function wrapObserverForOutcomeCapture(observer, onPlanned) {
|