lurqrun 0.1.6 → 0.1.8

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 (239) hide show
  1. package/README.md +311 -139
  2. package/dist/auditHandler-VWCXSDVO.js +24 -0
  3. package/dist/autopilotInit-Q62MX5M6.js +178 -0
  4. package/dist/bin/lurq.js +3255 -23319
  5. package/dist/browserAuth-J7APSD4P.js +96 -0
  6. package/dist/cache-AEAKCV4I.js +12 -0
  7. package/dist/check-2JTQDQA6.js +2613 -0
  8. package/dist/check-PQSQ2MMA.js +192 -0
  9. package/dist/checkUpgrade-5YW77OBL.js +24 -0
  10. package/dist/chunk-2GAYNIHG.js +40 -0
  11. package/dist/chunk-2O6Z37IT.js +423 -0
  12. package/dist/chunk-2WD4QAH4.js +116 -0
  13. package/dist/chunk-3676XOBU.js +2235 -0
  14. package/dist/chunk-3D2MPGOQ.js +181 -0
  15. package/dist/chunk-3GHJR7XR.js +2049 -0
  16. package/dist/chunk-4ESO33J6.js +34 -0
  17. package/dist/chunk-4JHDSVIN.js +1229 -0
  18. package/dist/chunk-4KCPOMG6.js +68 -0
  19. package/dist/chunk-53SG6XWA.js +141 -0
  20. package/dist/chunk-5ABNDB3I.js +37 -0
  21. package/dist/chunk-5ALIJFDA.js +114 -0
  22. package/dist/chunk-63MUJNZL.js +318 -0
  23. package/dist/chunk-64ZF7KO4.js +1571 -0
  24. package/dist/chunk-6DM6UQFD.js +318 -0
  25. package/dist/chunk-6EQ3ARXA.js +304 -0
  26. package/dist/chunk-6L67QMCP.js +92 -0
  27. package/dist/chunk-72Y2FDVS.js +172 -0
  28. package/dist/chunk-A3TYI2TF.js +288 -0
  29. package/dist/chunk-B2UUYRBX.js +536 -0
  30. package/dist/chunk-BJT2LHAR.js +320 -0
  31. package/dist/chunk-BM3LF5T6.js +132 -0
  32. package/dist/chunk-BN3NM47Q.js +214 -0
  33. package/dist/chunk-BUALU27S.js +123 -0
  34. package/dist/chunk-C6GLE626.js +160 -0
  35. package/dist/chunk-D3K6IZVR.js +12845 -0
  36. package/dist/chunk-D3VTZS7V.js +222 -0
  37. package/dist/chunk-DM37MTOO.js +636 -0
  38. package/dist/chunk-DONTW3NE.js +171 -0
  39. package/dist/chunk-DSROTZ3Z.js +38 -0
  40. package/dist/chunk-ELGCAM7P.js +184 -0
  41. package/dist/chunk-EQCXENKZ.js +130 -0
  42. package/dist/chunk-EYAKM6YN.js +96 -0
  43. package/dist/chunk-FDFPMBCA.js +112 -0
  44. package/dist/chunk-FVYFV5HA.js +154 -0
  45. package/dist/chunk-GE37NVLN.js +15 -0
  46. package/dist/chunk-GM5Y555O.js +143 -0
  47. package/dist/chunk-GRJXQBQZ.js +793 -0
  48. package/dist/chunk-HWFX4BC4.js +177 -0
  49. package/dist/chunk-I3M2KJXB.js +56 -0
  50. package/dist/chunk-IFNONGRQ.js +603 -0
  51. package/dist/chunk-J3U2CPSK.js +136 -0
  52. package/dist/chunk-J6XQ7OPZ.js +74 -0
  53. package/dist/chunk-KMV4Y6R3.js +127 -0
  54. package/dist/chunk-KP5ZDDPE.js +340 -0
  55. package/dist/chunk-KYKSZ3XZ.js +202 -0
  56. package/dist/chunk-LEGPB7DO.js +81 -0
  57. package/dist/chunk-LUAKDHLZ.js +40 -0
  58. package/dist/chunk-MHUEVBVO.js +35 -0
  59. package/dist/chunk-MYGSLK44.js +37 -0
  60. package/dist/chunk-NEZNAPPN.js +41 -0
  61. package/dist/chunk-NPVN2THM.js +197 -0
  62. package/dist/chunk-NYZU5NCW.js +23 -0
  63. package/dist/chunk-O4KHCV6I.js +320 -0
  64. package/dist/chunk-ONDVTXUO.js +240 -0
  65. package/dist/chunk-OTJFHESY.js +176 -0
  66. package/dist/chunk-P6MIKSPY.js +243 -0
  67. package/dist/chunk-Q5VPF4WI.js +26 -0
  68. package/dist/chunk-QCRBX3LV.js +165 -0
  69. package/dist/chunk-QKGYDMWB.js +7409 -0
  70. package/dist/chunk-QSL6QN5X.js +115 -0
  71. package/dist/chunk-QUIMQ7YL.js +73 -0
  72. package/dist/chunk-RG3YLU6E.js +49 -0
  73. package/dist/chunk-SHCEBP3J.js +107 -0
  74. package/dist/chunk-SHZFOSXC.js +462 -0
  75. package/dist/chunk-SOXFMMXC.js +151 -0
  76. package/dist/chunk-TDTYV6QI.js +119 -0
  77. package/dist/chunk-TNTXWSYA.js +19 -0
  78. package/dist/chunk-TUXQ32WE.js +2251 -0
  79. package/dist/chunk-VGCDRK3S.js +37 -0
  80. package/dist/chunk-VLRHFMGJ.js +58 -0
  81. package/dist/chunk-WHX2ZFCG.js +4048 -0
  82. package/dist/chunk-X4W64MHU.js +2005 -0
  83. package/dist/chunk-XBQA4I36.js +92 -0
  84. package/dist/chunk-XGOV6KV4.js +413 -0
  85. package/dist/chunk-XIFQIFSZ.js +940 -0
  86. package/dist/chunk-XLXPVN3Y.js +15393 -0
  87. package/dist/chunk-ZJMLQ37G.js +90 -0
  88. package/dist/client-MU4EUDZV.js +15 -0
  89. package/dist/commands-UOOTMBKA.js +1023 -0
  90. package/dist/compat-Q5DVPITN.js +201 -0
  91. package/dist/constants-DJFOFZ44.js +24 -0
  92. package/dist/dashboardIssue-KBKLQMGC.js +274 -0
  93. package/dist/diff-I4SNUHU3.js +13 -0
  94. package/dist/dist-4XXIXHHZ.js +12945 -0
  95. package/dist/domains-VRT4BRVZ.js +14 -0
  96. package/dist/e2b-FVPHDULZ.js +172 -0
  97. package/dist/env-UN6KGZ7S.js +15 -0
  98. package/dist/envCheck-KUPTORFQ.js +71 -0
  99. package/dist/extract-6WG265BL.js +455 -0
  100. package/dist/fetch-PJ3SC32M.js +22 -0
  101. package/dist/firstTouch-COJCMOB3.js +55 -0
  102. package/dist/fix-3EDWNKW3.js +220 -0
  103. package/dist/handlers-4Q37WIFT.js +55 -0
  104. package/dist/hook-NA66XJLC.js +412 -0
  105. package/dist/http-25GJ6SKK.js +6928 -0
  106. package/dist/ingestQueue-FSVJC3AA.js +37 -0
  107. package/dist/install-G2HHXYJ2.js +20 -0
  108. package/dist/installSkill-5TIMYIJZ.js +70 -0
  109. package/dist/inventory-5AWSLJYU.js +31 -0
  110. package/dist/local-XPZMRH5R.js +13 -0
  111. package/dist/manifest-ENMIC54B.js +13 -0
  112. package/dist/mcp-PENLL2PK.js +500 -0
  113. package/dist/mcpConfig-3LYPRY5Q.js +80 -0
  114. package/dist/mcpHandlers-PO7GENA7.js +22 -0
  115. package/dist/mcpScan-ULP626TQ.js +1735 -0
  116. package/dist/mcpScanWorkflow-27O44FOE.js +98 -0
  117. package/dist/mcpStack-ZNYIFXZ5.js +20 -0
  118. package/dist/model-ASMZWLM7.js +214 -0
  119. package/dist/packages-RWF2LXST.js +40 -0
  120. package/dist/plan-SDILIDZT.js +465 -0
  121. package/dist/planView-ZAKRTGVS.js +82 -0
  122. package/dist/policy-JAGNMQJI.js +115 -0
  123. package/dist/probe-3IK646WN.js +610 -0
  124. package/dist/publicUpgrades-WTBGLDIK.js +42 -0
  125. package/dist/references-I6Y4BSRR.js +16 -0
  126. package/dist/release-7IU2R4YG.js +128 -0
  127. package/dist/remote-FN6225AH.js +42 -0
  128. package/dist/rename-OS6JYBZQ.js +204 -0
  129. package/dist/reportRuns-O4X7ZFTX.js +77 -0
  130. package/dist/safeFetch-COERXGFN.js +19 -0
  131. package/dist/sandbox-SAPSRKEI.js +39 -0
  132. package/dist/sarif-WLVJFJ7U.js +125 -0
  133. package/dist/server-OLTY3NYT.js +59 -0
  134. package/dist/surface-7MHE3RL7.js +143 -0
  135. package/dist/surface-JS2XU3U3.js +38 -0
  136. package/dist/surfaceHandlers-4B6TMZ34.js +20 -0
  137. package/dist/typecheck-NGOKNAJY.js +282 -0
  138. package/dist/types-M5JP2W3D.js +10 -0
  139. package/dist/uninstall-I2IJP5JZ.js +200 -0
  140. package/dist/upgrade-FS26DJGG.js +650 -0
  141. package/dist/upgradePlan-ZS5IOVMZ.js +181 -0
  142. package/dist/upkeepHandler-VFGYXJKB.js +13 -0
  143. package/dist/userConfig-ICASHI47.js +20 -0
  144. package/dist/watch-OCNEUXG6.js +204 -0
  145. package/package.json +26 -20
  146. package/templates/agent-rules.md +4 -4
  147. package/templates/skill-instructions.md +35 -17
  148. package/dist/bin/lurq.js.map +0 -1
  149. package/dist/index.d.ts +0 -805
  150. package/dist/index.js +0 -23570
  151. package/dist/index.js.map +0 -1
  152. package/drizzle/0000_confused_fabian_cortez.sql +0 -54
  153. package/drizzle/0001_aspiring_timeslip.sql +0 -15
  154. package/drizzle/0002_lyrical_lila_cheney.sql +0 -14
  155. package/drizzle/0003_violet_giant_girl.sql +0 -14
  156. package/drizzle/0004_slim_valeria_richards.sql +0 -15
  157. package/drizzle/0005_petite_luke_cage.sql +0 -12
  158. package/drizzle/0006_calm_nighthawk.sql +0 -3
  159. package/drizzle/0007_slimy_naoko.sql +0 -1
  160. package/drizzle/0008_peaceful_tigra.sql +0 -1
  161. package/drizzle/0009_smooth_harrier.sql +0 -10
  162. package/drizzle/0010_curved_amphibian.sql +0 -2
  163. package/drizzle/0011_compat_provenance_closures.sql +0 -11
  164. package/drizzle/0012_api_surfaces.sql +0 -9
  165. package/drizzle/0013_nice_thanos.sql +0 -1
  166. package/drizzle/0014_luxuriant_malcolm_colcord.sql +0 -10
  167. package/drizzle/0015_past_fat_cobra.sql +0 -11
  168. package/drizzle/0016_futuristic_junta.sql +0 -50
  169. package/drizzle/0017_absent_grandmaster.sql +0 -20
  170. package/drizzle/0018_rainy_proemial_gods.sql +0 -1
  171. package/drizzle/0019_dashing_korvac.sql +0 -11
  172. package/drizzle/0020_normal_vulture.sql +0 -3
  173. package/drizzle/0021_dazzling_blue_shield.sql +0 -17
  174. package/drizzle/0022_massive_ghost_rider.sql +0 -24
  175. package/drizzle/0023_next_shatterstar.sql +0 -1
  176. package/drizzle/0024_dusty_maelstrom.sql +0 -15
  177. package/drizzle/0025_gifted_harpoon.sql +0 -5
  178. package/drizzle/0026_awesome_mordo.sql +0 -1
  179. package/drizzle/0027_charming_ulik.sql +0 -2
  180. package/drizzle/0028_romantic_loners.sql +0 -2
  181. package/drizzle/0029_busy_korvac.sql +0 -16
  182. package/drizzle/0030_steady_mathemanic.sql +0 -6
  183. package/drizzle/0031_redundant_maginty.sql +0 -2
  184. package/drizzle/0032_stack_resolutions.sql +0 -14
  185. package/drizzle/0033_graceful_tyger_tiger.sql +0 -3
  186. package/drizzle/0034_uneven_thunderbird.sql +0 -1
  187. package/drizzle/0035_api_key_scopes.sql +0 -1
  188. package/drizzle/0036_policy_audit.sql +0 -21
  189. package/drizzle/0037_subscription_seats.sql +0 -1
  190. package/drizzle/0038_symbol_offsets.sql +0 -2
  191. package/drizzle/0039_mcp_runtime_scans.sql +0 -80
  192. package/drizzle/0040_subscription_overage_and_interval.sql +0 -4
  193. package/drizzle/0041_account_email.sql +0 -38
  194. package/drizzle/0042_alert_channels.sql +0 -21
  195. package/drizzle/meta/0000_snapshot.json +0 -370
  196. package/drizzle/meta/0001_snapshot.json +0 -482
  197. package/drizzle/meta/0002_snapshot.json +0 -575
  198. package/drizzle/meta/0003_snapshot.json +0 -667
  199. package/drizzle/meta/0004_snapshot.json +0 -769
  200. package/drizzle/meta/0005_snapshot.json +0 -864
  201. package/drizzle/meta/0006_snapshot.json +0 -882
  202. package/drizzle/meta/0007_snapshot.json +0 -876
  203. package/drizzle/meta/0008_snapshot.json +0 -882
  204. package/drizzle/meta/0009_snapshot.json +0 -948
  205. package/drizzle/meta/0010_snapshot.json +0 -969
  206. package/drizzle/meta/0011_snapshot.json +0 -1049
  207. package/drizzle/meta/0012_snapshot.json +0 -1115
  208. package/drizzle/meta/0013_snapshot.json +0 -1121
  209. package/drizzle/meta/0014_snapshot.json +0 -1190
  210. package/drizzle/meta/0015_snapshot.json +0 -1280
  211. package/drizzle/meta/0016_snapshot.json +0 -1683
  212. package/drizzle/meta/0017_snapshot.json +0 -1834
  213. package/drizzle/meta/0018_snapshot.json +0 -1834
  214. package/drizzle/meta/0019_snapshot.json +0 -1909
  215. package/drizzle/meta/0020_snapshot.json +0 -1921
  216. package/drizzle/meta/0021_snapshot.json +0 -2045
  217. package/drizzle/meta/0022_snapshot.json +0 -2246
  218. package/drizzle/meta/0023_snapshot.json +0 -2252
  219. package/drizzle/meta/0024_snapshot.json +0 -2375
  220. package/drizzle/meta/0025_snapshot.json +0 -2407
  221. package/drizzle/meta/0026_snapshot.json +0 -2413
  222. package/drizzle/meta/0027_snapshot.json +0 -2425
  223. package/drizzle/meta/0028_snapshot.json +0 -2438
  224. package/drizzle/meta/0029_snapshot.json +0 -2546
  225. package/drizzle/meta/0030_snapshot.json +0 -2586
  226. package/drizzle/meta/0031_snapshot.json +0 -2598
  227. package/drizzle/meta/0032_snapshot.json +0 -2699
  228. package/drizzle/meta/0033_snapshot.json +0 -2712
  229. package/drizzle/meta/0034_snapshot.json +0 -2719
  230. package/drizzle/meta/0035_snapshot.json +0 -2726
  231. package/drizzle/meta/0036_snapshot.json +0 -2876
  232. package/drizzle/meta/0037_snapshot.json +0 -2883
  233. package/drizzle/meta/0038_snapshot.json +0 -2895
  234. package/drizzle/meta/0039_snapshot.json +0 -3501
  235. package/drizzle/meta/0040_snapshot.json +0 -3527
  236. package/drizzle/meta/0041_snapshot.json +0 -3824
  237. package/drizzle/meta/0042_snapshot.json +0 -3960
  238. package/drizzle/meta/_journal.json +0 -307
  239. package/src/data/seed.json +0 -253
@@ -0,0 +1,220 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ SCAN_LIMIT,
4
+ fixableTargets,
5
+ parseUpgradeSpec,
6
+ planUpgrades
7
+ } from "./chunk-QCRBX3LV.js";
8
+ import {
9
+ manifestFindings
10
+ } from "./chunk-5ALIJFDA.js";
11
+ import {
12
+ applyEdits,
13
+ deterministic,
14
+ editsByFile,
15
+ unifiedDiff
16
+ } from "./chunk-BM3LF5T6.js";
17
+ import "./chunk-3GHJR7XR.js";
18
+ import {
19
+ init_esm_shims
20
+ } from "./chunk-I3M2KJXB.js";
21
+
22
+ // src/cli/fix.ts
23
+ init_esm_shims();
24
+ import { readFileSync, writeFileSync } from "fs";
25
+ import { join, relative } from "path";
26
+ async function derivePlanTargets(dir, opts) {
27
+ const { buildUpgradePlan } = await import("./upgradePlan-ZS5IOVMZ.js");
28
+ try {
29
+ const plan = await buildUpgradePlan(dir, {
30
+ url: opts.url,
31
+ apiKey: opts.apiKey,
32
+ repo: opts.repo
33
+ });
34
+ return fixableTargets(plan.upgrades, opts.max);
35
+ } catch (err) {
36
+ if (err instanceof Error && err.name === "MissingKeyError") {
37
+ throw new Error(
38
+ `${err.message}
39
+
40
+ Or skip the lookup: \`lurq fix --upgrade pkg@from..to\` reads both versions straight from npm and needs no key.`
41
+ );
42
+ }
43
+ throw err;
44
+ }
45
+ }
46
+ function stage(root, findings) {
47
+ const writes = /* @__PURE__ */ new Map();
48
+ let diff = "";
49
+ for (const [file, edits] of editsByFile(findings.filter(deterministic))) {
50
+ const before = readFileSync(join(root, file), "utf8");
51
+ diff += unifiedDiff(file, before, edits);
52
+ writes.set(file, applyEdits(before, edits));
53
+ }
54
+ return { writes, diff };
55
+ }
56
+ async function runFix(dir, opts) {
57
+ const { scanReferences } = await import("./references-I6Y4BSRR.js");
58
+ const { checkUpgrade } = await import("./upgrade-FS26DJGG.js");
59
+ const { renamePlan } = await import("./rename-OS6JYBZQ.js");
60
+ const asked = Boolean(opts.plan) || (opts.upgrade?.length ?? 0) > 0;
61
+ const split = asked ? {
62
+ ...fixableTargets(opts.plan ? planUpgrades(opts.plan) : [], opts.max),
63
+ named: (opts.upgrade ?? []).map(parseUpgradeSpec)
64
+ } : { ...await derivePlanTargets(dir, opts), named: [] };
65
+ const targets = [...split.targets, ...split.named];
66
+ const skipped = split.skipped;
67
+ const { runDomains, SOURCE_DOMAINS } = await import("./domains-VRT4BRVZ.js");
68
+ const source = await runDomains({ dir, domains: SOURCE_DOMAINS });
69
+ const unchecked = source.skipped.map((d) => ({ domain: d.domain, reason: d.reason }));
70
+ if (targets.length === 0 && source.findings.length === 0) {
71
+ const empty = {
72
+ root: dir,
73
+ files: [],
74
+ applied: [],
75
+ remaining: [],
76
+ refused: [],
77
+ skipped,
78
+ unchecked
79
+ };
80
+ const lines = skipped.length ? [
81
+ `Nothing attempted in ${dir}. ${skipped.length} upgrade(s) deliberately not tried:`,
82
+ ...skippedLines(skipped)
83
+ ] : [
84
+ `Nothing to fix in ${dir}: ${asked ? "no upgrade named here needs a change" : "every dependency is current or held by the repo policy"}, ${// Never "the source is clean" when no detector survived to look.
85
+ // `ran` is empty only when every source domain threw, and that is
86
+ // the one case where the reassuring sentence would be false.
87
+ source.ran.length ? "and nothing in the source needs changing" : "and the source could not be scanned"}.`
88
+ ];
89
+ lines.push(...uncheckedLines(unchecked));
90
+ console.log(opts.json ? JSON.stringify(empty, null, 2) : lines.join("\n"));
91
+ return;
92
+ }
93
+ let findings = [];
94
+ const refused = [];
95
+ if (targets.length > 0) {
96
+ const refs = scanReferences(dir, { limit: SCAN_LIMIT });
97
+ const report = await checkUpgrade(targets, refs, { rootDir: dir });
98
+ const renames = renamePlan(report);
99
+ const { findManifests } = await import("./upgradePlan-ZS5IOVMZ.js");
100
+ const manifests = manifestFindings(dir, targets, {
101
+ files: findManifests(dir).map((abs) => relative(dir, abs) || "package.json")
102
+ });
103
+ findings = [...renames.findings, ...manifests.findings];
104
+ refused.push(
105
+ ...renames.refused,
106
+ ...manifests.refused.map((r) => ({ symbol: r.package, file: r.file, reason: r.reason }))
107
+ );
108
+ }
109
+ findings = [...findings, ...source.findings];
110
+ const result = {
111
+ root: dir,
112
+ files: [],
113
+ applied: [],
114
+ remaining: [],
115
+ refused: refused.map((r) => ({ symbol: r.symbol, file: r.file, reason: r.reason })),
116
+ skipped,
117
+ unchecked
118
+ };
119
+ const { writes, diff } = stage(dir, findings);
120
+ result.files = [...writes.keys()];
121
+ for (const f of findings) {
122
+ if (deterministic(f)) {
123
+ result.applied.push({
124
+ code: f.code,
125
+ summary: f.fix.summary,
126
+ files: [...new Set(f.fix.edits.map((e) => e.file))]
127
+ });
128
+ } else {
129
+ result.remaining.push({
130
+ code: f.code,
131
+ detail: f.detail,
132
+ instruction: f.fix?.task?.instruction,
133
+ files: f.fix?.task?.files,
134
+ evidence: f.fix?.task?.evidence
135
+ });
136
+ }
137
+ }
138
+ if (opts.apply && writes.size > 0) {
139
+ const { writeFileAtomic } = await import("./installSkill-5TIMYIJZ.js");
140
+ for (const [file, contents] of writes) writeFileAtomic(join(dir, file), contents);
141
+ }
142
+ if (opts.sarif) {
143
+ const { toSarif } = await import("./sarif-WLVJFJ7U.js");
144
+ const { VERSION } = await import("./constants-DJFOFZ44.js");
145
+ const sarif = toSarif(findings, {
146
+ version: VERSION,
147
+ // Read from disk rather than reusing the staged text: regions must
148
+ // describe the file as it is, not as it would be after the fix.
149
+ read: (file) => {
150
+ try {
151
+ return readFileSync(join(dir, file), "utf8");
152
+ } catch {
153
+ return null;
154
+ }
155
+ }
156
+ });
157
+ writeFileSync(opts.sarif, `${JSON.stringify(sarif, null, 2)}
158
+ `, "utf8");
159
+ console.error(`wrote ${opts.sarif}`);
160
+ }
161
+ if (opts.json) {
162
+ console.log(JSON.stringify({ ...result, applied_to_disk: Boolean(opts.apply) }, null, 2));
163
+ } else {
164
+ console.log(formatFix(result, diff, Boolean(opts.apply)));
165
+ }
166
+ if (opts.exitCode && result.remaining.length > 0) process.exitCode = 1;
167
+ }
168
+ function uncheckedLines(unchecked) {
169
+ if (unchecked.length === 0) return [];
170
+ return [
171
+ "",
172
+ `${unchecked.length} domain(s) could not be checked:`,
173
+ ...unchecked.map((u) => ` ${u.domain}: ${u.reason}`)
174
+ ];
175
+ }
176
+ function skippedLines(skipped) {
177
+ return skipped.map((s) => ` ${s.package}: ${s.reason}`);
178
+ }
179
+ function formatFix(result, diff, applied) {
180
+ const out = [];
181
+ if (result.applied.length === 0 && result.remaining.length === 0) {
182
+ return [
183
+ `Nothing to fix in ${result.root}: no upgrade in this plan renames a symbol this code references,`,
184
+ "every declared range already admits its target, and nothing in the source names a retired model",
185
+ "or reads an undeclared variable."
186
+ ].join(" ");
187
+ }
188
+ if (result.applied.length > 0) {
189
+ out.push(
190
+ applied ? `Wrote ${result.files.length} file(s) in ${result.root}:` : `Would write ${result.files.length} file(s) in ${result.root} (pass --apply):`
191
+ );
192
+ for (const a of result.applied) out.push(` ${a.summary} \u2014 ${a.files.join(", ")}`);
193
+ if (!applied && diff) out.push("", diff.trimEnd());
194
+ }
195
+ if (result.remaining.length > 0) {
196
+ out.push("", `${result.remaining.length} change(s) lurq will not make for you:`);
197
+ for (const r of result.remaining) {
198
+ out.push(` ${r.detail}`);
199
+ if (r.instruction) out.push(` do: ${r.instruction}`);
200
+ if (r.files?.length) out.push(` in: ${r.files.join(", ")}`);
201
+ for (const e of r.evidence ?? []) out.push(` use: ${e}`);
202
+ }
203
+ }
204
+ if (result.skipped.length > 0) {
205
+ out.push("", `${result.skipped.length} upgrade(s) deliberately not attempted:`);
206
+ out.push(...skippedLines(result.skipped));
207
+ }
208
+ out.push(...uncheckedLines(result.unchecked));
209
+ if (result.refused.length > 0) {
210
+ out.push("", "Proven renames left alone:");
211
+ for (const r of result.refused) out.push(` ${r.file ?? r.symbol}: ${r.reason}`);
212
+ }
213
+ return out.join("\n");
214
+ }
215
+ export {
216
+ formatFix,
217
+ runFix,
218
+ stage,
219
+ uncheckedLines
220
+ };
@@ -0,0 +1,55 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ USAGE_PAGE_SIZE,
4
+ handleCompare,
5
+ handleCompat,
6
+ handleEvaluate,
7
+ handlePolicy,
8
+ handleRecommend,
9
+ handleReportOutcome,
10
+ handleUsage,
11
+ handleVerify,
12
+ latestDataAsOf,
13
+ rowToEvaluate
14
+ } from "./chunk-64ZF7KO4.js";
15
+ import "./chunk-QSL6QN5X.js";
16
+ import "./chunk-NYZU5NCW.js";
17
+ import "./chunk-2WD4QAH4.js";
18
+ import "./chunk-DSROTZ3Z.js";
19
+ import "./chunk-TUXQ32WE.js";
20
+ import "./chunk-BUALU27S.js";
21
+ import "./chunk-QUIMQ7YL.js";
22
+ import "./chunk-6DM6UQFD.js";
23
+ import "./chunk-EYAKM6YN.js";
24
+ import "./chunk-D3VTZS7V.js";
25
+ import "./chunk-4ESO33J6.js";
26
+ import "./chunk-NPVN2THM.js";
27
+ import "./chunk-VLRHFMGJ.js";
28
+ import "./chunk-VGCDRK3S.js";
29
+ import "./chunk-4JHDSVIN.js";
30
+ import "./chunk-GM5Y555O.js";
31
+ import "./chunk-2GAYNIHG.js";
32
+ import "./chunk-KYKSZ3XZ.js";
33
+ import "./chunk-A3TYI2TF.js";
34
+ import "./chunk-HWFX4BC4.js";
35
+ import "./chunk-6L67QMCP.js";
36
+ import "./chunk-3GHJR7XR.js";
37
+ import "./chunk-GRJXQBQZ.js";
38
+ import "./chunk-WHX2ZFCG.js";
39
+ import "./chunk-LUAKDHLZ.js";
40
+ import "./chunk-MYGSLK44.js";
41
+ import "./chunk-72Y2FDVS.js";
42
+ import "./chunk-I3M2KJXB.js";
43
+ export {
44
+ USAGE_PAGE_SIZE,
45
+ handleCompare,
46
+ handleCompat,
47
+ handleEvaluate,
48
+ handlePolicy,
49
+ handleRecommend,
50
+ handleReportOutcome,
51
+ handleUsage,
52
+ handleVerify,
53
+ latestDataAsOf,
54
+ rowToEvaluate
55
+ };
@@ -0,0 +1,412 @@
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/cli/hook.ts
7
+ init_esm_shims();
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
9
+ import { tmpdir } from "os";
10
+ import { basename, dirname, isAbsolute, join } from "path";
11
+
12
+ // src/benchmark/normalize.ts
13
+ init_esm_shims();
14
+ var NPM_NAME_RE = /^(@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
15
+ function isValidNpmName(name) {
16
+ if (!name || name.length > 214) return false;
17
+ return NPM_NAME_RE.test(name);
18
+ }
19
+
20
+ // src/cli/hook.ts
21
+ var MANAGERS = /* @__PURE__ */ new Map([
22
+ ["npm", /* @__PURE__ */ new Set(["install", "i", "in", "add"])],
23
+ ["pnpm", /* @__PURE__ */ new Set(["add", "install", "i"])],
24
+ ["yarn", /* @__PURE__ */ new Set(["add"])],
25
+ ["bun", /* @__PURE__ */ new Set(["add", "install", "i"])]
26
+ ]);
27
+ var VALUE_FLAGS = /* @__PURE__ */ new Set([
28
+ "--prefix",
29
+ "--registry",
30
+ "--filter",
31
+ "-F",
32
+ "-C",
33
+ "--dir",
34
+ "--cwd",
35
+ "--workspace",
36
+ "-w",
37
+ "--tag",
38
+ "--cache",
39
+ "--userconfig"
40
+ ]);
41
+ var MAX_NAMES = 10;
42
+ var VERIFY_TIMEOUT_MS = 8e3;
43
+ function specName(spec) {
44
+ if (/[:/\\]/.test(spec.replace(/^@[^/]+\//, "")) || /\.(tgz|tar|tar\.gz)$/.test(spec))
45
+ return null;
46
+ const at = spec.indexOf("@", 1);
47
+ const name = at === -1 ? spec : spec.slice(0, at);
48
+ return isValidNpmName(name) ? name : null;
49
+ }
50
+ var ALLOW_ENV = "LURQ_ALLOW=1";
51
+ function commandStart(tokens) {
52
+ let i = 0;
53
+ while (i < tokens.length && (tokens[i] === "sudo" || /^[A-Za-z_]\w*=/.test(tokens[i]))) {
54
+ if (tokens[i] === ALLOW_ENV) return -1;
55
+ i++;
56
+ }
57
+ return i;
58
+ }
59
+ function installTargets(command) {
60
+ const names = /* @__PURE__ */ new Set();
61
+ for (const segment of command.split(/&&|\|\||[;|\n]/)) {
62
+ const tokens = segment.trim().split(/\s+/);
63
+ const i = commandStart(tokens);
64
+ if (i === -1) continue;
65
+ if (!MANAGERS.get(tokens[i] ?? "")?.has(tokens[i + 1] ?? "")) continue;
66
+ for (let j = i + 2; j < tokens.length; j++) {
67
+ const t = tokens[j];
68
+ if (VALUE_FLAGS.has(t)) j++;
69
+ else if (!t.startsWith("-")) {
70
+ const name = specName(t);
71
+ if (name) names.add(name);
72
+ }
73
+ }
74
+ }
75
+ return [...names];
76
+ }
77
+ var RUNNERS = [
78
+ ["npx", null],
79
+ ["bunx", null],
80
+ ["pnpm", "dlx"],
81
+ ["yarn", "dlx"]
82
+ ];
83
+ function runTargets(command, hasLocalBin = () => false) {
84
+ const names = /* @__PURE__ */ new Set();
85
+ for (const segment of command.split(/&&|\|\||[;|\n]/)) {
86
+ const tokens = segment.trim().split(/\s+/);
87
+ const i = commandStart(tokens);
88
+ if (i === -1) continue;
89
+ const runner = RUNNERS.find(
90
+ ([bin, verb]) => tokens[i] === bin && (verb === null || tokens[i + 1] === verb)
91
+ );
92
+ if (!runner) continue;
93
+ for (let j = i + (runner[1] ? 2 : 1); j < tokens.length; j++) {
94
+ const t = tokens[j];
95
+ if (t === "-p" || t === "--package") {
96
+ const name = specName(tokens[++j] ?? "");
97
+ if (name) names.add(name);
98
+ } else if (t.startsWith("--package=")) {
99
+ const name = specName(t.slice("--package=".length));
100
+ if (name) names.add(name);
101
+ } else if (!t.startsWith("-")) {
102
+ const name = specName(t);
103
+ if (name && !hasLocalBin(name)) names.add(name);
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ return [...names];
109
+ }
110
+ var DEP_FIELDS = [
111
+ "dependencies",
112
+ "devDependencies",
113
+ "peerDependencies",
114
+ "optionalDependencies"
115
+ ];
116
+ function addedDependencies(before, after) {
117
+ const read = (text) => {
118
+ try {
119
+ const v = JSON.parse(text);
120
+ return v && typeof v === "object" && !Array.isArray(v) ? v : null;
121
+ } catch {
122
+ return null;
123
+ }
124
+ };
125
+ const [was, now] = [read(before || "{}"), read(after)];
126
+ if (!was || !now) return null;
127
+ const had = new Set(DEP_FIELDS.flatMap((f) => Object.keys(was[f] ?? {})));
128
+ const added = /* @__PURE__ */ new Set();
129
+ for (const field of DEP_FIELDS) {
130
+ for (const [name, range] of Object.entries(now[field] ?? {})) {
131
+ if (had.has(name) || typeof range !== "string" || /[:/]/.test(range)) continue;
132
+ if (specName(name) === name) added.add(name);
133
+ }
134
+ }
135
+ return [...added];
136
+ }
137
+ var clip = (s, n = 240) => {
138
+ const line = s.replace(/\s+/g, " ").trim();
139
+ return line.length > n ? `${line.slice(0, n - 1)}\u2026` : line;
140
+ };
141
+ function decide(checked, opts = {}) {
142
+ const list = (xs) => xs.map((x) => x.name).join(", ");
143
+ const why = (xs) => xs.map((x) => `${x.name}: ${clip(x.verdict.reasons[0] ?? x.verdict.scope)}`).join("; ");
144
+ const invalid = opts.deny === false ? [] : checked.filter((c) => c.verdict.level === "invalid");
145
+ if (invalid.length) {
146
+ return {
147
+ permissionDecision: "deny",
148
+ permissionDecisionReason: `lurq: ${list(invalid)} ${invalid.length === 1 ? "is not a real npm package" : "are not real npm packages"}, so this was stopped before it ran. Check the name for a typo or a package that never existed, and tell the user what lurq found. (${why(invalid)})`
149
+ };
150
+ }
151
+ const high = checked.filter((c) => c.verdict.level === "high");
152
+ if (high.length) {
153
+ return {
154
+ permissionDecision: "ask",
155
+ permissionDecisionReason: `lurq flags ${list(high)} as high risk: ${why(high)}. Run \`lurq verify <package>\` for the evidence.`
156
+ };
157
+ }
158
+ return null;
159
+ }
160
+ function unseen(sessionId, keys, dir = join(tmpdir(), "lurq-hooks")) {
161
+ if (typeof sessionId !== "string" || !sessionId || keys.length === 0) return [];
162
+ const path = join(dir, `${sessionId.replace(/[^\w-]/g, "").slice(0, 80)}.json`);
163
+ let seen = [];
164
+ try {
165
+ seen = JSON.parse(readFileSync(path, "utf8")).seen ?? [];
166
+ } catch {
167
+ }
168
+ const fresh = [...new Set(keys)].filter((k) => !seen.includes(k));
169
+ if (fresh.length) {
170
+ mkdirSync(dir, { recursive: true });
171
+ writeFileSync(path, JSON.stringify({ seen: [...seen, ...fresh] }));
172
+ }
173
+ return fresh;
174
+ }
175
+ function isJsProject(cwd) {
176
+ if (typeof cwd !== "string" || !cwd) return false;
177
+ for (let dir = cwd; ; dir = dirname(dir)) {
178
+ if (existsSync(join(dir, "package.json"))) return true;
179
+ if (dirname(dir) === dir) return false;
180
+ }
181
+ }
182
+ var PROMPT_TIPS = [
183
+ {
184
+ kind: "choose",
185
+ test: /\b(which|best|recommend\w*|alternatives?|librar(y|ies)|sdks?|frameworks?)\b/i,
186
+ tip: "lurq is connected. If this means choosing a library, name the candidates you know and check them with lurq compare (evaluate for one), then verify the pick: your sense of package health is from training, lurq is current."
187
+ },
188
+ {
189
+ kind: "upgrade",
190
+ test: /\b(upgrad\w*|bump\w*|migrat\w*|deprecat\w*|breaking|major version|latest version)\b/i,
191
+ tip: "lurq is connected. For an upgrade, call lurq diff_surface with the package and both versions to see what was removed or changed, and compat for the resulting set, before editing code."
192
+ },
193
+ {
194
+ kind: "install",
195
+ test: /\b(install\w*|dependenc(y|ies)|add (a |an |the )?(package|library|dep))\b/i,
196
+ tip: "lurq is connected. Call lurq verify before adding a package and usage before writing code against one. Installs in this session are also checked automatically."
197
+ }
198
+ ];
199
+ function promptTips(prompt2) {
200
+ return PROMPT_TIPS.filter((t) => t.test.test(prompt2)).map(({ kind, tip }) => ({ kind, tip }));
201
+ }
202
+ function applyEdits(text, edits) {
203
+ let out = text;
204
+ for (const e of edits) {
205
+ if (typeof e.old_string !== "string" || typeof e.new_string !== "string" || !out.includes(e.old_string))
206
+ return null;
207
+ out = e.replace_all ? out.split(e.old_string).join(e.new_string) : out.replace(e.old_string, () => e.new_string);
208
+ }
209
+ return out;
210
+ }
211
+ var readIfExists = (path) => existsSync(path) ? readFileSync(path, "utf8") : "";
212
+ function patchedPackageJsons(patch, cwd, read = readIfExists) {
213
+ const files = [];
214
+ for (const section of patch.split(/^\*\*\* (?=(?:Add|Update|Delete) File: )/m).slice(1)) {
215
+ const [header = "", ...rest] = section.split("\n");
216
+ const m = /^(Add|Update) File: (.+)$/.exec(header.trim());
217
+ if (!m || basename(m[2]) !== "package.json") continue;
218
+ const body = rest.filter((l) => !l.startsWith("*** "));
219
+ if (m[1] === "Add") {
220
+ files.push({
221
+ before: "",
222
+ after: body.filter((l) => l.startsWith("+")).map((l) => l.slice(1)).join("\n")
223
+ });
224
+ continue;
225
+ }
226
+ const before = read(isAbsolute(m[2]) ? m[2] : join(cwd, m[2]));
227
+ const edits = body.join("\n").split(/^@@.*$/m).map((h) => h.split("\n").filter((l) => /^[ +-]/.test(l))).filter((h) => h.length > 0).map((h) => ({
228
+ old_string: h.filter((l) => !l.startsWith("+")).map((l) => l.slice(1)).join("\n"),
229
+ new_string: h.filter((l) => !l.startsWith("-")).map((l) => l.slice(1)).join("\n")
230
+ }));
231
+ const after = applyEdits(before, edits);
232
+ if (after !== null) files.push({ before, after });
233
+ }
234
+ return files;
235
+ }
236
+ function targets(tool, input, cwd) {
237
+ const none = { installs: [], runs: [] };
238
+ if (typeof input.command === "string" && tool === "Bash") {
239
+ return {
240
+ installs: installTargets(input.command),
241
+ runs: runTargets(input.command, (n) => existsSync(join(cwd, "node_modules", ".bin", n)))
242
+ };
243
+ }
244
+ if (typeof input.command === "string" && tool === "apply_patch") {
245
+ const installs = patchedPackageJsons(input.command, cwd).flatMap(
246
+ (f) => addedDependencies(f.before, f.after) ?? []
247
+ );
248
+ return { installs: [...new Set(installs)], runs: [] };
249
+ }
250
+ if (typeof input.file_path !== "string" || basename(input.file_path) !== "package.json")
251
+ return none;
252
+ const before = readIfExists(input.file_path);
253
+ const after = tool === "Write" ? typeof input.content === "string" ? input.content : null : tool === "Edit" ? applyEdits(before, [input]) : tool === "MultiEdit" && Array.isArray(input.edits) ? applyEdits(before, input.edits) : null;
254
+ return { installs: after === null ? [] : addedDependencies(before, after) ?? [], runs: [] };
255
+ }
256
+ var usageNudge = (names) => `Before writing code against ${names.join(", ")}, call lurq usage with ${names.length === 1 ? "it" : "each"} (with knownVersion if you remember one): APIs move, and what you remember is from training.`;
257
+ function freshUsage(sessionId, names) {
258
+ return unseen(
259
+ sessionId,
260
+ names.map((n) => `usage:${n}`)
261
+ ).map((k) => k.slice("usage:".length));
262
+ }
263
+ async function preToolUse(input, nudge) {
264
+ const cwd = typeof input.cwd === "string" ? input.cwd : process.cwd();
265
+ const { installs, runs } = targets(input.tool_name, input.tool_input ?? {}, cwd);
266
+ const names = [.../* @__PURE__ */ new Set([...installs, ...runs])].slice(0, MAX_NAMES);
267
+ if (names.length === 0) return null;
268
+ const { callTool } = await import("./remote-FN6225AH.js");
269
+ const settled = await Promise.allSettled(
270
+ names.map(
271
+ (name) => callTool(
272
+ "verify",
273
+ { package: name },
274
+ { timeoutMs: VERIFY_TIMEOUT_MS }
275
+ ).then((r) => ({ name, verdict: r.verdict }))
276
+ )
277
+ );
278
+ const checked = settled.flatMap(
279
+ (s) => s.status === "fulfilled" && s.value.verdict ? [{ name: s.value.name, verdict: s.value.verdict }] : []
280
+ );
281
+ const installed = checked.filter((c) => installs.includes(c.name));
282
+ const decision = decide(installed) ?? decide(
283
+ checked.filter((c) => !installs.includes(c.name)),
284
+ { deny: false }
285
+ );
286
+ if (decision) return { decision };
287
+ if (!nudge) return null;
288
+ const clean = installed.filter((c) => c.verdict.level !== "invalid" && c.verdict.level !== "high").map((c) => c.name);
289
+ const fresh = freshUsage(input.session_id, clean);
290
+ return fresh.length ? { context: `lurq verified ${fresh.join(", ")} before this ran. ${usageNudge(fresh)}` } : null;
291
+ }
292
+ function postToolUse(input) {
293
+ const command = input.tool_input?.command;
294
+ if (typeof command !== "string") return null;
295
+ const fresh = freshUsage(input.session_id, installTargets(command));
296
+ return fresh.length ? { context: `lurq checked ${fresh.join(", ")} before install. ${usageNudge(fresh)}` } : null;
297
+ }
298
+ var brief = (agent) => `lurq is connected to this session: package installs${agent === "cursor" ? "" : " and package.json dependency edits"} are verified automatically. Call lurq usage before writing code against a package API you know from training, and compare or evaluate when choosing a package.`;
299
+ var SCAN_TIMEOUT_MS = 5e3;
300
+ async function sessionDrift(input) {
301
+ const cwd = input.cwd;
302
+ if (typeof cwd !== "string" || !isJsProject(cwd)) return null;
303
+ if (unseen(input.session_id, [`scan:${cwd}`]).length === 0) return null;
304
+ try {
305
+ const { buildUpgradePlan, planHeadline, scanSourceDrift } = await import("./upgradePlan-ZS5IOVMZ.js");
306
+ const [plan, source] = await Promise.all([
307
+ buildUpgradePlan(cwd, { timeoutMs: SCAN_TIMEOUT_MS }),
308
+ scanSourceDrift(cwd)
309
+ ]);
310
+ const headline = planHeadline(plan, source);
311
+ return headline && `lurq scanned this project: ${headline}`;
312
+ } catch {
313
+ return null;
314
+ }
315
+ }
316
+ async function sessionStart(input, agent) {
317
+ const { apiKey, getAlerts } = await import("./remote-FN6225AH.js");
318
+ apiKey();
319
+ const [alerts, drift] = await Promise.all([
320
+ getAlerts({ timeoutMs: 3e3, agent: agent === "claude" ? "claude-code" : agent }).catch(
321
+ () => null
322
+ ),
323
+ sessionDrift(input)
324
+ ]);
325
+ const text = [isJsProject(input.cwd) ? brief(agent) : null, drift, alerts].filter(Boolean).join("\n\n");
326
+ return text ? { context: text } : null;
327
+ }
328
+ function prompt(input) {
329
+ if (typeof input.prompt !== "string" || !isJsProject(input.cwd)) return null;
330
+ const tips = promptTips(input.prompt);
331
+ const fresh = new Set(
332
+ unseen(
333
+ input.session_id,
334
+ tips.map((t) => t.kind)
335
+ )
336
+ );
337
+ const text = tips.filter((t) => fresh.has(t.kind)).map((t) => t.tip).join("\n");
338
+ return text ? { context: text } : null;
339
+ }
340
+ var HOOK_AGENTS = ["claude", "codex", "cursor"];
341
+ function normalize(agent, input) {
342
+ if (agent !== "cursor") return input;
343
+ const command = typeof input.command === "string" ? input.command : input.tool_input?.command;
344
+ return {
345
+ session_id: input.conversation_id ?? input.session_id,
346
+ cwd: input.cwd ?? input.workspace_roots?.[0],
347
+ ...typeof command === "string" ? { tool_name: "Bash", tool_input: { command } } : {}
348
+ };
349
+ }
350
+ var CLAUDE_EVENT = {
351
+ "session-start": "SessionStart",
352
+ prompt: "UserPromptSubmit",
353
+ "pre-tool-use": "PreToolUse"
354
+ };
355
+ function render(agent, event, outcome) {
356
+ if (!outcome) return null;
357
+ const { decision, context } = outcome;
358
+ if (agent === "cursor") {
359
+ if (decision) {
360
+ const message = decision.permissionDecisionReason;
361
+ return {
362
+ permission: decision.permissionDecision,
363
+ user_message: message,
364
+ agent_message: message
365
+ };
366
+ }
367
+ return context ? { additional_context: context } : null;
368
+ }
369
+ const hookEventName = CLAUDE_EVENT[event];
370
+ if (!hookEventName) return null;
371
+ if (decision) {
372
+ const asCodex = agent === "codex" && decision.permissionDecision === "ask" ? {
373
+ permissionDecision: "deny",
374
+ permissionDecisionReason: `${decision.permissionDecisionReason} Tell the user what lurq found. Only if they approve, run the install again prefixed with ${ALLOW_ENV}.`
375
+ } : decision;
376
+ return { hookSpecificOutput: { hookEventName, ...asCodex } };
377
+ }
378
+ return context ? { hookSpecificOutput: { hookEventName, additionalContext: context } } : null;
379
+ }
380
+ async function readStdin() {
381
+ const chunks = [];
382
+ for await (const chunk of process.stdin) chunks.push(chunk);
383
+ return Buffer.concat(chunks).toString("utf8");
384
+ }
385
+ async function runHook(event, agentName = "claude") {
386
+ try {
387
+ const agent = HOOK_AGENTS.find((a) => a === agentName);
388
+ if (!agent) return;
389
+ const input = normalize(agent, JSON.parse(await readStdin()));
390
+ const outcome = event === "pre-tool-use" ? await preToolUse(input, agent !== "cursor") : event === "post-tool-use" ? postToolUse(input) : event === "session-start" ? await sessionStart(input, agent) : event === "prompt" ? prompt(input) : null;
391
+ const output = render(agent, event, outcome);
392
+ if (output) process.stdout.write(JSON.stringify(output));
393
+ } catch {
394
+ }
395
+ }
396
+ export {
397
+ ALLOW_ENV,
398
+ HOOK_AGENTS,
399
+ addedDependencies,
400
+ applyEdits,
401
+ decide,
402
+ installTargets,
403
+ isJsProject,
404
+ normalize,
405
+ patchedPackageJsons,
406
+ promptTips,
407
+ render,
408
+ runHook,
409
+ runTargets,
410
+ specName,
411
+ unseen
412
+ };