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,214 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
loadStored,
|
|
4
|
+
rowsToSurface
|
|
5
|
+
} from "./chunk-DB2VF5UD.js";
|
|
6
|
+
import {
|
|
7
|
+
configRequestLine,
|
|
8
|
+
fetchServerManifest,
|
|
9
|
+
missingConfig
|
|
10
|
+
} from "./chunk-LEGPB7DO.js";
|
|
11
|
+
import {
|
|
12
|
+
MCP_TIER,
|
|
13
|
+
contractOf,
|
|
14
|
+
diffMcpSurfaces,
|
|
15
|
+
summarizeDrift
|
|
16
|
+
} from "./chunk-6EQ3ARXA.js";
|
|
17
|
+
import {
|
|
18
|
+
enqueueSurface
|
|
19
|
+
} from "./chunk-LO35HLQZ.js";
|
|
20
|
+
import {
|
|
21
|
+
cached
|
|
22
|
+
} from "./chunk-HWBBVLOT.js";
|
|
23
|
+
import {
|
|
24
|
+
init_esm_shims
|
|
25
|
+
} from "./chunk-I3M2KJXB.js";
|
|
26
|
+
|
|
27
|
+
// src/mcp/mcpHandlers.ts
|
|
28
|
+
init_esm_shims();
|
|
29
|
+
import { createHash } from "crypto";
|
|
30
|
+
function ckey(parts) {
|
|
31
|
+
return createHash("sha1").update(JSON.stringify(parts)).digest("hex").slice(0, 24);
|
|
32
|
+
}
|
|
33
|
+
var MISS = (server, version) => ({
|
|
34
|
+
server,
|
|
35
|
+
version,
|
|
36
|
+
verdict: "unknown",
|
|
37
|
+
class: null,
|
|
38
|
+
tier: null,
|
|
39
|
+
tools: [],
|
|
40
|
+
requires: [],
|
|
41
|
+
configRequest: null,
|
|
42
|
+
coverageNote: "not yet probed, queued; retry shortly. This is NOT evidence that the server exposes no tools.",
|
|
43
|
+
observedAt: null
|
|
44
|
+
});
|
|
45
|
+
function toolViews(stored) {
|
|
46
|
+
const surface = rowsToSurface("", null, stored.rows, MCP_TIER);
|
|
47
|
+
return surface.symbols.map((s) => {
|
|
48
|
+
const c = contractOf(s);
|
|
49
|
+
const input = c?.input ?? null;
|
|
50
|
+
const props = input && typeof input.properties === "object" ? input.properties : {};
|
|
51
|
+
const required = Array.isArray(input?.required) ? input.required : [];
|
|
52
|
+
return {
|
|
53
|
+
name: s.path,
|
|
54
|
+
required: [...required].sort(),
|
|
55
|
+
params: Object.keys(props ?? {}).sort(),
|
|
56
|
+
annotations: c?.annotations ?? {
|
|
57
|
+
readOnlyHint: false,
|
|
58
|
+
destructiveHint: true,
|
|
59
|
+
idempotentHint: false,
|
|
60
|
+
openWorldHint: true
|
|
61
|
+
},
|
|
62
|
+
hasOutputSchema: c?.output != null,
|
|
63
|
+
deprecated: s.deprecated
|
|
64
|
+
};
|
|
65
|
+
}).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
66
|
+
}
|
|
67
|
+
async function handleMcpSurface(db, input) {
|
|
68
|
+
return cached(
|
|
69
|
+
"mcp_surface",
|
|
70
|
+
ckey([input.server, input.version ?? null]),
|
|
71
|
+
() => mcpSurfaceUncached(db, input),
|
|
72
|
+
{ skipCache: (v) => v.verdict === "unknown" }
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
async function mcpSurfaceUncached(db, input) {
|
|
76
|
+
const version = input.version ?? null;
|
|
77
|
+
const [stored, manifest] = await Promise.all([
|
|
78
|
+
loadStored(db, input.server, version, 0, "mcp_server"),
|
|
79
|
+
// Best-effort and never fatal: the registry being down must not change what
|
|
80
|
+
// we say about a server.
|
|
81
|
+
fetchServerManifest(input.server).catch(() => null)
|
|
82
|
+
]);
|
|
83
|
+
const requires = manifest?.env ?? [];
|
|
84
|
+
const missing = missingConfig(manifest);
|
|
85
|
+
const configRequest = missing.length ? configRequestLine(input.server, missing) : null;
|
|
86
|
+
const base = { server: input.server, version, requires, configRequest };
|
|
87
|
+
if (missing.length > 0 && (!stored || stored.rows.length === 0)) {
|
|
88
|
+
return {
|
|
89
|
+
...base,
|
|
90
|
+
verdict: "unverifiable",
|
|
91
|
+
class: null,
|
|
92
|
+
tier: null,
|
|
93
|
+
tools: [],
|
|
94
|
+
coverageNote: "server declares required settings this environment does not have, so it was not probed. UNVERIFIABLE, not a fault: nothing here is evidence about whether the server works. Supply the values in `requires` and ask again.",
|
|
95
|
+
observedAt: null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (manifest?.remoteOnly) {
|
|
99
|
+
return {
|
|
100
|
+
...base,
|
|
101
|
+
verdict: "unverifiable",
|
|
102
|
+
class: null,
|
|
103
|
+
tier: null,
|
|
104
|
+
tools: [],
|
|
105
|
+
coverageNote: `server is published only as a remote ${manifest.transport ?? "endpoint"}; there is no package to install, so this stdio probe does not apply to it`,
|
|
106
|
+
observedAt: null
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (stored?.verdict === "verified_false") {
|
|
110
|
+
return {
|
|
111
|
+
...base,
|
|
112
|
+
verdict: "verified_false",
|
|
113
|
+
class: stored.class,
|
|
114
|
+
tier: stored.tier,
|
|
115
|
+
tools: [],
|
|
116
|
+
coverageNote: "server was probed and did not complete the MCP handshake, so it exposes no callable tools in a clean install. This is a verdict about the server, not a gap in our coverage.",
|
|
117
|
+
observedAt: stored.observedAt
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (!stored || stored.rows.length === 0) {
|
|
121
|
+
await enqueueSurface(db, input.server, version, "mcp_server").catch(() => {
|
|
122
|
+
});
|
|
123
|
+
return { ...MISS(input.server, version), requires, configRequest };
|
|
124
|
+
}
|
|
125
|
+
if (stored.verdict === "undeclared") {
|
|
126
|
+
return {
|
|
127
|
+
...base,
|
|
128
|
+
verdict: "undeclared",
|
|
129
|
+
class: stored.class,
|
|
130
|
+
tier: stored.tier,
|
|
131
|
+
tools: [],
|
|
132
|
+
coverageNote: "server started and completed the handshake but listed no tools; UNDECLARED, which is a measurement gap, not proof it has none",
|
|
133
|
+
observedAt: stored.observedAt
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const tools = toolViews(stored);
|
|
137
|
+
const noContract = tools.filter((t) => t.params.length === 0 && t.required.length === 0).length;
|
|
138
|
+
return {
|
|
139
|
+
...base,
|
|
140
|
+
verdict: stored.verdict,
|
|
141
|
+
class: stored.class,
|
|
142
|
+
tier: stored.tier,
|
|
143
|
+
tools,
|
|
144
|
+
coverageNote: `${tools.length} tool(s) read from tools/list` + (noContract ? `; ${noContract} declare no input parameters (either genuinely nullary, or probed before schemas were captured)` : "") + (requires.length ? `; the server declares ${requires.length} setting(s) in \`requires\` that a caller must supply` : "") + ". Declared contract only: that a tool is listed is not evidence that calling it succeeds.",
|
|
145
|
+
observedAt: stored.observedAt
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async function handleMcpDrift(db, input) {
|
|
149
|
+
return cached(
|
|
150
|
+
"mcp_drift",
|
|
151
|
+
ckey([input.server, input.fromVersion, input.toVersion]),
|
|
152
|
+
() => mcpDriftUncached(db, input),
|
|
153
|
+
{ skipCache: (v) => v.verdict === "unknown" }
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
async function mcpDriftUncached(db, input) {
|
|
157
|
+
const [a, b] = await Promise.all([
|
|
158
|
+
loadStored(db, input.server, input.fromVersion, 0, "mcp_server"),
|
|
159
|
+
loadStored(db, input.server, input.toVersion, 0, "mcp_server")
|
|
160
|
+
]);
|
|
161
|
+
const missing = [];
|
|
162
|
+
if (!a || a.rows.length === 0) missing.push(input.fromVersion);
|
|
163
|
+
if (!b || b.rows.length === 0) missing.push(input.toVersion);
|
|
164
|
+
if (missing.length) {
|
|
165
|
+
for (const v of missing) {
|
|
166
|
+
await enqueueSurface(db, input.server, v, "mcp_server").catch(() => {
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const blank = diffMcpSurfaces(
|
|
170
|
+
{
|
|
171
|
+
package: input.server,
|
|
172
|
+
version: input.fromVersion,
|
|
173
|
+
tier: MCP_TIER,
|
|
174
|
+
entry: null,
|
|
175
|
+
symbols: [],
|
|
176
|
+
filesWalked: 0,
|
|
177
|
+
externalReExports: []
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
package: input.server,
|
|
181
|
+
version: input.toVersion,
|
|
182
|
+
tier: MCP_TIER,
|
|
183
|
+
entry: null,
|
|
184
|
+
symbols: [],
|
|
185
|
+
filesWalked: 0,
|
|
186
|
+
externalReExports: []
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
return {
|
|
190
|
+
...blank,
|
|
191
|
+
inconclusive: `no probed surface for ${missing.join(", ")}, queued; retry shortly. NOT evidence that tools were removed.`,
|
|
192
|
+
verdict: "unknown",
|
|
193
|
+
class: null,
|
|
194
|
+
summary: "unknown: not yet probed",
|
|
195
|
+
observedAt: null
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const drift = diffMcpSurfaces(
|
|
199
|
+
rowsToSurface(input.server, input.fromVersion, a.rows, MCP_TIER),
|
|
200
|
+
rowsToSurface(input.server, input.toVersion, b.rows, MCP_TIER)
|
|
201
|
+
);
|
|
202
|
+
return {
|
|
203
|
+
...drift,
|
|
204
|
+
verdict: drift.inconclusive ? "unknown" : "verified_true",
|
|
205
|
+
class: drift.inconclusive ? null : "derived",
|
|
206
|
+
summary: drift.inconclusive ?? summarizeDrift(drift),
|
|
207
|
+
observedAt: b.observedAt
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export {
|
|
212
|
+
handleMcpSurface,
|
|
213
|
+
handleMcpDrift
|
|
214
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
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/core/concurrency.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
function withBudget(task, ms) {
|
|
9
|
+
let timer;
|
|
10
|
+
return Promise.race([
|
|
11
|
+
task,
|
|
12
|
+
new Promise((resolve) => {
|
|
13
|
+
timer = setTimeout(resolve, ms, null);
|
|
14
|
+
})
|
|
15
|
+
]).finally(() => clearTimeout(timer));
|
|
16
|
+
}
|
|
17
|
+
async function pMap(items, mapper, concurrency) {
|
|
18
|
+
const results = new Array(items.length);
|
|
19
|
+
let cursor = 0;
|
|
20
|
+
const workerCount = Math.max(1, Math.min(concurrency, items.length));
|
|
21
|
+
const workers = Array.from({ length: workerCount }, async () => {
|
|
22
|
+
while (cursor < items.length) {
|
|
23
|
+
const index = cursor++;
|
|
24
|
+
results[index] = await mapper(items[index], index);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
await Promise.all(workers);
|
|
28
|
+
return results;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
withBudget,
|
|
33
|
+
pMap
|
|
34
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
classifyRuntimeTarget,
|
|
4
|
+
inferCategory
|
|
5
|
+
} from "./chunk-FW6BD2NO.js";
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_ECOSYSTEM
|
|
8
|
+
} from "./chunk-VLRHFMGJ.js";
|
|
9
|
+
import {
|
|
10
|
+
packages
|
|
11
|
+
} from "./chunk-LYMPYETA.js";
|
|
12
|
+
import {
|
|
13
|
+
init_esm_shims
|
|
14
|
+
} from "./chunk-I3M2KJXB.js";
|
|
15
|
+
|
|
16
|
+
// src/mcp/diagram.ts
|
|
17
|
+
init_esm_shims();
|
|
18
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
19
|
+
var UNCLASSIFIED = "Unclassified";
|
|
20
|
+
var LAYER_OF = {
|
|
21
|
+
framework: "Presentation",
|
|
22
|
+
"meta-framework": "Presentation",
|
|
23
|
+
"ui-component-library": "Presentation",
|
|
24
|
+
styling: "Presentation",
|
|
25
|
+
animation: "Presentation",
|
|
26
|
+
charts: "Presentation",
|
|
27
|
+
"state-management": "Client Logic",
|
|
28
|
+
routing: "Client Logic",
|
|
29
|
+
forms: "Client Logic",
|
|
30
|
+
validation: "Client Logic",
|
|
31
|
+
"data-fetching": "Client Logic",
|
|
32
|
+
"http-client": "Client Logic",
|
|
33
|
+
i18n: "Client Logic",
|
|
34
|
+
"date-time": "Client Logic",
|
|
35
|
+
utility: "Client Logic",
|
|
36
|
+
auth: "Backend",
|
|
37
|
+
orm: "Data",
|
|
38
|
+
"database-client": "Data",
|
|
39
|
+
"build-tool": "Tooling",
|
|
40
|
+
bundler: "Tooling",
|
|
41
|
+
linting: "Tooling",
|
|
42
|
+
testing: "Tooling"
|
|
43
|
+
};
|
|
44
|
+
var FLOW_LAYERS = ["Presentation", "Client Logic", "Backend", "Data"];
|
|
45
|
+
function layerFor(item) {
|
|
46
|
+
if (!item.category) return UNCLASSIFIED;
|
|
47
|
+
if (item.category === "framework" && item.runtimeTarget === "node") return "Backend";
|
|
48
|
+
return LAYER_OF[item.category] ?? UNCLASSIFIED;
|
|
49
|
+
}
|
|
50
|
+
function nodeId(label, i) {
|
|
51
|
+
return `n${i}_${label.replace(/[^a-zA-Z0-9]/g, "_")}`;
|
|
52
|
+
}
|
|
53
|
+
function buildMermaid(items) {
|
|
54
|
+
const byLayer = /* @__PURE__ */ new Map();
|
|
55
|
+
for (const item of items) {
|
|
56
|
+
const layer = layerFor(item);
|
|
57
|
+
const list = byLayer.get(layer) ?? [];
|
|
58
|
+
list.push(item);
|
|
59
|
+
byLayer.set(layer, list);
|
|
60
|
+
}
|
|
61
|
+
const lines = ["flowchart TD", " user([User])"];
|
|
62
|
+
const ids = /* @__PURE__ */ new Map();
|
|
63
|
+
let counter = 0;
|
|
64
|
+
const repNode = /* @__PURE__ */ new Map();
|
|
65
|
+
const emitLayer = (layer) => {
|
|
66
|
+
const list = byLayer.get(layer);
|
|
67
|
+
if (!list?.length) return;
|
|
68
|
+
lines.push(` subgraph ${layer.replace(/\s+/g, "_")}["${layer}"]`);
|
|
69
|
+
for (const item of list) {
|
|
70
|
+
const id = nodeId(item.label, counter++);
|
|
71
|
+
ids.set(item.label, id);
|
|
72
|
+
if (!repNode.has(layer)) repNode.set(layer, id);
|
|
73
|
+
const text = layer === UNCLASSIFIED ? item.label : `${item.category}: ${item.label}`;
|
|
74
|
+
lines.push(` ${id}["${text}"]`);
|
|
75
|
+
}
|
|
76
|
+
lines.push(" end");
|
|
77
|
+
};
|
|
78
|
+
for (const layer of FLOW_LAYERS) emitLayer(layer);
|
|
79
|
+
emitLayer("Tooling");
|
|
80
|
+
emitLayer(UNCLASSIFIED);
|
|
81
|
+
const present = FLOW_LAYERS.filter((l) => byLayer.has(l));
|
|
82
|
+
let prev = "user";
|
|
83
|
+
for (const layer of present) {
|
|
84
|
+
lines.push(` ${prev} --> ${repNode.get(layer)}`);
|
|
85
|
+
prev = repNode.get(layer);
|
|
86
|
+
}
|
|
87
|
+
if (byLayer.has("Data")) lines.push(` ${repNode.get("Data")} --> db[(Database)]`);
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
async function handleDiagram(db, input) {
|
|
91
|
+
if (!input.stack?.length) {
|
|
92
|
+
return {
|
|
93
|
+
mermaid: "flowchart TD\n user([User]) --> app[Application]",
|
|
94
|
+
note: "Provide a `stack` of package names to diagram. lurq labels a stack you choose; it does not infer an architecture from a description."
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const rows = await db.select({
|
|
98
|
+
name: packages.name,
|
|
99
|
+
category: packages.category,
|
|
100
|
+
runtimeTarget: packages.runtimeTarget
|
|
101
|
+
}).from(packages).where(
|
|
102
|
+
and(inArray(packages.name, input.stack), eq(packages.ecosystem, DEFAULT_ECOSYSTEM))
|
|
103
|
+
);
|
|
104
|
+
const known = new Map(rows.map((r) => [r.name, r]));
|
|
105
|
+
const items = input.stack.map((name) => {
|
|
106
|
+
const row = known.get(name);
|
|
107
|
+
return {
|
|
108
|
+
label: name,
|
|
109
|
+
category: row?.category ?? inferCategory(name),
|
|
110
|
+
// Fall back to the name-only classifier for a package that predates the
|
|
111
|
+
// column or is not indexed at all: the curated overrides still resolve the
|
|
112
|
+
// frameworks people actually diagram, and an unclassifiable one keeps the
|
|
113
|
+
// old Presentation default rather than moving on a null.
|
|
114
|
+
runtimeTarget: row?.runtimeTarget ?? classifyRuntimeTarget({
|
|
115
|
+
name,
|
|
116
|
+
hasBrowserField: false,
|
|
117
|
+
keywords: [],
|
|
118
|
+
engines: null,
|
|
119
|
+
peerDependencies: null
|
|
120
|
+
})
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
const unclassified = items.filter((i) => layerFor(i) === UNCLASSIFIED).map((i) => i.label);
|
|
124
|
+
const note = unclassified.length ? `Reference pattern derived from the provided stack: partial, not authoritative. Could not place ${unclassified.length} package(s): ${unclassified.join(", ")} (not in lurq's index and no category match), shown under Unclassified, outside the flow.` : "Reference pattern derived from the provided stack. A labeled starting point, not a validated architecture.";
|
|
125
|
+
return { mermaid: buildMermaid(items), note };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
layerFor,
|
|
130
|
+
buildMermaid,
|
|
131
|
+
handleDiagram
|
|
132
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
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/format.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
var ESC = "\x1B[";
|
|
9
|
+
function colorEnabled() {
|
|
10
|
+
if (process.env.NO_COLOR) return false;
|
|
11
|
+
const force = process.env.FORCE_COLOR;
|
|
12
|
+
if (force !== void 0) return force !== "0" && force !== "false";
|
|
13
|
+
return process.stdout.isTTY === true;
|
|
14
|
+
}
|
|
15
|
+
var wrap = (code, s) => colorEnabled() ? `${ESC}${code}m${s}${ESC}0m` : s;
|
|
16
|
+
var bold = (s) => wrap("1", s);
|
|
17
|
+
var dim = (s) => wrap("2", s);
|
|
18
|
+
var red = (s) => wrap("31", s);
|
|
19
|
+
var green = (s) => wrap("32", s);
|
|
20
|
+
var yellow = (s) => wrap("33", s);
|
|
21
|
+
var ANSI_RE = /\[[0-9;]*m/g;
|
|
22
|
+
var width = (s) => s.replace(ANSI_RE, "").length;
|
|
23
|
+
function table(headers, rows) {
|
|
24
|
+
const widths = headers.map((h, i) => Math.max(width(h), ...rows.map((r) => width(r[i] ?? ""))));
|
|
25
|
+
const pad = (s, w) => s + " ".repeat(Math.max(0, w - width(s)));
|
|
26
|
+
const line = (cells) => cells.map((c, i) => pad(c, widths[i])).join(" ");
|
|
27
|
+
const out = [bold(line(headers)), dim(widths.map((w) => "\u2500".repeat(w)).join(" "))];
|
|
28
|
+
for (const r of rows) out.push(line(r));
|
|
29
|
+
return out.join("\n");
|
|
30
|
+
}
|
|
31
|
+
function detail(pairs) {
|
|
32
|
+
const labelWidth = Math.max(...pairs.map(([k]) => k.length));
|
|
33
|
+
return pairs.map(([k, v]) => `${dim((k + ":").padEnd(labelWidth + 1))} ${v}`).join("\n");
|
|
34
|
+
}
|
|
35
|
+
function formatNumber(n) {
|
|
36
|
+
if (n == null) return "-";
|
|
37
|
+
if (n >= 1e6) return `${Math.round(n / 1e5) / 10}M`;
|
|
38
|
+
if (n >= 1e3) return `${Math.round(n / 100) / 10}k`;
|
|
39
|
+
return String(n);
|
|
40
|
+
}
|
|
41
|
+
function formatDate(iso) {
|
|
42
|
+
return iso ? iso.slice(0, 10) : "-";
|
|
43
|
+
}
|
|
44
|
+
function formatPercent(fraction) {
|
|
45
|
+
if (fraction == null) return "-";
|
|
46
|
+
const pct = Math.round(fraction * 1e3) / 10;
|
|
47
|
+
return `${pct > 0 ? "+" : ""}${pct}%`;
|
|
48
|
+
}
|
|
49
|
+
function confidenceLabel(c) {
|
|
50
|
+
if (c === "proven") return green(c);
|
|
51
|
+
if (c === "emerging") return yellow(c);
|
|
52
|
+
if (c === "promising") return green(c);
|
|
53
|
+
return red(c);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
bold,
|
|
58
|
+
dim,
|
|
59
|
+
red,
|
|
60
|
+
green,
|
|
61
|
+
yellow,
|
|
62
|
+
table,
|
|
63
|
+
detail,
|
|
64
|
+
formatNumber,
|
|
65
|
+
formatDate,
|
|
66
|
+
formatPercent,
|
|
67
|
+
confidenceLabel
|
|
68
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
resolveApiKey,
|
|
4
|
+
resolveEndpoint
|
|
5
|
+
} from "./chunk-Y5GI7RL3.js";
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_ENDPOINT
|
|
8
|
+
} from "./chunk-GPTKSNR6.js";
|
|
9
|
+
import {
|
|
10
|
+
init_esm_shims
|
|
11
|
+
} from "./chunk-I3M2KJXB.js";
|
|
12
|
+
|
|
13
|
+
// src/cli/remote.ts
|
|
14
|
+
init_esm_shims();
|
|
15
|
+
var RemoteError = class extends Error {
|
|
16
|
+
constructor(message, status) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.name = "RemoteError";
|
|
20
|
+
}
|
|
21
|
+
status;
|
|
22
|
+
};
|
|
23
|
+
var MissingKeyError = class extends RemoteError {
|
|
24
|
+
constructor(message = "No API key configured. Run `lurq setup` to connect this machine.") {
|
|
25
|
+
super(message, 401);
|
|
26
|
+
this.name = "MissingKeyError";
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
function endpoint(override) {
|
|
30
|
+
const base = resolveEndpoint(override) ?? DEFAULT_ENDPOINT;
|
|
31
|
+
return base.replace(/\/mcp\/?$/, "").replace(/\/$/, "");
|
|
32
|
+
}
|
|
33
|
+
function mcpUrl(override) {
|
|
34
|
+
return `${endpoint(override)}/mcp`;
|
|
35
|
+
}
|
|
36
|
+
function apiKey(override) {
|
|
37
|
+
const key = resolveApiKey(override);
|
|
38
|
+
if (!key) throw new MissingKeyError();
|
|
39
|
+
return key;
|
|
40
|
+
}
|
|
41
|
+
function errorText(body) {
|
|
42
|
+
const err = body?.error;
|
|
43
|
+
if (typeof err === "string") return err;
|
|
44
|
+
const message = err?.message;
|
|
45
|
+
return typeof message === "string" ? message : void 0;
|
|
46
|
+
}
|
|
47
|
+
async function postJson(url, body, headers, timeoutMs = 6e4, method = "POST") {
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
50
|
+
try {
|
|
51
|
+
return await fetch(url, {
|
|
52
|
+
method,
|
|
53
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
54
|
+
// fetch rejects a GET that carries a body, even an empty one.
|
|
55
|
+
body: method === "GET" ? void 0 : JSON.stringify(body),
|
|
56
|
+
signal: controller.signal
|
|
57
|
+
});
|
|
58
|
+
} catch (err) {
|
|
59
|
+
const aborted = err instanceof Error && err.name === "AbortError";
|
|
60
|
+
throw new RemoteError(aborted ? `Timed out calling ${url}` : `Could not reach ${url}`, 0);
|
|
61
|
+
} finally {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
var post = (path, body, opts = {}) => request("POST", path, body, opts);
|
|
66
|
+
async function request(method, path, body, opts = {}) {
|
|
67
|
+
const url = `${endpoint(opts.url)}${path}`;
|
|
68
|
+
const res = await postJson(
|
|
69
|
+
url,
|
|
70
|
+
body,
|
|
71
|
+
{ Authorization: `Bearer ${apiKey(opts.apiKey)}` },
|
|
72
|
+
opts.timeoutMs,
|
|
73
|
+
method
|
|
74
|
+
);
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
const detail = await res.json().then(errorText).catch(() => void 0);
|
|
77
|
+
throw new RemoteError(detail ?? `${path} failed with HTTP ${res.status}`, res.status);
|
|
78
|
+
}
|
|
79
|
+
return await res.json();
|
|
80
|
+
}
|
|
81
|
+
async function callTool(tool, args, opts = {}) {
|
|
82
|
+
const url = mcpUrl(opts.url);
|
|
83
|
+
const res = await postJson(
|
|
84
|
+
url,
|
|
85
|
+
{ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: tool, arguments: args } },
|
|
86
|
+
{
|
|
87
|
+
// The streamable-HTTP transport rejects a request that doesn't accept
|
|
88
|
+
// both, even when it has already decided to answer with plain JSON.
|
|
89
|
+
Accept: "application/json, text/event-stream",
|
|
90
|
+
Authorization: `Bearer ${apiKey(opts.apiKey)}`
|
|
91
|
+
},
|
|
92
|
+
opts.timeoutMs
|
|
93
|
+
);
|
|
94
|
+
const body = parseRpcBody(await res.text());
|
|
95
|
+
if (!res.ok) {
|
|
96
|
+
throw new RemoteError(errorText(body) ?? `${tool} failed with HTTP ${res.status}`, res.status);
|
|
97
|
+
}
|
|
98
|
+
const message = errorText(body);
|
|
99
|
+
if (message) throw new RemoteError(message, 200);
|
|
100
|
+
const result = body?.result;
|
|
101
|
+
const text = result?.content?.find((c) => c.type === "text")?.text;
|
|
102
|
+
if (text === void 0) throw new RemoteError(`${tool} returned no content.`, 502);
|
|
103
|
+
if (result?.isError) throw new RemoteError(text, 200);
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(text);
|
|
106
|
+
} catch {
|
|
107
|
+
throw new RemoteError(`${tool} returned a non-JSON result: ${text.slice(0, 200)}`, 502);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function parseRpcBody(raw) {
|
|
111
|
+
const text = raw.trimStart().startsWith("{") ? raw : (raw.split("\n").filter((l) => l.startsWith("data:")).pop() ?? "").slice(5);
|
|
112
|
+
try {
|
|
113
|
+
return JSON.parse(text);
|
|
114
|
+
} catch {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function fetchUpgradePlan(deps, opts = {}) {
|
|
119
|
+
const body = opts.repo ? { deps, repo: opts.repo } : { deps };
|
|
120
|
+
return post("/upgrade-plan", body, opts);
|
|
121
|
+
}
|
|
122
|
+
function reportUpgradeRuns(runs, opts = {}) {
|
|
123
|
+
return post("/upgrade-runs", { runs }, opts);
|
|
124
|
+
}
|
|
125
|
+
async function getPolicy(opts = {}) {
|
|
126
|
+
return (await request("GET", "/policy", void 0, opts)).policy;
|
|
127
|
+
}
|
|
128
|
+
function putPolicy(policy, opts = {}) {
|
|
129
|
+
return request("PUT", "/policy", { policy }, opts);
|
|
130
|
+
}
|
|
131
|
+
async function getPolicyHistory(opts = {}) {
|
|
132
|
+
return (await request("GET", "/policy/history", void 0, opts)).changes;
|
|
133
|
+
}
|
|
134
|
+
async function getPolicyDecisions(days, opts = {}) {
|
|
135
|
+
const path = `/policy/decisions?days=${encodeURIComponent(days)}`;
|
|
136
|
+
return (await request("GET", path, void 0, opts)).decisions;
|
|
137
|
+
}
|
|
138
|
+
function uploadMcpScan(body, opts = {}) {
|
|
139
|
+
return post("/mcp-scans", body, { timeoutMs: 12e4, ...opts });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export {
|
|
143
|
+
RemoteError,
|
|
144
|
+
MissingKeyError,
|
|
145
|
+
endpoint,
|
|
146
|
+
apiKey,
|
|
147
|
+
callTool,
|
|
148
|
+
fetchUpgradePlan,
|
|
149
|
+
reportUpgradeRuns,
|
|
150
|
+
getPolicy,
|
|
151
|
+
putPolicy,
|
|
152
|
+
getPolicyHistory,
|
|
153
|
+
getPolicyDecisions,
|
|
154
|
+
uploadMcpScan
|
|
155
|
+
};
|