seaworthycode 1.2.12 → 1.2.13
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/dist/index.js +89 -7
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
- package/wasm/tree-sitter-sql.wasm +0 -0
package/dist/index.js
CHANGED
|
@@ -407,10 +407,11 @@ async function crawl(options) {
|
|
|
407
407
|
const { isBinary, isGenerated } = await peekFileHead(fullPath);
|
|
408
408
|
if (isBinary || isGenerated) continue;
|
|
409
409
|
if (await shouldSkipMinifiedJs(fullPath, entry.name)) continue;
|
|
410
|
+
let cachedContent;
|
|
410
411
|
files.push({
|
|
411
412
|
path: fullPath,
|
|
412
413
|
relativePath: relPath,
|
|
413
|
-
content: () => fs.readFile(fullPath, "utf-8"),
|
|
414
|
+
content: () => cachedContent ??= fs.readFile(fullPath, "utf-8"),
|
|
414
415
|
language: inferLanguage(entry.name)
|
|
415
416
|
});
|
|
416
417
|
} catch {
|
|
@@ -427,10 +428,11 @@ async function crawl(options) {
|
|
|
427
428
|
const { isBinary, isGenerated } = await peekFileHead(fullPath);
|
|
428
429
|
if (isBinary || isGenerated) continue;
|
|
429
430
|
if (await shouldSkipMinifiedJs(fullPath, entry.name)) continue;
|
|
431
|
+
let cachedContent;
|
|
430
432
|
files.push({
|
|
431
433
|
path: fullPath,
|
|
432
434
|
relativePath: relPath,
|
|
433
|
-
content: () => fs.readFile(fullPath, "utf-8"),
|
|
435
|
+
content: () => cachedContent ??= fs.readFile(fullPath, "utf-8"),
|
|
434
436
|
language: inferLanguage(entry.name)
|
|
435
437
|
});
|
|
436
438
|
} catch {
|
|
@@ -789,6 +791,7 @@ var copy = {
|
|
|
789
791
|
"report.cta.hasFindings": `Fix these before you ship. ${SITE_URL}/docs`,
|
|
790
792
|
"report.cta.critical": `\u26A0 Critical issues found \u2014 patch before you deploy. ${SITE_URL}/docs`,
|
|
791
793
|
"report.proUpsellNamed": (names, count) => `\u2693 Pro unlocks ${count} more check${count === 1 ? "" : "s"} (${names}). ${SITE_URL}`,
|
|
794
|
+
"report.timedOutChecks": (names, count) => `\u26A0 ${count} check${count === 1 ? "" : "s"} timed out and were skipped (${names}). Use SEAWORTHY_CHECK_TIMEOUT_MS to extend the limit.`,
|
|
792
795
|
"report.preScanNotice": (count) => `\u2693 Pro unlocks ${count} additional checks. Upgrade at ${SITE_URL}`,
|
|
793
796
|
"report.llmPrivacyWarning": "Pro checks will send code context to your LLM provider via your API key. No data is sent to Seaworthy servers.",
|
|
794
797
|
"report.confidenceHigh": "high confidence",
|
|
@@ -1601,6 +1604,16 @@ async function runWithConcurrencyCollect(items, fn, concurrency) {
|
|
|
1601
1604
|
await Promise.all(workers);
|
|
1602
1605
|
return results;
|
|
1603
1606
|
}
|
|
1607
|
+
var DEFAULT_CHECK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1608
|
+
var SLOW_CHECK_THRESHOLD_RATIO = 0.5;
|
|
1609
|
+
function getCheckTimeoutMs() {
|
|
1610
|
+
const env2 = process.env.SEAWORTHY_CHECK_TIMEOUT_MS;
|
|
1611
|
+
if (env2 !== void 0) {
|
|
1612
|
+
const n = parseInt(env2, 10);
|
|
1613
|
+
if (!isNaN(n) && n > 0) return n;
|
|
1614
|
+
}
|
|
1615
|
+
return DEFAULT_CHECK_TIMEOUT_MS;
|
|
1616
|
+
}
|
|
1604
1617
|
var ScanRunner = class {
|
|
1605
1618
|
async run(options) {
|
|
1606
1619
|
const { concurrency = 4 } = options;
|
|
@@ -1628,15 +1641,54 @@ var ScanRunner = class {
|
|
|
1628
1641
|
}
|
|
1629
1642
|
const categoryCompleted = /* @__PURE__ */ new Map();
|
|
1630
1643
|
let completedCount = 0;
|
|
1644
|
+
const timedOutChecks = [];
|
|
1645
|
+
const checkTimeoutMs = getCheckTimeoutMs();
|
|
1631
1646
|
await runWithConcurrency(
|
|
1632
1647
|
checks,
|
|
1633
1648
|
async (check2) => {
|
|
1649
|
+
if (options.debug) {
|
|
1650
|
+
process.stderr.write(`[seaworthy] check.start ${check2.id}
|
|
1651
|
+
`);
|
|
1652
|
+
}
|
|
1653
|
+
const startMs = Date.now();
|
|
1654
|
+
let timedOut = false;
|
|
1655
|
+
let softTimer;
|
|
1656
|
+
let hardTimer;
|
|
1634
1657
|
try {
|
|
1635
|
-
const findings2 = await
|
|
1636
|
-
|
|
1658
|
+
const findings2 = await new Promise((resolve22, reject) => {
|
|
1659
|
+
softTimer = setTimeout(() => {
|
|
1660
|
+
process.stderr.write(
|
|
1661
|
+
`[seaworthy] check.slow ${check2.id} \u2014 still running after ${Math.round(checkTimeoutMs * SLOW_CHECK_THRESHOLD_RATIO / 1e3)}s
|
|
1662
|
+
`
|
|
1663
|
+
);
|
|
1664
|
+
}, checkTimeoutMs * SLOW_CHECK_THRESHOLD_RATIO);
|
|
1665
|
+
hardTimer = setTimeout(() => {
|
|
1666
|
+
timedOut = true;
|
|
1667
|
+
process.stderr.write(
|
|
1668
|
+
`[seaworthy] check.timeout ${check2.id} \u2014 aborting after ${Math.round(checkTimeoutMs / 1e3)}s
|
|
1669
|
+
`
|
|
1670
|
+
);
|
|
1671
|
+
resolve22([]);
|
|
1672
|
+
}, checkTimeoutMs);
|
|
1673
|
+
check2.run(ctx).then(resolve22, reject);
|
|
1674
|
+
});
|
|
1675
|
+
clearTimeout(softTimer);
|
|
1676
|
+
clearTimeout(hardTimer);
|
|
1677
|
+
if (timedOut) {
|
|
1678
|
+
timedOutChecks.push({ id: check2.id, name: check2.name, category: check2.category });
|
|
1679
|
+
checkResults.set(check2.id, []);
|
|
1680
|
+
} else {
|
|
1681
|
+
checkResults.set(check2.id, findings2);
|
|
1682
|
+
}
|
|
1637
1683
|
} catch (err) {
|
|
1684
|
+
clearTimeout(softTimer);
|
|
1685
|
+
clearTimeout(hardTimer);
|
|
1638
1686
|
console.error(`Check "${check2.id}" failed: ${String(err)}`);
|
|
1639
1687
|
}
|
|
1688
|
+
if (options.debug) {
|
|
1689
|
+
process.stderr.write(`[seaworthy] check.done ${check2.id} ${Date.now() - startMs}ms
|
|
1690
|
+
`);
|
|
1691
|
+
}
|
|
1640
1692
|
options.onCheckComplete?.(++completedCount, checks.length, check2.name);
|
|
1641
1693
|
if (options.onCategoryComplete) {
|
|
1642
1694
|
const catDone = (categoryCompleted.get(check2.category) ?? 0) + 1;
|
|
@@ -1685,7 +1737,8 @@ var ScanRunner = class {
|
|
|
1685
1737
|
return {
|
|
1686
1738
|
findings,
|
|
1687
1739
|
scannedFileCount: files.length,
|
|
1688
|
-
skippedChecks
|
|
1740
|
+
skippedChecks,
|
|
1741
|
+
timedOutChecks
|
|
1689
1742
|
};
|
|
1690
1743
|
}
|
|
1691
1744
|
};
|
|
@@ -2486,7 +2539,7 @@ function renderCollapsedGroup(group, showIds) {
|
|
|
2486
2539
|
}
|
|
2487
2540
|
var TerminalReporter = class {
|
|
2488
2541
|
generate(input) {
|
|
2489
|
-
const { findings: rawFindings, targetDir, tier, licensedTo, scannedFileCount, skippedChecks = [], showIds = false, all = false } = input;
|
|
2542
|
+
const { findings: rawFindings, targetDir, tier, licensedTo, scannedFileCount, skippedChecks = [], timedOutChecks = [], showIds = false, all = false } = input;
|
|
2490
2543
|
const findings = dedupeDegradedFindings(rawFindings);
|
|
2491
2544
|
if (findings.length === 0) {
|
|
2492
2545
|
const lines2 = [];
|
|
@@ -2500,6 +2553,10 @@ var TerminalReporter = class {
|
|
|
2500
2553
|
lines2.push("");
|
|
2501
2554
|
lines2.push(text.link(buildProUpsell(skippedChecks)));
|
|
2502
2555
|
}
|
|
2556
|
+
if (timedOutChecks.length > 0) {
|
|
2557
|
+
lines2.push("");
|
|
2558
|
+
lines2.push(text.warning(buildTimedOutNote(timedOutChecks)));
|
|
2559
|
+
}
|
|
2503
2560
|
return lines2.join("\n");
|
|
2504
2561
|
}
|
|
2505
2562
|
const lines = [];
|
|
@@ -2549,9 +2606,18 @@ var TerminalReporter = class {
|
|
|
2549
2606
|
if (skippedChecks.length > 0) {
|
|
2550
2607
|
lines.push(text.link(buildProUpsell(skippedChecks)));
|
|
2551
2608
|
}
|
|
2609
|
+
if (timedOutChecks.length > 0) {
|
|
2610
|
+
lines.push(text.warning(buildTimedOutNote(timedOutChecks)));
|
|
2611
|
+
}
|
|
2552
2612
|
return lines.join("\n");
|
|
2553
2613
|
}
|
|
2554
2614
|
};
|
|
2615
|
+
function buildTimedOutNote(timedOutChecks) {
|
|
2616
|
+
const count = timedOutChecks.length;
|
|
2617
|
+
const names = timedOutChecks.slice(0, 2).map((c) => c.name.toLowerCase()).join(", ");
|
|
2618
|
+
const suffix = count > 2 ? ", \u2026" : "";
|
|
2619
|
+
return getCopy("report.timedOutChecks", names + suffix, count);
|
|
2620
|
+
}
|
|
2555
2621
|
function buildProUpsell(skippedChecks) {
|
|
2556
2622
|
const count = skippedChecks.length;
|
|
2557
2623
|
const names = skippedChecks.slice(0, 2).map((c) => c.name.toLowerCase()).join(", ");
|
|
@@ -5908,6 +5974,14 @@ function classifyError(err) {
|
|
|
5908
5974
|
return "llm.unexpected";
|
|
5909
5975
|
}
|
|
5910
5976
|
var LLM_TIMEOUT_MS = 9e4;
|
|
5977
|
+
function getMaxFilesPerLlmCheck() {
|
|
5978
|
+
const env2 = process.env.SEAWORTHY_LLM_MAX_FILES;
|
|
5979
|
+
if (env2 !== void 0) {
|
|
5980
|
+
const n = parseInt(env2, 10);
|
|
5981
|
+
if (!isNaN(n) && n > 0) return n;
|
|
5982
|
+
}
|
|
5983
|
+
return 150;
|
|
5984
|
+
}
|
|
5911
5985
|
function withLLMTimeout(promise, ms) {
|
|
5912
5986
|
return new Promise((resolve22, reject) => {
|
|
5913
5987
|
const timerId = setTimeout(() => {
|
|
@@ -6149,7 +6223,7 @@ async function runLLMCheck(ctx, template) {
|
|
|
6149
6223
|
return cached;
|
|
6150
6224
|
}
|
|
6151
6225
|
}
|
|
6152
|
-
|
|
6226
|
+
let eligibleFiles = await filterFilesByBudget(proEligibleFiles, template.tokenBudget);
|
|
6153
6227
|
if (eligibleFiles.length === 0) {
|
|
6154
6228
|
let mechFindings = await runMechanicalCheck(ctx, template);
|
|
6155
6229
|
if (template.projectScoped) {
|
|
@@ -6165,6 +6239,13 @@ async function runLLMCheck(ctx, template) {
|
|
|
6165
6239
|
}
|
|
6166
6240
|
return withRemediation;
|
|
6167
6241
|
}
|
|
6242
|
+
const maxFiles = getMaxFilesPerLlmCheck();
|
|
6243
|
+
if (eligibleFiles.length > maxFiles) {
|
|
6244
|
+
console.error(
|
|
6245
|
+
`[seaworthy] ${template.checkId}: ${eligibleFiles.length} eligible files \u2014 capping LLM prompt to ${maxFiles}`
|
|
6246
|
+
);
|
|
6247
|
+
eligibleFiles = eligibleFiles.slice(0, maxFiles);
|
|
6248
|
+
}
|
|
6168
6249
|
const prompt = `${PROMPT_PREAMBLE}
|
|
6169
6250
|
|
|
6170
6251
|
${await template.buildPrompt(eligibleFiles)}`;
|
|
@@ -16142,6 +16223,7 @@ async function executeScan(args, ctx) {
|
|
|
16142
16223
|
licensedTo: ctx.licensedTo ?? "free tier",
|
|
16143
16224
|
scannedFileCount: result.scannedFileCount,
|
|
16144
16225
|
skippedChecks: result.skippedChecks,
|
|
16226
|
+
timedOutChecks: result.timedOutChecks,
|
|
16145
16227
|
showIds: args.showIds ?? args.debug,
|
|
16146
16228
|
all: args.all
|
|
16147
16229
|
};
|