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.
- package/README.md +18 -10
- package/dist/auditHandler-JCOJSUYW.js +23 -0
- package/dist/bin/lurq.js +3090 -23306
- package/dist/browserAuth-B6G27USY.js +95 -0
- package/dist/cache-DKI34SVS.js +12 -0
- package/dist/check-2FDGUOV7.js +192 -0
- package/dist/checkUpgrade-F2WESBPM.js +103 -0
- package/dist/chunk-2VMOWSRY.js +300 -0
- package/dist/chunk-3GHJR7XR.js +2049 -0
- package/dist/chunk-3N3Q3DSW.js +214 -0
- package/dist/chunk-4ESO33J6.js +34 -0
- package/dist/chunk-4F7ZESPO.js +132 -0
- package/dist/chunk-4KCPOMG6.js +68 -0
- package/dist/chunk-4ZYCIMY4.js +155 -0
- package/dist/chunk-63MUJNZL.js +318 -0
- package/dist/chunk-6AAEVQ7I.js +6336 -0
- package/dist/chunk-6EQ3ARXA.js +304 -0
- package/dist/chunk-6L3U7DZ5.js +23 -0
- package/dist/chunk-AHBP533R.js +220 -0
- package/dist/chunk-B43LCXBM.js +223 -0
- package/dist/chunk-BCANRN5B.js +33 -0
- package/dist/chunk-BUALU27S.js +123 -0
- package/dist/chunk-BULZAX2U.js +1554 -0
- package/dist/chunk-BV32UNLL.js +154 -0
- package/dist/chunk-C6GLE626.js +160 -0
- package/dist/chunk-CIDWNUAP.js +145 -0
- package/dist/chunk-CUP36ND3.js +2126 -0
- package/dist/chunk-CW5HJ3LX.js +96 -0
- package/dist/chunk-DB2VF5UD.js +315 -0
- package/dist/chunk-DWAGCNEL.js +210 -0
- package/dist/chunk-EA3DP5HG.js +293 -0
- package/dist/chunk-ELGCAM7P.js +184 -0
- package/dist/chunk-FW6BD2NO.js +1915 -0
- package/dist/chunk-GE37NVLN.js +15 -0
- package/dist/chunk-GPTKSNR6.js +171 -0
- package/dist/chunk-GRJXQBQZ.js +793 -0
- package/dist/chunk-HWBBVLOT.js +92 -0
- package/dist/chunk-I2JUKN6Z.js +24 -0
- package/dist/chunk-I3M2KJXB.js +56 -0
- package/dist/chunk-IQ4SDKKY.js +733 -0
- package/dist/chunk-J5FZYN4A.js +116 -0
- package/dist/chunk-L6N4JFW2.js +263 -0
- package/dist/chunk-LBFGSSF2.js +126 -0
- package/dist/chunk-LEGPB7DO.js +81 -0
- package/dist/chunk-LO35HLQZ.js +219 -0
- package/dist/chunk-LRD4GBYE.js +73 -0
- package/dist/chunk-LUAKDHLZ.js +40 -0
- package/dist/chunk-LYMPYETA.js +965 -0
- package/dist/chunk-M6NYEXCW.js +38 -0
- package/dist/chunk-MHUEVBVO.js +35 -0
- package/dist/chunk-MYGSLK44.js +37 -0
- package/dist/chunk-NH5I4KHH.js +201 -0
- package/dist/chunk-OQS4GUSI.js +1391 -0
- package/dist/chunk-PSX3GIAN.js +176 -0
- package/dist/chunk-Q5VPF4WI.js +26 -0
- package/dist/chunk-QKGYDMWB.js +7409 -0
- package/dist/chunk-QSL6QN5X.js +115 -0
- package/dist/chunk-SHCEBP3J.js +107 -0
- package/dist/chunk-SJOVFF7B.js +201 -0
- package/dist/chunk-ST2X2GYN.js +373 -0
- package/dist/chunk-TNTXWSYA.js +19 -0
- package/dist/chunk-U5AT3TD4.js +2128 -0
- package/dist/chunk-UDVNA7EA.js +483 -0
- package/dist/chunk-VL2E5T2A.js +109 -0
- package/dist/chunk-VLRHFMGJ.js +58 -0
- package/dist/chunk-WHX2ZFCG.js +4048 -0
- package/dist/chunk-WQ23REYT.js +37 -0
- package/dist/chunk-XBIDMHSK.js +15425 -0
- package/dist/chunk-Y5GI7RL3.js +66 -0
- package/dist/client-IRKAMDYZ.js +15 -0
- package/dist/commands-FIL5ET6P.js +911 -0
- package/dist/compat-R3UTFQ5Q.js +201 -0
- package/dist/dashboardIssue-WYYMBFIB.js +192 -0
- package/dist/diff-GZA2774U.js +13 -0
- package/dist/dist-4XXIXHHZ.js +12945 -0
- package/dist/e2b-FVPHDULZ.js +172 -0
- package/dist/extract-NKGKLIVT.js +444 -0
- package/dist/fetch-QYTUJVG2.js +22 -0
- package/dist/firstTouch-QQTJH4QX.js +55 -0
- package/dist/handlers-GEJAVZDK.js +53 -0
- package/dist/http-ETPYMBGD.js +5360 -0
- package/dist/ingestQueue-VKN4KBIF.js +35 -0
- package/dist/install-EK3W2COX.js +20 -0
- package/dist/installSkill-VQJWJVCL.js +52 -0
- package/dist/inventory-5AWSLJYU.js +31 -0
- package/dist/local-XPZMRH5R.js +13 -0
- package/dist/mcp-3JHD5SUZ.js +472 -0
- package/dist/mcpHandlers-QFN4MCFL.js +22 -0
- package/dist/mcpScan-QZHWENIP.js +1871 -0
- package/dist/mcpScanWorkflow-JPYCBGC4.js +81 -0
- package/dist/mcpStack-BYJCZNIV.js +20 -0
- package/dist/packages-THVFMWFP.js +42 -0
- package/dist/plan-V4OEI3J4.js +463 -0
- package/dist/planView-JRXGCG2N.js +79 -0
- package/dist/policy-3P6BGRDN.js +115 -0
- package/dist/references-6N7VEPHT.js +14 -0
- package/dist/release-4U4ABNSJ.js +128 -0
- package/dist/remote-YGCXYI4V.js +32 -0
- package/dist/reportRuns-CKQQYLY4.js +64 -0
- package/dist/sandbox-MEZLAODF.js +39 -0
- package/dist/server-KFUD5X57.js +55 -0
- package/dist/surface-V62GE554.js +141 -0
- package/dist/surface-YL6O67W3.js +36 -0
- package/dist/surfaceHandlers-X2IZKA3E.js +20 -0
- package/dist/typecheck-X7U5ELMR.js +268 -0
- package/dist/types-M5JP2W3D.js +10 -0
- package/dist/uninstall-P7RGBX6G.js +174 -0
- package/dist/upgrade-NQ5IWFZB.js +596 -0
- package/dist/upgradePlan-A4LRKLEG.js +146 -0
- package/dist/userConfig-Z3GQE776.js +20 -0
- package/dist/watch-DGFMWUDL.js +214 -0
- package/package.json +26 -21
- package/templates/agent-rules.md +4 -4
- package/templates/skill-instructions.md +13 -14
- package/dist/bin/lurq.js.map +0 -1
- package/dist/index.d.ts +0 -805
- package/dist/index.js +0 -23570
- package/dist/index.js.map +0 -1
- package/drizzle/0000_confused_fabian_cortez.sql +0 -54
- package/drizzle/0001_aspiring_timeslip.sql +0 -15
- package/drizzle/0002_lyrical_lila_cheney.sql +0 -14
- package/drizzle/0003_violet_giant_girl.sql +0 -14
- package/drizzle/0004_slim_valeria_richards.sql +0 -15
- package/drizzle/0005_petite_luke_cage.sql +0 -12
- package/drizzle/0006_calm_nighthawk.sql +0 -3
- package/drizzle/0007_slimy_naoko.sql +0 -1
- package/drizzle/0008_peaceful_tigra.sql +0 -1
- package/drizzle/0009_smooth_harrier.sql +0 -10
- package/drizzle/0010_curved_amphibian.sql +0 -2
- package/drizzle/0011_compat_provenance_closures.sql +0 -11
- package/drizzle/0012_api_surfaces.sql +0 -9
- package/drizzle/0013_nice_thanos.sql +0 -1
- package/drizzle/0014_luxuriant_malcolm_colcord.sql +0 -10
- package/drizzle/0015_past_fat_cobra.sql +0 -11
- package/drizzle/0016_futuristic_junta.sql +0 -50
- package/drizzle/0017_absent_grandmaster.sql +0 -20
- package/drizzle/0018_rainy_proemial_gods.sql +0 -1
- package/drizzle/0019_dashing_korvac.sql +0 -11
- package/drizzle/0020_normal_vulture.sql +0 -3
- package/drizzle/0021_dazzling_blue_shield.sql +0 -17
- package/drizzle/0022_massive_ghost_rider.sql +0 -24
- package/drizzle/0023_next_shatterstar.sql +0 -1
- package/drizzle/0024_dusty_maelstrom.sql +0 -15
- package/drizzle/0025_gifted_harpoon.sql +0 -5
- package/drizzle/0026_awesome_mordo.sql +0 -1
- package/drizzle/0027_charming_ulik.sql +0 -2
- package/drizzle/0028_romantic_loners.sql +0 -2
- package/drizzle/0029_busy_korvac.sql +0 -16
- package/drizzle/0030_steady_mathemanic.sql +0 -6
- package/drizzle/0031_redundant_maginty.sql +0 -2
- package/drizzle/0032_stack_resolutions.sql +0 -14
- package/drizzle/0033_graceful_tyger_tiger.sql +0 -3
- package/drizzle/0034_uneven_thunderbird.sql +0 -1
- package/drizzle/0035_api_key_scopes.sql +0 -1
- package/drizzle/0036_policy_audit.sql +0 -21
- package/drizzle/0037_subscription_seats.sql +0 -1
- package/drizzle/0038_symbol_offsets.sql +0 -2
- package/drizzle/0039_mcp_runtime_scans.sql +0 -80
- package/drizzle/0040_subscription_overage_and_interval.sql +0 -4
- package/drizzle/0041_account_email.sql +0 -38
- package/drizzle/0042_alert_channels.sql +0 -21
- package/drizzle/meta/0000_snapshot.json +0 -370
- package/drizzle/meta/0001_snapshot.json +0 -482
- package/drizzle/meta/0002_snapshot.json +0 -575
- package/drizzle/meta/0003_snapshot.json +0 -667
- package/drizzle/meta/0004_snapshot.json +0 -769
- package/drizzle/meta/0005_snapshot.json +0 -864
- package/drizzle/meta/0006_snapshot.json +0 -882
- package/drizzle/meta/0007_snapshot.json +0 -876
- package/drizzle/meta/0008_snapshot.json +0 -882
- package/drizzle/meta/0009_snapshot.json +0 -948
- package/drizzle/meta/0010_snapshot.json +0 -969
- package/drizzle/meta/0011_snapshot.json +0 -1049
- package/drizzle/meta/0012_snapshot.json +0 -1115
- package/drizzle/meta/0013_snapshot.json +0 -1121
- package/drizzle/meta/0014_snapshot.json +0 -1190
- package/drizzle/meta/0015_snapshot.json +0 -1280
- package/drizzle/meta/0016_snapshot.json +0 -1683
- package/drizzle/meta/0017_snapshot.json +0 -1834
- package/drizzle/meta/0018_snapshot.json +0 -1834
- package/drizzle/meta/0019_snapshot.json +0 -1909
- package/drizzle/meta/0020_snapshot.json +0 -1921
- package/drizzle/meta/0021_snapshot.json +0 -2045
- package/drizzle/meta/0022_snapshot.json +0 -2246
- package/drizzle/meta/0023_snapshot.json +0 -2252
- package/drizzle/meta/0024_snapshot.json +0 -2375
- package/drizzle/meta/0025_snapshot.json +0 -2407
- package/drizzle/meta/0026_snapshot.json +0 -2413
- package/drizzle/meta/0027_snapshot.json +0 -2425
- package/drizzle/meta/0028_snapshot.json +0 -2438
- package/drizzle/meta/0029_snapshot.json +0 -2546
- package/drizzle/meta/0030_snapshot.json +0 -2586
- package/drizzle/meta/0031_snapshot.json +0 -2598
- package/drizzle/meta/0032_snapshot.json +0 -2699
- package/drizzle/meta/0033_snapshot.json +0 -2712
- package/drizzle/meta/0034_snapshot.json +0 -2719
- package/drizzle/meta/0035_snapshot.json +0 -2726
- package/drizzle/meta/0036_snapshot.json +0 -2876
- package/drizzle/meta/0037_snapshot.json +0 -2883
- package/drizzle/meta/0038_snapshot.json +0 -2895
- package/drizzle/meta/0039_snapshot.json +0 -3501
- package/drizzle/meta/0040_snapshot.json +0 -3527
- package/drizzle/meta/0041_snapshot.json +0 -3824
- package/drizzle/meta/0042_snapshot.json +0 -3960
- package/drizzle/meta/_journal.json +0 -307
- package/src/data/seed.json +0 -253
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
diffSurfaces
|
|
4
|
+
} from "./chunk-SHCEBP3J.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-I3M2KJXB.js";
|
|
8
|
+
|
|
9
|
+
// src/surface/mcp.ts
|
|
10
|
+
init_esm_shims();
|
|
11
|
+
import { createHash } from "crypto";
|
|
12
|
+
var MCP_TIER = "mcp_tools_list";
|
|
13
|
+
var PROSE_KEYS = /* @__PURE__ */ new Set(["description", "title", "$comment", "examples", "$schema"]);
|
|
14
|
+
function canonicalize(value) {
|
|
15
|
+
if (Array.isArray(value)) return value.map(canonicalize);
|
|
16
|
+
if (value === null || typeof value !== "object") return value;
|
|
17
|
+
const src = value;
|
|
18
|
+
const out = {};
|
|
19
|
+
for (const k of Object.keys(src).sort()) {
|
|
20
|
+
if (PROSE_KEYS.has(k)) continue;
|
|
21
|
+
const v = canonicalize(src[k]);
|
|
22
|
+
if (v === void 0) continue;
|
|
23
|
+
out[k] = v;
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(out.type) && out.type.every((t) => typeof t === "string")) {
|
|
26
|
+
const t = [...new Set(out.type)].sort();
|
|
27
|
+
out.type = t.length === 1 ? t[0] : t;
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(out.required) && out.required.every((r) => typeof r === "string")) {
|
|
30
|
+
const r = [...new Set(out.required)].sort();
|
|
31
|
+
if (r.length === 0) delete out.required;
|
|
32
|
+
else out.required = r;
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
var ANNOTATION_DEFAULTS = {
|
|
37
|
+
readOnlyHint: false,
|
|
38
|
+
destructiveHint: true,
|
|
39
|
+
idempotentHint: false,
|
|
40
|
+
openWorldHint: true
|
|
41
|
+
};
|
|
42
|
+
function resolveAnnotations(a) {
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const k of Object.keys(ANNOTATION_DEFAULTS)) {
|
|
45
|
+
const v = a?.[k];
|
|
46
|
+
out[k] = typeof v === "boolean" ? v : ANNOTATION_DEFAULTS[k];
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
var WIDENS_WHEN_FALSE = {
|
|
51
|
+
readOnlyHint: true,
|
|
52
|
+
// true → false: the tool started writing
|
|
53
|
+
destructiveHint: false,
|
|
54
|
+
// false → true: the tool started destroying
|
|
55
|
+
idempotentHint: true,
|
|
56
|
+
// true → false: retries are no longer safe
|
|
57
|
+
openWorldHint: false
|
|
58
|
+
// false → true: the tool started reaching outside
|
|
59
|
+
};
|
|
60
|
+
var sha = (s) => createHash("sha256").update(s).digest("hex");
|
|
61
|
+
function toolContract(t) {
|
|
62
|
+
return {
|
|
63
|
+
input: canonicalize(t.inputSchema ?? null),
|
|
64
|
+
output: canonicalize(t.outputSchema ?? null),
|
|
65
|
+
annotations: resolveAnnotations(t.annotations),
|
|
66
|
+
prose: sha(`${t.title ?? ""}\0${t.description ?? ""}`).slice(0, 16)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function properties(c) {
|
|
70
|
+
const input = c?.input;
|
|
71
|
+
if (!input || typeof input !== "object") return {};
|
|
72
|
+
const props = input.properties;
|
|
73
|
+
return props && typeof props === "object" ? props : {};
|
|
74
|
+
}
|
|
75
|
+
function requiredSet(c) {
|
|
76
|
+
const input = c?.input;
|
|
77
|
+
if (!input || typeof input !== "object") return /* @__PURE__ */ new Set();
|
|
78
|
+
const req = input.required;
|
|
79
|
+
return new Set(Array.isArray(req) ? req.filter((r) => typeof r === "string") : []);
|
|
80
|
+
}
|
|
81
|
+
function requiredParams(t) {
|
|
82
|
+
return [...requiredSet(toolContract(t))].sort();
|
|
83
|
+
}
|
|
84
|
+
var DEPRECATED_RE = /^\s*[[(]?\s*(?:@)?deprecated\b/i;
|
|
85
|
+
function looksDeprecated(t) {
|
|
86
|
+
return DEPRECATED_RE.test(t.description ?? "") || DEPRECATED_RE.test(t.title ?? "");
|
|
87
|
+
}
|
|
88
|
+
function toolToSymbol(t) {
|
|
89
|
+
return {
|
|
90
|
+
path: t.name,
|
|
91
|
+
kind: "function",
|
|
92
|
+
arity: requiredParams(t).length,
|
|
93
|
+
// MCP has no re-export mechanism: every tool a server lists is its own.
|
|
94
|
+
origin: "local",
|
|
95
|
+
deprecated: looksDeprecated(t),
|
|
96
|
+
tier: MCP_TIER,
|
|
97
|
+
signature: JSON.stringify(toolContract(t))
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function mcpSurface(server, version, tools) {
|
|
101
|
+
return {
|
|
102
|
+
package: server,
|
|
103
|
+
version,
|
|
104
|
+
tier: MCP_TIER,
|
|
105
|
+
entry: null,
|
|
106
|
+
symbols: tools.map(toolToSymbol),
|
|
107
|
+
filesWalked: 0,
|
|
108
|
+
externalReExports: [],
|
|
109
|
+
...tools.length === 0 ? { undeclaredReason: "server listed no tools" } : {}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function surfaceHash(tools) {
|
|
113
|
+
const canon = [...tools].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0).map((t) => [t.name, toolContract(t)]);
|
|
114
|
+
return sha(JSON.stringify(canon));
|
|
115
|
+
}
|
|
116
|
+
function contractOf(s) {
|
|
117
|
+
if (!s.signature) return null;
|
|
118
|
+
try {
|
|
119
|
+
return JSON.parse(s.signature);
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
var emptyDrift = (from, to, reason) => ({
|
|
125
|
+
server: from.package,
|
|
126
|
+
fromVersion: from.version,
|
|
127
|
+
toVersion: to.version,
|
|
128
|
+
tier: MCP_TIER,
|
|
129
|
+
removedTools: [],
|
|
130
|
+
addedTools: [],
|
|
131
|
+
requiredAdded: [],
|
|
132
|
+
requiredRelaxed: [],
|
|
133
|
+
paramsRemoved: [],
|
|
134
|
+
paramsAdded: [],
|
|
135
|
+
typeChanged: [],
|
|
136
|
+
outputChanged: [],
|
|
137
|
+
annotationFlips: [],
|
|
138
|
+
silentDrift: [],
|
|
139
|
+
prosePolished: [],
|
|
140
|
+
deprecated: [],
|
|
141
|
+
breaking: false,
|
|
142
|
+
inconclusive: reason
|
|
143
|
+
});
|
|
144
|
+
function typeSet(p) {
|
|
145
|
+
const t = p.type;
|
|
146
|
+
if (typeof t === "string") return /* @__PURE__ */ new Set([t]);
|
|
147
|
+
if (Array.isArray(t)) return new Set(t.filter((x) => typeof x === "string"));
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
function enumSet(p) {
|
|
151
|
+
return Array.isArray(p.enum) ? new Set(p.enum.map((v) => JSON.stringify(v))) : null;
|
|
152
|
+
}
|
|
153
|
+
function accepts(a, b) {
|
|
154
|
+
if (b === null) return true;
|
|
155
|
+
if (a === null) return false;
|
|
156
|
+
return [...a].every((v) => b.has(v));
|
|
157
|
+
}
|
|
158
|
+
var RELAXABLE = /* @__PURE__ */ new Set([
|
|
159
|
+
"type",
|
|
160
|
+
"enum",
|
|
161
|
+
"additionalProperties",
|
|
162
|
+
"required",
|
|
163
|
+
"properties",
|
|
164
|
+
"items"
|
|
165
|
+
]);
|
|
166
|
+
function isWidening(a, b) {
|
|
167
|
+
if (JSON.stringify(a) === JSON.stringify(b)) return true;
|
|
168
|
+
if (!a || typeof a !== "object" || !b || typeof b !== "object") return false;
|
|
169
|
+
if (Array.isArray(a) || Array.isArray(b)) return false;
|
|
170
|
+
const pa = a;
|
|
171
|
+
const pb = b;
|
|
172
|
+
for (const k of /* @__PURE__ */ new Set([...Object.keys(pa), ...Object.keys(pb)])) {
|
|
173
|
+
if (RELAXABLE.has(k)) continue;
|
|
174
|
+
if (JSON.stringify(pa[k]) !== JSON.stringify(pb[k])) return false;
|
|
175
|
+
}
|
|
176
|
+
if (!accepts(typeSet(pa), typeSet(pb))) return false;
|
|
177
|
+
if (!accepts(enumSet(pa), enumSet(pb))) return false;
|
|
178
|
+
if (JSON.stringify(pa.additionalProperties) !== JSON.stringify(pb.additionalProperties)) {
|
|
179
|
+
if (pa.additionalProperties !== false) return false;
|
|
180
|
+
}
|
|
181
|
+
const ra = new Set(Array.isArray(pa.required) ? pa.required : []);
|
|
182
|
+
const rb = new Set(Array.isArray(pb.required) ? pb.required : []);
|
|
183
|
+
for (const k of rb) if (!ra.has(k)) return false;
|
|
184
|
+
const propsA = pa.properties ?? {};
|
|
185
|
+
const propsB = pb.properties ?? {};
|
|
186
|
+
for (const k of Object.keys(propsA)) {
|
|
187
|
+
if (!(k in propsB)) {
|
|
188
|
+
if (pb.additionalProperties === false) return false;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (!isWidening(propsA[k], propsB[k])) return false;
|
|
192
|
+
}
|
|
193
|
+
if ("items" in pa || "items" in pb) {
|
|
194
|
+
if (!isWidening(pa.items ?? {}, pb.items ?? {})) return false;
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
function diffMcpSurfaces(from, to) {
|
|
199
|
+
const base = diffSurfaces(from, to);
|
|
200
|
+
if (base.inconclusive) return emptyDrift(from, to, base.inconclusive);
|
|
201
|
+
const drift = emptyDrift(from, to, "");
|
|
202
|
+
delete drift.inconclusive;
|
|
203
|
+
drift.removedTools = base.removed.map((s) => s.path).sort();
|
|
204
|
+
drift.addedTools = base.added.map((s) => s.path).sort();
|
|
205
|
+
drift.deprecated = base.deprecated.map((s) => s.path).sort();
|
|
206
|
+
const fromByName = new Map(from.symbols.map((s) => [s.path, s]));
|
|
207
|
+
for (const toSym of to.symbols) {
|
|
208
|
+
const fromSym = fromByName.get(toSym.path);
|
|
209
|
+
if (!fromSym) continue;
|
|
210
|
+
const a = contractOf(fromSym);
|
|
211
|
+
const b = contractOf(toSym);
|
|
212
|
+
if (!a || !b) continue;
|
|
213
|
+
const tool = toSym.path;
|
|
214
|
+
const pa = properties(a);
|
|
215
|
+
const pb = properties(b);
|
|
216
|
+
const ra = requiredSet(a);
|
|
217
|
+
const rb = requiredSet(b);
|
|
218
|
+
const gone = Object.keys(pa).filter((k) => !(k in pb)).sort();
|
|
219
|
+
const fresh = Object.keys(pb).filter((k) => !(k in pa)).sort();
|
|
220
|
+
if (gone.length) drift.paramsRemoved.push({ tool, params: gone });
|
|
221
|
+
if (fresh.length) drift.paramsAdded.push({ tool, params: fresh });
|
|
222
|
+
const nowRequired = [...rb].filter((k) => !ra.has(k)).sort();
|
|
223
|
+
const nowOptional = [...ra].filter((k) => !rb.has(k) && k in pb).sort();
|
|
224
|
+
if (nowRequired.length) drift.requiredAdded.push({ tool, params: nowRequired });
|
|
225
|
+
if (nowOptional.length) drift.requiredRelaxed.push({ tool, params: nowOptional });
|
|
226
|
+
for (const param of Object.keys(pb)) {
|
|
227
|
+
if (!(param in pa)) continue;
|
|
228
|
+
const before = JSON.stringify(pa[param]);
|
|
229
|
+
const after = JSON.stringify(pb[param]);
|
|
230
|
+
if (before === after) continue;
|
|
231
|
+
drift.typeChanged.push({
|
|
232
|
+
tool,
|
|
233
|
+
param,
|
|
234
|
+
from: before,
|
|
235
|
+
to: after,
|
|
236
|
+
widened: isWidening(pa[param], pb[param])
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
if (JSON.stringify(a.output) !== JSON.stringify(b.output)) drift.outputChanged.push(tool);
|
|
240
|
+
for (const hint of Object.keys(ANNOTATION_DEFAULTS)) {
|
|
241
|
+
if (a.annotations[hint] === b.annotations[hint]) continue;
|
|
242
|
+
drift.annotationFlips.push({
|
|
243
|
+
tool,
|
|
244
|
+
hint,
|
|
245
|
+
from: a.annotations[hint],
|
|
246
|
+
to: b.annotations[hint],
|
|
247
|
+
widensPrivilege: b.annotations[hint] === !WIDENS_WHEN_FALSE[hint]
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
const contractMoved = JSON.stringify(a.input) !== JSON.stringify(b.input) || JSON.stringify(a.output) !== JSON.stringify(b.output) || JSON.stringify(a.annotations) !== JSON.stringify(b.annotations);
|
|
251
|
+
const proseMoved = a.prose !== b.prose;
|
|
252
|
+
if (contractMoved && !proseMoved) drift.silentDrift.push(tool);
|
|
253
|
+
if (proseMoved && !contractMoved) drift.prosePolished.push(tool);
|
|
254
|
+
}
|
|
255
|
+
drift.breaking = drift.removedTools.length > 0 || drift.requiredAdded.length > 0 || drift.paramsRemoved.length > 0 || drift.typeChanged.some((c) => !c.widened);
|
|
256
|
+
return drift;
|
|
257
|
+
}
|
|
258
|
+
function summarizeDrift(d) {
|
|
259
|
+
const alarming = [];
|
|
260
|
+
const benign = [];
|
|
261
|
+
const widened = d.annotationFlips.filter((f) => f.widensPrivilege);
|
|
262
|
+
if (widened.length) {
|
|
263
|
+
alarming.push(
|
|
264
|
+
`${widened.length} privilege widening(s): ` + widened.map((f) => `${f.tool}.${f.hint} ${f.from}\u2192${f.to}`).join(", ")
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
if (d.removedTools.length) alarming.push(`${d.removedTools.length} tool(s) removed`);
|
|
268
|
+
if (d.requiredAdded.length) {
|
|
269
|
+
alarming.push(`${d.requiredAdded.length} tool(s) gained required params`);
|
|
270
|
+
}
|
|
271
|
+
if (d.paramsRemoved.length) alarming.push(`${d.paramsRemoved.length} tool(s) dropped params`);
|
|
272
|
+
const narrowed = d.typeChanged.filter((c) => !c.widened);
|
|
273
|
+
if (narrowed.length) alarming.push(`${narrowed.length} param type(s) narrowed`);
|
|
274
|
+
if (d.silentDrift.length) {
|
|
275
|
+
alarming.push(
|
|
276
|
+
`${d.silentDrift.length} SILENT change(s) (contract moved, description unchanged): ${d.silentDrift.join(", ")}`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
if (d.addedTools.length) benign.push(`${d.addedTools.length} tool(s) added`);
|
|
280
|
+
const relaxed = d.typeChanged.length - narrowed.length;
|
|
281
|
+
if (relaxed) benign.push(`${relaxed} param type(s) relaxed`);
|
|
282
|
+
if (d.requiredRelaxed.length) {
|
|
283
|
+
benign.push(`${d.requiredRelaxed.length} tool(s) made params optional`);
|
|
284
|
+
}
|
|
285
|
+
if (d.paramsAdded.length) benign.push(`${d.paramsAdded.length} tool(s) gained optional params`);
|
|
286
|
+
if (d.outputChanged.length) benign.push(`${d.outputChanged.length} output schema(s) changed`);
|
|
287
|
+
const safeFlips = d.annotationFlips.length - widened.length;
|
|
288
|
+
if (safeFlips) benign.push(`${safeFlips} annotation(s) narrowed`);
|
|
289
|
+
if (d.deprecated.length) benign.push(`${d.deprecated.length} tool(s) newly deprecated`);
|
|
290
|
+
if (d.prosePolished.length) benign.push(`${d.prosePolished.length} description(s) edited`);
|
|
291
|
+
if (alarming.length) return alarming.join("; ");
|
|
292
|
+
if (benign.length) return `compatible: ${benign.join(", ")}`;
|
|
293
|
+
return "no contract change";
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export {
|
|
297
|
+
MCP_TIER,
|
|
298
|
+
resolveAnnotations,
|
|
299
|
+
mcpSurface,
|
|
300
|
+
surfaceHash,
|
|
301
|
+
contractOf,
|
|
302
|
+
diffMcpSurfaces,
|
|
303
|
+
summarizeDrift
|
|
304
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
verificationRuns
|
|
4
|
+
} from "./chunk-LYMPYETA.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-I3M2KJXB.js";
|
|
8
|
+
|
|
9
|
+
// src/db/verification.ts
|
|
10
|
+
init_esm_shims();
|
|
11
|
+
import { desc, eq } from "drizzle-orm";
|
|
12
|
+
async function storeVerificationRun(db, run) {
|
|
13
|
+
await db.insert(verificationRuns).values(run);
|
|
14
|
+
}
|
|
15
|
+
async function getLatestVerificationByName(db, packageName) {
|
|
16
|
+
const rows = await db.select().from(verificationRuns).where(eq(verificationRuns.packageName, packageName)).orderBy(desc(verificationRuns.ranAt)).limit(1);
|
|
17
|
+
return rows[0] ?? null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
storeVerificationRun,
|
|
22
|
+
getLatestVerificationByName
|
|
23
|
+
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
httpGetJson
|
|
4
|
+
} from "./chunk-SJOVFF7B.js";
|
|
5
|
+
import {
|
|
6
|
+
CACHE_TTL
|
|
7
|
+
} from "./chunk-GPTKSNR6.js";
|
|
8
|
+
import {
|
|
9
|
+
init_esm_shims
|
|
10
|
+
} from "./chunk-I3M2KJXB.js";
|
|
11
|
+
|
|
12
|
+
// src/ingestion/sources/npmRegistry.ts
|
|
13
|
+
init_esm_shims();
|
|
14
|
+
var HOST = "registry.npmjs.org";
|
|
15
|
+
function encodeNpmName(name) {
|
|
16
|
+
return name.startsWith("@") ? name.replace("/", "%2F") : name;
|
|
17
|
+
}
|
|
18
|
+
function parseGithubRepo(url) {
|
|
19
|
+
if (!url) return null;
|
|
20
|
+
const match = url.match(/github\.com[/:]([^/]+)\/([^/#?]+?)(?:\.git)?(?:[/#?].*)?$/i);
|
|
21
|
+
if (!match) return null;
|
|
22
|
+
const owner = match[1];
|
|
23
|
+
const repo = match[2];
|
|
24
|
+
if (!owner || !repo) return null;
|
|
25
|
+
return { owner, repo };
|
|
26
|
+
}
|
|
27
|
+
function normalizeRepoUrl(repository, homepage) {
|
|
28
|
+
let raw = null;
|
|
29
|
+
if (typeof repository === "string") raw = repository;
|
|
30
|
+
else if (repository && typeof repository === "object" && "url" in repository) {
|
|
31
|
+
raw = String(repository.url);
|
|
32
|
+
}
|
|
33
|
+
const repo = parseGithubRepo(raw) ?? parseGithubRepo(homepage);
|
|
34
|
+
const repoUrl = repo ? `https://github.com/${repo.owner}/${repo.repo}` : cleanUrl(raw) ?? null;
|
|
35
|
+
return { repoUrl, repo };
|
|
36
|
+
}
|
|
37
|
+
function cleanUrl(url) {
|
|
38
|
+
if (!url) return null;
|
|
39
|
+
return url.replace(/^git\+/, "").replace(/^git:\/\//, "https://").replace(/\.git$/, "");
|
|
40
|
+
}
|
|
41
|
+
function pickLicense(value) {
|
|
42
|
+
if (!value) return null;
|
|
43
|
+
if (typeof value === "string") return value;
|
|
44
|
+
if (typeof value === "object" && "type" in value) return String(value.type);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
function toDate(value) {
|
|
48
|
+
if (typeof value !== "string") return null;
|
|
49
|
+
const ms = Date.parse(value);
|
|
50
|
+
return Number.isNaN(ms) ? null : new Date(ms);
|
|
51
|
+
}
|
|
52
|
+
function parseNpmRegistry(json) {
|
|
53
|
+
const latest = json?.["dist-tags"]?.latest ?? null;
|
|
54
|
+
const latestManifest = latest ? json?.versions?.[latest] ?? {} : {};
|
|
55
|
+
const time = json?.time ?? {};
|
|
56
|
+
const repository = json?.repository ?? latestManifest?.repository;
|
|
57
|
+
const homepage = json?.homepage ?? latestManifest?.homepage ?? null;
|
|
58
|
+
const { repoUrl, repo } = normalizeRepoUrl(repository, homepage);
|
|
59
|
+
const deprecated = Boolean(latestManifest?.deprecated ?? json?.deprecated);
|
|
60
|
+
const maintainers = Array.isArray(json?.maintainers) ? json.maintainers.length : null;
|
|
61
|
+
const name = json?.name ?? "";
|
|
62
|
+
return {
|
|
63
|
+
name,
|
|
64
|
+
description: json?.description ?? latestManifest?.description ?? null,
|
|
65
|
+
latestVersion: latest,
|
|
66
|
+
license: pickLicense(json?.license ?? latestManifest?.license),
|
|
67
|
+
homepage,
|
|
68
|
+
repo,
|
|
69
|
+
repoUrl,
|
|
70
|
+
firstPublishedAt: toDate(time?.created),
|
|
71
|
+
lastReleaseAt: toDate(latest ? time?.[latest] : null) ?? toDate(time?.modified),
|
|
72
|
+
deprecated,
|
|
73
|
+
maintainersCount: maintainers,
|
|
74
|
+
readme: typeof json?.readme === "string" ? json.readme : null,
|
|
75
|
+
keywords: parseKeywords(json?.keywords ?? latestManifest?.keywords),
|
|
76
|
+
hasTypes: detectTypes(name, latestManifest),
|
|
77
|
+
hasTestScript: detectTestScript(latestManifest),
|
|
78
|
+
directDependenciesCount: countDeps(latestManifest?.dependencies),
|
|
79
|
+
hasProvenance: detectProvenance(latestManifest),
|
|
80
|
+
hasInstallScripts: detectInstallScripts(latestManifest),
|
|
81
|
+
hasBrowserField: latestManifest?.browser != null,
|
|
82
|
+
peerDependencies: parseDepMap(latestManifest?.peerDependencies),
|
|
83
|
+
peerDependenciesMeta: parsePeerMeta(latestManifest?.peerDependenciesMeta),
|
|
84
|
+
engines: parseDepMap(latestManifest?.engines),
|
|
85
|
+
versionTimeline: parseVersionTimeline(json)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function parseDepMap(value) {
|
|
89
|
+
if (!value || typeof value !== "object") return null;
|
|
90
|
+
const out = {};
|
|
91
|
+
for (const [name, range] of Object.entries(value)) {
|
|
92
|
+
if (typeof range === "string" && range.trim() !== "") out[name] = range;
|
|
93
|
+
}
|
|
94
|
+
return Object.keys(out).length ? out : null;
|
|
95
|
+
}
|
|
96
|
+
function parsePeerMeta(value) {
|
|
97
|
+
if (!value || typeof value !== "object") return null;
|
|
98
|
+
const out = {};
|
|
99
|
+
for (const [name, meta] of Object.entries(value)) {
|
|
100
|
+
if (meta && typeof meta === "object" && "optional" in meta) {
|
|
101
|
+
out[name] = { optional: Boolean(meta.optional) };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return Object.keys(out).length ? out : null;
|
|
105
|
+
}
|
|
106
|
+
function detectInstallScripts(manifest) {
|
|
107
|
+
const scripts = manifest?.scripts;
|
|
108
|
+
if (!scripts || typeof scripts !== "object") return false;
|
|
109
|
+
return ["preinstall", "install", "postinstall"].some(
|
|
110
|
+
(hook) => typeof scripts[hook] === "string" && scripts[hook].trim() !== ""
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
function parseVersionTimeline(json) {
|
|
114
|
+
const versions = json?.versions;
|
|
115
|
+
if (!versions || typeof versions !== "object") return [];
|
|
116
|
+
const time = json?.time ?? {};
|
|
117
|
+
return Object.keys(versions).map((version) => ({
|
|
118
|
+
version,
|
|
119
|
+
publishedAt: toDate(time?.[version]),
|
|
120
|
+
// Already in this document — no second fetch, no per-version round trip.
|
|
121
|
+
peerDependencies: parseDepMap(versions[version]?.peerDependencies),
|
|
122
|
+
engines: parseDepMap(versions[version]?.engines)
|
|
123
|
+
})).sort((a, b) => (b.publishedAt?.getTime() ?? 0) - (a.publishedAt?.getTime() ?? 0));
|
|
124
|
+
}
|
|
125
|
+
function parseKeywords(value) {
|
|
126
|
+
if (!Array.isArray(value)) return [];
|
|
127
|
+
return value.filter((k) => typeof k === "string");
|
|
128
|
+
}
|
|
129
|
+
function detectTypes(name, manifest) {
|
|
130
|
+
if (typeof manifest?.types === "string" || typeof manifest?.typings === "string") return true;
|
|
131
|
+
if (name.startsWith("@types/")) return true;
|
|
132
|
+
const exportsField = manifest?.exports;
|
|
133
|
+
if (exportsField && typeof exportsField === "object") {
|
|
134
|
+
const serialized = JSON.stringify(exportsField);
|
|
135
|
+
if (serialized.includes('"types"')) return true;
|
|
136
|
+
}
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
function detectTestScript(manifest) {
|
|
140
|
+
const test = manifest?.scripts?.test;
|
|
141
|
+
if (typeof test !== "string" || test.trim() === "") return false;
|
|
142
|
+
return !/no test specified/i.test(test);
|
|
143
|
+
}
|
|
144
|
+
function countDeps(deps) {
|
|
145
|
+
if (!deps || typeof deps !== "object") return 0;
|
|
146
|
+
return Object.keys(deps).length;
|
|
147
|
+
}
|
|
148
|
+
function detectProvenance(manifest) {
|
|
149
|
+
return Boolean(manifest?.dist?.attestations);
|
|
150
|
+
}
|
|
151
|
+
async function fetchNpmRegistry(name, fetchImpl) {
|
|
152
|
+
const url = `https://${HOST}/${encodeNpmName(name)}`;
|
|
153
|
+
const { data } = await httpGetJson(url, {
|
|
154
|
+
host: HOST,
|
|
155
|
+
ttlMs: CACHE_TTL.npmRegistry,
|
|
156
|
+
fetchImpl
|
|
157
|
+
});
|
|
158
|
+
return parseNpmRegistry(data);
|
|
159
|
+
}
|
|
160
|
+
async function fetchNpmCompatAtVersion(name, version, fetchImpl) {
|
|
161
|
+
const url = `https://${HOST}/${encodeNpmName(name)}`;
|
|
162
|
+
try {
|
|
163
|
+
const { data } = await httpGetJson(url, {
|
|
164
|
+
host: HOST,
|
|
165
|
+
ttlMs: CACHE_TTL.npmRegistry,
|
|
166
|
+
fetchImpl
|
|
167
|
+
});
|
|
168
|
+
const latest = data?.["dist-tags"]?.latest ?? null;
|
|
169
|
+
const wanted = version ? data?.versions?.[version] ? version : null : latest && data?.versions?.[latest] ? latest : null;
|
|
170
|
+
if (!wanted) return null;
|
|
171
|
+
const manifest = data.versions[wanted] ?? {};
|
|
172
|
+
return {
|
|
173
|
+
version: wanted,
|
|
174
|
+
peerDependencies: parseDepMap(manifest.peerDependencies),
|
|
175
|
+
peerDependenciesMeta: parsePeerMeta(manifest.peerDependenciesMeta),
|
|
176
|
+
engines: parseDepMap(manifest.engines)
|
|
177
|
+
};
|
|
178
|
+
} catch {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function npmVersionExists(name, version, fetchImpl) {
|
|
183
|
+
const url = `https://${HOST}/${encodeNpmName(name)}`;
|
|
184
|
+
try {
|
|
185
|
+
const { data } = await httpGetJson(url, {
|
|
186
|
+
host: HOST,
|
|
187
|
+
ttlMs: CACHE_TTL.npmRegistry,
|
|
188
|
+
fetchImpl
|
|
189
|
+
});
|
|
190
|
+
if (!data?.versions || typeof data.versions !== "object") return null;
|
|
191
|
+
return Object.prototype.hasOwnProperty.call(data.versions, version);
|
|
192
|
+
} catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async function npmPackageExists(name, fetchImpl) {
|
|
197
|
+
const url = `https://${HOST}/${encodeNpmName(name)}`;
|
|
198
|
+
try {
|
|
199
|
+
const { status } = await httpGetJson(url, {
|
|
200
|
+
host: HOST,
|
|
201
|
+
ttlMs: 0,
|
|
202
|
+
retries: 1,
|
|
203
|
+
fetchImpl
|
|
204
|
+
});
|
|
205
|
+
return status === 200;
|
|
206
|
+
} catch (err) {
|
|
207
|
+
if (err && typeof err === "object" && "status" in err && err.status === 404) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
throw err;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export {
|
|
215
|
+
encodeNpmName,
|
|
216
|
+
fetchNpmRegistry,
|
|
217
|
+
fetchNpmCompatAtVersion,
|
|
218
|
+
npmVersionExists,
|
|
219
|
+
npmPackageExists
|
|
220
|
+
};
|