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,95 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ openInBrowser
4
+ } from "./chunk-TNTXWSYA.js";
5
+ import {
6
+ API_KEY_PREFIX
7
+ } from "./chunk-GPTKSNR6.js";
8
+ import {
9
+ init_esm_shims
10
+ } from "./chunk-I3M2KJXB.js";
11
+
12
+ // src/cli/browserAuth.ts
13
+ init_esm_shims();
14
+ import { randomBytes, timingSafeEqual } from "crypto";
15
+ import { createServer } from "http";
16
+ var WEB_ORIGIN = process.env.LURQ_WEB_URL ?? "https://lurq.run";
17
+ var DEADLINE_MS = 3 * 6e4;
18
+ var MAX_BODY = 4096;
19
+ function equal(a, b) {
20
+ const left = Buffer.from(a);
21
+ const right = Buffer.from(b);
22
+ return left.length === right.length && timingSafeEqual(left, right);
23
+ }
24
+ async function readBody(req) {
25
+ let out = "";
26
+ for await (const chunk of req) {
27
+ out += chunk;
28
+ if (out.length > MAX_BODY) return "";
29
+ }
30
+ return out;
31
+ }
32
+ function keyViaBrowser(opts) {
33
+ return new Promise((resolve) => {
34
+ const nonce = randomBytes(18).toString("base64url");
35
+ let settled = false;
36
+ const finish = (value) => {
37
+ if (settled) return;
38
+ settled = true;
39
+ clearTimeout(timer);
40
+ server.close();
41
+ resolve(value);
42
+ };
43
+ const server = createServer((req, res) => {
44
+ res.setHeader("Access-Control-Allow-Origin", WEB_ORIGIN);
45
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
46
+ res.setHeader("Access-Control-Allow-Private-Network", "true");
47
+ if (req.method === "OPTIONS") {
48
+ res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
49
+ res.writeHead(204).end();
50
+ return;
51
+ }
52
+ if (req.method !== "POST") {
53
+ res.writeHead(405).end();
54
+ return;
55
+ }
56
+ void readBody(req).then((raw) => {
57
+ let key = "";
58
+ let label = null;
59
+ try {
60
+ const body = JSON.parse(raw);
61
+ if (typeof body.nonce === "string" && equal(body.nonce, nonce)) {
62
+ if (typeof body.key === "string" && body.key.startsWith("lurq_")) key = body.key;
63
+ if (typeof body.label === "string") label = body.label;
64
+ }
65
+ } catch {
66
+ }
67
+ if (!key) {
68
+ res.writeHead(400, { "Content-Type": "application/json" });
69
+ res.end(JSON.stringify({ ok: false }));
70
+ return;
71
+ }
72
+ res.writeHead(200, { "Content-Type": "application/json" });
73
+ res.end(JSON.stringify({ ok: true }));
74
+ finish({ key, label });
75
+ });
76
+ });
77
+ const timer = setTimeout(() => finish(null), DEADLINE_MS);
78
+ timer.unref?.();
79
+ server.on("error", () => finish(null));
80
+ opts.signal?.addEventListener("abort", () => finish(null), { once: true });
81
+ server.listen(0, "127.0.0.1", () => {
82
+ const { port } = server.address();
83
+ const url = `${WEB_ORIGIN}/dashboard/cli?port=${port}&nonce=${encodeURIComponent(nonce)}`;
84
+ opts.onUrl(url);
85
+ if (!opts.noOpen) openInBrowser(url);
86
+ });
87
+ });
88
+ }
89
+ function looksLikeKey(value) {
90
+ return value.startsWith("lurq_") || value.startsWith(API_KEY_PREFIX);
91
+ }
92
+ export {
93
+ keyViaBrowser,
94
+ looksLikeKey
95
+ };
@@ -0,0 +1,12 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ cached,
4
+ invalidateCache
5
+ } from "./chunk-HWBBVLOT.js";
6
+ import "./chunk-MYGSLK44.js";
7
+ import "./chunk-GPTKSNR6.js";
8
+ import "./chunk-I3M2KJXB.js";
9
+ export {
10
+ cached,
11
+ invalidateCache
12
+ };
@@ -0,0 +1,192 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ checkApi
4
+ } from "./chunk-CIDWNUAP.js";
5
+ import {
6
+ require_dist
7
+ } from "./chunk-QKGYDMWB.js";
8
+ import "./chunk-3GHJR7XR.js";
9
+ import {
10
+ __toESM,
11
+ init_esm_shims
12
+ } from "./chunk-I3M2KJXB.js";
13
+
14
+ // src/api/check.ts
15
+ init_esm_shims();
16
+ import { execFile } from "child_process";
17
+ import { existsSync, readFileSync } from "fs";
18
+ import { relative, resolve } from "path";
19
+ import { promisify } from "util";
20
+
21
+ // src/api/openapi.ts
22
+ init_esm_shims();
23
+ var import_yaml = __toESM(require_dist(), 1);
24
+ var METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
25
+ var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
26
+ function deref(root, node, seen = /* @__PURE__ */ new Set()) {
27
+ if (!isRecord(node)) return null;
28
+ const ref = node.$ref;
29
+ if (typeof ref !== "string") return node;
30
+ if (!ref.startsWith("#/") || seen.has(ref)) return null;
31
+ seen.add(ref);
32
+ let cursor = root;
33
+ for (const segment of ref.slice(2).split("/")) {
34
+ if (!isRecord(cursor)) return null;
35
+ cursor = cursor[segment.replace(/~1/g, "/").replace(/~0/g, "~")];
36
+ }
37
+ return deref(root, cursor, seen);
38
+ }
39
+ function readParams(root, shared, own) {
40
+ const required = /* @__PURE__ */ new Set();
41
+ const optional = /* @__PURE__ */ new Set();
42
+ for (const list of [shared, own]) {
43
+ if (!Array.isArray(list)) continue;
44
+ for (const raw of list) {
45
+ const param = deref(root, raw);
46
+ const name = param?.name;
47
+ if (typeof name !== "string") continue;
48
+ const key = `${name} (${typeof param?.in === "string" ? param.in : "unknown"})`;
49
+ if (param?.required === true) {
50
+ required.add(key);
51
+ optional.delete(key);
52
+ } else if (!required.has(key)) {
53
+ optional.add(key);
54
+ }
55
+ }
56
+ }
57
+ return { required: [...required].sort(), optional: [...optional].sort() };
58
+ }
59
+ function readBodyFields(root, requestBody) {
60
+ const body = deref(root, requestBody);
61
+ if (!body || body.required !== true) return [];
62
+ const content = body.content;
63
+ if (!isRecord(content)) return [];
64
+ const out = /* @__PURE__ */ new Set();
65
+ for (const media of Object.values(content)) {
66
+ const schema = deref(root, isRecord(media) ? media.schema : null);
67
+ const required = schema?.required;
68
+ if (!Array.isArray(required)) continue;
69
+ for (const field of required) if (typeof field === "string") out.add(field);
70
+ }
71
+ return [...out].sort();
72
+ }
73
+ function extractApiSurface(source, label = "document") {
74
+ const empty = { title: null, version: null, operations: /* @__PURE__ */ new Map() };
75
+ let doc;
76
+ try {
77
+ doc = (0, import_yaml.parse)(source);
78
+ } catch (err) {
79
+ return {
80
+ ...empty,
81
+ unreadableReason: `${label} is not valid YAML or JSON: ${err instanceof Error ? err.message : String(err)}`
82
+ };
83
+ }
84
+ if (!isRecord(doc)) return { ...empty, unreadableReason: `${label} is not an object` };
85
+ if (!doc.openapi && !doc.swagger) {
86
+ return { ...empty, unreadableReason: `${label} has no openapi/swagger version field` };
87
+ }
88
+ const info = isRecord(doc.info) ? doc.info : {};
89
+ const paths = isRecord(doc.paths) ? doc.paths : {};
90
+ const operations = /* @__PURE__ */ new Map();
91
+ for (const [path, rawItem] of Object.entries(paths)) {
92
+ const item = deref(doc, rawItem);
93
+ if (!item) continue;
94
+ for (const method of METHODS) {
95
+ const op = item[method];
96
+ if (!isRecord(op)) continue;
97
+ const { required, optional } = readParams(doc, item.parameters, op.parameters);
98
+ const responses = isRecord(op.responses) ? Object.keys(op.responses).sort() : [];
99
+ const id = `${method.toUpperCase()} ${path}`;
100
+ operations.set(id, {
101
+ id,
102
+ method: method.toUpperCase(),
103
+ path,
104
+ requiredParams: required,
105
+ optionalParams: optional,
106
+ requiredBodyFields: readBodyFields(doc, op.requestBody),
107
+ responseCodes: responses,
108
+ deprecated: op.deprecated === true
109
+ });
110
+ }
111
+ }
112
+ return {
113
+ title: typeof info.title === "string" ? info.title : null,
114
+ version: typeof info.version === "string" ? info.version : null,
115
+ operations,
116
+ ...operations.size === 0 ? { unreadableReason: `${label} declares no operations` } : {}
117
+ };
118
+ }
119
+
120
+ // src/api/check.ts
121
+ var execFileP = promisify(execFile);
122
+ var CANDIDATES = [
123
+ "openapi.yaml",
124
+ "openapi.yml",
125
+ "openapi.json",
126
+ "swagger.yaml",
127
+ "swagger.yml",
128
+ "swagger.json",
129
+ "api/openapi.yaml",
130
+ "api/openapi.yml",
131
+ "api/openapi.json",
132
+ "docs/openapi.yaml",
133
+ "docs/openapi.yml"
134
+ ];
135
+ function findSpec(dir) {
136
+ for (const candidate of CANDIDATES) {
137
+ const full = resolve(dir, candidate);
138
+ if (existsSync(full)) return full;
139
+ }
140
+ return null;
141
+ }
142
+ async function showAtRevision(dir, rev, repoPath) {
143
+ try {
144
+ const { stdout } = await execFileP("git", ["show", `${rev}:${repoPath}`], {
145
+ cwd: dir,
146
+ maxBuffer: 32 * 1024 * 1024
147
+ });
148
+ return stdout;
149
+ } catch {
150
+ return null;
151
+ }
152
+ }
153
+ async function runApiCheck(dir, opts = {}) {
154
+ const against = opts.against ?? "HEAD";
155
+ const specPath = opts.spec ? resolve(dir, opts.spec) : findSpec(dir);
156
+ const spec = specPath ? relative(dir, specPath) || specPath : "(none found)";
157
+ const base = { spec, against, title: null, fromVersion: null, toVersion: null };
158
+ if (!specPath) {
159
+ return {
160
+ ...base,
161
+ verdict: "inconclusive",
162
+ versionCovers: null,
163
+ diff: {
164
+ breaking: [],
165
+ other: [],
166
+ inconclusive: `no OpenAPI document found in ${dir}. Name one: lurq check-api <file>`
167
+ }
168
+ };
169
+ }
170
+ const current = extractApiSurface(readFileSync(specPath, "utf8"), spec);
171
+ const previousSource = await showAtRevision(dir, against, spec);
172
+ if (previousSource === null) {
173
+ return {
174
+ ...base,
175
+ title: current.title,
176
+ toVersion: current.version,
177
+ verdict: "inconclusive",
178
+ versionCovers: null,
179
+ diff: {
180
+ breaking: [],
181
+ other: [],
182
+ inconclusive: `${spec} does not exist at ${against}, so there is nothing to compare against`
183
+ }
184
+ };
185
+ }
186
+ const previous = extractApiSurface(previousSource, `${spec} at ${against}`);
187
+ return { ...base, ...checkApi(previous, current) };
188
+ }
189
+ export {
190
+ findSpec,
191
+ runApiCheck
192
+ };
@@ -0,0 +1,103 @@
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/checkUpgrade.ts
7
+ init_esm_shims();
8
+ import { readFileSync } from "fs";
9
+ var SCAN_LIMIT = 2e4;
10
+ function parseUpgradeSpec(spec) {
11
+ const at = spec.lastIndexOf("@");
12
+ const name = spec.slice(0, at);
13
+ const [fromVersion, toVersion] = spec.slice(at + 1).split("..");
14
+ if (!name || !fromVersion || !toVersion) {
15
+ throw new Error(`bad --upgrade '${spec}', expected pkg@from..to`);
16
+ }
17
+ return { package: name, fromVersion, toVersion };
18
+ }
19
+ function targetsFromPlanFile(path) {
20
+ let text;
21
+ try {
22
+ text = readFileSync(path, "utf8");
23
+ } catch (err) {
24
+ const why = err.code === "ENOENT" ? "does not exist" : String(err);
25
+ throw new Error(`plan file ${path} ${why}. Did \`lurq upgrade-plan --json\` run?`);
26
+ }
27
+ if (!text.trim()) {
28
+ throw new Error(`plan file ${path} is empty. Did \`lurq upgrade-plan --json\` run?`);
29
+ }
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(text);
33
+ } catch (err) {
34
+ throw new Error(`plan file ${path} is not valid JSON: ${err.message}`);
35
+ }
36
+ if (!Array.isArray(parsed.upgrades)) {
37
+ throw new Error(`${path} is not an upgrade plan (no "upgrades" array)`);
38
+ }
39
+ return parsed.upgrades.filter((u) => u.package && u.fromVersion && u.toVersion).filter((u) => u.inScope !== false).map((u) => ({ package: u.package, fromVersion: u.fromVersion, toVersion: u.toVersion }));
40
+ }
41
+ async function reportOutcome(report, targets, opts) {
42
+ const { buildRunReports, runContextFromEnv } = await import("./reportRuns-CKQQYLY4.js");
43
+ const ctx = runContextFromEnv();
44
+ if (!ctx) {
45
+ console.error("--report: no $GITHUB_REPOSITORY, so there is no run to attribute this to. Skipped.");
46
+ return;
47
+ }
48
+ const runs = buildRunReports(report, targets, ctx);
49
+ if (runs.length === 0) return;
50
+ try {
51
+ const { reportUpgradeRuns } = await import("./remote-YGCXYI4V.js");
52
+ const { recorded, rejected } = await reportUpgradeRuns(runs, {
53
+ url: opts.url,
54
+ apiKey: opts.apiKey
55
+ });
56
+ console.error(
57
+ `reported ${recorded} upgrade result(s) to the lurq dashboard` + (rejected ? ` (${rejected} rejected)` : "")
58
+ );
59
+ } catch (err) {
60
+ const message = err instanceof Error ? err.message : String(err);
61
+ const noKey = /no api key/i.test(message);
62
+ console.error(
63
+ noKey ? "--report: no API key, so there was nothing to report with. Set LURQ_API_KEY in this repository's secrets to see these results on your dashboard. The check itself is unaffected." : `--report: could not reach the lurq dashboard (${message}). The check itself is unaffected.`
64
+ );
65
+ }
66
+ }
67
+ async function runCheckUpgrade(dir, opts) {
68
+ const { scanReferences } = await import("./references-6N7VEPHT.js");
69
+ const { checkUpgrade, formatUpgradeReport } = await import("./upgrade-NQ5IWFZB.js");
70
+ const targets = [
71
+ ...opts.plan ? targetsFromPlanFile(opts.plan) : [],
72
+ ...(opts.upgrade ?? []).map(parseUpgradeSpec)
73
+ ];
74
+ if (targets.length === 0) {
75
+ if (opts.plan) {
76
+ const empty = { safe: true, breaking: [], ok: [], unverified: [] };
77
+ console.log(opts.json ? JSON.stringify(empty, null, 2) : "Nothing to check.");
78
+ return;
79
+ }
80
+ throw new Error("give --plan <file> or at least one --upgrade pkg@from..to");
81
+ }
82
+ const scan = { files: 0, truncated: false };
83
+ const refs = scanReferences(dir, { limit: SCAN_LIMIT, stats: scan });
84
+ const typeCheck = opts.types === false ? void 0 : await (await import("./typecheck-X7U5ELMR.js")).createTypeChecker(dir);
85
+ const report = await checkUpgrade(targets, refs, { typeCheck, rootDir: dir });
86
+ if (scan.truncated) {
87
+ report.unverified.push({
88
+ package: "(source scan)",
89
+ reason: `stopped after ${scan.files} source files; references in the rest were not checked`
90
+ });
91
+ report.safe = false;
92
+ }
93
+ console.log(
94
+ opts.json ? JSON.stringify(report, null, 2) : formatUpgradeReport(report, `upgrade check on ${dir}`)
95
+ );
96
+ if (opts.report) await reportOutcome(report, targets, opts);
97
+ if (opts.exitCode && !report.safe) process.exitCode = 1;
98
+ }
99
+ export {
100
+ parseUpgradeSpec,
101
+ runCheckUpgrade,
102
+ targetsFromPlanFile
103
+ };
@@ -0,0 +1,300 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ projectWeightsPath,
4
+ userWeightsPath
5
+ } from "./chunk-LUAKDHLZ.js";
6
+ import {
7
+ init_esm_shims
8
+ } from "./chunk-I3M2KJXB.js";
9
+
10
+ // src/scoring/weights.ts
11
+ init_esm_shims();
12
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
13
+ import { dirname } from "path";
14
+ var HEALTH_WEIGHTS = {
15
+ maintenance: 0.35,
16
+ adoption: 0.3,
17
+ reliability: 0.25,
18
+ efficiency: 0.1
19
+ };
20
+ var COMPOSITE = {
21
+ lambda: 0.35
22
+ };
23
+ var RANKING = {
24
+ relevance: 0.45,
25
+ composite: 0.35,
26
+ confidence: 0.2
27
+ };
28
+ var CONFIDENCE_WEIGHT = {
29
+ proven: 1,
30
+ emerging: 0.55,
31
+ promising: 0.45,
32
+ unproven: 0.1
33
+ };
34
+ var QUALITY_WEIGHTS = {
35
+ types: 0.25,
36
+ tests: 0.2,
37
+ docs: 0.2,
38
+ changelog: 0.1,
39
+ deps: 0.1,
40
+ license: 0.1,
41
+ provenance: 0.05
42
+ };
43
+ var QUALITY = {
44
+ /** README at/above this many characters scores full marks on doc length. */
45
+ docsFullLengthChars: 1200,
46
+ /** Direct-dependency count at/above this scores 0 on the deps component (log-scaled). */
47
+ depsLogMax: 30,
48
+ /** A license string present but not OSI-recognized scores this (vs 100 / 0). */
49
+ licenseUnrecognizedScore: 60
50
+ };
51
+ var MAINTENANCE_WEIGHTS = {
52
+ recency: 0.5,
53
+ cadence: 0.25,
54
+ closeRatio: 0.25
55
+ };
56
+ var MAINTENANCE = {
57
+ /** A release within this many days scores full recency. */
58
+ freshDays: 30,
59
+ /** Recency decays linearly to 0 by this many days (~24 months). */
60
+ staleDays: 730,
61
+ /** Releases/12mo at or above this cap full cadence. */
62
+ cadenceCap: 12,
63
+ /** deprecated/archived hard-cap maintenance at this value. */
64
+ deadCap: 15
65
+ };
66
+ var ADOPTION = {
67
+ /** log10(weekly downloads): this maps to 0. */
68
+ downloadsLogMin: 1,
69
+ // 10/wk
70
+ /** log10(weekly downloads): this maps to 100. */
71
+ downloadsLogMax: 7,
72
+ // 10M/wk
73
+ /** log10(stars) that maps to 100. */
74
+ starsLogMax: 5,
75
+ // 100k stars
76
+ /** Weight of the stars component when available (downloads gets the rest). */
77
+ starsWeight: 0.2,
78
+ /** Growth bonus: growth fraction × this, clamped to ±cap. */
79
+ growthMultiplier: 30,
80
+ growthBonusCap: 20
81
+ };
82
+ var RELIABILITY = {
83
+ /** Used when no Scorecard is available (unknown security posture). */
84
+ neutralWhenUnknown: 50,
85
+ /** Advisory penalties by severity. */
86
+ penalty: {
87
+ critical: 40,
88
+ high: 20,
89
+ moderate: 8,
90
+ low: 3,
91
+ info: 0
92
+ }
93
+ };
94
+ var EFFICIENCY = {
95
+ /** Bundle size at the category median maps to this score; smaller → higher. */
96
+ medianScore: 50
97
+ };
98
+ var FIELD = {
99
+ /** Weight when evidence exists — ~9% of the blend (0.10 / 1.10). */
100
+ weight: 0.1,
101
+ /**
102
+ * Bayesian shrinkage strength: how many prior observations the neutral rate is
103
+ * worth. One failed report out of one is not a 0-scoring package, and a raw
104
+ * success rate would say it is. At m=12, a single failure lands near 69 rather
105
+ * than 0, and it takes real volume to move the number far — which is the
106
+ * correct epistemics for a signal users can trivially poison.
107
+ */
108
+ priorWeight: 12,
109
+ /**
110
+ * The prior success rate a package is assumed to have before anyone reports.
111
+ * Set at the observed base rate of "installs and builds fine", not 0.5:
112
+ * most packages do work, so 0.5 would penalise the first honest reporter.
113
+ */
114
+ priorRate: 0.75,
115
+ /** Reports at or above this cap the confidence note as fully-evidenced. */
116
+ wellEvidencedReports: 25
117
+ };
118
+ var DEFAULT_WEIGHTS = {
119
+ health: { ...HEALTH_WEIGHTS },
120
+ composite: { ...COMPOSITE }
121
+ };
122
+ function activeWeightsPath() {
123
+ if (existsSync(projectWeightsPath())) return { path: projectWeightsPath(), source: "project-config" };
124
+ if (existsSync(userWeightsPath())) return { path: userWeightsPath(), source: "user-config" };
125
+ return null;
126
+ }
127
+ var cachedWeights;
128
+ function loadWeights() {
129
+ if (cachedWeights) return cachedWeights;
130
+ let merged = structuredClone(DEFAULT_WEIGHTS);
131
+ const active = activeWeightsPath();
132
+ if (active) {
133
+ try {
134
+ const fromFile = JSON.parse(readFileSync(active.path, "utf8"));
135
+ merged = mergeWeights(merged, fromFile);
136
+ } catch {
137
+ }
138
+ }
139
+ const envLambda = process.env.LURQ_COMPOSITE_LAMBDA;
140
+ if (envLambda !== void 0 && envLambda !== "") {
141
+ const n = Number(envLambda);
142
+ if (Number.isFinite(n)) merged.composite.lambda = n;
143
+ }
144
+ cachedWeights = validateWeights(merged).weights;
145
+ return cachedWeights;
146
+ }
147
+ function resetWeightsCache() {
148
+ cachedWeights = void 0;
149
+ }
150
+ function mergeWeights(base, over) {
151
+ return {
152
+ health: { ...base.health, ...over.health ?? {} },
153
+ composite: { ...base.composite, ...over.composite ?? {} }
154
+ };
155
+ }
156
+ function validateWeights(w) {
157
+ const lambda = Math.max(0, Math.min(1, w.composite.lambda));
158
+ const h = w.health;
159
+ const sum = h.maintenance + h.adoption + h.reliability + h.efficiency;
160
+ let normalized = false;
161
+ let health = h;
162
+ if (sum <= 0) {
163
+ health = { ...DEFAULT_WEIGHTS.health };
164
+ normalized = true;
165
+ } else if (Math.abs(sum - 1) > 1e-6) {
166
+ health = {
167
+ maintenance: h.maintenance / sum,
168
+ adoption: h.adoption / sum,
169
+ reliability: h.reliability / sum,
170
+ efficiency: h.efficiency / sum
171
+ };
172
+ normalized = true;
173
+ }
174
+ return { weights: { health, composite: { lambda } }, normalized };
175
+ }
176
+ var SETTABLE = {
177
+ "health.maintenance": (w, v) => w.health.maintenance = v,
178
+ "health.adoption": (w, v) => w.health.adoption = v,
179
+ "health.reliability": (w, v) => w.health.reliability = v,
180
+ "health.efficiency": (w, v) => w.health.efficiency = v,
181
+ "composite.lambda": (w, v) => w.composite.lambda = v
182
+ };
183
+ function settableKeys() {
184
+ return Object.keys(SETTABLE);
185
+ }
186
+ function applyOverrides(base, sets) {
187
+ const next = structuredClone(base);
188
+ for (const entry of sets) {
189
+ const eq = entry.indexOf("=");
190
+ if (eq < 0) throw new Error(`Invalid --set "${entry}" (expected key=value).`);
191
+ const key = entry.slice(0, eq).trim();
192
+ const value = Number(entry.slice(eq + 1).trim());
193
+ const apply = SETTABLE[key];
194
+ if (!apply) {
195
+ throw new Error(`Unknown weight key "${key}". Settable: ${settableKeys().join(", ")}.`);
196
+ }
197
+ if (!Number.isFinite(value)) throw new Error(`Value for "${key}" must be a number.`);
198
+ apply(next, value);
199
+ }
200
+ return next;
201
+ }
202
+ function saveWeights(w, scope = "user") {
203
+ const path = scope === "project" ? projectWeightsPath() : userWeightsPath();
204
+ mkdirSync(dirname(path), { recursive: true });
205
+ writeFileSync(path, JSON.stringify(w, null, 2) + "\n", "utf8");
206
+ resetWeightsCache();
207
+ return path;
208
+ }
209
+ function resetWeights() {
210
+ const removed = [];
211
+ for (const path of [projectWeightsPath(), userWeightsPath()]) {
212
+ if (existsSync(path)) {
213
+ rmSync(path);
214
+ removed.push(path);
215
+ }
216
+ }
217
+ resetWeightsCache();
218
+ return removed;
219
+ }
220
+ var WEIGHT_EXPLANATIONS = {
221
+ maintenance: "release recency, cadence, and issue close-ratio (weights.ts MAINTENANCE_WEIGHTS).",
222
+ adoption: "weekly downloads (log-scaled), stars, and 90-day growth (weights.ts ADOPTION).",
223
+ reliability: "OpenSSF Scorecard scaled 0\u2013100, minus advisory penalties (weights.ts RELIABILITY).",
224
+ efficiency: "bundle size vs the category median; frontend categories only (weights.ts EFFICIENCY).",
225
+ quality: "intrinsic, adoption-independent: types, tests, docs, changelog, deps, license, provenance (weights.ts QUALITY_WEIGHTS). A standalone axis, it does NOT feed health.",
226
+ lambda: "how much the default sort composite favors quality over health: (1\u2212\u03BB)\xB7health + \u03BB\xB7quality."
227
+ };
228
+ var CONFIDENCE = {
229
+ proven: {
230
+ minWeeklyDownloads: 1e5,
231
+ minAgeMonths: 12,
232
+ /**
233
+ * Recency ceiling for the top tier.
234
+ *
235
+ * Was 6 months, which quietly punished stability. Because the stored label
236
+ * is frozen at ingest, nothing surfaced it until confidence was re-derived
237
+ * — at which point `p-limit` (273M weekly downloads, ten years old, last
238
+ * release 6.2 months ago) dropped out of `proven`, along with
239
+ * `@testing-library/react` at 6.7 months and 44M/wk. A mature utility that
240
+ * has not needed a release is the most proven kind of package there is.
241
+ *
242
+ * Abandonment is already caught three other ways that do not confuse it
243
+ * with maturity: `deprecated` and `archived` are hard-checked right here,
244
+ * and the maintenance component of health decays to zero over 24 months
245
+ * while carrying 35% of the health weight. Recency was the fourth penalty
246
+ * on the same fact, and the strictest.
247
+ */
248
+ maxLastReleaseMonths: 18
249
+ },
250
+ emerging: {
251
+ minWeeklyDownloads: 5e3,
252
+ strongGrowth: 0.5,
253
+ /**
254
+ * Absolute floor the growth path must also clear.
255
+ *
256
+ * Growth alone used to qualify a package for `emerging`, and a percentage
257
+ * computed on a tiny base is noise: 4 → 17 weekly downloads is +325% and
258
+ * cleared the bar outright. That is how `@podgres/pg` (17/wk) and
259
+ * `@bungres/orm` (275/wk) came to wear the same evidence label as a package
260
+ * with five thousand real installs, and — because `recommend` treats the
261
+ * label as meaningful — outrank Prisma for "an orm for postgres".
262
+ *
263
+ * 1,000/wk is where a 50% swing stops being one CI pipeline changing its
264
+ * schedule. Below it the growth signal is not measuring adoption.
265
+ */
266
+ minDownloadsForGrowth: 1e3,
267
+ /** Same reasoning as `proven` above: 9 months demoted `@emotion/react`
268
+ * (14.7M/wk, last release 9.2 months ago) to `unproven`. */
269
+ maxLastReleaseMonths: 18
270
+ },
271
+ /** `promising` (§1): new but intrinsically high-quality, regardless of adoption. */
272
+ promising: {
273
+ minQuality: 70,
274
+ maxLastReleaseMonths: 12
275
+ }
276
+ };
277
+
278
+ export {
279
+ HEALTH_WEIGHTS,
280
+ COMPOSITE,
281
+ RANKING,
282
+ CONFIDENCE_WEIGHT,
283
+ QUALITY_WEIGHTS,
284
+ QUALITY,
285
+ MAINTENANCE_WEIGHTS,
286
+ MAINTENANCE,
287
+ ADOPTION,
288
+ RELIABILITY,
289
+ EFFICIENCY,
290
+ FIELD,
291
+ activeWeightsPath,
292
+ loadWeights,
293
+ validateWeights,
294
+ settableKeys,
295
+ applyOverrides,
296
+ saveWeights,
297
+ resetWeights,
298
+ WEIGHT_EXPLANATIONS,
299
+ CONFIDENCE
300
+ };