lurqrun 0.1.6 → 0.1.7

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 (206) hide show
  1. package/README.md +18 -10
  2. package/dist/auditHandler-JCOJSUYW.js +23 -0
  3. package/dist/bin/lurq.js +3090 -23306
  4. package/dist/browserAuth-B6G27USY.js +95 -0
  5. package/dist/cache-DKI34SVS.js +12 -0
  6. package/dist/check-2FDGUOV7.js +192 -0
  7. package/dist/checkUpgrade-F2WESBPM.js +103 -0
  8. package/dist/chunk-2VMOWSRY.js +300 -0
  9. package/dist/chunk-3GHJR7XR.js +2049 -0
  10. package/dist/chunk-3N3Q3DSW.js +214 -0
  11. package/dist/chunk-4ESO33J6.js +34 -0
  12. package/dist/chunk-4F7ZESPO.js +132 -0
  13. package/dist/chunk-4KCPOMG6.js +68 -0
  14. package/dist/chunk-4ZYCIMY4.js +155 -0
  15. package/dist/chunk-63MUJNZL.js +318 -0
  16. package/dist/chunk-6AAEVQ7I.js +6336 -0
  17. package/dist/chunk-6EQ3ARXA.js +304 -0
  18. package/dist/chunk-6L3U7DZ5.js +23 -0
  19. package/dist/chunk-AHBP533R.js +220 -0
  20. package/dist/chunk-B43LCXBM.js +223 -0
  21. package/dist/chunk-BCANRN5B.js +33 -0
  22. package/dist/chunk-BUALU27S.js +123 -0
  23. package/dist/chunk-BULZAX2U.js +1554 -0
  24. package/dist/chunk-BV32UNLL.js +154 -0
  25. package/dist/chunk-C6GLE626.js +160 -0
  26. package/dist/chunk-CIDWNUAP.js +145 -0
  27. package/dist/chunk-CUP36ND3.js +2126 -0
  28. package/dist/chunk-CW5HJ3LX.js +96 -0
  29. package/dist/chunk-DB2VF5UD.js +315 -0
  30. package/dist/chunk-DWAGCNEL.js +210 -0
  31. package/dist/chunk-EA3DP5HG.js +293 -0
  32. package/dist/chunk-ELGCAM7P.js +184 -0
  33. package/dist/chunk-FW6BD2NO.js +1915 -0
  34. package/dist/chunk-GE37NVLN.js +15 -0
  35. package/dist/chunk-GPTKSNR6.js +171 -0
  36. package/dist/chunk-GRJXQBQZ.js +793 -0
  37. package/dist/chunk-HWBBVLOT.js +92 -0
  38. package/dist/chunk-I2JUKN6Z.js +24 -0
  39. package/dist/chunk-I3M2KJXB.js +56 -0
  40. package/dist/chunk-IQ4SDKKY.js +733 -0
  41. package/dist/chunk-J5FZYN4A.js +116 -0
  42. package/dist/chunk-L6N4JFW2.js +263 -0
  43. package/dist/chunk-LBFGSSF2.js +126 -0
  44. package/dist/chunk-LEGPB7DO.js +81 -0
  45. package/dist/chunk-LO35HLQZ.js +219 -0
  46. package/dist/chunk-LRD4GBYE.js +73 -0
  47. package/dist/chunk-LUAKDHLZ.js +40 -0
  48. package/dist/chunk-LYMPYETA.js +965 -0
  49. package/dist/chunk-M6NYEXCW.js +38 -0
  50. package/dist/chunk-MHUEVBVO.js +35 -0
  51. package/dist/chunk-MYGSLK44.js +37 -0
  52. package/dist/chunk-NH5I4KHH.js +201 -0
  53. package/dist/chunk-OQS4GUSI.js +1391 -0
  54. package/dist/chunk-PSX3GIAN.js +176 -0
  55. package/dist/chunk-Q5VPF4WI.js +26 -0
  56. package/dist/chunk-QKGYDMWB.js +7409 -0
  57. package/dist/chunk-QSL6QN5X.js +115 -0
  58. package/dist/chunk-SHCEBP3J.js +107 -0
  59. package/dist/chunk-SJOVFF7B.js +201 -0
  60. package/dist/chunk-ST2X2GYN.js +373 -0
  61. package/dist/chunk-TNTXWSYA.js +19 -0
  62. package/dist/chunk-U5AT3TD4.js +2128 -0
  63. package/dist/chunk-UDVNA7EA.js +483 -0
  64. package/dist/chunk-VL2E5T2A.js +109 -0
  65. package/dist/chunk-VLRHFMGJ.js +58 -0
  66. package/dist/chunk-WHX2ZFCG.js +4048 -0
  67. package/dist/chunk-WQ23REYT.js +37 -0
  68. package/dist/chunk-XBIDMHSK.js +15425 -0
  69. package/dist/chunk-Y5GI7RL3.js +66 -0
  70. package/dist/client-IRKAMDYZ.js +15 -0
  71. package/dist/commands-FIL5ET6P.js +911 -0
  72. package/dist/compat-R3UTFQ5Q.js +201 -0
  73. package/dist/dashboardIssue-WYYMBFIB.js +192 -0
  74. package/dist/diff-GZA2774U.js +13 -0
  75. package/dist/dist-4XXIXHHZ.js +12945 -0
  76. package/dist/e2b-FVPHDULZ.js +172 -0
  77. package/dist/extract-NKGKLIVT.js +444 -0
  78. package/dist/fetch-QYTUJVG2.js +22 -0
  79. package/dist/firstTouch-QQTJH4QX.js +55 -0
  80. package/dist/handlers-GEJAVZDK.js +53 -0
  81. package/dist/http-ETPYMBGD.js +5360 -0
  82. package/dist/ingestQueue-VKN4KBIF.js +35 -0
  83. package/dist/install-EK3W2COX.js +20 -0
  84. package/dist/installSkill-VQJWJVCL.js +52 -0
  85. package/dist/inventory-5AWSLJYU.js +31 -0
  86. package/dist/local-XPZMRH5R.js +13 -0
  87. package/dist/mcp-3JHD5SUZ.js +472 -0
  88. package/dist/mcpHandlers-QFN4MCFL.js +22 -0
  89. package/dist/mcpScan-QZHWENIP.js +1871 -0
  90. package/dist/mcpScanWorkflow-JPYCBGC4.js +81 -0
  91. package/dist/mcpStack-BYJCZNIV.js +20 -0
  92. package/dist/packages-THVFMWFP.js +42 -0
  93. package/dist/plan-V4OEI3J4.js +463 -0
  94. package/dist/planView-JRXGCG2N.js +79 -0
  95. package/dist/policy-3P6BGRDN.js +115 -0
  96. package/dist/references-6N7VEPHT.js +14 -0
  97. package/dist/release-4U4ABNSJ.js +128 -0
  98. package/dist/remote-YGCXYI4V.js +32 -0
  99. package/dist/reportRuns-CKQQYLY4.js +64 -0
  100. package/dist/sandbox-MEZLAODF.js +39 -0
  101. package/dist/server-KFUD5X57.js +55 -0
  102. package/dist/surface-V62GE554.js +141 -0
  103. package/dist/surface-YL6O67W3.js +36 -0
  104. package/dist/surfaceHandlers-X2IZKA3E.js +20 -0
  105. package/dist/typecheck-X7U5ELMR.js +268 -0
  106. package/dist/types-M5JP2W3D.js +10 -0
  107. package/dist/uninstall-P7RGBX6G.js +174 -0
  108. package/dist/upgrade-NQ5IWFZB.js +596 -0
  109. package/dist/upgradePlan-A4LRKLEG.js +146 -0
  110. package/dist/userConfig-Z3GQE776.js +20 -0
  111. package/dist/watch-DGFMWUDL.js +214 -0
  112. package/package.json +26 -21
  113. package/templates/agent-rules.md +4 -4
  114. package/templates/skill-instructions.md +13 -14
  115. package/dist/bin/lurq.js.map +0 -1
  116. package/dist/index.d.ts +0 -805
  117. package/dist/index.js +0 -23570
  118. package/dist/index.js.map +0 -1
  119. package/drizzle/0000_confused_fabian_cortez.sql +0 -54
  120. package/drizzle/0001_aspiring_timeslip.sql +0 -15
  121. package/drizzle/0002_lyrical_lila_cheney.sql +0 -14
  122. package/drizzle/0003_violet_giant_girl.sql +0 -14
  123. package/drizzle/0004_slim_valeria_richards.sql +0 -15
  124. package/drizzle/0005_petite_luke_cage.sql +0 -12
  125. package/drizzle/0006_calm_nighthawk.sql +0 -3
  126. package/drizzle/0007_slimy_naoko.sql +0 -1
  127. package/drizzle/0008_peaceful_tigra.sql +0 -1
  128. package/drizzle/0009_smooth_harrier.sql +0 -10
  129. package/drizzle/0010_curved_amphibian.sql +0 -2
  130. package/drizzle/0011_compat_provenance_closures.sql +0 -11
  131. package/drizzle/0012_api_surfaces.sql +0 -9
  132. package/drizzle/0013_nice_thanos.sql +0 -1
  133. package/drizzle/0014_luxuriant_malcolm_colcord.sql +0 -10
  134. package/drizzle/0015_past_fat_cobra.sql +0 -11
  135. package/drizzle/0016_futuristic_junta.sql +0 -50
  136. package/drizzle/0017_absent_grandmaster.sql +0 -20
  137. package/drizzle/0018_rainy_proemial_gods.sql +0 -1
  138. package/drizzle/0019_dashing_korvac.sql +0 -11
  139. package/drizzle/0020_normal_vulture.sql +0 -3
  140. package/drizzle/0021_dazzling_blue_shield.sql +0 -17
  141. package/drizzle/0022_massive_ghost_rider.sql +0 -24
  142. package/drizzle/0023_next_shatterstar.sql +0 -1
  143. package/drizzle/0024_dusty_maelstrom.sql +0 -15
  144. package/drizzle/0025_gifted_harpoon.sql +0 -5
  145. package/drizzle/0026_awesome_mordo.sql +0 -1
  146. package/drizzle/0027_charming_ulik.sql +0 -2
  147. package/drizzle/0028_romantic_loners.sql +0 -2
  148. package/drizzle/0029_busy_korvac.sql +0 -16
  149. package/drizzle/0030_steady_mathemanic.sql +0 -6
  150. package/drizzle/0031_redundant_maginty.sql +0 -2
  151. package/drizzle/0032_stack_resolutions.sql +0 -14
  152. package/drizzle/0033_graceful_tyger_tiger.sql +0 -3
  153. package/drizzle/0034_uneven_thunderbird.sql +0 -1
  154. package/drizzle/0035_api_key_scopes.sql +0 -1
  155. package/drizzle/0036_policy_audit.sql +0 -21
  156. package/drizzle/0037_subscription_seats.sql +0 -1
  157. package/drizzle/0038_symbol_offsets.sql +0 -2
  158. package/drizzle/0039_mcp_runtime_scans.sql +0 -80
  159. package/drizzle/0040_subscription_overage_and_interval.sql +0 -4
  160. package/drizzle/0041_account_email.sql +0 -38
  161. package/drizzle/0042_alert_channels.sql +0 -21
  162. package/drizzle/meta/0000_snapshot.json +0 -370
  163. package/drizzle/meta/0001_snapshot.json +0 -482
  164. package/drizzle/meta/0002_snapshot.json +0 -575
  165. package/drizzle/meta/0003_snapshot.json +0 -667
  166. package/drizzle/meta/0004_snapshot.json +0 -769
  167. package/drizzle/meta/0005_snapshot.json +0 -864
  168. package/drizzle/meta/0006_snapshot.json +0 -882
  169. package/drizzle/meta/0007_snapshot.json +0 -876
  170. package/drizzle/meta/0008_snapshot.json +0 -882
  171. package/drizzle/meta/0009_snapshot.json +0 -948
  172. package/drizzle/meta/0010_snapshot.json +0 -969
  173. package/drizzle/meta/0011_snapshot.json +0 -1049
  174. package/drizzle/meta/0012_snapshot.json +0 -1115
  175. package/drizzle/meta/0013_snapshot.json +0 -1121
  176. package/drizzle/meta/0014_snapshot.json +0 -1190
  177. package/drizzle/meta/0015_snapshot.json +0 -1280
  178. package/drizzle/meta/0016_snapshot.json +0 -1683
  179. package/drizzle/meta/0017_snapshot.json +0 -1834
  180. package/drizzle/meta/0018_snapshot.json +0 -1834
  181. package/drizzle/meta/0019_snapshot.json +0 -1909
  182. package/drizzle/meta/0020_snapshot.json +0 -1921
  183. package/drizzle/meta/0021_snapshot.json +0 -2045
  184. package/drizzle/meta/0022_snapshot.json +0 -2246
  185. package/drizzle/meta/0023_snapshot.json +0 -2252
  186. package/drizzle/meta/0024_snapshot.json +0 -2375
  187. package/drizzle/meta/0025_snapshot.json +0 -2407
  188. package/drizzle/meta/0026_snapshot.json +0 -2413
  189. package/drizzle/meta/0027_snapshot.json +0 -2425
  190. package/drizzle/meta/0028_snapshot.json +0 -2438
  191. package/drizzle/meta/0029_snapshot.json +0 -2546
  192. package/drizzle/meta/0030_snapshot.json +0 -2586
  193. package/drizzle/meta/0031_snapshot.json +0 -2598
  194. package/drizzle/meta/0032_snapshot.json +0 -2699
  195. package/drizzle/meta/0033_snapshot.json +0 -2712
  196. package/drizzle/meta/0034_snapshot.json +0 -2719
  197. package/drizzle/meta/0035_snapshot.json +0 -2726
  198. package/drizzle/meta/0036_snapshot.json +0 -2876
  199. package/drizzle/meta/0037_snapshot.json +0 -2883
  200. package/drizzle/meta/0038_snapshot.json +0 -2895
  201. package/drizzle/meta/0039_snapshot.json +0 -3501
  202. package/drizzle/meta/0040_snapshot.json +0 -3527
  203. package/drizzle/meta/0041_snapshot.json +0 -3824
  204. package/drizzle/meta/0042_snapshot.json +0 -3960
  205. package/drizzle/meta/_journal.json +0 -307
  206. package/src/data/seed.json +0 -253
@@ -0,0 +1,96 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ DEFAULT_ECOSYSTEM
4
+ } from "./chunk-VLRHFMGJ.js";
5
+ import {
6
+ compatEdges,
7
+ compatVerifyQueue,
8
+ packages
9
+ } from "./chunk-LYMPYETA.js";
10
+ import {
11
+ init_esm_shims
12
+ } from "./chunk-I3M2KJXB.js";
13
+
14
+ // src/db/compat.ts
15
+ init_esm_shims();
16
+ import { and, eq, inArray, sql } from "drizzle-orm";
17
+ async function getCompatMetadata(db, names, ecosystem = DEFAULT_ECOSYSTEM) {
18
+ if (names.length === 0) return [];
19
+ return db.select({
20
+ name: packages.name,
21
+ latestVersion: packages.latestVersion,
22
+ peerDependencies: packages.peerDependencies,
23
+ peerDependenciesMeta: packages.peerDependenciesMeta,
24
+ engines: packages.engines
25
+ }).from(packages).where(and(inArray(packages.name, names), eq(packages.ecosystem, ecosystem)));
26
+ }
27
+ function canonicalPair(a, b) {
28
+ const [low, high] = a.name <= b.name ? [a, b] : [b, a];
29
+ return { packageA: low.name, versionA: low.version, packageB: high.name, versionB: high.version };
30
+ }
31
+ function provenanceRank(col) {
32
+ return sql`case ${col} when 'conflict' then 3 when 'verified' then 2 when 'observed' then 1 else 0 end`;
33
+ }
34
+ function conflictSet() {
35
+ const incomingWins = sql`${provenanceRank(sql`excluded.provenance`)} >= ${provenanceRank(compatEdges.provenance)}`;
36
+ return {
37
+ status: sql`case when ${incomingWins} then excluded.status else ${compatEdges.status} end`,
38
+ provenance: sql`case when ${incomingWins} then excluded.provenance else ${compatEdges.provenance} end`,
39
+ driver: sql`case when ${incomingWins} then excluded.driver else ${compatEdges.driver} end`,
40
+ ranAt: sql`case when ${incomingWins} then excluded.ran_at else ${compatEdges.ranAt} end`,
41
+ witnessCount: sql`${compatEdges.witnessCount} + excluded.witness_count`
42
+ };
43
+ }
44
+ var CONFLICT_TARGET = [
45
+ compatEdges.packageA,
46
+ compatEdges.versionA,
47
+ compatEdges.packageB,
48
+ compatEdges.versionB
49
+ ];
50
+ async function upsertCompatEdge(db, edge) {
51
+ await db.insert(compatEdges).values(edge).onConflictDoUpdate({ target: [...CONFLICT_TARGET], set: conflictSet() });
52
+ }
53
+ async function getSandboxEdges(db, names) {
54
+ if (names.length === 0) return [];
55
+ return db.select().from(compatEdges).where(
56
+ and(
57
+ inArray(compatEdges.packageA, names),
58
+ inArray(compatEdges.packageB, names),
59
+ inArray(compatEdges.provenance, ["verified", "conflict"])
60
+ )
61
+ );
62
+ }
63
+ function pairKey(a, b) {
64
+ return a <= b ? `${a}|${b}` : `${b}|${a}`;
65
+ }
66
+ function compatSetKey(names) {
67
+ return [...new Set(names)].sort().join("|");
68
+ }
69
+ async function enqueueCompatVerify(db, names) {
70
+ const packages2 = [...new Set(names)].filter(Boolean);
71
+ if (packages2.length < 2) return false;
72
+ const inserted = await db.insert(compatVerifyQueue).values({ setKey: compatSetKey(packages2), packages: packages2 }).onConflictDoNothing({ target: compatVerifyQueue.setKey }).returning({ id: compatVerifyQueue.id });
73
+ return inserted.length > 0;
74
+ }
75
+ async function getPendingCompatVerify(db, limit) {
76
+ return db.select().from(compatVerifyQueue).orderBy(compatVerifyQueue.requestedAt).limit(limit);
77
+ }
78
+ async function deleteCompatVerify(db, id) {
79
+ await db.delete(compatVerifyQueue).where(eq(compatVerifyQueue.id, id));
80
+ }
81
+ async function bumpCompatVerifyAttempt(db, id) {
82
+ const [row] = await db.update(compatVerifyQueue).set({ attempts: sql`${compatVerifyQueue.attempts} + 1` }).where(eq(compatVerifyQueue.id, id)).returning({ attempts: compatVerifyQueue.attempts });
83
+ return row?.attempts ?? 0;
84
+ }
85
+
86
+ export {
87
+ getCompatMetadata,
88
+ canonicalPair,
89
+ upsertCompatEdge,
90
+ getSandboxEdges,
91
+ pairKey,
92
+ enqueueCompatVerify,
93
+ getPendingCompatVerify,
94
+ deleteCompatVerify,
95
+ bumpCompatVerifyAttempt
96
+ };
@@ -0,0 +1,315 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ diffSurfaces
4
+ } from "./chunk-SHCEBP3J.js";
5
+ import {
6
+ canonicalKey,
7
+ enqueueSurface,
8
+ mcpSurfaceRef,
9
+ surfaceRef
10
+ } from "./chunk-LO35HLQZ.js";
11
+ import {
12
+ cached
13
+ } from "./chunk-HWBBVLOT.js";
14
+ import {
15
+ UNBOUNDED_ARITY,
16
+ claims,
17
+ entities,
18
+ observations,
19
+ symbols
20
+ } from "./chunk-LYMPYETA.js";
21
+ import {
22
+ logger
23
+ } from "./chunk-MYGSLK44.js";
24
+ import {
25
+ init_esm_shims
26
+ } from "./chunk-I3M2KJXB.js";
27
+
28
+ // src/mcp/surfaceHandlers.ts
29
+ init_esm_shims();
30
+ import { createHash } from "crypto";
31
+ import { and, desc, eq } from "drizzle-orm";
32
+
33
+ // src/pipeline/fillSurface.ts
34
+ init_esm_shims();
35
+ import { sql } from "drizzle-orm";
36
+ var TIER = "shipped_js_ast";
37
+ var MAX_QUEUED = 32;
38
+ var MAX_ATTEMPTED = 5e4;
39
+ var BATCH = 500;
40
+ var attempted = /* @__PURE__ */ new Set();
41
+ var pending = /* @__PURE__ */ new Set();
42
+ var queue = [];
43
+ var draining = null;
44
+ function needsFill(rows) {
45
+ const tierA = rows.filter((r) => r.tier === TIER);
46
+ return tierA.length > 0 && tierA.every((r) => r.sourceOffset === null && r.maxArity === null);
47
+ }
48
+ function scheduleFill(db, pkg, version, entityId, fill = fillOne) {
49
+ const key = `${pkg}@${version}`;
50
+ if (pending.has(key)) return true;
51
+ if (attempted.has(key) || queue.length >= MAX_QUEUED) return false;
52
+ if (attempted.size >= MAX_ATTEMPTED) attempted.clear();
53
+ attempted.add(key);
54
+ pending.add(key);
55
+ queue.push({ db, pkg, version, entityId, fill });
56
+ draining ??= drain().finally(() => {
57
+ draining = null;
58
+ });
59
+ return true;
60
+ }
61
+ async function drain() {
62
+ for (let job = queue.shift(); job; job = queue.shift()) {
63
+ const key = `${job.pkg}@${job.version}`;
64
+ try {
65
+ const updated = await job.fill(job.db, job.pkg, job.version, job.entityId);
66
+ logger.info(`surface fill ${key}: ${updated} symbol row(s) updated`);
67
+ } catch (err) {
68
+ logger.warn(`surface fill failed for ${key}: ${err instanceof Error ? err.message : String(err)}`);
69
+ } finally {
70
+ pending.delete(key);
71
+ }
72
+ await new Promise((resolve) => setImmediate(resolve));
73
+ }
74
+ }
75
+ async function fillOne(db, pkg, version, entityId) {
76
+ const { fetchAndExtract } = await import("./fetch-QYTUJVG2.js");
77
+ const fetched = await fetchAndExtract(pkg, version);
78
+ if (!fetched) return 0;
79
+ const values = fetched.surface.symbols.filter((s) => s.tier === TIER && (s.sourceRef?.offset !== void 0 || s.maxArity !== void 0)).map((s) => ({
80
+ path: s.path,
81
+ offset: s.sourceRef?.offset ?? null,
82
+ maxArity: s.maxArity === void 0 ? null : s.maxArity ?? UNBOUNDED_ARITY
83
+ }));
84
+ let updated = 0;
85
+ for (let i = 0; i < values.length; i += BATCH) {
86
+ const res = await db.execute(fillStatement(entityId, values.slice(i, i + BATCH)));
87
+ updated += res.count ?? 0;
88
+ }
89
+ return updated;
90
+ }
91
+ function fillStatement(entityId, values) {
92
+ const rows = sql.join(
93
+ values.map((v) => sql`(${v.path}, ${v.offset}::int, ${v.maxArity}::int)`),
94
+ sql`, `
95
+ );
96
+ return sql`
97
+ UPDATE symbols AS s
98
+ SET source_offset = v.new_offset, max_arity = v.new_max_arity
99
+ FROM (VALUES ${rows}) AS v(path, new_offset, new_max_arity)
100
+ WHERE s.entity_id = ${entityId}
101
+ AND s.tier = ${TIER}
102
+ AND s.path = v.path
103
+ AND s.source_offset IS NULL
104
+ AND s.max_arity IS NULL`;
105
+ }
106
+
107
+ // src/mcp/surfaceHandlers.ts
108
+ function rowsToSurface(pkg, version, rows, tier) {
109
+ const symbolsOut = rows.map((r) => ({
110
+ path: r.path,
111
+ kind: r.kind,
112
+ arity: r.arity,
113
+ origin: r.origin,
114
+ deprecated: r.deprecated,
115
+ tier: r.tier,
116
+ // The signature was dropped on the way back out of the database, so every
117
+ // diff computed from STORED rows saw `signature: undefined` on both sides
118
+ // and reported no signature drift — for tier C, where signatures are the
119
+ // only thing that tier can report, and for the MCP tier, where the entire
120
+ // tool contract is serialized into this field.
121
+ ...r.signature !== null ? { signature: r.signature } : {},
122
+ // Offset and maximum arity come back too. Without them a diff computed from
123
+ // stored rows could never find a proven rename or a dropped trailing
124
+ // parameter, and every consumer of the index would see less than the CLI.
125
+ ...r.sourceFile ? {
126
+ sourceRef: {
127
+ file: r.sourceFile,
128
+ line: r.sourceLine ?? 0,
129
+ ...r.sourceOffset !== null ? { offset: r.sourceOffset } : {}
130
+ }
131
+ } : {},
132
+ ...r.maxArity !== null ? { maxArity: r.maxArity === UNBOUNDED_ARITY ? null : r.maxArity } : {}
133
+ }));
134
+ return {
135
+ package: pkg,
136
+ version,
137
+ tier,
138
+ entry: null,
139
+ symbols: symbolsOut,
140
+ filesWalked: 0,
141
+ externalReExports: []
142
+ };
143
+ }
144
+ async function loadStored(db, pkg, version, tenantId = 0, kind = "package_surface") {
145
+ let entity;
146
+ if (version === null) {
147
+ const rows2 = await db.select({ e: entities, at: observations.observedAt }).from(entities).innerJoin(claims, eq(claims.subjectId, entities.id)).innerJoin(observations, eq(observations.claimId, claims.id)).where(and(eq(entities.kind, kind), eq(entities.name, pkg))).orderBy(desc(observations.observedAt)).limit(1);
148
+ entity = rows2.find((r) => r.e.tenantId === tenantId)?.e;
149
+ } else {
150
+ const key = canonicalKey(
151
+ kind === "mcp_server" ? mcpSurfaceRef(pkg, version) : surfaceRef(pkg, version)
152
+ );
153
+ const ents = await db.select().from(entities).where(eq(entities.canonicalKey, key)).limit(2);
154
+ entity = ents.find((e) => e.tenantId === tenantId);
155
+ }
156
+ if (!entity) return null;
157
+ const obs = await db.select({ o: observations }).from(observations).innerJoin(claims, eq(observations.claimId, claims.id)).where(eq(claims.subjectId, entity.id)).orderBy(desc(observations.observedAt)).limit(1);
158
+ const latest = obs[0]?.o ?? null;
159
+ const rows = await db.select().from(symbols).where(eq(symbols.entityId, entity.id));
160
+ return {
161
+ entityId: entity.id,
162
+ rows,
163
+ verdict: latest?.verdict ?? "unknown",
164
+ class: latest?.class ?? null,
165
+ tier: latest?.tier ?? null,
166
+ observedAt: latest?.observedAt ? latest.observedAt.toISOString() : null
167
+ };
168
+ }
169
+ var MISS = {
170
+ verdict: "unknown",
171
+ class: null,
172
+ tier: null,
173
+ symbols: [],
174
+ coverageNote: "not yet extracted, queued; retry shortly. This is NOT evidence of absence.",
175
+ observedAt: null
176
+ };
177
+ function ckey(parts) {
178
+ return createHash("sha1").update(JSON.stringify(parts)).digest("hex").slice(0, 24);
179
+ }
180
+ async function handleResolveSurface(db, input) {
181
+ return cached(
182
+ "resolve_surface",
183
+ ckey([input.package, input.version ?? null]),
184
+ () => resolveSurfaceUncached(db, input),
185
+ { skipCache: (v) => v.verdict === "unknown" }
186
+ );
187
+ }
188
+ async function resolveSurfaceUncached(db, input) {
189
+ const version = input.version ?? null;
190
+ let stored = await loadStored(db, input.package, version);
191
+ if (!stored || stored.verdict === "unknown" && stored.rows.length === 0) {
192
+ const { firstTouchSurface } = await import("./firstTouch-QQTJH4QX.js");
193
+ if (await firstTouchSurface(db, input.package, version)) {
194
+ stored = await loadStored(db, input.package, version);
195
+ }
196
+ }
197
+ if (!stored || stored.verdict === "unknown" && stored.rows.length === 0) {
198
+ await enqueueSurface(db, input.package, version).catch(() => {
199
+ });
200
+ return { package: input.package, version, ...MISS };
201
+ }
202
+ if (stored.verdict === "undeclared") {
203
+ return {
204
+ package: input.package,
205
+ version,
206
+ verdict: "undeclared",
207
+ class: stored.class,
208
+ tier: stored.tier,
209
+ symbols: [],
210
+ coverageNote: "package ships no artifact this tier can read, UNDECLARED, which is a measurement gap, not an empty API",
211
+ observedAt: stored.observedAt
212
+ };
213
+ }
214
+ const runtime = stored.rows.filter((r) => r.kind !== "type_only" && r.origin === "local");
215
+ const excluded = stored.rows.length - runtime.length;
216
+ return {
217
+ package: input.package,
218
+ version,
219
+ verdict: stored.verdict,
220
+ class: stored.class,
221
+ tier: stored.tier,
222
+ symbols: runtime.map((r) => ({
223
+ path: r.path,
224
+ kind: r.kind,
225
+ arity: r.arity,
226
+ deprecated: r.deprecated
227
+ })),
228
+ coverageNote: `${runtime.length} runtime symbol(s)` + (excluded ? `; ${excluded} excluded as type-only or re-exported from another package` : "") + (stored.tier === "shipped_js_ast" ? ". Runtime existence only, signatures require tier C." : ""),
229
+ observedAt: stored.observedAt
230
+ };
231
+ }
232
+ async function handleDiffSurface(db, input) {
233
+ let filling = false;
234
+ return cached(
235
+ "diff_surface",
236
+ ckey([input.package, input.fromVersion, input.toVersion]),
237
+ () => diffSurfaceUncached(db, input, () => filling = true),
238
+ { skipCache: (v) => v.verdict === "unknown" || filling }
239
+ );
240
+ }
241
+ async function diffSurfaceUncached(db, input, onFill) {
242
+ let [a, b] = await Promise.all([
243
+ loadStored(db, input.package, input.fromVersion),
244
+ loadStored(db, input.package, input.toVersion)
245
+ ]);
246
+ if (!a || !b || a.rows.length === 0 || b.rows.length === 0) {
247
+ const { firstTouchPair } = await import("./firstTouch-QQTJH4QX.js");
248
+ if (await firstTouchPair(db, input.package, input.fromVersion, input.toVersion)) {
249
+ [a, b] = await Promise.all([
250
+ loadStored(db, input.package, input.fromVersion),
251
+ loadStored(db, input.package, input.toVersion)
252
+ ]);
253
+ }
254
+ }
255
+ const missing = [];
256
+ if (!a || a.rows.length === 0) missing.push(input.fromVersion);
257
+ if (!b || b.rows.length === 0) missing.push(input.toVersion);
258
+ if (missing.length) {
259
+ for (const v of missing) await enqueueSurface(db, input.package, v).catch(() => {
260
+ });
261
+ return {
262
+ package: input.package,
263
+ fromVersion: input.fromVersion,
264
+ toVersion: input.toVersion,
265
+ verdict: "unknown",
266
+ inconclusive: `no extracted surface for ${missing.join(", ")}, queued; retry shortly. NOT evidence that symbols were removed.`,
267
+ removed: [],
268
+ added: [],
269
+ arityChanged: [],
270
+ typeOnlyRemoved: [],
271
+ // Present-but-empty like every other list above, so a miss and a hit have
272
+ // the same shape and callers never have to branch on which one they got.
273
+ deprecated: [],
274
+ renamed: [],
275
+ observedAt: null
276
+ };
277
+ }
278
+ for (const [stored, version] of [
279
+ [a, input.fromVersion],
280
+ [b, input.toVersion]
281
+ ]) {
282
+ if (needsFill(stored.rows) && scheduleFill(db, input.package, version, stored.entityId)) onFill();
283
+ }
284
+ const diff = diffSurfaces(
285
+ rowsToSurface(input.package, input.fromVersion, a.rows, a.tier ?? "shipped_js_ast"),
286
+ rowsToSurface(input.package, input.toVersion, b.rows, b.tier ?? "shipped_js_ast")
287
+ );
288
+ return {
289
+ package: input.package,
290
+ fromVersion: input.fromVersion,
291
+ toVersion: input.toVersion,
292
+ verdict: diff.inconclusive ? "unknown" : "verified_true",
293
+ class: "derived",
294
+ tier: diff.tier,
295
+ ...diff.inconclusive ? { inconclusive: diff.inconclusive } : {},
296
+ /** Breaks `node`. */
297
+ removed: diff.removed.map((s) => ({ path: s.path, kind: s.kind, arity: s.arity })),
298
+ added: diff.added.map((s) => ({ path: s.path, kind: s.kind })),
299
+ arityChanged: diff.arityChanged,
300
+ /** Breaks `tsc`, NOT `node` — returned separately on purpose (§8.1). */
301
+ typeOnlyRemoved: diff.typeOnlyRemoved.map((s) => s.path),
302
+ deprecated: diff.deprecated.map((s) => s.path),
303
+ /** Removed names whose implementation the package still exports under another
304
+ * name. Empty for surfaces stored before declaration offsets were recorded. */
305
+ renamed: diff.renamed,
306
+ observedAt: b.observedAt
307
+ };
308
+ }
309
+
310
+ export {
311
+ rowsToSurface,
312
+ loadStored,
313
+ handleResolveSurface,
314
+ handleDiffSurface
315
+ };
@@ -0,0 +1,210 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ detectInstallCommand
4
+ } from "./chunk-B43LCXBM.js";
5
+ import {
6
+ REPO_MANIFEST_CAP
7
+ } from "./chunk-BCANRN5B.js";
8
+ import {
9
+ HttpError,
10
+ httpRequest
11
+ } from "./chunk-SJOVFF7B.js";
12
+ import {
13
+ getConfig
14
+ } from "./chunk-GRJXQBQZ.js";
15
+ import {
16
+ logger
17
+ } from "./chunk-MYGSLK44.js";
18
+ import {
19
+ init_esm_shims
20
+ } from "./chunk-I3M2KJXB.js";
21
+
22
+ // src/github/app.ts
23
+ init_esm_shims();
24
+ import { createSign } from "crypto";
25
+ var API_HOST = "api.github.com";
26
+ var API = `https://${API_HOST}`;
27
+ var JWT_TTL_S = 9 * 60;
28
+ var TOKEN_SKEW_MS = 6e4;
29
+ var GithubAppError = class extends Error {
30
+ constructor(message, status) {
31
+ super(message);
32
+ this.status = status;
33
+ this.name = "GithubAppError";
34
+ }
35
+ status;
36
+ };
37
+ function githubAppCredentials() {
38
+ const config = getConfig();
39
+ const appId = config.LURQ_GITHUB_APP_ID;
40
+ const rawKey = config.LURQ_GITHUB_APP_PRIVATE_KEY;
41
+ if (!appId || !rawKey) return null;
42
+ const privateKey = rawKey.includes("\\n") ? rawKey.replace(/\\n/g, "\n") : rawKey;
43
+ return { appId, privateKey };
44
+ }
45
+ function b64url(input) {
46
+ return Buffer.from(input).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
47
+ }
48
+ function appJwt(creds, now = /* @__PURE__ */ new Date()) {
49
+ const issued = Math.floor(now.getTime() / 1e3) - 60;
50
+ const header = b64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
51
+ const payload = b64url(
52
+ JSON.stringify({ iat: issued, exp: issued + JWT_TTL_S, iss: creds.appId })
53
+ );
54
+ const signature = createSign("RSA-SHA256").update(`${header}.${payload}`).sign(creds.privateKey);
55
+ return `${header}.${payload}.${b64url(signature)}`;
56
+ }
57
+ var tokenCache = /* @__PURE__ */ new Map();
58
+ async function installationToken(installationId) {
59
+ const cached = tokenCache.get(installationId);
60
+ if (cached && cached.expiresAt - TOKEN_SKEW_MS > Date.now()) return cached.token;
61
+ const creds = githubAppCredentials();
62
+ if (!creds) throw new GithubAppError("GitHub App is not configured.", 503);
63
+ let res;
64
+ try {
65
+ res = await httpRequest(
66
+ `${API}/app/installations/${installationId}/access_tokens`,
67
+ {
68
+ host: API_HOST,
69
+ ttlMs: 0,
70
+ // never cache credentials to disk
71
+ method: "POST",
72
+ headers: {
73
+ Authorization: `Bearer ${appJwt(creds)}`,
74
+ Accept: "application/vnd.github+json",
75
+ "X-GitHub-Api-Version": "2022-11-28"
76
+ }
77
+ }
78
+ );
79
+ } catch (err) {
80
+ if (err instanceof HttpError && err.status === 404) {
81
+ throw new GithubAppError("This GitHub installation no longer exists.", 404);
82
+ }
83
+ throw new GithubAppError(
84
+ err instanceof Error ? err.message : "Could not authenticate with GitHub.",
85
+ 502
86
+ );
87
+ }
88
+ const token = res.data?.token;
89
+ if (!token) throw new GithubAppError("GitHub returned no installation token.", 502);
90
+ const expiresAt = res.data.expires_at ? Date.parse(res.data.expires_at) : NaN;
91
+ tokenCache.set(installationId, {
92
+ token,
93
+ // A token with an unparseable expiry is still valid; treat it as short-lived
94
+ // rather than caching it forever on a malformed timestamp.
95
+ expiresAt: Number.isNaN(expiresAt) ? Date.now() + 5 * 6e4 : expiresAt
96
+ });
97
+ return token;
98
+ }
99
+ async function installationGet(installationId, path) {
100
+ const token = await installationToken(installationId);
101
+ const res = await httpRequest(`${API}${path}`, {
102
+ host: API_HOST,
103
+ ttlMs: 0,
104
+ // repo state changes under us; a cached manifest is a wrong answer
105
+ headers: {
106
+ Authorization: `Bearer ${token}`,
107
+ Accept: "application/vnd.github+json",
108
+ "X-GitHub-Api-Version": "2022-11-28"
109
+ }
110
+ });
111
+ return res.data;
112
+ }
113
+
114
+ // src/github/manifests.ts
115
+ init_esm_shims();
116
+ var PAGE_SIZE = 100;
117
+ var MAX_PAGES = 20;
118
+ async function listInstallationRepos(installationId) {
119
+ const out = [];
120
+ for (let page = 1; page <= MAX_PAGES; page++) {
121
+ const data = await installationGet(
122
+ installationId,
123
+ `/installation/repositories?per_page=${PAGE_SIZE}&page=${page}`
124
+ );
125
+ const batch = data.repositories ?? [];
126
+ for (const repo of batch) {
127
+ out.push({
128
+ fullName: repo.full_name,
129
+ defaultBranch: repo.default_branch,
130
+ isPrivate: repo.private,
131
+ pushedAt: repo.pushed_at ?? null
132
+ });
133
+ }
134
+ if (batch.length < PAGE_SIZE) break;
135
+ }
136
+ return out;
137
+ }
138
+ function manifestPaths(tree) {
139
+ return tree.filter(
140
+ (node) => node.type === "blob" && (node.path === "package.json" || node.path.endsWith("/package.json")) && // A committed node_modules is rare but real, and its manifests are not
141
+ // this project's dependencies — counting them would invent drift.
142
+ !node.path.split("/").includes("node_modules")
143
+ ).sort((a, b) => a.path.split("/").length - b.path.split("/").length).map((node) => node.path);
144
+ }
145
+ function parseManifest(path, json) {
146
+ if (!json || typeof json !== "object") return null;
147
+ const pkg = json;
148
+ const deps = {};
149
+ for (const block of ["dependencies", "devDependencies"]) {
150
+ const entry = pkg[block];
151
+ if (!entry || typeof entry !== "object") continue;
152
+ for (const [name, range] of Object.entries(entry)) {
153
+ if (typeof range !== "string") continue;
154
+ if (/^(file|link|workspace|git|github|https?|portal):/i.test(range)) continue;
155
+ if (range.includes("/") && !range.startsWith(">") && !range.startsWith("<")) continue;
156
+ deps[name] = range;
157
+ }
158
+ }
159
+ return Object.keys(deps).length > 0 ? { path, deps } : null;
160
+ }
161
+ async function fetchManifests(installationId, fullName, branch) {
162
+ let tree;
163
+ try {
164
+ tree = await installationGet(
165
+ installationId,
166
+ `/repos/${fullName}/git/trees/${encodeURIComponent(branch)}?recursive=1`
167
+ );
168
+ } catch (err) {
169
+ if (err instanceof HttpError && err.status === 409) {
170
+ return { manifests: [], installCommand: detectInstallCommand([]), partial: false, empty: true };
171
+ }
172
+ throw err;
173
+ }
174
+ const nodes = tree.tree ?? [];
175
+ const allPaths = manifestPaths(nodes);
176
+ const lockfiles = nodes.filter((n) => !n.path.includes("/")).map((n) => n.path);
177
+ const paths = allPaths.slice(0, REPO_MANIFEST_CAP);
178
+ const manifests = [];
179
+ for (const path of paths) {
180
+ try {
181
+ const res = await installationGet(
182
+ installationId,
183
+ `/repos/${fullName}/contents/${path.split("/").map(encodeURIComponent).join("/")}?ref=${encodeURIComponent(branch)}`
184
+ );
185
+ if (!res.content || res.encoding !== "base64") continue;
186
+ const parsed = parseManifest(
187
+ path,
188
+ JSON.parse(Buffer.from(res.content, "base64").toString("utf8"))
189
+ );
190
+ if (parsed) manifests.push(parsed);
191
+ } catch (err) {
192
+ logger.debug(`manifest read failed for ${fullName}/${path}: ${err.message}`);
193
+ }
194
+ }
195
+ return {
196
+ manifests,
197
+ installCommand: detectInstallCommand(lockfiles),
198
+ partial: Boolean(tree.truncated) || allPaths.length > paths.length,
199
+ empty: false
200
+ };
201
+ }
202
+
203
+ export {
204
+ GithubAppError,
205
+ githubAppCredentials,
206
+ installationGet,
207
+ listInstallationRepos,
208
+ parseManifest,
209
+ fetchManifests
210
+ };