@merittdev/horus 0.15.0 → 0.15.2
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.cjs +45 -5
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -65880,7 +65880,7 @@ init_cjs_shims();
|
|
|
65880
65880
|
|
|
65881
65881
|
// ../../packages/core/src/version.ts
|
|
65882
65882
|
init_cjs_shims();
|
|
65883
|
-
var HORUS_VERSION = true ? "0.15.
|
|
65883
|
+
var HORUS_VERSION = true ? "0.15.2" : "dev";
|
|
65884
65884
|
var PINNED_SOURCE_VERSION = "2.0.2";
|
|
65885
65885
|
|
|
65886
65886
|
// ../../packages/core/src/evidence.ts
|
|
@@ -93610,6 +93610,19 @@ function detectFixedCadence(body2, name2) {
|
|
|
93610
93610
|
}
|
|
93611
93611
|
return null;
|
|
93612
93612
|
}
|
|
93613
|
+
function detectExactMatchQuery(body2, name2) {
|
|
93614
|
+
const sql2 = /\bWHERE\b[^;]*?["'`]?\b\w+\b["'`]?\s*=\s*[$?:]\w*/i.exec(body2);
|
|
93615
|
+
if (sql2 && !/\b(?:LIKE|ILIKE|LOWER|UPPER|TRIM|SIMILAR|REGEXP)\b/i.test(grp(sql2, 0))) {
|
|
93616
|
+
const frag = grp(sql2, 0).trim().slice(0, 48);
|
|
93617
|
+
return { pattern: "exact-match-query", matched: frag, baseScore: 0.2, title: hedged(name2, `matches on an exact-equality query (\`${frag}\`) with no normalization, so a value differing only in formatting (case, whitespace, leading zeros) returns no rows`) };
|
|
93618
|
+
}
|
|
93619
|
+
const orm = /\.(?:find|findOne|findFirst|findUnique)\s*\(\s*\{\s*\w+\s*:/.exec(body2);
|
|
93620
|
+
if (orm) {
|
|
93621
|
+
const frag = grp(orm, 0).trim().slice(0, 40);
|
|
93622
|
+
return { pattern: "exact-match-query", matched: frag, baseScore: 0.2, title: hedged(name2, `looks up by an exact field match (\`${frag}\`) with no normalization, so a value differing only in formatting returns no match`) };
|
|
93623
|
+
}
|
|
93624
|
+
return null;
|
|
93625
|
+
}
|
|
93613
93626
|
function detectInPlaceMutation(body2, ctx) {
|
|
93614
93627
|
const hay = `${ctx.symbol.name} ${ctx.symbol.filePath ?? ""} ${ctx.symbol.signature ?? ""}`;
|
|
93615
93628
|
const contextual = /reduc|\bslice\b|store|mutat|\bstate\b/i.test(hay) || ctx.imports.some((i3) => /redux|zustand|immer|valtio|mobx/i.test(i3));
|
|
@@ -93665,7 +93678,14 @@ function detectDataFlowCause(ctx) {
|
|
|
93665
93678
|
if (raw.length < 40) return null;
|
|
93666
93679
|
const body2 = stripComments(raw);
|
|
93667
93680
|
const nm = ctx.symbol.name;
|
|
93668
|
-
return detectFixedCadence(body2, nm) ?? detectInPlaceMutation(body2, ctx) ?? detectUnawaitedWrite(body2, ctx) ?? detectHardcodedBound(body2, nm);
|
|
93681
|
+
return detectFixedCadence(body2, nm) ?? detectExactMatchQuery(body2, nm) ?? detectInPlaceMutation(body2, ctx) ?? detectUnawaitedWrite(body2, ctx) ?? detectHardcodedBound(body2, nm);
|
|
93682
|
+
}
|
|
93683
|
+
function detectDataFlowCauseAcross(contexts) {
|
|
93684
|
+
for (const c4 of contexts) {
|
|
93685
|
+
const f5 = detectDataFlowCause(c4);
|
|
93686
|
+
if (f5) return f5;
|
|
93687
|
+
}
|
|
93688
|
+
return null;
|
|
93669
93689
|
}
|
|
93670
93690
|
|
|
93671
93691
|
// ../../packages/engine/src/hypotheses.ts
|
|
@@ -95200,6 +95220,17 @@ var TYPE_LIKE_NAME = new RegExp(`(?:${TYPE_SUFFIX.source})|(?:${INTERFACE_PREFIX
|
|
|
95200
95220
|
function isTypeLikeName(name2) {
|
|
95201
95221
|
return TYPE_LIKE_NAME.test(name2);
|
|
95202
95222
|
}
|
|
95223
|
+
var CODEGEN_PATH_RE = /(^|\/)(?:__generated__|generated)\//i;
|
|
95224
|
+
var CODEGEN_FILE_RE = /(?:(?:^|\/)generated|[._-](?:generated|gen))\.[jt]sx?$/i;
|
|
95225
|
+
var GQL_GEN_FILE_RE = /\.(?:graphql|gql)\.[jt]sx?$/i;
|
|
95226
|
+
function isCodegenPath(filePath) {
|
|
95227
|
+
return CODEGEN_PATH_RE.test(filePath) || CODEGEN_FILE_RE.test(filePath) || GQL_GEN_FILE_RE.test(filePath);
|
|
95228
|
+
}
|
|
95229
|
+
var TYPE_DECL_KIND_RE = /^(?:type_alias|typealias|type|interface|enum)$/i;
|
|
95230
|
+
function isTypeDeclarationSymbol(s5) {
|
|
95231
|
+
const kind = s5.id.split(":", 1)[0] ?? "";
|
|
95232
|
+
return TYPE_DECL_KIND_RE.test(kind);
|
|
95233
|
+
}
|
|
95203
95234
|
function executableBaseName(name2) {
|
|
95204
95235
|
const stripped = name2.replace(TYPE_SUFFIX, "").replace(INTERFACE_PREFIX, "");
|
|
95205
95236
|
return stripped !== name2 && stripped.length >= 4 ? stripped : null;
|
|
@@ -95331,6 +95362,8 @@ function scoreSeed(s5, index2, hintTokens, changedFiles, hintHasCode, qualifier,
|
|
|
95331
95362
|
score += Math.max(0, 5 - index2) * (hintHasCode ? 0.8 : 0.1);
|
|
95332
95363
|
if (s5.score !== void 0) score += s5.score * (hintHasCode ? 8 : 2);
|
|
95333
95364
|
if (/\.[jt]sx?$/i.test(s5.name)) score -= 5;
|
|
95365
|
+
if (isCodegenPath(s5.filePath)) score -= 5;
|
|
95366
|
+
if (isTypeDeclarationSymbol(s5)) score -= 6;
|
|
95334
95367
|
if (hintTokens !== void 0 && hintTokens.length > 0) {
|
|
95335
95368
|
let hintBoost = 0;
|
|
95336
95369
|
for (const tok of hintTokens) {
|
|
@@ -95350,6 +95383,9 @@ function isDeprioritizedSeedPath(filePath) {
|
|
|
95350
95383
|
filePath
|
|
95351
95384
|
);
|
|
95352
95385
|
}
|
|
95386
|
+
function isDeprioritizedSeed(s5) {
|
|
95387
|
+
return isDeprioritizedSeedPath(s5.filePath) || isCodegenPath(s5.filePath) || isTypeDeclarationSymbol(s5);
|
|
95388
|
+
}
|
|
95353
95389
|
function isAnchoredExactSeed(s5, qualifier, hintHasCode, preferNamed) {
|
|
95354
95390
|
if (qualifier && qualifierBoost(s5, qualifier) >= 40) return true;
|
|
95355
95391
|
if (preferNamed !== void 0 && s5.name.toLowerCase() === preferNamed.toLowerCase()) return true;
|
|
@@ -95362,7 +95398,7 @@ function rankSeeds(seeds, hintTokens, changedFiles, hintHasCode, qualifier, pref
|
|
|
95362
95398
|
score: scoreSeed(symbol, i3, hintTokens, changedFiles, hintHasCode, qualifier, preferNamed),
|
|
95363
95399
|
role: seedRole(symbol),
|
|
95364
95400
|
i: i3,
|
|
95365
|
-
deprio:
|
|
95401
|
+
deprio: isDeprioritizedSeed(symbol),
|
|
95366
95402
|
// HOR-430: a deprioritized candidate the request anchors on exactly is exempt from the
|
|
95367
95403
|
// hard demotion below — it keeps only the soft path penalty so a strong/exact match in an
|
|
95368
95404
|
// example/test file can still surface.
|
|
@@ -97778,8 +97814,12 @@ async function investigate(input, deps) {
|
|
|
97778
97814
|
});
|
|
97779
97815
|
}
|
|
97780
97816
|
}
|
|
97781
|
-
if (top && seedEv && ctx && !sourceImpactHint) {
|
|
97782
|
-
const
|
|
97817
|
+
if (top && seedEv && ctx && code && !sourceImpactHint) {
|
|
97818
|
+
const scanIds = [
|
|
97819
|
+
.../* @__PURE__ */ new Set([...seeds.slice(1, 4).map((s5) => s5.id), ...(ctx.callees ?? []).slice(0, 4).map((c4) => c4.id)])
|
|
97820
|
+
].filter((id) => id !== top.id);
|
|
97821
|
+
const extraCtxs = (await Promise.all(scanIds.map((id) => code.context(id).catch(() => null)))).filter((c4) => c4 !== null);
|
|
97822
|
+
const dataFlow = detectDataFlowCauseAcross([ctx, ...extraCtxs]);
|
|
97783
97823
|
if (dataFlow) {
|
|
97784
97824
|
causeInputs.push({
|
|
97785
97825
|
id: "cause:seed-data-flow",
|