lurqrun 0.1.7 → 0.1.9

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.
Files changed (122) hide show
  1. package/README.md +312 -148
  2. package/dist/{auditHandler-JCOJSUYW.js → auditHandler-G7PHKMZR.js} +12 -11
  3. package/dist/autopilotInit-JO2SH5K3.js +266 -0
  4. package/dist/bin/lurq.js +238 -83
  5. package/dist/{browserAuth-B6G27USY.js → browserAuth-PVYODBNR.js} +4 -3
  6. package/dist/{cache-DKI34SVS.js → cache-ND4VOUVY.js} +2 -2
  7. package/dist/check-A3FJE62G.js +2613 -0
  8. package/dist/{check-2FDGUOV7.js → check-PQSQ2MMA.js} +1 -1
  9. package/dist/checkUpgrade-Q4CV7GXG.js +24 -0
  10. package/dist/{chunk-BCANRN5B.js → chunk-2GAYNIHG.js} +8 -1
  11. package/dist/chunk-2LXYRDUN.js +92 -0
  12. package/dist/chunk-2XMD4H2I.js +243 -0
  13. package/dist/chunk-3D2MPGOQ.js +181 -0
  14. package/dist/chunk-53SG6XWA.js +141 -0
  15. package/dist/chunk-5ABNDB3I.js +37 -0
  16. package/dist/chunk-5ALIJFDA.js +114 -0
  17. package/dist/{chunk-LYMPYETA.js → chunk-6353IJJ5.js} +270 -6
  18. package/dist/{chunk-M6NYEXCW.js → chunk-64DPQSXV.js} +1 -1
  19. package/dist/chunk-64YOP5BQ.js +320 -0
  20. package/dist/{chunk-2VMOWSRY.js → chunk-6DM6UQFD.js} +19 -1
  21. package/dist/{chunk-NH5I4KHH.js → chunk-75LMEMJ3.js} +1 -5
  22. package/dist/{chunk-FW6BD2NO.js → chunk-ABH4BTK4.js} +458 -121
  23. package/dist/chunk-AHRDDKNO.js +90 -0
  24. package/dist/chunk-AQ6IVSFB.js +119 -0
  25. package/dist/chunk-BM3LF5T6.js +132 -0
  26. package/dist/chunk-D3K6IZVR.js +12845 -0
  27. package/dist/chunk-DONTW3NE.js +171 -0
  28. package/dist/{chunk-UDVNA7EA.js → chunk-ETY4FSOW.js} +161 -8
  29. package/dist/{chunk-VL2E5T2A.js → chunk-FHRT32JH.js} +6 -3
  30. package/dist/{chunk-DWAGCNEL.js → chunk-GM5Y555O.js} +36 -103
  31. package/dist/{chunk-6L3U7DZ5.js → chunk-GNNGXVCG.js} +1 -1
  32. package/dist/{chunk-PSX3GIAN.js → chunk-HWFX4BC4.js} +2 -1
  33. package/dist/{checkUpgrade-F2WESBPM.js → chunk-ILKYIVYV.js} +72 -10
  34. package/dist/{chunk-HWBBVLOT.js → chunk-J3NUERU7.js} +1 -1
  35. package/dist/chunk-J3U2CPSK.js +136 -0
  36. package/dist/{chunk-Y5GI7RL3.js → chunk-J6XQ7OPZ.js} +9 -1
  37. package/dist/{chunk-3N3Q3DSW.js → chunk-JGIJZJ3X.js} +8 -8
  38. package/dist/{chunk-DB2VF5UD.js → chunk-JJCQVOC6.js} +16 -11
  39. package/dist/{chunk-LBFGSSF2.js → chunk-KMV4Y6R3.js} +2 -1
  40. package/dist/{chunk-L6N4JFW2.js → chunk-KP5ZDDPE.js} +81 -4
  41. package/dist/{chunk-CW5HJ3LX.js → chunk-KT7PWDNV.js} +1 -1
  42. package/dist/{chunk-SJOVFF7B.js → chunk-KYKSZ3XZ.js} +3 -2
  43. package/dist/{chunk-GPTKSNR6.js → chunk-L3V7AVM6.js} +2 -1
  44. package/dist/{chunk-CUP36ND3.js → chunk-M2CYYBAH.js} +145 -36
  45. package/dist/{chunk-IQ4SDKKY.js → chunk-N2NYPTRU.js} +31 -228
  46. package/dist/chunk-N4TJO44E.js +603 -0
  47. package/dist/chunk-NEZNAPPN.js +41 -0
  48. package/dist/{chunk-WQ23REYT.js → chunk-NGMJQBOV.js} +1 -1
  49. package/dist/{chunk-BULZAX2U.js → chunk-POHTPT37.js} +55 -38
  50. package/dist/{chunk-EA3DP5HG.js → chunk-PZZU3FQY.js} +155 -25
  51. package/dist/{chunk-4F7ZESPO.js → chunk-Q7CMOU5C.js} +3 -5
  52. package/dist/{chunk-LRD4GBYE.js → chunk-QUIMQ7YL.js} +1 -1
  53. package/dist/chunk-RG3YLU6E.js +49 -0
  54. package/dist/{chunk-4ZYCIMY4.js → chunk-SFY5MPJE.js} +25 -4
  55. package/dist/{chunk-ST2X2GYN.js → chunk-SHZFOSXC.js} +109 -20
  56. package/dist/{chunk-CIDWNUAP.js → chunk-SOXFMMXC.js} +8 -2
  57. package/dist/{chunk-B43LCXBM.js → chunk-SWMWVK2R.js} +81 -16
  58. package/dist/{chunk-J5FZYN4A.js → chunk-TVOCVIM7.js} +1 -1
  59. package/dist/{chunk-U5AT3TD4.js → chunk-X4W64MHU.js} +1735 -1858
  60. package/dist/{chunk-BV32UNLL.js → chunk-XA2SLNBR.js} +2 -2
  61. package/dist/{chunk-AHBP533R.js → chunk-XBTYJQEK.js} +7 -5
  62. package/dist/chunk-XGOV6KV4.js +413 -0
  63. package/dist/{chunk-OQS4GUSI.js → chunk-XIFQIFSZ.js} +210 -661
  64. package/dist/{chunk-XBIDMHSK.js → chunk-XLXPVN3Y.js} +2 -34
  65. package/dist/{chunk-LO35HLQZ.js → chunk-ZJ5XHA77.js} +25 -4
  66. package/dist/{client-IRKAMDYZ.js → client-SJIWK4CK.js} +3 -3
  67. package/dist/{commands-FIL5ET6P.js → commands-6BBLN5N5.js} +145 -33
  68. package/dist/{compat-R3UTFQ5Q.js → compat-6B3CRT5F.js} +6 -6
  69. package/dist/constants-HX3RTD6Q.js +24 -0
  70. package/dist/{dashboardIssue-WYYMBFIB.js → dashboardIssue-KBKLQMGC.js} +105 -23
  71. package/dist/{diff-GZA2774U.js → diff-I4SNUHU3.js} +1 -1
  72. package/dist/domains-RKRPVP5A.js +14 -0
  73. package/dist/env-UN6KGZ7S.js +15 -0
  74. package/dist/envCheck-IL22OTSC.js +71 -0
  75. package/dist/{extract-NKGKLIVT.js → extract-6WG265BL.js} +14 -3
  76. package/dist/{fetch-QYTUJVG2.js → fetch-GHIP3VHN.js} +4 -4
  77. package/dist/{firstTouch-QQTJH4QX.js → firstTouch-M64T2MWF.js} +1 -1
  78. package/dist/fix-Z7ZY55HB.js +220 -0
  79. package/dist/{handlers-GEJAVZDK.js → handlers-GOXW2GWZ.js} +19 -17
  80. package/dist/hook-TWFLIDK3.js +412 -0
  81. package/dist/{http-ETPYMBGD.js → http-7VF2RE2D.js} +2097 -509
  82. package/dist/{ingestQueue-VKN4KBIF.js → ingestQueue-RSEPMORK.js} +14 -12
  83. package/dist/{install-EK3W2COX.js → install-55EPX34C.js} +6 -6
  84. package/dist/{installSkill-VQJWJVCL.js → installSkill-A7KKPDMS.js} +21 -3
  85. package/dist/manifest-ENMIC54B.js +13 -0
  86. package/dist/{mcp-3JHD5SUZ.js → mcp-CM6CDLHM.js} +60 -32
  87. package/dist/mcpConfig-FENV6NI7.js +80 -0
  88. package/dist/{mcpHandlers-QFN4MCFL.js → mcpHandlers-2UCLKMWN.js} +7 -7
  89. package/dist/{mcpScan-QZHWENIP.js → mcpScan-CKBQNK5H.js} +306 -442
  90. package/dist/{mcpScanWorkflow-JPYCBGC4.js → mcpScanWorkflow-NFUD3S7U.js} +29 -12
  91. package/dist/{mcpStack-BYJCZNIV.js → mcpStack-FLQ6XY2P.js} +1 -1
  92. package/dist/model-ASMZWLM7.js +214 -0
  93. package/dist/{packages-THVFMWFP.js → packages-2XRHNBJ7.js} +3 -5
  94. package/dist/{plan-V4OEI3J4.js → plan-XRZS6C7Z.js} +23 -21
  95. package/dist/{planView-JRXGCG2N.js → planView-ZAKRTGVS.js} +4 -1
  96. package/dist/{policy-3P6BGRDN.js → policy-EQT43P7S.js} +5 -5
  97. package/dist/probe-ZEZFNIQZ.js +610 -0
  98. package/dist/publicUpgrades-JZEOV24A.js +42 -0
  99. package/dist/{references-6N7VEPHT.js → references-I6Y4BSRR.js} +3 -1
  100. package/dist/{release-4U4ABNSJ.js → release-EUOM5I3R.js} +5 -5
  101. package/dist/{remote-YGCXYI4V.js → remote-I5O43WAY.js} +13 -3
  102. package/dist/rename-OS6JYBZQ.js +204 -0
  103. package/dist/{reportRuns-CKQQYLY4.js → reportRuns-O4X7ZFTX.js} +15 -2
  104. package/dist/safeFetch-COERXGFN.js +19 -0
  105. package/dist/{sandbox-MEZLAODF.js → sandbox-46TZNYZT.js} +4 -4
  106. package/dist/sarif-WLVJFJ7U.js +125 -0
  107. package/dist/server-LROMHS62.js +59 -0
  108. package/dist/{surface-YL6O67W3.js → surface-CZMHQLV3.js} +5 -3
  109. package/dist/{surface-V62GE554.js → surface-OH4TZR32.js} +18 -16
  110. package/dist/{surfaceHandlers-X2IZKA3E.js → surfaceHandlers-BDYRZMAC.js} +5 -5
  111. package/dist/{typecheck-X7U5ELMR.js → typecheck-NGOKNAJY.js} +23 -9
  112. package/dist/{uninstall-P7RGBX6G.js → uninstall-4E5YUDQO.js} +30 -4
  113. package/dist/{upgrade-NQ5IWFZB.js → upgrade-S72W7JVC.js} +86 -32
  114. package/dist/{upgradePlan-A4LRKLEG.js → upgradePlan-F3OUNL3E.js} +46 -11
  115. package/dist/upkeepHandler-7Q56A4UA.js +13 -0
  116. package/dist/{userConfig-Z3GQE776.js → userConfig-ICASHI47.js} +1 -1
  117. package/dist/{watch-DGFMWUDL.js → watch-LZPOKWCL.js} +24 -34
  118. package/package.json +3 -2
  119. package/templates/skill-instructions.md +22 -3
  120. package/dist/chunk-6AAEVQ7I.js +0 -6336
  121. package/dist/chunk-I2JUKN6Z.js +0 -24
  122. package/dist/server-KFUD5X57.js +0 -55
@@ -0,0 +1,320 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ handleDiffSurface
4
+ } from "./chunk-JJCQVOC6.js";
5
+ import {
6
+ getPackageByName
7
+ } from "./chunk-75LMEMJ3.js";
8
+ import {
9
+ enqueueSurface
10
+ } from "./chunk-ZJ5XHA77.js";
11
+ import {
12
+ packages,
13
+ surfaceQueue
14
+ } from "./chunk-6353IJJ5.js";
15
+ import {
16
+ require_semver
17
+ } from "./chunk-3GHJR7XR.js";
18
+ import {
19
+ logger
20
+ } from "./chunk-MYGSLK44.js";
21
+ import {
22
+ __toESM,
23
+ init_esm_shims
24
+ } from "./chunk-I3M2KJXB.js";
25
+
26
+ // src/mcp/publicUpgrades.ts
27
+ init_esm_shims();
28
+ var import_semver = __toESM(require_semver(), 1);
29
+ import { and as and2, count, desc as desc2, gte, isNotNull as isNotNull2, sql } from "drizzle-orm";
30
+
31
+ // src/mcp/publicSet.ts
32
+ init_esm_shims();
33
+ import { and, desc, isNotNull } from "drizzle-orm";
34
+ var PUBLIC_TOP_LIMIT = 5e3;
35
+ var NPM_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/i;
36
+ function validPackageName(name) {
37
+ return name.length > 0 && name.length <= 214 && NPM_NAME.test(name);
38
+ }
39
+ var floor = null;
40
+ async function publicDownloadFloor(db) {
41
+ if (floor && Date.now() - floor.at < 36e5) return floor.value;
42
+ const rows = await db.select({ downloads: packages.weeklyDownloads }).from(packages).where(and(isNotNull(packages.weeklyDownloads), isNotNull(packages.healthScore))).orderBy(desc(packages.weeklyDownloads)).offset(PUBLIC_TOP_LIMIT - 1).limit(1);
43
+ floor = { at: Date.now(), value: Number(rows[0]?.downloads ?? 0) };
44
+ return floor.value;
45
+ }
46
+ async function publicPackageRow(db, name) {
47
+ const [row, min] = await Promise.all([getPackageByName(db, name), publicDownloadFloor(db)]);
48
+ if (!row || row.healthScore === null || (row.weeklyDownloads ?? 0) < min) return null;
49
+ return row;
50
+ }
51
+
52
+ // src/mcp/publicUpgrades.ts
53
+ var PAIRS_PER_PACKAGE = 3;
54
+ var LIST_CAP = 500;
55
+ function majorPairs(latest, keep = PAIRS_PER_PACKAGE) {
56
+ const sorted = [...latest].sort((a, b) => a.major - b.major);
57
+ const pairs = [];
58
+ for (let i = 1; i < sorted.length; i++) {
59
+ const from = sorted[i - 1];
60
+ const to = sorted[i];
61
+ pairs.push({
62
+ fromMajor: from.major,
63
+ toMajor: to.major,
64
+ fromVersion: from.version,
65
+ toVersion: to.version,
66
+ ready: from.stored && to.stored
67
+ });
68
+ }
69
+ return pairs.slice(-keep);
70
+ }
71
+ function unextractedSides(latest, keep = PAIRS_PER_PACKAGE) {
72
+ if (latest.length < 2) return [];
73
+ const involved = [...latest].sort((a, b) => a.major - b.major).slice(-(keep + 1));
74
+ return involved.reverse().filter((l) => !l.stored && !l.attempted).map((l) => l.version);
75
+ }
76
+ function upgradeVerdict(d) {
77
+ if (d.inconclusive) return "unknown";
78
+ if (d.removed.length > 0 || d.renamed.length > 0) return "removes-exports";
79
+ if (d.arityChanged.length > 0) return "arity-changed";
80
+ if (d.typeOnlyRemoved.length > 0) return "types-only";
81
+ return "clean";
82
+ }
83
+ function toPublicUpgrade(pkg, pair, diff) {
84
+ const renamedPaths = new Set(diff.renamed.map((r) => r.path));
85
+ const removed = diff.removed.filter((r) => !renamedPaths.has(r.path));
86
+ const lists = [
87
+ removed,
88
+ diff.renamed,
89
+ diff.arityChanged,
90
+ diff.typeOnlyRemoved,
91
+ diff.deprecated
92
+ ];
93
+ const cap = (xs) => xs.slice(0, LIST_CAP);
94
+ return {
95
+ package: pkg,
96
+ pair,
97
+ status: "ready",
98
+ verdict: upgradeVerdict({ ...diff, removed }),
99
+ removed: cap(removed.map((r) => ({ path: r.path, kind: r.kind }))),
100
+ renamed: cap(diff.renamed),
101
+ arityChanged: cap(diff.arityChanged),
102
+ typeOnlyRemoved: cap(diff.typeOnlyRemoved),
103
+ deprecated: cap(diff.deprecated),
104
+ added: diff.added.length,
105
+ truncated: lists.some((l) => l.length > LIST_CAP),
106
+ tier: diff.tier ?? null,
107
+ inconclusive: diff.inconclusive ?? null,
108
+ observedAt: diff.observedAt ? new Date(diff.observedAt).toISOString() : null
109
+ };
110
+ }
111
+ function pendingUpgrade(pkg, pair) {
112
+ return {
113
+ package: pkg,
114
+ pair,
115
+ status: "pending",
116
+ verdict: "unknown",
117
+ removed: [],
118
+ renamed: [],
119
+ arityChanged: [],
120
+ typeOnlyRemoved: [],
121
+ deprecated: [],
122
+ added: 0,
123
+ truncated: false,
124
+ tier: null,
125
+ inconclusive: "Both versions are queued for extraction. NOT evidence that nothing changed.",
126
+ observedAt: null
127
+ };
128
+ }
129
+ function rowsOf(result) {
130
+ return result.rows ?? result;
131
+ }
132
+ async function latestOfMajors(db, names) {
133
+ const out = /* @__PURE__ */ new Map();
134
+ if (names.length === 0) return out;
135
+ const result = await db.execute(sql`
136
+ with stable as (
137
+ select package_name, version, (regexp_match(version, '^([0-9]+)\\.'))[1]::int as major
138
+ from package_versions
139
+ where package_name in (${sql.join(
140
+ names.map((n) => sql`${n}`),
141
+ sql`, `
142
+ )})
143
+ -- Stable releases only: an upgrade does not land on a prerelease.
144
+ and version ~ '^[0-9]+\\.[0-9]+\\.[0-9]+$'
145
+ ),
146
+ latest as (
147
+ select distinct on (package_name, major) package_name, major, version
148
+ from stable
149
+ -- Numeric, not lexical (16.10.0 is newer than 16.9.0), and numeric rather
150
+ -- than int so a date-stamped version cannot overflow the cast.
151
+ order by package_name, major, string_to_array(version, '.')::numeric[] desc
152
+ )
153
+ select
154
+ l.package_name,
155
+ l.major,
156
+ l.version,
157
+ exists (
158
+ select 1 from entities e
159
+ join symbols s on s.entity_id = e.id and s.tier = 'shipped_js_ast'
160
+ where e.canonical_key = 'package_surface:npm:' || l.package_name || ':' || l.version
161
+ and e.tenant_id = 0
162
+ ) as stored,
163
+ exists (
164
+ select 1 from entities e
165
+ where e.canonical_key = 'package_surface:npm:' || l.package_name || ':' || l.version
166
+ and e.tenant_id = 0
167
+ ) as attempted
168
+ from latest l
169
+ `);
170
+ for (const r of rowsOf(result)) {
171
+ const list = out.get(r.package_name) ?? [];
172
+ list.push({
173
+ major: Number(r.major),
174
+ version: r.version,
175
+ stored: Boolean(r.stored),
176
+ attempted: Boolean(r.attempted)
177
+ });
178
+ out.set(r.package_name, list);
179
+ }
180
+ return out;
181
+ }
182
+ async function upgradePairsFor(db, name) {
183
+ return majorPairs((await latestOfMajors(db, [name])).get(name) ?? []);
184
+ }
185
+ async function upgradeGuideFor(db, pkg, fromVersion, toVersion, webUrl) {
186
+ const from = import_semver.default.coerce(fromVersion)?.major;
187
+ const to = import_semver.default.coerce(toVersion)?.major;
188
+ if (from === void 0 || to === void 0 || to <= from) return null;
189
+ if (!await publicPackageRow(db, pkg)) return null;
190
+ const pair = (await upgradePairsFor(db, pkg)).find(
191
+ (p) => p.fromMajor === from && p.toMajor === to && p.ready
192
+ );
193
+ if (!pair) return null;
194
+ const path = `/npm/${pkg.split("/").map(encodeURIComponent).join("/")}/${from}-to-${to}`;
195
+ return {
196
+ url: `${webUrl.replace(/\/$/, "")}${path}`,
197
+ fromVersion: pair.fromVersion,
198
+ toVersion: pair.toVersion
199
+ };
200
+ }
201
+ async function publicNames(db, limit = PUBLIC_TOP_LIMIT) {
202
+ const min = await publicDownloadFloor(db);
203
+ const rows = await db.select({ name: packages.name }).from(packages).where(and2(isNotNull2(packages.healthScore), gte(packages.weeklyDownloads, min))).orderBy(desc2(packages.weeklyDownloads)).limit(limit);
204
+ return rows.map((r) => r.name);
205
+ }
206
+ var QUEUE_HEADROOM = 20;
207
+ async function enqueuePublicUpgrades(db, opts = {}) {
208
+ const [{ pending } = { pending: 0 }] = await db.select({ pending: count() }).from(surfaceQueue);
209
+ let budget = QUEUE_HEADROOM - Number(pending);
210
+ if (budget <= 0) return 0;
211
+ const names = await publicNames(db, opts.packages ?? 1e3);
212
+ let queued = 0;
213
+ for (let i = 0; i < names.length && budget > 0; i += 250) {
214
+ const chunk = names.slice(i, i + 250);
215
+ const latest = await latestOfMajors(db, chunk);
216
+ for (const name of chunk) {
217
+ for (const version of unextractedSides(latest.get(name) ?? [])) {
218
+ if (budget <= 0) break;
219
+ await enqueueSurface(db, name, version);
220
+ queued++;
221
+ budget--;
222
+ }
223
+ if (budget <= 0) break;
224
+ }
225
+ }
226
+ return queued;
227
+ }
228
+ function registerPublicUpgradeRoutes(app, db, limiter) {
229
+ const cacheable = (res) => res.setHeader("Cache-Control", "public, max-age=3600, s-maxage=86400");
230
+ app.get("/public/upgrade", limiter, async (req, res) => {
231
+ const name = typeof req.query.name === "string" ? req.query.name.trim() : "";
232
+ const from = Number(req.query.from);
233
+ const to = Number(req.query.to);
234
+ if (!validPackageName(name) || !Number.isInteger(from) || !Number.isInteger(to) || from < 0 || to <= from) {
235
+ res.status(400).json({ error: "Give an npm package name and two majors, from < to." });
236
+ return;
237
+ }
238
+ try {
239
+ if (!await publicPackageRow(db, name)) {
240
+ res.status(404).json({ error: "No public upgrade pages for that package." });
241
+ return;
242
+ }
243
+ const pairs = await upgradePairsFor(db, name);
244
+ const pair = pairs.find((p) => p.fromMajor === from && p.toMajor === to);
245
+ if (!pair) {
246
+ res.status(404).json({ error: "No upgrade page for that version jump.", pairs });
247
+ return;
248
+ }
249
+ if (!pair.ready) {
250
+ await Promise.all([
251
+ enqueueSurface(db, name, pair.fromVersion),
252
+ enqueueSurface(db, name, pair.toVersion)
253
+ ]).catch(() => {
254
+ });
255
+ res.setHeader("Cache-Control", "public, max-age=300, s-maxage=900");
256
+ res.json(pendingUpgrade(name, pair));
257
+ return;
258
+ }
259
+ const diff = await handleDiffSurface(db, {
260
+ package: name,
261
+ fromVersion: pair.fromVersion,
262
+ toVersion: pair.toVersion
263
+ });
264
+ const body = toPublicUpgrade(name, pair, diff);
265
+ if (body.verdict === "unknown")
266
+ res.setHeader("Cache-Control", "public, max-age=300, s-maxage=900");
267
+ else cacheable(res);
268
+ res.json(body);
269
+ } catch (err) {
270
+ logger.error("public upgrade read failed:", err instanceof Error ? err.message : String(err));
271
+ res.status(500).json({ error: "Could not read that upgrade." });
272
+ }
273
+ });
274
+ let index = null;
275
+ app.get("/public/upgrades", limiter, async (_req, res) => {
276
+ try {
277
+ if (!index || Date.now() - index.at > 36e5) {
278
+ const names = await publicNames(db);
279
+ const value = [];
280
+ for (let i = 0; i < names.length; i += 500) {
281
+ const chunk = names.slice(i, i + 500);
282
+ const latest = await latestOfMajors(db, chunk);
283
+ for (const name of chunk) {
284
+ const ready = majorPairs(latest.get(name) ?? []).filter((p) => p.ready);
285
+ if (ready.length) value.push({ package: name, pairs: ready });
286
+ }
287
+ }
288
+ index = { at: Date.now(), value };
289
+ }
290
+ cacheable(res);
291
+ res.json({ upgrades: index.value });
292
+ } catch (err) {
293
+ logger.error(
294
+ "public upgrade index failed:",
295
+ err instanceof Error ? err.message : String(err)
296
+ );
297
+ res.status(500).json({ error: "Could not list upgrade pages." });
298
+ }
299
+ });
300
+ }
301
+
302
+ export {
303
+ PUBLIC_TOP_LIMIT,
304
+ validPackageName,
305
+ publicDownloadFloor,
306
+ publicPackageRow,
307
+ PAIRS_PER_PACKAGE,
308
+ LIST_CAP,
309
+ majorPairs,
310
+ unextractedSides,
311
+ upgradeVerdict,
312
+ toPublicUpgrade,
313
+ pendingUpgrade,
314
+ latestOfMajors,
315
+ upgradePairsFor,
316
+ upgradeGuideFor,
317
+ QUEUE_HEADROOM,
318
+ enqueuePublicUpgrades,
319
+ registerPublicUpgradeRoutes
320
+ };
@@ -115,12 +115,29 @@ var FIELD = {
115
115
  /** Reports at or above this cap the confidence note as fully-evidenced. */
116
116
  wellEvidencedReports: 25
117
117
  };
118
+ var DISCOVERY = {
119
+ /** A queued candidate must clear this quality pre-score to graduate to ingest. */
120
+ minPreScore: 45,
121
+ /** Max candidates fully ingested per crawler run (cost bound). */
122
+ perRunCap: 25,
123
+ /** npm-search hits to pull per category keyword. */
124
+ searchSizePerCategory: 10,
125
+ /** Max dependency-graph neighbors to enqueue per tracked seed. */
126
+ graphNeighborsPerSeed: 20,
127
+ /** Ingest failures a candidate gets before it is marked `failed` and stops
128
+ * being retried. Three, because the failures worth retrying are transient
129
+ * (a registry 5xx, a GitHub rate limit) and clear within an hour or two,
130
+ * while the ones that are not — a manifest we cannot parse — would otherwise
131
+ * re-buy an LLM summary every cycle for as long as the crawler runs. */
132
+ maxIngestAttempts: 3
133
+ };
118
134
  var DEFAULT_WEIGHTS = {
119
135
  health: { ...HEALTH_WEIGHTS },
120
136
  composite: { ...COMPOSITE }
121
137
  };
122
138
  function activeWeightsPath() {
123
- if (existsSync(projectWeightsPath())) return { path: projectWeightsPath(), source: "project-config" };
139
+ if (existsSync(projectWeightsPath()))
140
+ return { path: projectWeightsPath(), source: "project-config" };
124
141
  if (existsSync(userWeightsPath())) return { path: userWeightsPath(), source: "user-config" };
125
142
  return null;
126
143
  }
@@ -288,6 +305,7 @@ export {
288
305
  RELIABILITY,
289
306
  EFFICIENCY,
290
307
  FIELD,
308
+ DISCOVERY,
291
309
  activeWeightsPath,
292
310
  loadWeights,
293
311
  validateWeights,
@@ -7,7 +7,7 @@ import {
7
7
  packages,
8
8
  seedPackages,
9
9
  syncRuns
10
- } from "./chunk-LYMPYETA.js";
10
+ } from "./chunk-6353IJJ5.js";
11
11
  import {
12
12
  logger
13
13
  } from "./chunk-MYGSLK44.js";
@@ -108,9 +108,6 @@ async function getTopPackageNames(db, limit = 1e3) {
108
108
  const rows = await db.select({ name: packages.name }).from(packages).where(isNotNull(packages.weeklyDownloads)).orderBy(desc(packages.weeklyDownloads)).limit(limit);
109
109
  return rows.map((r) => r.name);
110
110
  }
111
- async function ensureSeedEntry(db, name, category) {
112
- await db.insert(seedPackages).values({ name, category }).onConflictDoNothing({ target: seedPackages.name });
113
- }
114
111
  async function upsertPackage(db, row) {
115
112
  const { name: _name, ecosystem: _ecosystem, createdAt: _createdAt, ...mutable } = row;
116
113
  await db.insert(packages).values(row).onConflictDoUpdate({
@@ -192,7 +189,6 @@ export {
192
189
  upsertPackageVersions,
193
190
  getPackageVersions,
194
191
  getTopPackageNames,
195
- ensureSeedEntry,
196
192
  upsertPackage,
197
193
  stampFirstRequester,
198
194
  getContributionsByOwner,