@hraness/wordcell 0.20.0-bootstrap.1
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/LICENSE +21 -0
- package/README.md +749 -0
- package/dist/agent-context.js +35 -0
- package/dist/agent-guide-audit.js +18 -0
- package/dist/attachments.js +19 -0
- package/dist/authoring.js +33 -0
- package/dist/benchmark.js +19 -0
- package/dist/capture.js +49 -0
- package/dist/cli.js +57 -0
- package/dist/clip/acquire.js +57 -0
- package/dist/clip/args.js +21 -0
- package/dist/clip/bounded-byte-buffer.js +9 -0
- package/dist/clip/browser-profiles.js +17 -0
- package/dist/clip/bundle-reader.js +11 -0
- package/dist/clip/cli.js +27 -0
- package/dist/clip/cookies.js +21 -0
- package/dist/clip/defuddle-worker.js +84 -0
- package/dist/clip/doctor.js +32 -0
- package/dist/clip/jobs.js +784 -0
- package/dist/clip/network-proxy.js +9 -0
- package/dist/clip/network.js +28 -0
- package/dist/clip/persist.js +30 -0
- package/dist/clip/refresh.js +11 -0
- package/dist/clip/terminal.js +11 -0
- package/dist/evaluation-builder.js +12238 -0
- package/dist/evaluation-kb.js +26 -0
- package/dist/evaluation.js +35 -0
- package/dist/git.js +39 -0
- package/dist/graph.js +41 -0
- package/dist/index-054mb7d3.js +1974 -0
- package/dist/index-06c9ctr6.js +738 -0
- package/dist/index-180zbkkt.js +2480 -0
- package/dist/index-1gwbassd.js +743 -0
- package/dist/index-1xxnjn0d.js +171 -0
- package/dist/index-23z4zxgg.js +119 -0
- package/dist/index-2gv8y733.js +432 -0
- package/dist/index-3ehtt59c.js +199 -0
- package/dist/index-3rm7cz6h.js +373 -0
- package/dist/index-48pz4jpc.js +392 -0
- package/dist/index-4j3tt0c3.js +234 -0
- package/dist/index-5n05se68.js +307 -0
- package/dist/index-5vwpzb5a.js +764 -0
- package/dist/index-6jcz0m1c.js +712 -0
- package/dist/index-6sw24nvv.js +1189 -0
- package/dist/index-8a08v6x8.js +56 -0
- package/dist/index-adx6khj5.js +488 -0
- package/dist/index-b88v3vtm.js +805 -0
- package/dist/index-bcknqxrq.js +1943 -0
- package/dist/index-bs0yf4pp.js +711 -0
- package/dist/index-by0pbant.js +827 -0
- package/dist/index-d13v9ckt.js +150 -0
- package/dist/index-dfag79p7.js +370 -0
- package/dist/index-e4fagfjz.js +44 -0
- package/dist/index-e5fbsywq.js +658 -0
- package/dist/index-ekpwvbra.js +1070 -0
- package/dist/index-f984hw45.js +927 -0
- package/dist/index-gh719d91.js +63 -0
- package/dist/index-h170byqw.js +371 -0
- package/dist/index-hgve9rh2.js +2046 -0
- package/dist/index-hya40gb2.js +474 -0
- package/dist/index-j4zgmzjr.js +152 -0
- package/dist/index-m7et4rz4.js +966 -0
- package/dist/index-mxxxytys.js +1254 -0
- package/dist/index-n05s3wsb.js +2728 -0
- package/dist/index-nd6nynv2.js +1162 -0
- package/dist/index-npg9z1a4.js +431 -0
- package/dist/index-pj501bh1.js +140 -0
- package/dist/index-rdd5f7jj.js +70 -0
- package/dist/index-sy0zety7.js +3630 -0
- package/dist/index-tkpxp48t.js +1166 -0
- package/dist/index-w2zc0vwa.js +571 -0
- package/dist/index-why54q5p.js +462 -0
- package/dist/index-x3fthpsc.js +585 -0
- package/dist/index-x6m57nfc.js +1041 -0
- package/dist/index.js +784 -0
- package/dist/kb-alias.js +55 -0
- package/dist/navigation.js +13 -0
- package/dist/pdf.js +85 -0
- package/dist/percolate.js +44 -0
- package/dist/portfolio.js +77 -0
- package/dist/query.js +29 -0
- package/dist/repository-memory.js +60 -0
- package/dist/sdk.js +36 -0
- package/dist/search-rules.js +34 -0
- package/dist/search.js +22 -0
- package/dist/semantic.js +39 -0
- package/dist/source-inbox.js +17 -0
- package/dist/untrusted-content.js +32 -0
- package/dist/url-intelligence.js +74 -0
- package/dist/workflow.js +23 -0
- package/dist/workflows/decision-context.js +20 -0
- package/dist/workflows/explain-change.js +8 -0
- package/dist/workflows/index.js +28 -0
- package/dist/workflows/plan-radar.js +10 -0
- package/package.json +421 -0
- package/skills/wordcell/AGENTS.md +22 -0
- package/skills/wordcell/SKILL.md +91 -0
- package/skills/wordcell/agents/openai.yaml +4 -0
- package/skills/wordcell/references/companion-skills.md +96 -0
- package/skills/wordcell/references/customize.md +123 -0
- package/skills/wordcell/references/pdf-review.md +51 -0
- package/skills/wordcell/references/percolate.md +176 -0
- package/skills/wordcell/references/plan-structure.md +105 -0
- package/skills/wordcell/references/plan.md +115 -0
- package/skills/wordcell/references/query.md +252 -0
- package/skills/wordcell/references/refresh.md +133 -0
- package/skills/wordcell/references/save-pdf.md +125 -0
- package/skills/wordcell/references/save-url.md +178 -0
- package/skills/wordcell/references/url-authentication.md +75 -0
- package/skills/wordcell/references/url-platforms.md +25 -0
- package/skills/wordcell/templates/companion-skill.template.md +57 -0
- package/src/agent-context.ts +1241 -0
- package/src/agent-guide-audit.ts +750 -0
- package/src/attachments.ts +723 -0
- package/src/authoring-model.ts +798 -0
- package/src/authoring-platform.ts +549 -0
- package/src/authoring-program.ts +278 -0
- package/src/authoring-runtime.ts +54 -0
- package/src/authoring.ts +75 -0
- package/src/benchmark.ts +362 -0
- package/src/capture.ts +68 -0
- package/src/cli-program.ts +3662 -0
- package/src/cli.ts +6 -0
- package/src/clip/acquire.ts +1273 -0
- package/src/clip/archive-today.ts +402 -0
- package/src/clip/args.ts +423 -0
- package/src/clip/assets.ts +262 -0
- package/src/clip/bounded-byte-buffer.ts +75 -0
- package/src/clip/browser-profiles.ts +372 -0
- package/src/clip/bundle-reader.ts +608 -0
- package/src/clip/capture.ts +1054 -0
- package/src/clip/cli.ts +181 -0
- package/src/clip/cookies.ts +512 -0
- package/src/clip/doctor.ts +1110 -0
- package/src/clip/extract.ts +868 -0
- package/src/clip/jobs.ts +959 -0
- package/src/clip/lib.ts +861 -0
- package/src/clip/media.ts +1474 -0
- package/src/clip/metadata-search-tool/Cargo.lock +2498 -0
- package/src/clip/metadata-search-tool/Cargo.toml +18 -0
- package/src/clip/metadata-search-tool/runner.ts +685 -0
- package/src/clip/metadata-search-tool/src/main.rs +389 -0
- package/src/clip/metadata-search.ts +687 -0
- package/src/clip/network-proxy.ts +627 -0
- package/src/clip/network.ts +950 -0
- package/src/clip/package-root.ts +54 -0
- package/src/clip/persist.ts +1472 -0
- package/src/clip/platforms.ts +1824 -0
- package/src/clip/refresh.ts +197 -0
- package/src/clip/structured.ts +432 -0
- package/src/clip/terminal.ts +197 -0
- package/src/clip/url-intelligence.ts +581 -0
- package/src/clip/url-metadata-backfill.ts +616 -0
- package/src/clip/url-metadata-cli.ts +251 -0
- package/src/clip/url-metadata.ts +1397 -0
- package/src/evaluation-analysis-v2.ts +1440 -0
- package/src/evaluation-builder.ts +2539 -0
- package/src/evaluation-corpus-authoring.ts +2052 -0
- package/src/evaluation-evidence.ts +1147 -0
- package/src/evaluation-execution-v2.ts +426 -0
- package/src/evaluation-implementation.ts +131 -0
- package/src/evaluation-kb-closure.ts +1430 -0
- package/src/evaluation-kb-runner-v2.ts +735 -0
- package/src/evaluation-kb-v2.ts +2567 -0
- package/src/evaluation-kb.ts +1018 -0
- package/src/evaluation-measurement-v2.ts +1462 -0
- package/src/evaluation-packing-v2.ts +452 -0
- package/src/evaluation-redaction.ts +28 -0
- package/src/evaluation-v2.ts +3857 -0
- package/src/evaluation.ts +1220 -0
- package/src/git.ts +1276 -0
- package/src/graph.ts +1494 -0
- package/src/index.ts +21 -0
- package/src/init.ts +123 -0
- package/src/kb-alias.ts +14 -0
- package/src/navigation.ts +277 -0
- package/src/note-lock.ts +529 -0
- package/src/oh-adoption.ts +444 -0
- package/src/pdf/args.ts +202 -0
- package/src/pdf/capture.ts +298 -0
- package/src/pdf/cli.ts +159 -0
- package/src/pdf/extract.ts +303 -0
- package/src/pdf/layout.ts +618 -0
- package/src/pdf/markdown.ts +154 -0
- package/src/pdf/model.ts +234 -0
- package/src/pdf/ocr.ts +190 -0
- package/src/pdf/persist.ts +314 -0
- package/src/pdf/source.ts +135 -0
- package/src/pdf/tools.ts +146 -0
- package/src/pdf.ts +92 -0
- package/src/percolate.ts +1948 -0
- package/src/portfolio-audit.ts +574 -0
- package/src/portfolio-identity.ts +162 -0
- package/src/portfolio-registry.ts +473 -0
- package/src/portfolio.ts +765 -0
- package/src/query.ts +646 -0
- package/src/repository-memory.ts +1150 -0
- package/src/sdk.ts +1452 -0
- package/src/search-rules.ts +712 -0
- package/src/search.ts +710 -0
- package/src/semantic-runtime.ts +1139 -0
- package/src/semantic.ts +2480 -0
- package/src/source-inbox.ts +232 -0
- package/src/untrusted-content.ts +401 -0
- package/src/url-intelligence.ts +104 -0
- package/src/vault.ts +636 -0
- package/src/workflow-model.ts +444 -0
- package/src/workflow-platform.ts +74 -0
- package/src/workflow-program.ts +183 -0
- package/src/workflow-runtime.ts +51 -0
- package/src/workflow.ts +23 -0
- package/src/workflows/decision-context.ts +81 -0
- package/src/workflows/explain-change.ts +73 -0
- package/src/workflows/index.ts +3 -0
- package/src/workflows/plan-radar.ts +101 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/clip/cookies.ts
|
|
3
|
+
import { closeSync, constants, fstatSync, openSync, readSync } from "fs";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
var MAX_COOKIE_RECORDS = 4096;
|
|
6
|
+
var MAX_COOKIE_BYTES = 2 * 1024 * 1024;
|
|
7
|
+
var cookieNamePattern = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
8
|
+
var cookieValuePattern = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*$/;
|
|
9
|
+
var quotedCookieValuePattern = /^"[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*"$/;
|
|
10
|
+
var cookieDomainPattern = /^[a-z0-9.-]+$/i;
|
|
11
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
|
+
var isUnknownArray = (value) => Array.isArray(value);
|
|
13
|
+
function hasControlCharacter(value) {
|
|
14
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
15
|
+
const code = value.charCodeAt(index);
|
|
16
|
+
if (code <= 31 || code === 127)
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function canonicalHostname(value) {
|
|
22
|
+
const trimmed = value.trim().toLowerCase().replace(/^\.+/, "").replace(/\.$/, "");
|
|
23
|
+
if (trimmed === "" || trimmed.length > 253 || trimmed.includes("..") || !cookieDomainPattern.test(trimmed)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const hostname = new URL(`http://${trimmed}/`).hostname.toLowerCase().replace(/\.$/, "");
|
|
28
|
+
return hostname === "" || hostname.length > 253 ? null : hostname;
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function domainMatches(hostname, domain, hostOnly) {
|
|
34
|
+
return hostname === domain || !hostOnly && hostname.endsWith(`.${domain}`);
|
|
35
|
+
}
|
|
36
|
+
function pathMatches(requestPath, cookiePath) {
|
|
37
|
+
if (requestPath === cookiePath)
|
|
38
|
+
return true;
|
|
39
|
+
if (!requestPath.startsWith(cookiePath))
|
|
40
|
+
return false;
|
|
41
|
+
return cookiePath.endsWith("/") || requestPath[cookiePath.length] === "/";
|
|
42
|
+
}
|
|
43
|
+
function safeCookiePath(value) {
|
|
44
|
+
const path = value === undefined ? "/" : value;
|
|
45
|
+
if (typeof path !== "string" || !path.startsWith("/") || path.length > 4096 || hasControlCharacter(path))
|
|
46
|
+
return null;
|
|
47
|
+
return path;
|
|
48
|
+
}
|
|
49
|
+
function cookieExpiry(value, nowSeconds) {
|
|
50
|
+
const raw = value.expires ?? value.expirationDate;
|
|
51
|
+
if (raw === undefined || raw === null)
|
|
52
|
+
return 0;
|
|
53
|
+
if (typeof raw !== "number" || !Number.isFinite(raw))
|
|
54
|
+
return null;
|
|
55
|
+
if (raw === 0)
|
|
56
|
+
return 0;
|
|
57
|
+
if (raw <= nowSeconds || raw > 253402300799)
|
|
58
|
+
return null;
|
|
59
|
+
return Math.trunc(raw);
|
|
60
|
+
}
|
|
61
|
+
function cookieSameSite(value) {
|
|
62
|
+
if (value.sameSite === undefined || value.sameSite === null)
|
|
63
|
+
return null;
|
|
64
|
+
if (typeof value.sameSite !== "string")
|
|
65
|
+
return;
|
|
66
|
+
switch (value.sameSite.toLowerCase()) {
|
|
67
|
+
case "strict":
|
|
68
|
+
return "Strict";
|
|
69
|
+
case "lax":
|
|
70
|
+
return "Lax";
|
|
71
|
+
case "none":
|
|
72
|
+
case "no_restriction":
|
|
73
|
+
return "None";
|
|
74
|
+
case "unspecified":
|
|
75
|
+
return null;
|
|
76
|
+
default:
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function candidateDomain(value, target) {
|
|
81
|
+
const targetHostname = target.hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
|
|
82
|
+
let rawDomain;
|
|
83
|
+
if (typeof value.domain === "string")
|
|
84
|
+
rawDomain = value.domain;
|
|
85
|
+
else if (value.domain !== undefined)
|
|
86
|
+
return null;
|
|
87
|
+
let urlHostname;
|
|
88
|
+
if (value.url !== undefined) {
|
|
89
|
+
if (typeof value.url !== "string" || value.url.length > 8192)
|
|
90
|
+
return null;
|
|
91
|
+
try {
|
|
92
|
+
const url = new URL(value.url);
|
|
93
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username !== "" || url.password !== "")
|
|
94
|
+
return null;
|
|
95
|
+
urlHostname = url.hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (rawDomain === undefined && urlHostname === undefined) {
|
|
101
|
+
return { domain: targetHostname, hostOnly: true };
|
|
102
|
+
}
|
|
103
|
+
const hadLeadingDot = rawDomain?.trim().startsWith(".") === true;
|
|
104
|
+
const domain = canonicalHostname(rawDomain ?? urlHostname ?? "");
|
|
105
|
+
if (domain === null)
|
|
106
|
+
return null;
|
|
107
|
+
const explicitHostOnly = value.hostOnly;
|
|
108
|
+
if (explicitHostOnly !== undefined && typeof explicitHostOnly !== "boolean")
|
|
109
|
+
return null;
|
|
110
|
+
const hostOnly = typeof explicitHostOnly === "boolean" ? explicitHostOnly : !hadLeadingDot;
|
|
111
|
+
if (!domainMatches(targetHostname, domain, hostOnly))
|
|
112
|
+
return null;
|
|
113
|
+
if (urlHostname !== undefined && !domainMatches(urlHostname, domain, hostOnly))
|
|
114
|
+
return null;
|
|
115
|
+
return { domain, hostOnly };
|
|
116
|
+
}
|
|
117
|
+
function hasSafeUnpartitionedProvenance(value) {
|
|
118
|
+
for (const field of ["partitionKey", "topFrameSiteKey", "top_frame_site_key", "originAttributes"]) {
|
|
119
|
+
const provenance = value[field];
|
|
120
|
+
if (provenance === undefined || provenance === null)
|
|
121
|
+
continue;
|
|
122
|
+
if (typeof provenance !== "string" || provenance.trim() !== "")
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
for (const field of ["partitioned", "partitionKeyOpaque"]) {
|
|
126
|
+
const flag = value[field];
|
|
127
|
+
if (flag === undefined || flag === null)
|
|
128
|
+
continue;
|
|
129
|
+
if (typeof flag !== "boolean" || flag)
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
for (const field of ["isPartitionedAttributeSet", "hasCrossSiteAncestor", "has_cross_site_ancestor"]) {
|
|
133
|
+
const flag = value[field];
|
|
134
|
+
if (flag === undefined || flag === null)
|
|
135
|
+
continue;
|
|
136
|
+
if (flag !== false && flag !== 0 && flag !== "0")
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
function validatedCookie(value, target, nowSeconds) {
|
|
142
|
+
if (!isRecord(value))
|
|
143
|
+
return null;
|
|
144
|
+
if (typeof value.name !== "string" || value.name.length > 1024 || !cookieNamePattern.test(value.name))
|
|
145
|
+
return null;
|
|
146
|
+
if (typeof value.value !== "string" || value.value.length > 64 * 1024 || !cookieValuePattern.test(value.value) && !quotedCookieValuePattern.test(value.value))
|
|
147
|
+
return null;
|
|
148
|
+
if (!hasSafeUnpartitionedProvenance(value))
|
|
149
|
+
return null;
|
|
150
|
+
const domain = candidateDomain(value, target);
|
|
151
|
+
const path = safeCookiePath(value.path);
|
|
152
|
+
const expires = cookieExpiry(value, nowSeconds);
|
|
153
|
+
const sameSite = cookieSameSite(value);
|
|
154
|
+
if (domain === null || path === null || expires === null || sameSite === undefined)
|
|
155
|
+
return null;
|
|
156
|
+
if (!pathMatches(target.pathname || "/", path))
|
|
157
|
+
return null;
|
|
158
|
+
if (value.secure !== undefined && typeof value.secure !== "boolean")
|
|
159
|
+
return null;
|
|
160
|
+
if (value.httpOnly !== undefined && typeof value.httpOnly !== "boolean")
|
|
161
|
+
return null;
|
|
162
|
+
const secure = value.secure === true;
|
|
163
|
+
if (secure && target.protocol !== "https:")
|
|
164
|
+
return null;
|
|
165
|
+
if (sameSite === "None" && !secure)
|
|
166
|
+
return null;
|
|
167
|
+
return {
|
|
168
|
+
name: value.name,
|
|
169
|
+
value: value.value,
|
|
170
|
+
domain: domain.domain,
|
|
171
|
+
hostOnly: domain.hostOnly,
|
|
172
|
+
path,
|
|
173
|
+
secure,
|
|
174
|
+
httpOnly: value.httpOnly === true,
|
|
175
|
+
sameSite,
|
|
176
|
+
expires
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function cookieBytes(cookie) {
|
|
180
|
+
return Buffer.byteLength(`${cookie.domain} ${cookie.path} ${cookie.name} ${cookie.value}
|
|
181
|
+
`, "utf8");
|
|
182
|
+
}
|
|
183
|
+
function filterCookies(values, target, nowSeconds = Math.floor(Date.now() / 1000)) {
|
|
184
|
+
const bounded = values.slice(0, MAX_COOKIE_RECORDS);
|
|
185
|
+
let rejected = Math.max(0, values.length - bounded.length);
|
|
186
|
+
let totalBytes = 0;
|
|
187
|
+
const cookies = new Map;
|
|
188
|
+
for (const value of bounded) {
|
|
189
|
+
const cookie = validatedCookie(value, target, nowSeconds);
|
|
190
|
+
if (cookie === null) {
|
|
191
|
+
rejected += 1;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const key = `${cookie.domain}\x00${cookie.hostOnly ? "host" : "domain"}\x00${cookie.path}\x00${cookie.name}`;
|
|
195
|
+
const previous = cookies.get(key);
|
|
196
|
+
const nextBytes = totalBytes - (previous === undefined ? 0 : cookieBytes(previous)) + cookieBytes(cookie);
|
|
197
|
+
if (nextBytes > MAX_COOKIE_BYTES) {
|
|
198
|
+
rejected += 1;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
cookies.set(key, cookie);
|
|
202
|
+
totalBytes = nextBytes;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
cookies: [...cookies.values()].sort((left, right) => right.path.length - left.path.length || left.name.localeCompare(right.name) || left.domain.localeCompare(right.domain)),
|
|
206
|
+
rejected
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function jsonCookieArray(value) {
|
|
210
|
+
if (isUnknownArray(value))
|
|
211
|
+
return value;
|
|
212
|
+
return isRecord(value) && isUnknownArray(value.cookies) ? value.cookies : null;
|
|
213
|
+
}
|
|
214
|
+
function parseJson(input) {
|
|
215
|
+
try {
|
|
216
|
+
return jsonCookieArray(JSON.parse(input));
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function parseBase64Json(input) {
|
|
222
|
+
const compact = input.replace(/\s+/g, "");
|
|
223
|
+
if (compact === "" || compact.length > MAX_COOKIE_BYTES * 2 || !/^[a-z0-9+/]+=*$/i.test(compact))
|
|
224
|
+
return null;
|
|
225
|
+
try {
|
|
226
|
+
const decoded = Buffer.from(compact, "base64");
|
|
227
|
+
return decoded.byteLength > MAX_COOKIE_BYTES ? null : parseJson(decoded.toString("utf8"));
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function hasExplicitCookieScope(value) {
|
|
233
|
+
if (!isRecord(value))
|
|
234
|
+
return false;
|
|
235
|
+
return typeof value.domain === "string" && value.domain.trim() !== "" || typeof value.url === "string" && value.url.trim() !== "";
|
|
236
|
+
}
|
|
237
|
+
function parseNetscape(input) {
|
|
238
|
+
const cookies = [];
|
|
239
|
+
let looksLikeNetscape = /^# Netscape HTTP Cookie File/im.test(input);
|
|
240
|
+
let cursor = 0;
|
|
241
|
+
while (cursor <= input.length && cookies.length <= MAX_COOKIE_RECORDS) {
|
|
242
|
+
const newline = input.indexOf(`
|
|
243
|
+
`, cursor);
|
|
244
|
+
const lineEnd = newline === -1 ? input.length : newline;
|
|
245
|
+
const rawLine = input.slice(cursor, lineEnd).replace(/\r$/, "");
|
|
246
|
+
cursor = newline === -1 ? input.length + 1 : newline + 1;
|
|
247
|
+
const line = rawLine.trim();
|
|
248
|
+
if (line === "" || line.startsWith("#") && !line.startsWith("#HttpOnly_"))
|
|
249
|
+
continue;
|
|
250
|
+
if (line.length > 80 * 1024)
|
|
251
|
+
continue;
|
|
252
|
+
const columns = line.split("\t", 8);
|
|
253
|
+
if (columns.length < 7)
|
|
254
|
+
continue;
|
|
255
|
+
looksLikeNetscape = true;
|
|
256
|
+
const rawDomain = columns[0];
|
|
257
|
+
const includeSubdomains = columns[1];
|
|
258
|
+
const path = columns[2];
|
|
259
|
+
const secure = columns[3];
|
|
260
|
+
const rawExpires = columns[4];
|
|
261
|
+
const name = columns[5];
|
|
262
|
+
const value = columns.slice(6).join("\t");
|
|
263
|
+
if (rawDomain === undefined || includeSubdomains === undefined || path === undefined || secure === undefined || rawExpires === undefined || name === undefined)
|
|
264
|
+
continue;
|
|
265
|
+
const httpOnly = rawDomain.startsWith("#HttpOnly_");
|
|
266
|
+
const domain = httpOnly ? rawDomain.slice("#HttpOnly_".length) : rawDomain;
|
|
267
|
+
const expires = Number(rawExpires);
|
|
268
|
+
cookies.push({
|
|
269
|
+
name,
|
|
270
|
+
value,
|
|
271
|
+
domain,
|
|
272
|
+
hostOnly: includeSubdomains.toUpperCase() !== "TRUE",
|
|
273
|
+
path,
|
|
274
|
+
secure: secure.toUpperCase() === "TRUE",
|
|
275
|
+
httpOnly,
|
|
276
|
+
...Number.isFinite(expires) && expires > 0 ? { expires } : {}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
return looksLikeNetscape ? cookies : null;
|
|
280
|
+
}
|
|
281
|
+
function unquote(value) {
|
|
282
|
+
const trimmed = value.trim();
|
|
283
|
+
const first = trimmed[0];
|
|
284
|
+
return (first === "'" || first === '"') && trimmed.at(-1) === first ? trimmed.slice(1, -1) : trimmed;
|
|
285
|
+
}
|
|
286
|
+
function parseCookieHeaderValue(value, target) {
|
|
287
|
+
const cookies = [];
|
|
288
|
+
const restrictivePath = target.pathname === "" ? "/" : target.pathname;
|
|
289
|
+
let cursor = 0;
|
|
290
|
+
while (cursor <= value.length && cookies.length <= MAX_COOKIE_RECORDS) {
|
|
291
|
+
const delimiter = value.indexOf(";", cursor);
|
|
292
|
+
const pairEnd = delimiter === -1 ? value.length : delimiter;
|
|
293
|
+
const pair = value.slice(cursor, pairEnd);
|
|
294
|
+
cursor = delimiter === -1 ? value.length + 1 : delimiter + 1;
|
|
295
|
+
const separator = pair.indexOf("=");
|
|
296
|
+
if (separator < 1)
|
|
297
|
+
continue;
|
|
298
|
+
cookies.push({
|
|
299
|
+
name: pair.slice(0, separator).trim(),
|
|
300
|
+
value: pair.slice(separator + 1).trim(),
|
|
301
|
+
domain: target.hostname,
|
|
302
|
+
hostOnly: true,
|
|
303
|
+
path: restrictivePath,
|
|
304
|
+
secure: target.protocol === "https:",
|
|
305
|
+
httpOnly: true,
|
|
306
|
+
sameSite: "Strict"
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return cookies;
|
|
310
|
+
}
|
|
311
|
+
function curlCookieValue(input) {
|
|
312
|
+
const patterns = [
|
|
313
|
+
/(?:^|\s)(?:-b|--cookie)(?:=|\s+)(('[^']*')|("[^"]*")|[^\s]+)/i,
|
|
314
|
+
/(?:^|\s)(?:-H|--header)(?:=|\s+)(('Cookie:\s*[^']*')|("Cookie:\s*[^"]*"))/i
|
|
315
|
+
];
|
|
316
|
+
for (const pattern of patterns) {
|
|
317
|
+
const raw = pattern.exec(input)?.[1];
|
|
318
|
+
if (raw === undefined)
|
|
319
|
+
continue;
|
|
320
|
+
return { value: unquote(raw).replace(/^Cookie:\s*/i, ""), curl: true };
|
|
321
|
+
}
|
|
322
|
+
const header = /^Cookie:\s*([^\r\n]*)$/im.exec(input)?.[1];
|
|
323
|
+
if (header !== undefined)
|
|
324
|
+
return { value: header, curl: false };
|
|
325
|
+
const trimmed = input.trim();
|
|
326
|
+
return !trimmed.includes(`
|
|
327
|
+
`) && trimmed.includes("=") ? { value: trimmed, curl: false } : null;
|
|
328
|
+
}
|
|
329
|
+
function parseCookiePayload(input, target, nowSeconds = Math.floor(Date.now() / 1000)) {
|
|
330
|
+
if (Buffer.byteLength(input, "utf8") > MAX_COOKIE_BYTES)
|
|
331
|
+
return { ok: false, reason: "too-large" };
|
|
332
|
+
if (input.trim() === "")
|
|
333
|
+
return { ok: false, reason: "empty" };
|
|
334
|
+
let values = parseJson(input);
|
|
335
|
+
let format = "json";
|
|
336
|
+
if (values === null) {
|
|
337
|
+
values = parseBase64Json(input);
|
|
338
|
+
format = "base64-json";
|
|
339
|
+
}
|
|
340
|
+
if (values === null) {
|
|
341
|
+
values = parseNetscape(input);
|
|
342
|
+
format = "netscape";
|
|
343
|
+
}
|
|
344
|
+
if (values === null) {
|
|
345
|
+
const header = curlCookieValue(input);
|
|
346
|
+
if (header !== null) {
|
|
347
|
+
values = parseCookieHeaderValue(header.value, target);
|
|
348
|
+
format = header.curl ? "curl" : "cookie-header";
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (values === null)
|
|
352
|
+
return { ok: false, reason: "invalid" };
|
|
353
|
+
const scopeProvenance = format === "netscape" || (format === "json" || format === "base64-json") && values.every(hasExplicitCookieScope) ? "explicit" : "target-inferred";
|
|
354
|
+
const filtered = filterCookies(values, target, nowSeconds);
|
|
355
|
+
return filtered.cookies.length === 0 ? { ok: false, reason: "empty" } : { ok: true, format, scopeProvenance, ...filtered };
|
|
356
|
+
}
|
|
357
|
+
function readCookieFile(path, target, options = {}) {
|
|
358
|
+
let descriptor;
|
|
359
|
+
try {
|
|
360
|
+
const absolute = resolve(path);
|
|
361
|
+
const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
|
|
362
|
+
const nonBlocking = "O_NONBLOCK" in constants ? constants.O_NONBLOCK : 0;
|
|
363
|
+
descriptor = openSync(absolute, constants.O_RDONLY | noFollow | nonBlocking);
|
|
364
|
+
} catch {
|
|
365
|
+
return { ok: false, reason: "unavailable" };
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
options.afterOpen?.();
|
|
369
|
+
const stats = fstatSync(descriptor);
|
|
370
|
+
if (!stats.isFile())
|
|
371
|
+
return { ok: false, reason: "unavailable" };
|
|
372
|
+
if (options.requirePrivate === true && ((stats.mode & 63) !== 0 || typeof process.getuid === "function" && stats.uid !== process.getuid()))
|
|
373
|
+
return { ok: false, reason: "unsafe-permissions" };
|
|
374
|
+
if (stats.size > MAX_COOKIE_BYTES)
|
|
375
|
+
return { ok: false, reason: "too-large" };
|
|
376
|
+
const chunks = [];
|
|
377
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
378
|
+
let total = 0;
|
|
379
|
+
for (;; ) {
|
|
380
|
+
const count = readSync(descriptor, buffer, 0, buffer.byteLength, null);
|
|
381
|
+
if (count === 0)
|
|
382
|
+
break;
|
|
383
|
+
total += count;
|
|
384
|
+
if (total > MAX_COOKIE_BYTES)
|
|
385
|
+
return { ok: false, reason: "too-large" };
|
|
386
|
+
chunks.push(Buffer.from(buffer.subarray(0, count)));
|
|
387
|
+
}
|
|
388
|
+
let text;
|
|
389
|
+
try {
|
|
390
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks, total));
|
|
391
|
+
} catch {
|
|
392
|
+
return { ok: false, reason: "invalid" };
|
|
393
|
+
}
|
|
394
|
+
return parseCookiePayload(text, target);
|
|
395
|
+
} catch {
|
|
396
|
+
return { ok: false, reason: "unavailable" };
|
|
397
|
+
} finally {
|
|
398
|
+
closeSync(descriptor);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function filterCookieProviderResult(value, target) {
|
|
402
|
+
if (!isRecord(value) || !Array.isArray(value.cookies)) {
|
|
403
|
+
return { validShape: false, cookies: [], rejected: 0, providerWarningCount: 0 };
|
|
404
|
+
}
|
|
405
|
+
const provenancePreserving = value.cookies.filter((cookie) => isRecord(cookie) && typeof cookie.hostOnly === "boolean");
|
|
406
|
+
const missingProvenance = value.cookies.length - provenancePreserving.length;
|
|
407
|
+
const filtered = filterCookies(provenancePreserving, target, Math.floor(Date.now() / 1000));
|
|
408
|
+
return {
|
|
409
|
+
validShape: true,
|
|
410
|
+
...filtered,
|
|
411
|
+
rejected: filtered.rejected + missingProvenance,
|
|
412
|
+
providerWarningCount: Array.isArray(value.warnings) ? value.warnings.length : 0
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function renderCookieHeader(cookies) {
|
|
416
|
+
return cookies.map(({ name, value }) => `${name}=${value}`).join("; ");
|
|
417
|
+
}
|
|
418
|
+
function renderNetscapeCookieJar(cookies, target) {
|
|
419
|
+
const hostname = target.hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
420
|
+
return [
|
|
421
|
+
"# Netscape HTTP Cookie File",
|
|
422
|
+
"# Created temporarily by wordcell clip; deleted after media capture.",
|
|
423
|
+
...cookies.map((cookie) => {
|
|
424
|
+
const domain = `${cookie.httpOnly ? "#HttpOnly_" : ""}${hostname}`;
|
|
425
|
+
return `${domain} FALSE ${cookie.path} ${cookie.secure ? "TRUE" : "FALSE"} ${cookie.expires} ${cookie.name} ${cookie.value}`;
|
|
426
|
+
}),
|
|
427
|
+
""
|
|
428
|
+
].join(`
|
|
429
|
+
`);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export { MAX_COOKIE_RECORDS, MAX_COOKIE_BYTES, filterCookies, parseCookiePayload, readCookieFile, filterCookieProviderResult, renderCookieHeader, renderNetscapeCookieJar };
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
fuseRankedCandidates
|
|
4
|
+
} from "./index-why54q5p.js";
|
|
5
|
+
|
|
6
|
+
// src/benchmark.ts
|
|
7
|
+
var MAX_BENCHMARK_CASES = 500;
|
|
8
|
+
var MAX_BENCHMARK_SYSTEMS = 16;
|
|
9
|
+
var MAX_JUDGMENTS_PER_CASE = 1000;
|
|
10
|
+
var MAX_RESULTS_PER_RANKING = 1000;
|
|
11
|
+
var MAX_CUTOFF = 100;
|
|
12
|
+
var MAX_RELEVANCE = 10;
|
|
13
|
+
function checkedCutoff(value) {
|
|
14
|
+
const cutoff = value ?? 10;
|
|
15
|
+
if (!Number.isSafeInteger(cutoff) || cutoff < 1 || cutoff > MAX_CUTOFF) {
|
|
16
|
+
throw new RangeError(`Benchmark cutoff must be an integer from 1 through ${MAX_CUTOFF}.`);
|
|
17
|
+
}
|
|
18
|
+
return cutoff;
|
|
19
|
+
}
|
|
20
|
+
function checkedLabel(value, label) {
|
|
21
|
+
if (value.trim() === "" || value !== value.trim()) {
|
|
22
|
+
throw new Error(`${label} must be non-empty and have no outer whitespace.`);
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function validatedJudgments(judgments) {
|
|
27
|
+
if (judgments.length === 0 || judgments.length > MAX_JUDGMENTS_PER_CASE) {
|
|
28
|
+
throw new RangeError(`A benchmark case requires from 1 through ${MAX_JUDGMENTS_PER_CASE} judgments.`);
|
|
29
|
+
}
|
|
30
|
+
const result = new Map;
|
|
31
|
+
for (const judgment of judgments) {
|
|
32
|
+
const id = checkedLabel(judgment.id, "Judgment id");
|
|
33
|
+
if (result.has(id))
|
|
34
|
+
throw new Error(`Duplicate judgment id: ${id}`);
|
|
35
|
+
if (!Number.isSafeInteger(judgment.relevance) || judgment.relevance < 1 || judgment.relevance > MAX_RELEVANCE) {
|
|
36
|
+
throw new RangeError(`Judgment relevance must be an integer from 1 through ${MAX_RELEVANCE}.`);
|
|
37
|
+
}
|
|
38
|
+
result.set(id, judgment.relevance);
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
function validatedRanking(ids) {
|
|
43
|
+
if (ids.length > MAX_RESULTS_PER_RANKING) {
|
|
44
|
+
throw new RangeError(`A benchmark ranking may contain at most ${MAX_RESULTS_PER_RANKING} results.`);
|
|
45
|
+
}
|
|
46
|
+
const seen = new Set;
|
|
47
|
+
return ids.map((rawId) => {
|
|
48
|
+
const id = checkedLabel(rawId, "Ranking result id");
|
|
49
|
+
if (seen.has(id))
|
|
50
|
+
throw new Error(`Duplicate ranking result id: ${id}`);
|
|
51
|
+
seen.add(id);
|
|
52
|
+
return id;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function discount(rank) {
|
|
56
|
+
return Math.log2(rank + 1);
|
|
57
|
+
}
|
|
58
|
+
function gain(relevance) {
|
|
59
|
+
return 2 ** relevance - 1;
|
|
60
|
+
}
|
|
61
|
+
function metricsForValidatedRanking(ranking, judgments, cutoff) {
|
|
62
|
+
const top = ranking.slice(0, cutoff);
|
|
63
|
+
let relevantRetrieved = 0;
|
|
64
|
+
let firstRelevantRank = null;
|
|
65
|
+
let dcg = 0;
|
|
66
|
+
for (const [index, id] of top.entries()) {
|
|
67
|
+
const relevance = judgments.get(id) ?? 0;
|
|
68
|
+
if (relevance === 0)
|
|
69
|
+
continue;
|
|
70
|
+
relevantRetrieved += 1;
|
|
71
|
+
firstRelevantRank ??= index + 1;
|
|
72
|
+
dcg += gain(relevance) / discount(index + 1);
|
|
73
|
+
}
|
|
74
|
+
const idealDcg = [...judgments.values()].toSorted((left, right) => right - left).slice(0, cutoff).reduce((sum, relevance, index) => sum + gain(relevance) / discount(index + 1), 0);
|
|
75
|
+
return {
|
|
76
|
+
recallAtK: relevantRetrieved / judgments.size,
|
|
77
|
+
mrrAtK: firstRelevantRank === null ? 0 : 1 / firstRelevantRank,
|
|
78
|
+
ndcgAtK: Math.min(1, dcg / idealDcg)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function evaluateRanking(ranking, judgments, cutoff = 10) {
|
|
82
|
+
return metricsForValidatedRanking(validatedRanking(ranking), validatedJudgments(judgments), checkedCutoff(cutoff));
|
|
83
|
+
}
|
|
84
|
+
function averageMetrics(evaluations) {
|
|
85
|
+
if (evaluations.length === 0) {
|
|
86
|
+
return { recallAtK: 0, mrrAtK: 0, ndcgAtK: 0 };
|
|
87
|
+
}
|
|
88
|
+
const totals = evaluations.reduce((sum, evaluation) => ({
|
|
89
|
+
recallAtK: sum.recallAtK + evaluation.metrics.recallAtK,
|
|
90
|
+
mrrAtK: sum.mrrAtK + evaluation.metrics.mrrAtK,
|
|
91
|
+
ndcgAtK: sum.ndcgAtK + evaluation.metrics.ndcgAtK
|
|
92
|
+
}), { recallAtK: 0, mrrAtK: 0, ndcgAtK: 0 });
|
|
93
|
+
return {
|
|
94
|
+
recallAtK: totals.recallAtK / evaluations.length,
|
|
95
|
+
mrrAtK: totals.mrrAtK / evaluations.length,
|
|
96
|
+
ndcgAtK: totals.ndcgAtK / evaluations.length
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function aggregateSystems(cases, systems) {
|
|
100
|
+
return systems.map((system) => {
|
|
101
|
+
const evaluations = cases.map((benchmarkCase) => {
|
|
102
|
+
const evaluation = benchmarkCase.systems.find((item) => item.system === system);
|
|
103
|
+
if (evaluation === undefined) {
|
|
104
|
+
throw new Error(`Missing system ${system} in evaluated case ${benchmarkCase.id}.`);
|
|
105
|
+
}
|
|
106
|
+
return evaluation;
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
system,
|
|
110
|
+
caseCount: evaluations.length,
|
|
111
|
+
metrics: averageMetrics(evaluations)
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function evaluateRetrievalBenchmark(benchmarkCases, options = {}) {
|
|
116
|
+
const cutoff = checkedCutoff(options.cutoff);
|
|
117
|
+
if (benchmarkCases.length === 0 || benchmarkCases.length > MAX_BENCHMARK_CASES) {
|
|
118
|
+
throw new RangeError(`A retrieval benchmark requires from 1 through ${MAX_BENCHMARK_CASES} cases.`);
|
|
119
|
+
}
|
|
120
|
+
const caseIds = new Set;
|
|
121
|
+
let expectedSystems = null;
|
|
122
|
+
const evaluated = benchmarkCases.map((benchmarkCase) => {
|
|
123
|
+
const id = checkedLabel(benchmarkCase.id, "Benchmark case id");
|
|
124
|
+
const queryClass = checkedLabel(benchmarkCase.queryClass, "Query class");
|
|
125
|
+
if (caseIds.has(id))
|
|
126
|
+
throw new Error(`Duplicate benchmark case id: ${id}`);
|
|
127
|
+
caseIds.add(id);
|
|
128
|
+
const judgments = validatedJudgments(benchmarkCase.judgments);
|
|
129
|
+
if (benchmarkCase.rankings.length === 0 || benchmarkCase.rankings.length > MAX_BENCHMARK_SYSTEMS) {
|
|
130
|
+
throw new RangeError(`A benchmark case requires from 1 through ${MAX_BENCHMARK_SYSTEMS} systems.`);
|
|
131
|
+
}
|
|
132
|
+
const systemNames = new Set;
|
|
133
|
+
const systems2 = benchmarkCase.rankings.map((ranking) => {
|
|
134
|
+
const system = checkedLabel(ranking.system, "Benchmark system");
|
|
135
|
+
if (systemNames.has(system))
|
|
136
|
+
throw new Error(`Duplicate benchmark system: ${system}`);
|
|
137
|
+
systemNames.add(system);
|
|
138
|
+
return {
|
|
139
|
+
system,
|
|
140
|
+
metrics: metricsForValidatedRanking(validatedRanking(ranking.ids), judgments, cutoff)
|
|
141
|
+
};
|
|
142
|
+
}).toSorted((left, right) => left.system.localeCompare(right.system));
|
|
143
|
+
const names = systems2.map(({ system }) => system);
|
|
144
|
+
if (expectedSystems === null) {
|
|
145
|
+
expectedSystems = names;
|
|
146
|
+
} else if (names.length !== expectedSystems.length || names.some((name, index) => name !== expectedSystems?.[index])) {
|
|
147
|
+
throw new Error("Every benchmark case must contain the same systems.");
|
|
148
|
+
}
|
|
149
|
+
return { id, queryClass, systems: systems2 };
|
|
150
|
+
}).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
151
|
+
const systems = expectedSystems ?? [];
|
|
152
|
+
const queryClasses = [...new Set(evaluated.map(({ queryClass }) => queryClass))].toSorted((left, right) => left.localeCompare(right));
|
|
153
|
+
return {
|
|
154
|
+
cutoff,
|
|
155
|
+
cases: evaluated,
|
|
156
|
+
overall: aggregateSystems(evaluated, systems),
|
|
157
|
+
byClass: queryClasses.map((queryClass) => {
|
|
158
|
+
const matching = evaluated.filter((item) => item.queryClass === queryClass);
|
|
159
|
+
return {
|
|
160
|
+
queryClass,
|
|
161
|
+
caseCount: matching.length,
|
|
162
|
+
systems: aggregateSystems(matching, systems)
|
|
163
|
+
};
|
|
164
|
+
})
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function fixtureCase(id, queryClass, judgments, exact, semanticLike) {
|
|
168
|
+
const hybrid = fuseRankedCandidates([
|
|
169
|
+
{ name: "exact", weight: 1, ids: exact },
|
|
170
|
+
{ name: "semantic-like", weight: 1, ids: semanticLike }
|
|
171
|
+
]).map(({ id: resultId }) => resultId);
|
|
172
|
+
return {
|
|
173
|
+
id,
|
|
174
|
+
queryClass,
|
|
175
|
+
judgments,
|
|
176
|
+
rankings: [
|
|
177
|
+
{ system: "exact", ids: exact },
|
|
178
|
+
{ system: "hybrid-rrf", ids: hybrid },
|
|
179
|
+
{ system: "semantic-like", ids: semanticLike }
|
|
180
|
+
]
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function createSyntheticRankFusionFixture() {
|
|
184
|
+
return [
|
|
185
|
+
fixtureCase("alias-identity", "identity", [{ id: "write-path", relevance: 3 }, { id: "agent-memory", relevance: 1 }], ["write-path", "agent-memory", "durable-notes"], ["durable-notes", "context-window", "write-path", "agent-memory"]),
|
|
186
|
+
fixtureCase("literal-title", "identity", [{ id: "repository-context", relevance: 3 }], ["repository-context", "repository-map"], ["repository-map", "repository-context", "shared-context"]),
|
|
187
|
+
fixtureCase("paraphrased-memory", "conceptual", [{ id: "durable-memory", relevance: 3 }, { id: "write-path", relevance: 1 }], ["chat-history", "context-window", "durable-memory", "write-path"], ["durable-memory", "write-path", "chat-history"]),
|
|
188
|
+
fixtureCase("meaning-without-keywords", "conceptual", [{ id: "retrieval-fusion", relevance: 3 }, { id: "local-search", relevance: 2 }], ["retrieval-fusion", "ranking-noise", "local-search"], ["embedding-noise", "retrieval-fusion", "local-search"]),
|
|
189
|
+
fixtureCase("implementation-decision", "mixed", [
|
|
190
|
+
{ id: "decision", relevance: 3 },
|
|
191
|
+
{ id: "evidence", relevance: 2 },
|
|
192
|
+
{ id: "history", relevance: 1 }
|
|
193
|
+
], ["decision", "filename-noise", "evidence", "tag-noise", "history"], ["semantic-noise", "evidence", "decision", "history"]),
|
|
194
|
+
fixtureCase("plan-context", "mixed", [{ id: "active-plan", relevance: 3 }, { id: "prior-rationale", relevance: 2 }], ["active-plan", "status-noise", "prior-rationale"], ["concept-noise", "prior-rationale", "active-plan"])
|
|
195
|
+
];
|
|
196
|
+
}
|
|
197
|
+
var createRepresentativeRetrievalFixture = createSyntheticRankFusionFixture;
|
|
198
|
+
|
|
199
|
+
export { evaluateRanking, evaluateRetrievalBenchmark, createSyntheticRankFusionFixture, createRepresentativeRetrievalFixture };
|