lurqrun 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +312 -148
  2. package/dist/{auditHandler-JCOJSUYW.js → auditHandler-G7PHKMZR.js} +12 -11
  3. package/dist/autopilotInit-JO2SH5K3.js +266 -0
  4. package/dist/bin/lurq.js +238 -83
  5. package/dist/{browserAuth-B6G27USY.js → browserAuth-PVYODBNR.js} +4 -3
  6. package/dist/{cache-DKI34SVS.js → cache-ND4VOUVY.js} +2 -2
  7. package/dist/check-A3FJE62G.js +2613 -0
  8. package/dist/{check-2FDGUOV7.js → check-PQSQ2MMA.js} +1 -1
  9. package/dist/checkUpgrade-Q4CV7GXG.js +24 -0
  10. package/dist/{chunk-BCANRN5B.js → chunk-2GAYNIHG.js} +8 -1
  11. package/dist/chunk-2LXYRDUN.js +92 -0
  12. package/dist/chunk-2XMD4H2I.js +243 -0
  13. package/dist/chunk-3D2MPGOQ.js +181 -0
  14. package/dist/chunk-53SG6XWA.js +141 -0
  15. package/dist/chunk-5ABNDB3I.js +37 -0
  16. package/dist/chunk-5ALIJFDA.js +114 -0
  17. package/dist/{chunk-LYMPYETA.js → chunk-6353IJJ5.js} +270 -6
  18. package/dist/{chunk-M6NYEXCW.js → chunk-64DPQSXV.js} +1 -1
  19. package/dist/chunk-64YOP5BQ.js +320 -0
  20. package/dist/{chunk-2VMOWSRY.js → chunk-6DM6UQFD.js} +19 -1
  21. package/dist/{chunk-NH5I4KHH.js → chunk-75LMEMJ3.js} +1 -5
  22. package/dist/{chunk-FW6BD2NO.js → chunk-ABH4BTK4.js} +458 -121
  23. package/dist/chunk-AHRDDKNO.js +90 -0
  24. package/dist/chunk-AQ6IVSFB.js +119 -0
  25. package/dist/chunk-BM3LF5T6.js +132 -0
  26. package/dist/chunk-D3K6IZVR.js +12845 -0
  27. package/dist/chunk-DONTW3NE.js +171 -0
  28. package/dist/{chunk-UDVNA7EA.js → chunk-ETY4FSOW.js} +161 -8
  29. package/dist/{chunk-VL2E5T2A.js → chunk-FHRT32JH.js} +6 -3
  30. package/dist/{chunk-DWAGCNEL.js → chunk-GM5Y555O.js} +36 -103
  31. package/dist/{chunk-6L3U7DZ5.js → chunk-GNNGXVCG.js} +1 -1
  32. package/dist/{chunk-PSX3GIAN.js → chunk-HWFX4BC4.js} +2 -1
  33. package/dist/{checkUpgrade-F2WESBPM.js → chunk-ILKYIVYV.js} +72 -10
  34. package/dist/{chunk-HWBBVLOT.js → chunk-J3NUERU7.js} +1 -1
  35. package/dist/chunk-J3U2CPSK.js +136 -0
  36. package/dist/{chunk-Y5GI7RL3.js → chunk-J6XQ7OPZ.js} +9 -1
  37. package/dist/{chunk-3N3Q3DSW.js → chunk-JGIJZJ3X.js} +8 -8
  38. package/dist/{chunk-DB2VF5UD.js → chunk-JJCQVOC6.js} +16 -11
  39. package/dist/{chunk-LBFGSSF2.js → chunk-KMV4Y6R3.js} +2 -1
  40. package/dist/{chunk-L6N4JFW2.js → chunk-KP5ZDDPE.js} +81 -4
  41. package/dist/{chunk-CW5HJ3LX.js → chunk-KT7PWDNV.js} +1 -1
  42. package/dist/{chunk-SJOVFF7B.js → chunk-KYKSZ3XZ.js} +3 -2
  43. package/dist/{chunk-GPTKSNR6.js → chunk-L3V7AVM6.js} +2 -1
  44. package/dist/{chunk-CUP36ND3.js → chunk-M2CYYBAH.js} +145 -36
  45. package/dist/{chunk-IQ4SDKKY.js → chunk-N2NYPTRU.js} +31 -228
  46. package/dist/chunk-N4TJO44E.js +603 -0
  47. package/dist/chunk-NEZNAPPN.js +41 -0
  48. package/dist/{chunk-WQ23REYT.js → chunk-NGMJQBOV.js} +1 -1
  49. package/dist/{chunk-BULZAX2U.js → chunk-POHTPT37.js} +55 -38
  50. package/dist/{chunk-EA3DP5HG.js → chunk-PZZU3FQY.js} +155 -25
  51. package/dist/{chunk-4F7ZESPO.js → chunk-Q7CMOU5C.js} +3 -5
  52. package/dist/{chunk-LRD4GBYE.js → chunk-QUIMQ7YL.js} +1 -1
  53. package/dist/chunk-RG3YLU6E.js +49 -0
  54. package/dist/{chunk-4ZYCIMY4.js → chunk-SFY5MPJE.js} +25 -4
  55. package/dist/{chunk-ST2X2GYN.js → chunk-SHZFOSXC.js} +109 -20
  56. package/dist/{chunk-CIDWNUAP.js → chunk-SOXFMMXC.js} +8 -2
  57. package/dist/{chunk-B43LCXBM.js → chunk-SWMWVK2R.js} +81 -16
  58. package/dist/{chunk-J5FZYN4A.js → chunk-TVOCVIM7.js} +1 -1
  59. package/dist/{chunk-U5AT3TD4.js → chunk-X4W64MHU.js} +1735 -1858
  60. package/dist/{chunk-BV32UNLL.js → chunk-XA2SLNBR.js} +2 -2
  61. package/dist/{chunk-AHBP533R.js → chunk-XBTYJQEK.js} +7 -5
  62. package/dist/chunk-XGOV6KV4.js +413 -0
  63. package/dist/{chunk-OQS4GUSI.js → chunk-XIFQIFSZ.js} +210 -661
  64. package/dist/{chunk-XBIDMHSK.js → chunk-XLXPVN3Y.js} +2 -34
  65. package/dist/{chunk-LO35HLQZ.js → chunk-ZJ5XHA77.js} +25 -4
  66. package/dist/{client-IRKAMDYZ.js → client-SJIWK4CK.js} +3 -3
  67. package/dist/{commands-FIL5ET6P.js → commands-6BBLN5N5.js} +145 -33
  68. package/dist/{compat-R3UTFQ5Q.js → compat-6B3CRT5F.js} +6 -6
  69. package/dist/constants-HX3RTD6Q.js +24 -0
  70. package/dist/{dashboardIssue-WYYMBFIB.js → dashboardIssue-KBKLQMGC.js} +105 -23
  71. package/dist/{diff-GZA2774U.js → diff-I4SNUHU3.js} +1 -1
  72. package/dist/domains-RKRPVP5A.js +14 -0
  73. package/dist/env-UN6KGZ7S.js +15 -0
  74. package/dist/envCheck-IL22OTSC.js +71 -0
  75. package/dist/{extract-NKGKLIVT.js → extract-6WG265BL.js} +14 -3
  76. package/dist/{fetch-QYTUJVG2.js → fetch-GHIP3VHN.js} +4 -4
  77. package/dist/{firstTouch-QQTJH4QX.js → firstTouch-M64T2MWF.js} +1 -1
  78. package/dist/fix-Z7ZY55HB.js +220 -0
  79. package/dist/{handlers-GEJAVZDK.js → handlers-GOXW2GWZ.js} +19 -17
  80. package/dist/hook-TWFLIDK3.js +412 -0
  81. package/dist/{http-ETPYMBGD.js → http-7VF2RE2D.js} +2097 -509
  82. package/dist/{ingestQueue-VKN4KBIF.js → ingestQueue-RSEPMORK.js} +14 -12
  83. package/dist/{install-EK3W2COX.js → install-55EPX34C.js} +6 -6
  84. package/dist/{installSkill-VQJWJVCL.js → installSkill-A7KKPDMS.js} +21 -3
  85. package/dist/manifest-ENMIC54B.js +13 -0
  86. package/dist/{mcp-3JHD5SUZ.js → mcp-CM6CDLHM.js} +60 -32
  87. package/dist/mcpConfig-FENV6NI7.js +80 -0
  88. package/dist/{mcpHandlers-QFN4MCFL.js → mcpHandlers-2UCLKMWN.js} +7 -7
  89. package/dist/{mcpScan-QZHWENIP.js → mcpScan-CKBQNK5H.js} +306 -442
  90. package/dist/{mcpScanWorkflow-JPYCBGC4.js → mcpScanWorkflow-NFUD3S7U.js} +29 -12
  91. package/dist/{mcpStack-BYJCZNIV.js → mcpStack-FLQ6XY2P.js} +1 -1
  92. package/dist/model-ASMZWLM7.js +214 -0
  93. package/dist/{packages-THVFMWFP.js → packages-2XRHNBJ7.js} +3 -5
  94. package/dist/{plan-V4OEI3J4.js → plan-XRZS6C7Z.js} +23 -21
  95. package/dist/{planView-JRXGCG2N.js → planView-ZAKRTGVS.js} +4 -1
  96. package/dist/{policy-3P6BGRDN.js → policy-EQT43P7S.js} +5 -5
  97. package/dist/probe-ZEZFNIQZ.js +610 -0
  98. package/dist/publicUpgrades-JZEOV24A.js +42 -0
  99. package/dist/{references-6N7VEPHT.js → references-I6Y4BSRR.js} +3 -1
  100. package/dist/{release-4U4ABNSJ.js → release-EUOM5I3R.js} +5 -5
  101. package/dist/{remote-YGCXYI4V.js → remote-I5O43WAY.js} +13 -3
  102. package/dist/rename-OS6JYBZQ.js +204 -0
  103. package/dist/{reportRuns-CKQQYLY4.js → reportRuns-O4X7ZFTX.js} +15 -2
  104. package/dist/safeFetch-COERXGFN.js +19 -0
  105. package/dist/{sandbox-MEZLAODF.js → sandbox-46TZNYZT.js} +4 -4
  106. package/dist/sarif-WLVJFJ7U.js +125 -0
  107. package/dist/server-LROMHS62.js +59 -0
  108. package/dist/{surface-YL6O67W3.js → surface-CZMHQLV3.js} +5 -3
  109. package/dist/{surface-V62GE554.js → surface-OH4TZR32.js} +18 -16
  110. package/dist/{surfaceHandlers-X2IZKA3E.js → surfaceHandlers-BDYRZMAC.js} +5 -5
  111. package/dist/{typecheck-X7U5ELMR.js → typecheck-NGOKNAJY.js} +23 -9
  112. package/dist/{uninstall-P7RGBX6G.js → uninstall-4E5YUDQO.js} +30 -4
  113. package/dist/{upgrade-NQ5IWFZB.js → upgrade-S72W7JVC.js} +86 -32
  114. package/dist/{upgradePlan-A4LRKLEG.js → upgradePlan-F3OUNL3E.js} +46 -11
  115. package/dist/upkeepHandler-7Q56A4UA.js +13 -0
  116. package/dist/{userConfig-Z3GQE776.js → userConfig-ICASHI47.js} +1 -1
  117. package/dist/{watch-DGFMWUDL.js → watch-LZPOKWCL.js} +24 -34
  118. package/package.json +3 -2
  119. package/templates/skill-instructions.md +22 -3
  120. package/dist/chunk-6AAEVQ7I.js +0 -6336
  121. package/dist/chunk-I2JUKN6Z.js +0 -24
  122. package/dist/server-KFUD5X57.js +0 -55
@@ -0,0 +1,141 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ SseError,
4
+ StreamableHTTPError,
5
+ UnauthorizedError
6
+ } from "./chunk-X4W64MHU.js";
7
+ import {
8
+ ErrorCode,
9
+ McpError
10
+ } from "./chunk-D3K6IZVR.js";
11
+ import {
12
+ init_esm_shims
13
+ } from "./chunk-I3M2KJXB.js";
14
+
15
+ // src/mcpScan/errors.ts
16
+ init_esm_shims();
17
+ var ENV_COMPLAINT = /\b([A-Z][A-Z0-9]{2,}(?:_[A-Z0-9]+)+)\b[^.\n]{0,60}?\b(required|must be set|not set|missing|is not defined)\b|\b(required|must be set|missing)\b[^.\n]{0,60}?\b([A-Z][A-Z0-9]{2,}(?:_[A-Z0-9]+)+)\b/;
18
+ function sniffMissingEnv(text) {
19
+ const m = ENV_COMPLAINT.exec(text);
20
+ return m ? m[1] ?? m[4] ?? null : null;
21
+ }
22
+ var NETWORK_CODES = /* @__PURE__ */ new Set([
23
+ "ECONNREFUSED",
24
+ "ENOTFOUND",
25
+ "EAI_AGAIN",
26
+ "ECONNRESET",
27
+ "ETIMEDOUT",
28
+ "EHOSTUNREACH",
29
+ "ENETUNREACH",
30
+ "UND_ERR_CONNECT_TIMEOUT",
31
+ "UND_ERR_SOCKET",
32
+ "CERT_HAS_EXPIRED",
33
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
34
+ "SELF_SIGNED_CERT_IN_CHAIN",
35
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
36
+ "ERR_TLS_CERT_ALTNAME_INVALID"
37
+ ]);
38
+ function causeCode(err) {
39
+ let cur = err;
40
+ for (let i = 0; i < 5 && cur; i++) {
41
+ const code = cur.code;
42
+ if (typeof code === "string") return code;
43
+ cur = cur.cause;
44
+ }
45
+ return null;
46
+ }
47
+ var msg = (err) => err instanceof Error ? err.message : String(err);
48
+ function classifyError(err, ctx) {
49
+ const message = msg(err).slice(0, 500);
50
+ if (err instanceof UnauthorizedError) {
51
+ return {
52
+ status: "auth_required",
53
+ error: message || "the server requires authorization",
54
+ hint: "this server signs in with OAuth, and lurq cannot reuse the token your agent holds; ask your agent to pass its tool list to the mcp_stack tool instead"
55
+ };
56
+ }
57
+ const httpCode = err instanceof StreamableHTTPError || err instanceof SseError ? err.code : void 0;
58
+ if (httpCode === 401 || httpCode === 403) {
59
+ return {
60
+ status: "auth_required",
61
+ error: `HTTP ${httpCode}`,
62
+ hint: "the server rejected the credentials in this config; check the Authorization header or token it is given"
63
+ };
64
+ }
65
+ if (typeof httpCode === "number" && httpCode > 0) {
66
+ return {
67
+ status: "unreachable",
68
+ error: `HTTP ${httpCode}: ${message}`,
69
+ hint: httpCode === 404 ? "nothing answers MCP at this url; check the path" : null
70
+ };
71
+ }
72
+ if (err instanceof McpError && err.code === ErrorCode.RequestTimeout) {
73
+ return {
74
+ status: "timeout",
75
+ error: message,
76
+ hint: ctx.transport === "stdio" ? "the server did not answer in time; a first run of npx/uvx downloads the package, so try again with a longer --timeout" : null
77
+ };
78
+ }
79
+ const code = causeCode(err);
80
+ if (code === "ENOENT" && ctx.transport === "stdio") {
81
+ return {
82
+ status: "spawn_failed",
83
+ error: `command not found: ${ctx.command ?? "(none)"}`,
84
+ hint: "install it, or use an absolute path in the config"
85
+ };
86
+ }
87
+ if (code && NETWORK_CODES.has(code)) {
88
+ return { status: "unreachable", error: `${code}: ${message}`, hint: null };
89
+ }
90
+ if (err instanceof TypeError && /fetch failed/i.test(message)) {
91
+ const cause = err.cause;
92
+ return {
93
+ status: "unreachable",
94
+ error: cause ? `fetch failed: ${msg(cause).slice(0, 300)}` : message,
95
+ hint: null
96
+ };
97
+ }
98
+ const closed = err instanceof McpError && err.code === ErrorCode.ConnectionClosed || /connection closed/i.test(message);
99
+ if (closed && ctx.transport === "stdio") {
100
+ const missing = sniffMissingEnv(ctx.stderrTail);
101
+ if (missing) {
102
+ return {
103
+ status: "needs_config",
104
+ error: `the server exited, and its output names ${missing} as required`,
105
+ hint: `set ${missing} in this server's env block`
106
+ };
107
+ }
108
+ if (ctx.stdoutNoise > 0 && !ctx.stderrTail.trim()) {
109
+ return {
110
+ status: "protocol_error",
111
+ error: "the server wrote non-protocol output to stdout and then closed",
112
+ hint: "stdio servers must log to stderr; stdout is reserved for JSON-RPC"
113
+ };
114
+ }
115
+ return {
116
+ status: "spawn_failed",
117
+ error: ctx.stderrTail.trim() ? `exited before completing the handshake: ${ctx.stderrTail.trim().split("\n").slice(-3).join(" | ")}` : "exited before completing the handshake",
118
+ hint: null
119
+ };
120
+ }
121
+ if (/protocol version is not supported/i.test(message)) {
122
+ return {
123
+ status: "protocol_error",
124
+ error: message,
125
+ hint: "the server speaks a protocol revision this lurq version does not; upgrade lurq"
126
+ };
127
+ }
128
+ if (ctx.stdoutNoise > 0) {
129
+ return {
130
+ status: "protocol_error",
131
+ error: `${message} (the server also wrote ${ctx.stdoutNoise} non-protocol line(s) to stdout)`,
132
+ hint: "stdio servers must log to stderr; stdout is reserved for JSON-RPC"
133
+ };
134
+ }
135
+ return { status: "protocol_error", error: message || "unknown error", hint: null };
136
+ }
137
+
138
+ export {
139
+ sniffMissingEnv,
140
+ classifyError
141
+ };
@@ -0,0 +1,37 @@
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/remoteProbe/url.ts
7
+ init_esm_shims();
8
+ var PLACEHOLDER = /\{[^{}]+\}/;
9
+ function endpointIdentity(raw) {
10
+ if (typeof raw !== "string") return null;
11
+ const trimmed = raw.trim();
12
+ if (!trimmed || trimmed.length > 2048) return null;
13
+ const templated = PLACEHOLDER.test(trimmed);
14
+ let parsed;
15
+ try {
16
+ parsed = new URL(templated ? trimmed.replace(/\{[^{}]+\}/g, "placeholder") : trimmed);
17
+ } catch {
18
+ return null;
19
+ }
20
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
21
+ const host = parsed.hostname.toLowerCase();
22
+ if (!host) return null;
23
+ if (templated) return { url: trimmed, host, templated: true };
24
+ parsed.hash = "";
25
+ const path = parsed.pathname === "/" ? "" : parsed.pathname;
26
+ const port = parsed.port ? `:${parsed.port}` : "";
27
+ const auth = parsed.username ? `${parsed.username}${parsed.password ? `:${parsed.password}` : ""}@` : "";
28
+ return {
29
+ url: `${parsed.protocol}//${auth}${host}${port}${path}${parsed.search}`,
30
+ host,
31
+ templated: false
32
+ };
33
+ }
34
+
35
+ export {
36
+ endpointIdentity
37
+ };
@@ -0,0 +1,114 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ require_semver
4
+ } from "./chunk-3GHJR7XR.js";
5
+ import {
6
+ __toESM,
7
+ init_esm_shims
8
+ } from "./chunk-I3M2KJXB.js";
9
+
10
+ // src/fix/manifest.ts
11
+ init_esm_shims();
12
+ var import_semver = __toESM(require_semver(), 1);
13
+ import { readFileSync } from "fs";
14
+ import { join } from "path";
15
+ import ts from "typescript";
16
+ var BLOCKS = ["dependencies", "devDependencies", "optionalDependencies"];
17
+ var SIMPLE_RANGE = /^(\^|~)?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/;
18
+ function declaredRange(text, pkg) {
19
+ const sf = ts.parseJsonText("package.json", text);
20
+ const root = sf.statements[0]?.expression;
21
+ if (!root || !ts.isObjectLiteralExpression(root)) return null;
22
+ const propNamed = (obj, name) => obj.properties.find(
23
+ (p) => ts.isPropertyAssignment(p) && ts.isStringLiteral(p.name) && p.name.text === name
24
+ );
25
+ for (const block of BLOCKS) {
26
+ const blockProp = propNamed(root, block);
27
+ if (!blockProp || !ts.isObjectLiteralExpression(blockProp.initializer)) continue;
28
+ const dep = propNamed(blockProp.initializer, pkg);
29
+ if (!dep || !ts.isStringLiteral(dep.initializer)) continue;
30
+ const node = dep.initializer;
31
+ return { block, range: node.text, start: node.getStart(sf) + 1, end: node.getEnd() - 1 };
32
+ }
33
+ return null;
34
+ }
35
+ function decideRange(file, found, toVersion) {
36
+ if (!import_semver.default.valid(toVersion)) {
37
+ return { refusedBecause: `${toVersion} is not an exact version` };
38
+ }
39
+ if (import_semver.default.validRange(found.range) && import_semver.default.satisfies(toVersion, found.range)) {
40
+ return { satisfied: true };
41
+ }
42
+ const simple = SIMPLE_RANGE.exec(found.range);
43
+ if (!simple) {
44
+ return {
45
+ refusedBecause: `"${found.range}" is not a plain ^, ~ or exact range, so what it should become is a judgement`
46
+ };
47
+ }
48
+ const prefix = simple[1] ?? "";
49
+ return {
50
+ edit: {
51
+ file,
52
+ start: found.start,
53
+ end: found.end,
54
+ text: `${prefix}${toVersion}`,
55
+ was: found.range
56
+ }
57
+ };
58
+ }
59
+ function manifestFindings(root, targets, opts = {}) {
60
+ const files = opts.files ?? ["package.json"];
61
+ const read = opts.read ?? ((file) => {
62
+ try {
63
+ return readFileSync(join(root, file), "utf8");
64
+ } catch {
65
+ return null;
66
+ }
67
+ });
68
+ const texts = /* @__PURE__ */ new Map();
69
+ for (const file of files) {
70
+ const text = read(file);
71
+ if (text !== null) texts.set(file, text);
72
+ }
73
+ const findings = [];
74
+ const refused = [];
75
+ for (const target of targets) {
76
+ const edits = [];
77
+ const bumped = [];
78
+ for (const [file, text] of texts) {
79
+ const found = declaredRange(text, target.package);
80
+ if (!found) continue;
81
+ const decision = decideRange(file, found, target.toVersion);
82
+ if (decision.edit) {
83
+ edits.push(decision.edit);
84
+ bumped.push(file);
85
+ } else if (decision.refusedBecause) {
86
+ refused.push({ package: target.package, file, reason: decision.refusedBecause });
87
+ }
88
+ }
89
+ if (edits.length === 0) continue;
90
+ findings.push({
91
+ domain: "package",
92
+ code: `outdated-range:${target.package}`,
93
+ // Blocking: with the source rewritten and the range still pinning the old
94
+ // major, the next install puts the old version back under new code.
95
+ severity: "blocking",
96
+ detail: `${target.package} is declared at a range that excludes ${target.toVersion} in ${bumped.length} manifest(s): ${bumped.join(", ")}`,
97
+ file: bumped[0],
98
+ evidence: `upgrading ${target.package} ${target.fromVersion} \u2192 ${target.toVersion}`,
99
+ fix: {
100
+ summary: `bump ${target.package} to ${target.toVersion} in ${bumped.length} manifest(s)`,
101
+ edits,
102
+ // Installing is the user's call; the type check is what proves the tree agrees.
103
+ verify: ["typecheck"]
104
+ }
105
+ });
106
+ }
107
+ return { findings, refused };
108
+ }
109
+
110
+ export {
111
+ declaredRange,
112
+ decideRange,
113
+ manifestFindings
114
+ };
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
2
  import {
3
3
  EMBEDDING_DIM
4
- } from "./chunk-GPTKSNR6.js";
4
+ } from "./chunk-L3V7AVM6.js";
5
5
  import {
6
6
  __export,
7
7
  init_esm_shims
@@ -14,6 +14,7 @@ __export(schema_exports, {
14
14
  apiKeys: () => apiKeys,
15
15
  apiSurfaces: () => apiSurfaces,
16
16
  askSpendDaily: () => askSpendDaily,
17
+ builderScans: () => builderScans,
17
18
  claims: () => claims,
18
19
  compatEdges: () => compatEdges,
19
20
  compatVerifyQueue: () => compatVerifyQueue,
@@ -23,8 +24,15 @@ __export(schema_exports, {
23
24
  mcpChangeEvents: () => mcpChangeEvents,
24
25
  mcpContracts: () => mcpContracts,
25
26
  mcpDeployments: () => mcpDeployments,
27
+ mcpEndpointChangeAcks: () => mcpEndpointChangeAcks,
28
+ mcpEndpointChanges: () => mcpEndpointChanges,
29
+ mcpEndpointObservations: () => mcpEndpointObservations,
30
+ mcpEndpointServers: () => mcpEndpointServers,
26
31
  mcpObservations: () => mcpObservations,
32
+ mcpPins: () => mcpPins,
27
33
  mcpPublicReports: () => mcpPublicReports,
34
+ mcpRegistryServers: () => mcpRegistryServers,
35
+ mcpRemoteEndpoints: () => mcpRemoteEndpoints,
28
36
  notificationChannels: () => notificationChannels,
29
37
  notificationDeliveries: () => notificationDeliveries,
30
38
  notificationItems: () => notificationItems,
@@ -36,6 +44,7 @@ __export(schema_exports, {
36
44
  policyDecisions: () => policyDecisions,
37
45
  recommendationOutcomes: () => recommendationOutcomes,
38
46
  repoAlerts: () => repoAlerts,
47
+ repoPolicyDefaults: () => repoPolicyDefaults,
39
48
  repos: () => repos,
40
49
  resolvedClosures: () => resolvedClosures,
41
50
  seedPackages: () => seedPackages,
@@ -161,7 +170,17 @@ var packages = pgTable(
161
170
  * Null for crawler/_changes-created packages, or ones ingested before
162
171
  * dashboard accounts existed. Stamped once via a standalone WHERE ... IS NULL
163
172
  * update kept out of upsertPackage, so re-syncs can never clobber it. */
164
- firstRequestedByOwnerId: text("first_requested_by_owner_id")
173
+ firstRequestedByOwnerId: text("first_requested_by_owner_id"),
174
+ /**
175
+ * Failed API-surface extractions for `surface_attempted_version`. The worker
176
+ * stops asking once a version has failed SURFACE_MAX_ATTEMPTS times; a new
177
+ * latest version starts the count again, since it may ship types the last
178
+ * one did not. Without this, a package with no extractable surface was
179
+ * re-attempted at random every hour, forever. Not in upsertPackage's row,
180
+ * so re-syncs never reset it.
181
+ */
182
+ surfaceAttempts: integer("surface_attempts").notNull().default(0),
183
+ surfaceAttemptedVersion: text("surface_attempted_version")
165
184
  },
166
185
  (table) => [
167
186
  uniqueIndex("packages_ecosystem_name_idx").on(table.ecosystem, table.name),
@@ -211,6 +230,13 @@ var discoveryQueue = pgTable(
211
230
  * and never reaching the write that would take it off the queue. Same
212
231
  * treatment `compat_verify_queue.attempts` already gives a failing set. */
213
232
  attempts: integer("attempts").notNull().default(0),
233
+ /**
234
+ * The account whose query asked for this package (`reactive` rows only),
235
+ * credited as first requester when it is ingested. Stored here because the
236
+ * on-demand ingest used to live only in the API process's memory, and a
237
+ * deploy mid-backlog dropped both the work and the attribution.
238
+ */
239
+ requestedByOwnerId: text("requested_by_owner_id"),
214
240
  discoveredAt: ts("discovered_at").notNull().defaultNow()
215
241
  },
216
242
  (table) => [index("discovery_queue_status_idx").on(table.status)]
@@ -392,6 +418,11 @@ var ownerUsageDaily = pgTable(
392
418
  index("owner_usage_daily_owner_date_idx").on(table.ownerId, table.date)
393
419
  ]
394
420
  );
421
+ var repoPolicyDefaults = pgTable("repo_policy_defaults", {
422
+ ownerId: text("owner_id").primaryKey(),
423
+ policy: jsonb("policy").$type().notNull(),
424
+ updatedAt: ts("updated_at").notNull().defaultNow()
425
+ });
395
426
  var repos = pgTable(
396
427
  "repos",
397
428
  {
@@ -458,6 +489,21 @@ var upgradeRuns = pgTable(
458
489
  * row per package+target and updates in place.
459
490
  */
460
491
  runUrl: text("run_url").notNull().default(""),
492
+ /**
493
+ * What started the run, from GITHUB_EVENT_NAME. See `RunTrigger`.
494
+ *
495
+ * NULLABLE, and deliberately NOT in the dedup index below. Every row
496
+ * written before this column existed has no trigger, and back-filling them
497
+ * with 'schedule' would invent evidence the log then presents as fact — the
498
+ * same rule `unverified` and `analysedOnly` follow. The dashboard renders
499
+ * null as "not recorded".
500
+ *
501
+ * Keeping it out of the dedup key is not a style choice: `runUrl` is in
502
+ * that key and is NOT NULL precisely because Postgres treats NULLs as
503
+ * distinct, so a nullable column there would let every re-post insert a
504
+ * duplicate instead of updating in place.
505
+ */
506
+ trigger: text("trigger").$type(),
461
507
  createdAt: ts("created_at").notNull().defaultNow()
462
508
  },
463
509
  (table) => [
@@ -480,7 +526,10 @@ var repoAlerts = pgTable(
480
526
  id: serial("id").primaryKey(),
481
527
  /** Clerk user id, copied from the repo — alerts are read owner-scoped. */
482
528
  ownerId: text("owner_id").notNull(),
483
- repoId: integer("repo_id").notNull(),
529
+ /** Null for an account that runs `check-upgrade` on a repo lurq has no
530
+ * GitHub App installation for: the alert is keyed by `repo_full_name` from
531
+ * its upgrade runs instead, and there is no repo page to link to. */
532
+ repoId: integer("repo_id"),
484
533
  /** Denormalized so the feed renders without a join, as in `upgrade_runs`. */
485
534
  repoFullName: text("repo_full_name").notNull(),
486
535
  packageName: text("package_name").notNull(),
@@ -507,7 +556,11 @@ var repoAlerts = pgTable(
507
556
  // One alert per repo per release. A re-sync of the same version — and the
508
557
  // watcher re-syncs on every publish, including non-latest backports — must
509
558
  // not re-notify.
510
- uniqueIndex("repo_alerts_dedup_idx").on(table.repoId, table.packageName, table.toVersion)
559
+ uniqueIndex("repo_alerts_dedup_idx").on(table.repoId, table.packageName, table.toVersion),
560
+ // The same rule for alerts with no connected repo. Postgres treats NULLs as
561
+ // distinct, so the index above can never dedupe those rows; this one covers
562
+ // exactly them. Partial, so adding it cannot fail on existing rows.
563
+ uniqueIndex("repo_alerts_cli_dedup_idx").on(table.ownerId, table.repoFullName, table.packageName, table.toVersion).where(sql`repo_id is null`)
511
564
  ]
512
565
  );
513
566
  var surfaceQueue = pgTable(
@@ -532,6 +585,12 @@ var surfaceQueue = pgTable(
532
585
  specKey: text("spec_key").notNull().unique(),
533
586
  /** Failed drains bump this; the worker drops a spec that keeps failing. */
534
587
  attempts: integer("attempts").notNull().default(0),
588
+ /**
589
+ * Not eligible before this. Set on every retry with an exponential delay, so
590
+ * a spec that just failed waits instead of being retried the next cycle and
591
+ * — oldest-first — blocking every newer spec behind it. Null = ready now.
592
+ */
593
+ nextAttemptAt: ts("next_attempt_at"),
535
594
  requestedAt: ts("requested_at").notNull().defaultNow()
536
595
  },
537
596
  (table) => [index("surface_queue_requested_idx").on(table.kind, table.requestedAt)]
@@ -801,7 +860,11 @@ var mcpDeployments = pgTable(
801
860
  lastChangedAt: ts("last_changed_at")
802
861
  },
803
862
  (table) => [
804
- uniqueIndex("mcp_deployments_identity_idx").on(table.ownerId, table.serverKey, table.configFingerprint),
863
+ uniqueIndex("mcp_deployments_identity_idx").on(
864
+ table.ownerId,
865
+ table.serverKey,
866
+ table.configFingerprint
867
+ ),
805
868
  index("mcp_deployments_owner_idx").on(table.ownerId, table.lastScannedAt)
806
869
  ]
807
870
  );
@@ -854,7 +917,9 @@ var mcpPublicReports = pgTable(
854
917
  reportedAt: ts("reported_at").notNull().defaultNow()
855
918
  },
856
919
  (table) => [
857
- primaryKey({ columns: [table.registry, table.packageName, table.version, table.contentHash, table.ownerId] }),
920
+ primaryKey({
921
+ columns: [table.registry, table.packageName, table.version, table.contentHash, table.ownerId]
922
+ }),
858
923
  index("mcp_public_reports_version_idx").on(table.registry, table.packageName, table.version)
859
924
  ]
860
925
  );
@@ -924,6 +989,196 @@ var notificationChannels = pgTable(
924
989
  },
925
990
  (table) => [index("notification_channels_owner_idx").on(table.ownerId)]
926
991
  );
992
+ var builderScans = pgTable(
993
+ "builder_scans",
994
+ {
995
+ ownerId: text("owner_id").notNull(),
996
+ target: text("target").notNull(),
997
+ login: text("login").notNull(),
998
+ archetype: text("archetype").$type().notNull(),
999
+ avatarUrl: text("avatar_url").notNull(),
1000
+ // What builderStanding.ts ranks on, copied out of `profile` at save, so
1001
+ // ranking reads seven integers per builder instead of every whole report.
1002
+ repos: integer("repos").notNull(),
1003
+ active90: integer("active_90").notNull(),
1004
+ stars: integer("stars").notNull(),
1005
+ depsTracked: integer("deps_tracked").notNull(),
1006
+ depsBehind: integer("deps_behind").notNull(),
1007
+ depsMajor: integer("deps_major").notNull(),
1008
+ advisories: integer("advisories").notNull(),
1009
+ profile: jsonb("profile").$type().notNull(),
1010
+ scannedAt: ts("scanned_at").notNull().defaultNow(),
1011
+ createdAt: ts("created_at").notNull().defaultNow()
1012
+ },
1013
+ (table) => [
1014
+ primaryKey({ columns: [table.ownerId, table.target] }),
1015
+ index("builder_scans_owner_recent_idx").on(table.ownerId, table.scannedAt)
1016
+ ]
1017
+ );
1018
+ var mcpRegistryServers = pgTable(
1019
+ "mcp_registry_servers",
1020
+ {
1021
+ name: text("name").notNull(),
1022
+ version: text("version").notNull(),
1023
+ title: text("title"),
1024
+ description: text("description"),
1025
+ websiteUrl: text("website_url"),
1026
+ repositoryUrl: text("repository_url"),
1027
+ /** `active`, `deprecated`, `deleted`, … as the registry reports it. */
1028
+ status: text("status").notNull(),
1029
+ isLatest: boolean("is_latest").notNull(),
1030
+ remotes: jsonb("remotes").$type().notNull(),
1031
+ packages: jsonb("packages").$type().notNull(),
1032
+ publishedAt: ts("published_at"),
1033
+ registryUpdatedAt: ts("registry_updated_at"),
1034
+ syncedAt: ts("synced_at").notNull().defaultNow()
1035
+ },
1036
+ (table) => [
1037
+ primaryKey({ columns: [table.name, table.version] }),
1038
+ index("mcp_registry_servers_latest_idx").on(table.name).where(sql`${table.isLatest}`),
1039
+ index("mcp_registry_servers_updated_idx").on(table.registryUpdatedAt)
1040
+ ]
1041
+ );
1042
+ var mcpRemoteEndpoints = pgTable(
1043
+ "mcp_remote_endpoints",
1044
+ {
1045
+ id: serial("id").primaryKey(),
1046
+ url: text("url").notNull().unique(),
1047
+ host: text("host").notNull(),
1048
+ /** Transport the registry declares: `streamable-http` or `sse`. */
1049
+ transport: text("transport").notNull(),
1050
+ /** URL carries `{placeholders}`: never probed, answered as setup-dependent. */
1051
+ templated: boolean("templated").notNull().default(false),
1052
+ /** A maintainer asked not to be probed. Never scheduled again. */
1053
+ optedOut: boolean("opted_out").notNull().default(false),
1054
+ lastStatus: text("last_status").$type(),
1055
+ lastHttpStatus: integer("last_http_status"),
1056
+ /** Content hash of the last contract read (a key into `mcp_contracts`). */
1057
+ lastContentHash: text("last_content_hash"),
1058
+ /** Hash of the auth profile, so an auth change is detectable without a diff. */
1059
+ lastAuthHash: text("last_auth_hash"),
1060
+ auth: jsonb("auth").$type(),
1061
+ violations: jsonb("violations").$type().notNull().default([]),
1062
+ protocolMode: text("protocol_mode").$type(),
1063
+ protocolVersion: text("protocol_version"),
1064
+ serverName: text("server_name"),
1065
+ serverVersion: text("server_version"),
1066
+ finalUrl: text("final_url"),
1067
+ latencyMs: integer("latency_ms"),
1068
+ lastError: text("last_error"),
1069
+ consecutiveFailures: integer("consecutive_failures").notNull().default(0),
1070
+ probeCount: integer("probe_count").notNull().default(0),
1071
+ firstSeenAt: ts("first_seen_at").notNull().defaultNow(),
1072
+ lastProbedAt: ts("last_probed_at"),
1073
+ lastChangedAt: ts("last_changed_at"),
1074
+ nextProbeAt: ts("next_probe_at").notNull().defaultNow(),
1075
+ leaseUntil: ts("lease_until"),
1076
+ /** No live registry entry names this URL any more. Kept for history. */
1077
+ removedAt: ts("removed_at"),
1078
+ /**
1079
+ * The key an account's own `lurq mcp-scan` gives this server (`remote:<host><path>`,
1080
+ * query dropped). Joining on it is how a change the public probe sees reaches
1081
+ * every account already running the server, without anyone rescanning.
1082
+ */
1083
+ scanKey: text("scan_key")
1084
+ },
1085
+ (table) => [
1086
+ index("mcp_remote_endpoints_scan_key_idx").on(table.scanKey),
1087
+ index("mcp_remote_endpoints_due_idx").on(table.nextProbeAt).where(
1088
+ sql`${table.optedOut} = false and ${table.templated} = false and ${table.removedAt} is null`
1089
+ ),
1090
+ index("mcp_remote_endpoints_host_idx").on(table.host)
1091
+ ]
1092
+ );
1093
+ var mcpEndpointServers = pgTable(
1094
+ "mcp_endpoint_servers",
1095
+ {
1096
+ endpointId: integer("endpoint_id").notNull().references(() => mcpRemoteEndpoints.id),
1097
+ serverName: text("server_name").notNull(),
1098
+ headers: jsonb("headers").$type().notNull().default([]),
1099
+ lastSeenAt: ts("last_seen_at").notNull().defaultNow(),
1100
+ /**
1101
+ * The server's latest registry version stopped naming this URL, or the
1102
+ * server was deleted. Marked, never deleted: rows in this schema are history.
1103
+ */
1104
+ removedAt: ts("removed_at")
1105
+ },
1106
+ (table) => [
1107
+ primaryKey({ columns: [table.endpointId, table.serverName] }),
1108
+ index("mcp_endpoint_servers_name_idx").on(table.serverName)
1109
+ ]
1110
+ );
1111
+ var mcpEndpointObservations = pgTable(
1112
+ "mcp_endpoint_observations",
1113
+ {
1114
+ id: serial("id").primaryKey(),
1115
+ endpointId: integer("endpoint_id").notNull().references(() => mcpRemoteEndpoints.id),
1116
+ status: text("status").$type().notNull(),
1117
+ httpStatus: integer("http_status"),
1118
+ contentHash: text("content_hash"),
1119
+ authHash: text("auth_hash"),
1120
+ violations: jsonb("violations").$type().notNull().default([]),
1121
+ protocolVersion: text("protocol_version"),
1122
+ error: text("error"),
1123
+ probeCount: integer("probe_count").notNull().default(1),
1124
+ firstSeenAt: ts("first_seen_at").notNull().defaultNow(),
1125
+ lastSeenAt: ts("last_seen_at").notNull().defaultNow()
1126
+ },
1127
+ (table) => [
1128
+ index("mcp_endpoint_observations_endpoint_idx").on(table.endpointId, table.firstSeenAt)
1129
+ ]
1130
+ );
1131
+ var mcpEndpointChanges = pgTable(
1132
+ "mcp_endpoint_changes",
1133
+ {
1134
+ id: serial("id").primaryKey(),
1135
+ endpointId: integer("endpoint_id").notNull().references(() => mcpRemoteEndpoints.id),
1136
+ kind: text("kind").$type().notNull(),
1137
+ fromKey: text("from_key").notNull(),
1138
+ toKey: text("to_key").notNull(),
1139
+ severity: text("severity").$type().notNull(),
1140
+ summary: text("summary").notNull(),
1141
+ diff: jsonb("diff").$type(),
1142
+ createdAt: ts("created_at").notNull().defaultNow()
1143
+ },
1144
+ (table) => [
1145
+ uniqueIndex("mcp_endpoint_changes_pair_idx").on(
1146
+ table.endpointId,
1147
+ table.kind,
1148
+ table.fromKey,
1149
+ table.toKey
1150
+ ),
1151
+ index("mcp_endpoint_changes_endpoint_idx").on(table.endpointId, table.createdAt),
1152
+ index("mcp_endpoint_changes_created_idx").on(table.createdAt)
1153
+ ]
1154
+ );
1155
+ var mcpPins = pgTable(
1156
+ "mcp_pins",
1157
+ {
1158
+ id: serial("id").primaryKey(),
1159
+ ownerId: text("owner_id").notNull(),
1160
+ endpointId: integer("endpoint_id").notNull().references(() => mcpRemoteEndpoints.id),
1161
+ /** Null when the contract was not readable without credentials at pin time. */
1162
+ contentHash: text("content_hash"),
1163
+ authHash: text("auth_hash"),
1164
+ note: text("note"),
1165
+ pinnedAt: ts("pinned_at").notNull().defaultNow(),
1166
+ removedAt: ts("removed_at")
1167
+ },
1168
+ (table) => [
1169
+ uniqueIndex("mcp_pins_owner_endpoint_idx").on(table.ownerId, table.endpointId),
1170
+ index("mcp_pins_endpoint_idx").on(table.endpointId)
1171
+ ]
1172
+ );
1173
+ var mcpEndpointChangeAcks = pgTable(
1174
+ "mcp_endpoint_change_acks",
1175
+ {
1176
+ ownerId: text("owner_id").notNull(),
1177
+ changeId: integer("change_id").notNull().references(() => mcpEndpointChanges.id),
1178
+ acknowledgedAt: ts("acknowledged_at").notNull().defaultNow()
1179
+ },
1180
+ (table) => [primaryKey({ columns: [table.ownerId, table.changeId] })]
1181
+ );
927
1182
 
928
1183
  export {
929
1184
  packages,
@@ -940,6 +1195,7 @@ export {
940
1195
  recommendationOutcomes,
941
1196
  askSpendDaily,
942
1197
  ownerUsageDaily,
1198
+ repoPolicyDefaults,
943
1199
  repos,
944
1200
  upgradeRuns,
945
1201
  repoAlerts,
@@ -961,5 +1217,13 @@ export {
961
1217
  mcpPublicReports,
962
1218
  notificationPreferences,
963
1219
  notificationChannels,
1220
+ builderScans,
1221
+ mcpRegistryServers,
1222
+ mcpRemoteEndpoints,
1223
+ mcpEndpointServers,
1224
+ mcpEndpointObservations,
1225
+ mcpEndpointChanges,
1226
+ mcpPins,
1227
+ mcpEndpointChangeAcks,
964
1228
  schema_exports
965
1229
  };
@@ -2,7 +2,7 @@ import { createRequire as __lurqCreateRequire } from 'node:module'; const requir
2
2
  import {
3
3
  apiSurfaces,
4
4
  packages
5
- } from "./chunk-LYMPYETA.js";
5
+ } from "./chunk-6353IJJ5.js";
6
6
  import {
7
7
  init_esm_shims
8
8
  } from "./chunk-I3M2KJXB.js";