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,201 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ getSandbox
4
+ } from "./chunk-I2JUKN6Z.js";
5
+ import "./chunk-C6GLE626.js";
6
+ import "./chunk-GE37NVLN.js";
7
+ import {
8
+ getStackResolution,
9
+ recordStackResolution,
10
+ resolveSet,
11
+ stackKey
12
+ } from "./chunk-J5FZYN4A.js";
13
+ import {
14
+ bumpCompatVerifyAttempt,
15
+ canonicalPair,
16
+ deleteCompatVerify,
17
+ getPendingCompatVerify,
18
+ pairKey,
19
+ upsertCompatEdge
20
+ } from "./chunk-CW5HJ3LX.js";
21
+ import {
22
+ getPackageByName,
23
+ getTopPackageNames
24
+ } from "./chunk-NH5I4KHH.js";
25
+ import "./chunk-VLRHFMGJ.js";
26
+ import "./chunk-LYMPYETA.js";
27
+ import "./chunk-GRJXQBQZ.js";
28
+ import "./chunk-WHX2ZFCG.js";
29
+ import {
30
+ logger
31
+ } from "./chunk-MYGSLK44.js";
32
+ import "./chunk-GPTKSNR6.js";
33
+ import {
34
+ init_esm_shims
35
+ } from "./chunk-I3M2KJXB.js";
36
+
37
+ // src/pipeline/compat.ts
38
+ init_esm_shims();
39
+ function pairwiseEdges(resolved, success) {
40
+ const edges = [];
41
+ if (success) {
42
+ for (let i = 0; i < resolved.length; i++) {
43
+ for (let j = i + 1; j < resolved.length; j++) {
44
+ edges.push({
45
+ a: resolved[i].name,
46
+ aVersion: resolved[i].version,
47
+ b: resolved[j].name,
48
+ bVersion: resolved[j].version,
49
+ status: "compatible"
50
+ });
51
+ }
52
+ }
53
+ } else if (resolved.length === 2) {
54
+ edges.push({
55
+ a: resolved[0].name,
56
+ aVersion: resolved[0].version,
57
+ b: resolved[1].name,
58
+ bVersion: resolved[1].version,
59
+ status: "conflict"
60
+ });
61
+ }
62
+ return edges;
63
+ }
64
+ function deriveCompatEdges(resolved, result) {
65
+ return pairwiseEdges(resolved, result.installed && result.loaded.every((l) => l.loaded === true));
66
+ }
67
+ async function verifyCompatibility(db, packages, opts = {}) {
68
+ const resolved = await Promise.all(
69
+ packages.map(async (name) => ({
70
+ name,
71
+ version: (await getPackageByName(db, name))?.latestVersion ?? "latest"
72
+ }))
73
+ );
74
+ const result = await (await getSandbox()).verifySet(
75
+ resolved.map((r) => ({ name: r.name, version: r.version === "latest" ? null : r.version })),
76
+ { allowScripts: opts.allowScripts }
77
+ );
78
+ const edges = deriveCompatEdges(resolved, result);
79
+ await persistCompatEdges(db, edges, "verified", result.driver);
80
+ const failed = !result.installed || !result.loaded.every((l) => l.loaded === true);
81
+ return { result, edges, unattributedConflict: failed && edges.length === 0 };
82
+ }
83
+ async function persistCompatEdges(db, edges, compatibleProvenance, driver) {
84
+ const now = /* @__PURE__ */ new Date();
85
+ for (const e of edges) {
86
+ const pair = canonicalPair(
87
+ { name: e.a, version: e.aVersion },
88
+ { name: e.b, version: e.bVersion }
89
+ );
90
+ await upsertCompatEdge(db, {
91
+ ...pair,
92
+ status: e.status,
93
+ provenance: e.status === "conflict" ? "conflict" : compatibleProvenance,
94
+ // Witness accrues for co-resolution evidence (`observed`); ignored otherwise.
95
+ witnessCount: e.status === "compatible" && compatibleProvenance === "observed" ? 1 : 0,
96
+ driver,
97
+ ranAt: now
98
+ }).catch(() => {
99
+ });
100
+ }
101
+ }
102
+ async function resolveVerifyCompatibility(db, packages) {
103
+ const resolved = await Promise.all(
104
+ packages.map(async (name) => ({
105
+ name,
106
+ version: (await getPackageByName(db, name))?.latestVersion ?? "latest"
107
+ }))
108
+ );
109
+ const res = await resolveSet(
110
+ resolved.map((r) => ({ name: r.name, version: r.version === "latest" ? null : r.version }))
111
+ );
112
+ const pinned = resolved.filter((r) => r.version !== "latest");
113
+ if (pinned.length === resolved.length && pinned.length >= 2) {
114
+ await recordStackResolution(db, {
115
+ members: pinned.map((r) => ({ name: r.name, version: r.version })),
116
+ resolved: res.resolved,
117
+ reason: res.reason,
118
+ detail: res.detail ?? null
119
+ }).catch((err) => logger.warn(`compat: caching resolution failed: ${String(err)}`));
120
+ }
121
+ return { edges: pairwiseEdges(resolved, res.resolved), resolved: res.resolved };
122
+ }
123
+ async function alreadyResolved(db, names) {
124
+ const members = [];
125
+ for (const name of [...new Set(names)]) {
126
+ const version = (await getPackageByName(db, name))?.latestVersion;
127
+ if (!version) return false;
128
+ members.push({ name, version });
129
+ }
130
+ if (members.length < 2) return true;
131
+ return await getStackResolution(db, stackKey(members)).catch(() => null) !== null;
132
+ }
133
+ async function runBackfill(db, opts, runner, label) {
134
+ const topN = opts.topN ?? 50;
135
+ const batchSize = Math.max(2, opts.batchSize ?? 5);
136
+ const names = await getTopPackageNames(db, topN);
137
+ let verified = 0;
138
+ let batches = 0;
139
+ let skipped = 0;
140
+ for (let i = 0; i < names.length; i += batchSize) {
141
+ const batch = names.slice(i, i + batchSize);
142
+ if (batch.length < 2) continue;
143
+ if (await alreadyResolved(db, batch)) {
144
+ skipped++;
145
+ continue;
146
+ }
147
+ logger.info(`${label}: ${batch.join(", ")}`);
148
+ const { edges } = await runner(db, batch).catch((err) => {
149
+ logger.warn(`${label} batch failed (${batch.join(", ")}): ${String(err)}`);
150
+ return { edges: [] };
151
+ });
152
+ verified += edges.length;
153
+ batches++;
154
+ }
155
+ logger.info(`${label}: ${verified} edges across ${batches} runs, ${skipped} batches skipped`);
156
+ return { batches, verified, skipped };
157
+ }
158
+ async function backfillVerify(db, opts = {}) {
159
+ return runBackfill(db, opts, verifyCompatibility, "backfill(sandbox)");
160
+ }
161
+ async function resolveBackfill(db, opts = {}) {
162
+ return runBackfill(db, opts, resolveVerifyCompatibility, "backfill(resolve)");
163
+ }
164
+ var MAX_COMPAT_VERIFY_ATTEMPTS = 3;
165
+ async function drainCompatVerifyQueue(db, opts = {}) {
166
+ const limit = Math.max(1, opts.limit ?? 10);
167
+ const pending = await getPendingCompatVerify(db, limit);
168
+ let verified = 0;
169
+ let dropped = 0;
170
+ for (const req of pending) {
171
+ const names = req.packages;
172
+ if (await alreadyResolved(db, names)) {
173
+ await deleteCompatVerify(db, req.id);
174
+ continue;
175
+ }
176
+ try {
177
+ const { edges } = await verifyCompatibility(db, names, {});
178
+ verified += edges.length;
179
+ await deleteCompatVerify(db, req.id);
180
+ } catch (err) {
181
+ logger.warn(`compat-verify drain failed for ${names.join(", ")}: ${String(err)}`);
182
+ const attempts = await bumpCompatVerifyAttempt(db, req.id);
183
+ if (attempts >= MAX_COMPAT_VERIFY_ATTEMPTS) {
184
+ await deleteCompatVerify(db, req.id);
185
+ dropped++;
186
+ }
187
+ }
188
+ }
189
+ logger.info(
190
+ `compat-verify(sandbox): ${verified} edge(s) from ${pending.length} queued set(s), ${dropped} dropped`
191
+ );
192
+ return { processed: pending.length, verified, dropped };
193
+ }
194
+ export {
195
+ backfillVerify,
196
+ deriveCompatEdges,
197
+ drainCompatVerifyQueue,
198
+ pairKey,
199
+ resolveBackfill,
200
+ verifyCompatibility
201
+ };
@@ -0,0 +1,192 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ init_esm_shims
4
+ } from "./chunk-I3M2KJXB.js";
5
+
6
+ // src/github/dashboardIssue.ts
7
+ init_esm_shims();
8
+ import { createHash } from "crypto";
9
+ var DASHBOARD_MARKER = "<!-- lurq:dashboard -->";
10
+ var DASHBOARD_LABEL = "lurq";
11
+ var DASHBOARD_TITLE = "lurq dashboard";
12
+ var MAX_ALERTED_KEYS = 200;
13
+ var MAX_ROWS = 25;
14
+ var sha = (s) => createHash("sha256").update(s).digest("hex");
15
+ function md(s, max = 200) {
16
+ const flat = s.replace(/\s+/g, " ").trim();
17
+ const clipped = flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
18
+ return clipped.replace(/[\\`*_[\]<>|~]/g, (c) => `\\${c}`).replace(/@/g, "@\u200B").replace(/#(?=\d)/g, "#\u200B").replace(/:\/\//g, ":\u200B//");
19
+ }
20
+ var code = (s) => `\`${s.replace(/[`\r\n]/g, "").slice(0, 120)}\``;
21
+ var RANK = { critical: 0, high: 1, moderate: 2, low: 3, info: 4 };
22
+ function mcpSection(scan, urgent) {
23
+ const lines = ["### MCP servers", ""];
24
+ if (!scan.servers.length) return [...lines, "No MCP servers are committed to this repository.", ""];
25
+ lines.push("| Server | Status | Tools | Can modify | Findings |", "| --- | --- | --- | --- | --- |");
26
+ for (const s of scan.servers.slice(0, MAX_ROWS)) {
27
+ const f = s.analysis?.findings.filter((x) => RANK[x.severity] <= RANK.moderate) ?? [];
28
+ const worst = f.sort((a, b) => RANK[a.severity] - RANK[b.severity])[0]?.severity;
29
+ lines.push(
30
+ `| ${code(s.alias)} | ${s.status.replace(/_/g, " ")} | ${s.analysis?.stats.tools ?? "\u2014"} | ${s.analysis?.stats.writes ?? "\u2014"} | ${f.length ? `${f.length}${worst ? ` (worst ${worst})` : ""}` : "\u2014"} |`
31
+ );
32
+ }
33
+ lines.push("");
34
+ const account = new Map((scan.account?.results ?? []).filter((r) => r.since).map((r) => [r.alias, r.since]));
35
+ const changes = scan.servers.flatMap((s) => {
36
+ const acc = account.get(s.alias);
37
+ if (acc) return [{ alias: s.alias, key: s.serverKey, severity: acc.severity, summary: acc.summary, rug: acc.rugPull.length > 0 }];
38
+ const d = s.sinceLastScan;
39
+ return d && !d.unchanged ? [{ alias: s.alias, key: s.serverKey, severity: d.severity, summary: d.summary, rug: d.rugPull.length > 0 || d.contract.annotationFlips.some((x) => x.widensPrivilege) }] : [];
40
+ });
41
+ if (changes.length) {
42
+ lines.push("**Changed since the last scan**", "");
43
+ for (const c of changes.sort((a, b) => RANK[a.severity] - RANK[b.severity])) {
44
+ const line = `- **${c.severity}** ${code(c.alias)}: ${md(c.summary, 300)}`;
45
+ lines.push(line);
46
+ if (c.rug || c.severity === "critical") urgent.push({ key: sha(`change|${c.key}|${c.summary}`).slice(0, 16), line });
47
+ }
48
+ lines.push("");
49
+ }
50
+ const findings = scan.servers.flatMap((s) => (s.analysis?.findings ?? []).map((f) => ({ ...f, alias: s.alias, serverKey: s.serverKey }))).concat(scan.findings.map((f) => ({ ...f, alias: f.server ?? "stack", serverKey: `stack:${f.server ?? ""}` }))).filter((f) => RANK[f.severity] <= RANK.high).sort((a, b) => RANK[a.severity] - RANK[b.severity]);
51
+ if (findings.length) {
52
+ lines.push("**Needs attention**", "");
53
+ for (const f of findings.slice(0, MAX_ROWS)) {
54
+ const line = `- **${f.severity}** ${code(f.alias)}${f.tool ? ` \u203A ${code(f.tool)}` : ""}: ${md(f.detail, 240)}`;
55
+ lines.push(line);
56
+ if (f.severity === "critical") urgent.push({ key: sha(`finding|${f.serverKey}|${f.kind}|${f.tool}|${f.where}|${f.evidence}`).slice(0, 16), line });
57
+ }
58
+ lines.push("");
59
+ }
60
+ const unread = scan.servers.filter((s) => !s.snapshot);
61
+ if (unread.length) {
62
+ lines.push(`<details><summary>${unread.length} server(s) could not be read</summary>`, "");
63
+ for (const s of unread.slice(0, MAX_ROWS)) lines.push(`- ${code(s.alias)}: ${s.status.replace(/_/g, " ")}${s.error ? `, ${md(s.error, 160)}` : ""}`);
64
+ lines.push("", "</details>", "");
65
+ }
66
+ return lines;
67
+ }
68
+ function dependencySection(plan, note) {
69
+ const lines = ["### Dependencies", ""];
70
+ if (!plan) return [...lines, note ?? "Not checked on this run.", ""];
71
+ if (!plan.upgrades.length) {
72
+ return [...lines, `Everything lurq tracks is on its latest release${plan.untracked ? ` (${plan.untracked} not yet indexed)` : ""}.`, ""];
73
+ }
74
+ lines.push("| Package | Upgrade | What it removes | Advisories |", "| --- | --- | --- | --- |");
75
+ const order = { "removes-exports": 0, "arity-changed": 1, unknown: 2, clean: 3 };
76
+ for (const u of [...plan.upgrades].sort((a, b) => order[a.verdict] - order[b.verdict] || b.advisories - a.advisories).slice(0, MAX_ROWS)) {
77
+ const removes = u.verdict === "removes-exports" ? `${u.removed.length} export(s)` : u.verdict === "arity-changed" ? "changed signatures" : u.verdict === "clean" ? "nothing" : "unknown";
78
+ lines.push(`| ${code(u.package)} | ${md(u.fromVersion, 40)} \u2192 ${md(u.toVersion, 40)}${u.majorsBehind ? ` (${u.majorsBehind} major)` : ""} | ${removes} | ${u.advisories || "\u2014"} |`);
79
+ }
80
+ if (plan.upgrades.length > MAX_ROWS) lines.push("", `and ${plan.upgrades.length - MAX_ROWS} more.`);
81
+ if (plan.untracked) lines.push("", `${plan.untracked} dependencies are not indexed yet, so they are not covered here.`);
82
+ lines.push("");
83
+ return lines;
84
+ }
85
+ function renderDashboardIssue(input) {
86
+ const urgent = [];
87
+ const content = [
88
+ ...input.scan ? mcpSection(input.scan, urgent) : ["### MCP servers", "", "Not scanned on this run.", ""],
89
+ ...dependencySection(input.plan, input.planNote)
90
+ ].join("\n");
91
+ const stamp = `Updated ${input.generatedAt.toISOString().slice(0, 16).replace("T", " ")} UTC${input.runUrl ? ` by [this run](${input.runUrl})` : ""}.`;
92
+ const body = [
93
+ DASHBOARD_MARKER,
94
+ `## ${DASHBOARD_TITLE}`,
95
+ "",
96
+ `${stamp} This issue is edited in place; lurq comments only when something needs a look today. [Open the dashboard](${input.dashboardUrl}).`,
97
+ "",
98
+ content,
99
+ "<sub>Close this issue to stop lurq updating it. Remove `--github-issue` from the workflow to stop creating it.</sub>"
100
+ ].join("\n");
101
+ return { title: DASHBOARD_TITLE, body, hash: sha(content).slice(0, 24), urgent };
102
+ }
103
+ var HASH_RE = /<!-- lurq:hash:([0-9a-f]+) -->/;
104
+ var ALERTED_RE = /<!-- lurq:alerted:([A-Za-z0-9,]*) -->/;
105
+ function readMarkers(body) {
106
+ return {
107
+ hash: HASH_RE.exec(body)?.[1] ?? null,
108
+ alerted: (ALERTED_RE.exec(body)?.[1] ?? "").split(",").filter(Boolean)
109
+ };
110
+ }
111
+ function withMarkers(body, hash, alerted) {
112
+ const keys = alerted.slice(-MAX_ALERTED_KEYS).join(",");
113
+ return body.replace(DASHBOARD_MARKER, `${DASHBOARD_MARKER}
114
+ <!-- lurq:hash:${hash} -->
115
+ <!-- lurq:alerted:${keys} -->`);
116
+ }
117
+ var GithubIssueError = class extends Error {
118
+ constructor(message, status) {
119
+ super(message);
120
+ this.status = status;
121
+ this.name = "GithubIssueError";
122
+ }
123
+ status;
124
+ };
125
+ function githubEnvFrom(env) {
126
+ const token = env.GITHUB_TOKEN;
127
+ const repo = env.GITHUB_REPOSITORY;
128
+ if (!token || !repo || !/^[\w.-]+\/[\w.-]+$/.test(repo)) return null;
129
+ return { token, repo, apiUrl: (env.GITHUB_API_URL ?? "https://api.github.com").replace(/\/$/, "") };
130
+ }
131
+ async function gh(env, method, path, body) {
132
+ const res = await (env.fetchImpl ?? fetch)(`${env.apiUrl}${path}`, {
133
+ method,
134
+ headers: {
135
+ Authorization: `Bearer ${env.token}`,
136
+ Accept: "application/vnd.github+json",
137
+ "X-GitHub-Api-Version": "2022-11-28",
138
+ "User-Agent": "lurq",
139
+ ...body ? { "Content-Type": "application/json" } : {}
140
+ },
141
+ body: body ? JSON.stringify(body) : void 0
142
+ });
143
+ const data = await res.json().catch(() => null);
144
+ if (!res.ok && !(method === "POST" && path.endsWith("/labels") && res.status === 422)) {
145
+ const message = data?.message ?? `HTTP ${res.status}`;
146
+ throw new GithubIssueError(
147
+ res.status === 403 || res.status === 404 ? `GitHub refused (${message}); the workflow needs \`permissions: issues: write\`` : `GitHub ${res.status}: ${message}`,
148
+ res.status
149
+ );
150
+ }
151
+ return { status: res.status, data };
152
+ }
153
+ async function upsertDashboardIssue(env, rendered) {
154
+ const { data: issues } = await gh(env, "GET", `/repos/${env.repo}/issues?labels=${DASHBOARD_LABEL}&state=all&per_page=100`);
155
+ const mine = (issues ?? []).filter((i) => !i.pull_request && (i.body ?? "").includes(DASHBOARD_MARKER));
156
+ const open = mine.find((i) => i.state === "open");
157
+ if (!open) {
158
+ if (mine.length) return { action: "closed", url: mine[0].html_url, commented: 0 };
159
+ await gh(env, "POST", `/repos/${env.repo}/labels`, { name: DASHBOARD_LABEL, color: "6e40c9", description: "lurq dependency and MCP dashboard" });
160
+ const { data } = await gh(env, "POST", `/repos/${env.repo}/issues`, {
161
+ title: rendered.title,
162
+ body: withMarkers(rendered.body, rendered.hash, rendered.urgent.map((u) => u.key)),
163
+ labels: [DASHBOARD_LABEL]
164
+ });
165
+ return { action: "created", url: data.html_url, commented: 0 };
166
+ }
167
+ const markers = readMarkers(open.body ?? "");
168
+ const fresh = rendered.urgent.filter((u) => !markers.alerted.includes(u.key));
169
+ if (markers.hash === rendered.hash && !fresh.length) return { action: "unchanged", url: open.html_url, commented: 0 };
170
+ await gh(env, "PATCH", `/repos/${env.repo}/issues/${open.number}`, {
171
+ body: withMarkers(rendered.body, rendered.hash, [...markers.alerted, ...fresh.map((u) => u.key)])
172
+ });
173
+ if (fresh.length) {
174
+ await gh(env, "POST", `/repos/${env.repo}/issues/${open.number}/comments`, {
175
+ body: [`lurq found ${fresh.length === 1 ? "something" : `${fresh.length} things`} that need a look today:`, "", ...fresh.map((u) => u.line)].join("\n")
176
+ });
177
+ }
178
+ return { action: "updated", url: open.html_url, commented: fresh.length ? 1 : 0 };
179
+ }
180
+ export {
181
+ DASHBOARD_LABEL,
182
+ DASHBOARD_MARKER,
183
+ DASHBOARD_TITLE,
184
+ GithubIssueError,
185
+ code,
186
+ githubEnvFrom,
187
+ md,
188
+ readMarkers,
189
+ renderDashboardIssue,
190
+ upsertDashboardIssue,
191
+ withMarkers
192
+ };
@@ -0,0 +1,13 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ checkApi,
4
+ diffApiSurfaces,
5
+ formatApiCheck
6
+ } from "./chunk-CIDWNUAP.js";
7
+ import "./chunk-3GHJR7XR.js";
8
+ import "./chunk-I3M2KJXB.js";
9
+ export {
10
+ checkApi,
11
+ diffApiSurfaces,
12
+ formatApiCheck
13
+ };