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,146 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
parseManifest
|
|
4
|
+
} from "./chunk-DWAGCNEL.js";
|
|
5
|
+
import "./chunk-B43LCXBM.js";
|
|
6
|
+
import "./chunk-BCANRN5B.js";
|
|
7
|
+
import "./chunk-SJOVFF7B.js";
|
|
8
|
+
import "./chunk-GRJXQBQZ.js";
|
|
9
|
+
import "./chunk-WHX2ZFCG.js";
|
|
10
|
+
import {
|
|
11
|
+
fetchUpgradePlan
|
|
12
|
+
} from "./chunk-4ZYCIMY4.js";
|
|
13
|
+
import "./chunk-MYGSLK44.js";
|
|
14
|
+
import "./chunk-Y5GI7RL3.js";
|
|
15
|
+
import "./chunk-GPTKSNR6.js";
|
|
16
|
+
import {
|
|
17
|
+
init_esm_shims
|
|
18
|
+
} from "./chunk-I3M2KJXB.js";
|
|
19
|
+
|
|
20
|
+
// src/cli/upgradePlan.ts
|
|
21
|
+
init_esm_shims();
|
|
22
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
23
|
+
import { join, relative } from "path";
|
|
24
|
+
var SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "coverage", "vendor"]);
|
|
25
|
+
var MAX_MANIFESTS = 25;
|
|
26
|
+
var MAX_DEPTH = 4;
|
|
27
|
+
function findManifests(dir, maxDepth = MAX_DEPTH) {
|
|
28
|
+
const found = [];
|
|
29
|
+
const walk = (current, depth) => {
|
|
30
|
+
if (found.length >= MAX_MANIFESTS || depth > maxDepth) return;
|
|
31
|
+
let entries;
|
|
32
|
+
try {
|
|
33
|
+
entries = readdirSync(current);
|
|
34
|
+
} catch {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (entries.includes("package.json")) found.push(join(current, "package.json"));
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (SKIP.has(entry) || entry.startsWith(".")) continue;
|
|
40
|
+
const child = join(current, entry);
|
|
41
|
+
try {
|
|
42
|
+
if (statSync(child).isDirectory()) walk(child, depth + 1);
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
walk(dir, 0);
|
|
48
|
+
return found;
|
|
49
|
+
}
|
|
50
|
+
function readManifests(dir) {
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const file of findManifests(dir)) {
|
|
53
|
+
try {
|
|
54
|
+
const parsed = parseManifest(
|
|
55
|
+
relative(dir, file) || "package.json",
|
|
56
|
+
JSON.parse(readFileSync(file, "utf8"))
|
|
57
|
+
);
|
|
58
|
+
if (parsed) out.push(parsed);
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
function mergedDeps(manifests) {
|
|
65
|
+
const out = {};
|
|
66
|
+
for (const manifest of manifests) {
|
|
67
|
+
for (const [name, range] of Object.entries(manifest.deps)) {
|
|
68
|
+
out[name] ??= range;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
function detectRepoFullName(explicit) {
|
|
74
|
+
const value = explicit ?? process.env.GITHUB_REPOSITORY ?? null;
|
|
75
|
+
return value && /^[\w.-]+\/[\w.-]+$/.test(value) ? value : null;
|
|
76
|
+
}
|
|
77
|
+
async function buildUpgradePlan(dir, opts = {}) {
|
|
78
|
+
const manifests = readManifests(dir);
|
|
79
|
+
const deps = mergedDeps(manifests);
|
|
80
|
+
if (Object.keys(deps).length === 0) {
|
|
81
|
+
throw new Error(`No package.json with dependencies found under ${dir}`);
|
|
82
|
+
}
|
|
83
|
+
const plan = await fetchUpgradePlan(deps, { ...opts, repo: detectRepoFullName(opts.repo) });
|
|
84
|
+
return { ...plan, manifests: manifests.length, deps: Object.keys(deps).length };
|
|
85
|
+
}
|
|
86
|
+
var VERDICT_LABEL = {
|
|
87
|
+
"removes-exports": "REMOVES ",
|
|
88
|
+
"arity-changed": "ARITY ",
|
|
89
|
+
clean: "CLEAN ",
|
|
90
|
+
unknown: "UNKNOWN "
|
|
91
|
+
};
|
|
92
|
+
function formatUpgradePlan(plan) {
|
|
93
|
+
const out = [
|
|
94
|
+
`lurq upgrade plan (${plan.deps} dependencies across ${plan.manifests} manifest(s))`
|
|
95
|
+
];
|
|
96
|
+
if (plan.scopeSource === "repo-policy") {
|
|
97
|
+
out.push(
|
|
98
|
+
`policy: scope=${plan.scope}` + (plan.outOfScope ? `, ${plan.outOfScope} upgrade(s) held back` : ", nothing held back")
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
out.push("");
|
|
102
|
+
if (plan.upgrades.length === 0) {
|
|
103
|
+
out.push("Everything lurq tracks is already on its latest release.");
|
|
104
|
+
}
|
|
105
|
+
for (const upgrade of plan.upgrades) {
|
|
106
|
+
const held = upgrade.inScope === false ? " [HELD]" : "";
|
|
107
|
+
out.push(
|
|
108
|
+
`${VERDICT_LABEL[upgrade.verdict]} ${upgrade.package} ${upgrade.fromVersion} \u2192 ${upgrade.toVersion}` + (upgrade.advisories ? ` (${upgrade.advisories} advisory)` : "") + held
|
|
109
|
+
);
|
|
110
|
+
if (upgrade.scopeReason) out.push(` held: ${upgrade.scopeReason}`);
|
|
111
|
+
if (upgrade.removed.length) {
|
|
112
|
+
const renamed = new Map((upgrade.renamed ?? []).map((r) => [r.path, r.to]));
|
|
113
|
+
const label = (path) => renamed.has(path) ? `${path} \u2192 ${renamed.get(path).join(" | ")}` : path;
|
|
114
|
+
out.push(` removes ${upgrade.removed.length}: ${upgrade.removed.slice(0, 8).map(label).join(", ")}`);
|
|
115
|
+
}
|
|
116
|
+
for (const change of upgrade.arityChanged.slice(0, 5)) {
|
|
117
|
+
out.push(` arity ${change.path}: ${change.from ?? "?"} \u2192 ${change.to ?? "?"}`);
|
|
118
|
+
}
|
|
119
|
+
if (upgrade.hops?.length) {
|
|
120
|
+
out.push(` via ${[upgrade.fromVersion, ...upgrade.hops.map((h) => h.toVersion)].join(" \u2192 ")}`);
|
|
121
|
+
for (const hop of upgrade.hops) {
|
|
122
|
+
const detail = hop.removed.length ? `removes ${hop.removed.slice(0, 5).join(", ")}` : hop.verdict === "unknown" ? "not yet analysed" : "no removals";
|
|
123
|
+
out.push(` ${hop.fromVersion} \u2192 ${hop.toVersion}: ${detail}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (upgrade.sequenceNote) out.push(` ${upgrade.sequenceNote}`);
|
|
127
|
+
if (upgrade.declaredIn?.length > 1) {
|
|
128
|
+
out.push(` declared in ${upgrade.declaredIn.map((d) => d.path).join(", ")}`);
|
|
129
|
+
}
|
|
130
|
+
if (upgrade.inconclusive) out.push(` ${upgrade.inconclusive}`);
|
|
131
|
+
}
|
|
132
|
+
const caveats = [];
|
|
133
|
+
if (plan.untracked > 0) caveats.push(`${plan.untracked} dependency(ies) not in the lurq index`);
|
|
134
|
+
if (plan.omitted > 0) caveats.push(`${plan.omitted} further upgrade(s) not shown`);
|
|
135
|
+
if (plan.pending > 0) caveats.push(`${plan.pending} awaiting surface extraction`);
|
|
136
|
+
if (caveats.length) out.push("", `NOT COVERED: ${caveats.join("; ")}.`);
|
|
137
|
+
return out.join("\n");
|
|
138
|
+
}
|
|
139
|
+
export {
|
|
140
|
+
buildUpgradePlan,
|
|
141
|
+
detectRepoFullName,
|
|
142
|
+
findManifests,
|
|
143
|
+
formatUpgradePlan,
|
|
144
|
+
mergedDeps,
|
|
145
|
+
readManifests
|
|
146
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
clearUserConfig,
|
|
4
|
+
lurqHome,
|
|
5
|
+
readUserConfig,
|
|
6
|
+
resolveApiKey,
|
|
7
|
+
resolveEndpoint,
|
|
8
|
+
userConfigPath,
|
|
9
|
+
writeUserConfig
|
|
10
|
+
} from "./chunk-Y5GI7RL3.js";
|
|
11
|
+
import "./chunk-I3M2KJXB.js";
|
|
12
|
+
export {
|
|
13
|
+
clearUserConfig,
|
|
14
|
+
lurqHome,
|
|
15
|
+
readUserConfig,
|
|
16
|
+
resolveApiKey,
|
|
17
|
+
resolveEndpoint,
|
|
18
|
+
userConfigPath,
|
|
19
|
+
writeUserConfig
|
|
20
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
enqueueSurface,
|
|
4
|
+
getMcpServerNames
|
|
5
|
+
} from "./chunk-LO35HLQZ.js";
|
|
6
|
+
import {
|
|
7
|
+
syncOnePackage
|
|
8
|
+
} from "./chunk-FW6BD2NO.js";
|
|
9
|
+
import "./chunk-BUALU27S.js";
|
|
10
|
+
import "./chunk-LRD4GBYE.js";
|
|
11
|
+
import "./chunk-BCANRN5B.js";
|
|
12
|
+
import "./chunk-2VMOWSRY.js";
|
|
13
|
+
import "./chunk-4ESO33J6.js";
|
|
14
|
+
import "./chunk-CW5HJ3LX.js";
|
|
15
|
+
import "./chunk-AHBP533R.js";
|
|
16
|
+
import "./chunk-SJOVFF7B.js";
|
|
17
|
+
import "./chunk-HWBBVLOT.js";
|
|
18
|
+
import {
|
|
19
|
+
getAllPackageNames
|
|
20
|
+
} from "./chunk-NH5I4KHH.js";
|
|
21
|
+
import "./chunk-VLRHFMGJ.js";
|
|
22
|
+
import "./chunk-WQ23REYT.js";
|
|
23
|
+
import {
|
|
24
|
+
discoveryQueue,
|
|
25
|
+
watchState
|
|
26
|
+
} from "./chunk-LYMPYETA.js";
|
|
27
|
+
import "./chunk-3GHJR7XR.js";
|
|
28
|
+
import "./chunk-GRJXQBQZ.js";
|
|
29
|
+
import "./chunk-WHX2ZFCG.js";
|
|
30
|
+
import "./chunk-LUAKDHLZ.js";
|
|
31
|
+
import {
|
|
32
|
+
logger
|
|
33
|
+
} from "./chunk-MYGSLK44.js";
|
|
34
|
+
import "./chunk-GPTKSNR6.js";
|
|
35
|
+
import {
|
|
36
|
+
init_esm_shims
|
|
37
|
+
} from "./chunk-I3M2KJXB.js";
|
|
38
|
+
|
|
39
|
+
// src/pipeline/watch.ts
|
|
40
|
+
init_esm_shims();
|
|
41
|
+
|
|
42
|
+
// src/db/discovery.ts
|
|
43
|
+
init_esm_shims();
|
|
44
|
+
import { eq, sql } from "drizzle-orm";
|
|
45
|
+
async function getQueuedNames(db) {
|
|
46
|
+
const rows = await db.select({ name: discoveryQueue.name }).from(discoveryQueue);
|
|
47
|
+
return new Set(rows.map((r) => r.name));
|
|
48
|
+
}
|
|
49
|
+
async function enqueueCandidates(db, candidates) {
|
|
50
|
+
if (candidates.length === 0) return 0;
|
|
51
|
+
const rows = candidates.map((c) => ({ name: c.name, discoveredVia: c.via }));
|
|
52
|
+
const inserted = await db.insert(discoveryQueue).values(rows).onConflictDoNothing({ target: discoveryQueue.name }).returning({ id: discoveryQueue.id });
|
|
53
|
+
return inserted.length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/db/watch.ts
|
|
57
|
+
init_esm_shims();
|
|
58
|
+
import { eq as eq2 } from "drizzle-orm";
|
|
59
|
+
async function getWatchCursor(db, id) {
|
|
60
|
+
const rows = await db.select({ seq: watchState.seq }).from(watchState).where(eq2(watchState.id, id)).limit(1);
|
|
61
|
+
return rows[0]?.seq ?? null;
|
|
62
|
+
}
|
|
63
|
+
async function setWatchCursor(db, id, seq) {
|
|
64
|
+
await db.insert(watchState).values({ id, seq, updatedAt: /* @__PURE__ */ new Date() }).onConflictDoUpdate({ target: watchState.id, set: { seq, updatedAt: /* @__PURE__ */ new Date() } });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/pipeline/watch.ts
|
|
68
|
+
var FEED_ID = "npm-changes";
|
|
69
|
+
var FEED_URL = "https://replicate.npmjs.com/_changes";
|
|
70
|
+
var PAGE_SIZE = 1e3;
|
|
71
|
+
var IDLE_POLL_MS = 3e4;
|
|
72
|
+
var TRACKED_REFRESH_MS = 5 * 6e4;
|
|
73
|
+
var MAX_BACKOFF_MS = 3e4;
|
|
74
|
+
var ENQUEUE_BATCH = 200;
|
|
75
|
+
function parseChange(obj) {
|
|
76
|
+
if (typeof obj !== "object" || obj === null) return null;
|
|
77
|
+
const rec = obj;
|
|
78
|
+
if (typeof rec.id !== "string" || rec.seq == null) return null;
|
|
79
|
+
if (typeof rec.seq !== "number" && typeof rec.seq !== "string") return null;
|
|
80
|
+
return { seq: rec.seq, id: rec.id, deleted: Boolean(rec.deleted) };
|
|
81
|
+
}
|
|
82
|
+
function parseChangesPage(body) {
|
|
83
|
+
if (typeof body !== "object" || body === null) return { changes: [], lastSeq: null };
|
|
84
|
+
const { results, last_seq: lastSeq } = body;
|
|
85
|
+
const changes = Array.isArray(results) ? results.map(parseChange).filter((c) => c !== null) : [];
|
|
86
|
+
return {
|
|
87
|
+
changes,
|
|
88
|
+
lastSeq: typeof lastSeq === "number" || typeof lastSeq === "string" ? String(lastSeq) : null
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function routeChange(change, tracked, queued) {
|
|
92
|
+
if (change.deleted) return "skip";
|
|
93
|
+
if (tracked.has(change.id)) return "resync";
|
|
94
|
+
if (queued.has(change.id)) return "skip";
|
|
95
|
+
return "enqueue";
|
|
96
|
+
}
|
|
97
|
+
async function getJson(url, fetchImpl, signal) {
|
|
98
|
+
const res = await fetchImpl(url, { signal });
|
|
99
|
+
if (!res.ok) throw new Error(`feed responded ${res.status}`);
|
|
100
|
+
return res.json();
|
|
101
|
+
}
|
|
102
|
+
async function fetchHeadSeq(fetchImpl = fetch, signal) {
|
|
103
|
+
const body = await getJson(`${FEED_URL}?descending=true&limit=1`, fetchImpl, signal);
|
|
104
|
+
return parseChangesPage(body).lastSeq;
|
|
105
|
+
}
|
|
106
|
+
async function loadSeenSets(db) {
|
|
107
|
+
const [tracked, queued, mcp] = await Promise.all([
|
|
108
|
+
getAllPackageNames(db),
|
|
109
|
+
getQueuedNames(db),
|
|
110
|
+
// Derived from what has actually been probed, so the roster grows with real
|
|
111
|
+
// demand instead of with a curated list somebody has to maintain. Failure
|
|
112
|
+
// is non-fatal: the npm half of the loop must keep running regardless.
|
|
113
|
+
getMcpServerNames(db).catch(() => [])
|
|
114
|
+
]);
|
|
115
|
+
return [new Set(tracked), queued, new Set(mcp)];
|
|
116
|
+
}
|
|
117
|
+
async function watchNpmChanges(db, opts = {}) {
|
|
118
|
+
const { signal, fetchImpl = fetch } = opts;
|
|
119
|
+
let backoff = 1e3;
|
|
120
|
+
let [tracked, queued, mcpServers] = await loadSeenSets(db);
|
|
121
|
+
let seenAt = Date.now();
|
|
122
|
+
let cursor = await getWatchCursor(db, FEED_ID) ?? opts.since ?? await fetchHeadSeq(fetchImpl, signal).catch(() => null);
|
|
123
|
+
if (cursor == null) {
|
|
124
|
+
logger.warn("watch: could not establish a starting sequence; giving up.");
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
logger.info(
|
|
128
|
+
`watch: following from seq=${cursor} (${tracked.size} tracked, ${queued.size} queued, ${mcpServers.size} mcp)`
|
|
129
|
+
);
|
|
130
|
+
while (!signal?.aborted) {
|
|
131
|
+
try {
|
|
132
|
+
const url = `${FEED_URL}?since=${encodeURIComponent(cursor)}&limit=${PAGE_SIZE}`;
|
|
133
|
+
const { changes, lastSeq } = parseChangesPage(await getJson(url, fetchImpl, signal));
|
|
134
|
+
backoff = 1e3;
|
|
135
|
+
if (Date.now() - seenAt > TRACKED_REFRESH_MS) {
|
|
136
|
+
[tracked, queued, mcpServers] = await loadSeenSets(db);
|
|
137
|
+
seenAt = Date.now();
|
|
138
|
+
}
|
|
139
|
+
const buffered = [];
|
|
140
|
+
const flush = async () => {
|
|
141
|
+
if (buffered.length === 0) return;
|
|
142
|
+
const batch = buffered.map((name) => ({ name, via: "npm-changes" }));
|
|
143
|
+
const inserted = await enqueueCandidates(db, batch).catch((err) => {
|
|
144
|
+
logger.warn(`watch: enqueue of ${batch.length} candidate(s) failed: ${String(err)}`);
|
|
145
|
+
return 0;
|
|
146
|
+
});
|
|
147
|
+
if (inserted > 0) logger.info(`watch: queued ${inserted} new discovery candidate(s)`);
|
|
148
|
+
buffered.length = 0;
|
|
149
|
+
};
|
|
150
|
+
let resynced = 0;
|
|
151
|
+
let mcpQueued = 0;
|
|
152
|
+
for (const change of changes) {
|
|
153
|
+
if (signal?.aborted) break;
|
|
154
|
+
const route = routeChange(change, tracked, queued);
|
|
155
|
+
if (route === "resync") {
|
|
156
|
+
await syncOnePackage(db, change.id).catch(
|
|
157
|
+
(err) => logger.warn(`watch: re-sync failed for ${change.id}: ${String(err)}`)
|
|
158
|
+
);
|
|
159
|
+
resynced++;
|
|
160
|
+
await enqueueSurface(db, change.id, null).catch(
|
|
161
|
+
(err) => logger.warn(`watch: surface enqueue failed for ${change.id}: ${String(err)}`)
|
|
162
|
+
);
|
|
163
|
+
if (mcpServers.has(change.id)) {
|
|
164
|
+
await enqueueSurface(db, change.id, null, "mcp_server").catch(
|
|
165
|
+
(err) => logger.warn(`watch: mcp probe enqueue failed for ${change.id}: ${String(err)}`)
|
|
166
|
+
);
|
|
167
|
+
mcpQueued++;
|
|
168
|
+
}
|
|
169
|
+
} else if (route === "enqueue") {
|
|
170
|
+
queued.add(change.id);
|
|
171
|
+
buffered.push(change.id);
|
|
172
|
+
if (buffered.length >= ENQUEUE_BATCH) await flush();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
await flush();
|
|
176
|
+
if (lastSeq !== null && lastSeq !== cursor) {
|
|
177
|
+
cursor = lastSeq;
|
|
178
|
+
await setWatchCursor(db, FEED_ID, cursor);
|
|
179
|
+
}
|
|
180
|
+
if (changes.length > 0) {
|
|
181
|
+
logger.info(
|
|
182
|
+
`watch: ${changes.length} change(s), ${resynced} re-synced` + (mcpQueued ? `, ${mcpQueued} mcp re-probe(s)` : "") + `, seq=${cursor}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if (changes.length < PAGE_SIZE) await sleep(IDLE_POLL_MS, signal);
|
|
186
|
+
} catch (err) {
|
|
187
|
+
if (signal?.aborted) break;
|
|
188
|
+
logger.warn(`watch: ${String(err)}, retrying in ${backoff}ms`);
|
|
189
|
+
await sleep(backoff, signal);
|
|
190
|
+
backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
logger.info("watch: stopped.");
|
|
194
|
+
}
|
|
195
|
+
function sleep(ms, signal) {
|
|
196
|
+
return new Promise((resolve) => {
|
|
197
|
+
const timer = setTimeout(resolve, ms);
|
|
198
|
+
signal?.addEventListener(
|
|
199
|
+
"abort",
|
|
200
|
+
() => {
|
|
201
|
+
clearTimeout(timer);
|
|
202
|
+
resolve();
|
|
203
|
+
},
|
|
204
|
+
{ once: true }
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
export {
|
|
209
|
+
fetchHeadSeq,
|
|
210
|
+
parseChange,
|
|
211
|
+
parseChangesPage,
|
|
212
|
+
routeChange,
|
|
213
|
+
watchNpmChanges
|
|
214
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lurqrun",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Verify npm packages before your AI coding agent installs them: hallucinated and typosquatted names, advisories, API drift and version conflicts. MCP server, CLI and agent skill for Claude Code, Cursor and VS Code.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,13 +40,32 @@
|
|
|
40
40
|
],
|
|
41
41
|
"files": [
|
|
42
42
|
"dist",
|
|
43
|
-
"src/data/seed.json",
|
|
44
43
|
"templates",
|
|
45
|
-
"drizzle",
|
|
46
44
|
"README.md"
|
|
47
45
|
],
|
|
48
46
|
"engines": {
|
|
49
|
-
"node": ">=20"
|
|
47
|
+
"node": ">=20.17.0"
|
|
48
|
+
},
|
|
49
|
+
"lurq": {
|
|
50
|
+
"inlinedDependencies": [
|
|
51
|
+
"@inquirer/prompts",
|
|
52
|
+
"@modelcontextprotocol/sdk",
|
|
53
|
+
"commander",
|
|
54
|
+
"dotenv",
|
|
55
|
+
"semver",
|
|
56
|
+
"yaml",
|
|
57
|
+
"zod"
|
|
58
|
+
],
|
|
59
|
+
"selfHostDependencies": [
|
|
60
|
+
"drizzle-orm",
|
|
61
|
+
"express",
|
|
62
|
+
"express-rate-limit",
|
|
63
|
+
"helmet",
|
|
64
|
+
"ioredis",
|
|
65
|
+
"postgres",
|
|
66
|
+
"rate-limit-redis",
|
|
67
|
+
"stripe"
|
|
68
|
+
]
|
|
50
69
|
},
|
|
51
70
|
"scripts": {
|
|
52
71
|
"build": "tsup",
|
|
@@ -66,29 +85,15 @@
|
|
|
66
85
|
"db:migrate": "tsx src/bin/operator.ts db migrate",
|
|
67
86
|
"operator": "tsx src/bin/operator.ts",
|
|
68
87
|
"operator:prod": "LURQ_ENV_FILE=.env.production tsx src/bin/operator.ts",
|
|
88
|
+
"prepack": "node scripts/publish-manifest.mjs strip",
|
|
89
|
+
"postpack": "node scripts/publish-manifest.mjs restore",
|
|
69
90
|
"prepublishOnly": "node scripts/assert-publish-from-main.mjs && npm test && npm run build",
|
|
70
91
|
"content:drift": "tsx scripts/gen-drift.ts",
|
|
71
92
|
"content:landing": "tsx scripts/build-landing-content.mts",
|
|
72
93
|
"content:releases": "tsx scripts/gen-releases.ts"
|
|
73
94
|
},
|
|
74
95
|
"dependencies": {
|
|
75
|
-
"
|
|
76
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
77
|
-
"commander": "^12.1.0",
|
|
78
|
-
"dotenv": "^16.4.5",
|
|
79
|
-
"drizzle-orm": "^0.45.2",
|
|
80
|
-
"express": "^5.2.1",
|
|
81
|
-
"express-rate-limit": "^8.5.2",
|
|
82
|
-
"helmet": "^8.2.0",
|
|
83
|
-
"ioredis": "^5.11.1",
|
|
84
|
-
"postgres": "^3.4.9",
|
|
85
|
-
"rate-limit-redis": "^4.3.1",
|
|
86
|
-
"semver": "^7.8.5",
|
|
87
|
-
"stripe": "^22.6.0",
|
|
88
|
-
"typescript": "^5.5.4",
|
|
89
|
-
"update-notifier": "^7.3.1",
|
|
90
|
-
"yaml": "^2.9.0",
|
|
91
|
-
"zod": "^3.23.8"
|
|
96
|
+
"typescript": "^5.5.4"
|
|
92
97
|
},
|
|
93
98
|
"devDependencies": {
|
|
94
99
|
"@eslint/js": "^9.9.0",
|
package/templates/agent-rules.md
CHANGED
|
@@ -8,13 +8,13 @@ Use it instead of recalling package facts:
|
|
|
8
8
|
|
|
9
9
|
- `verify <pkg>` before adding any dependency. Catches hallucinated, typosquatted,
|
|
10
10
|
deprecated, and advisory-carrying names. Cheapest and highest-value call.
|
|
11
|
-
- `
|
|
12
|
-
|
|
13
|
-
- `compare <pkgs>` to choose between options; `evaluate <pkg>` for the full evidence read.
|
|
11
|
+
- `compare <pkgs>` to choose between candidate libraries you already know of; `evaluate <pkg>`
|
|
12
|
+
for the full evidence read. lurq checks candidates, it does not search for them.
|
|
14
13
|
- `compat <pkgs>` before committing to a multi-package stack. Healthy packages can still
|
|
15
14
|
refuse to install together.
|
|
16
15
|
- `usage <pkg> --known <version-you-remember>` before writing code against an API that may
|
|
17
|
-
have moved. Returns real exported symbols plus the delta from the version you know.
|
|
16
|
+
have moved. Returns real exported symbols plus the delta from the version you know. Large
|
|
17
|
+
surfaces are paged: pass `query` with part of a name to find a symbol directly.
|
|
18
18
|
- `resolve_surface <pkg>` when you need to know whether a symbol exists at runtime, not
|
|
19
19
|
just in the types. A removed type breaks `tsc`; a removed runtime export breaks the
|
|
20
20
|
program. UNKNOWN means "not extracted yet", never "absent".
|
|
@@ -16,12 +16,10 @@ reads like a guess.
|
|
|
16
16
|
|
|
17
17
|
## Call lurq when you are about to:
|
|
18
18
|
|
|
19
|
-
- **Pick a library for a need** → `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
(e.g. "debounce a function", "deep clone an object", "parse dates"). Don't rebuild a
|
|
24
|
-
well-maintained, proven package.
|
|
19
|
+
- **Pick a library for a need** → name the candidates you know and `compare` them, then
|
|
20
|
+
`verify` the one you choose. lurq checks candidates against evidence; it does not
|
|
21
|
+
search for them, so the list is yours to bring. The same applies before hand-rolling
|
|
22
|
+
something a well-maintained package may already do.
|
|
25
23
|
- **Install a specific package** → `verify` with the exact name *before* adding it.
|
|
26
24
|
This catches hallucinated, deprecated, and typosquatted names (e.g. `lodahs` vs
|
|
27
25
|
`lodash`) and packages with known advisories. Cheap, and the highest-value call here.
|
|
@@ -31,17 +29,21 @@ reads like a guess.
|
|
|
31
29
|
and a usage guide (what it is, when to use it, how it fits).
|
|
32
30
|
- **Adding dependencies in a team codebase** → `policy` once, before choosing. It lists
|
|
33
31
|
the packages and thresholds the team's policy refuses, so you pick an allowed package
|
|
34
|
-
first instead of being refused after. `
|
|
32
|
+
first instead of being refused after. `evaluate` enforces it either way.
|
|
35
33
|
- **Commit to a multi-package stack** → `compat` with the whole set. Individually healthy
|
|
36
34
|
packages can still refuse to install together; this returns the exact clashing peer or
|
|
37
|
-
engine constraints, plus any conflicts already proven in a sandbox. Read-only
|
|
38
|
-
|
|
35
|
+
engine constraints, plus any conflicts already proven in a sandbox. Read-only — it never
|
|
36
|
+
runs an install. A set checked before answers immediately; a new one is resolved live
|
|
37
|
+
from registry metadata and can take up to ~25 seconds.
|
|
39
38
|
- **Write code against a package whose API may have moved** → `usage` with the package
|
|
40
39
|
and, if you know it, `knownVersion`. Returns the real exported symbols and signatures
|
|
41
40
|
extracted from that version's shipped `.d.ts`, plus the precise delta from the version
|
|
42
41
|
you remember: what was added, removed, renamed, or changed. None of this is in your
|
|
43
42
|
training data, and it is the difference between calling a function that exists and one
|
|
44
|
-
that used to.
|
|
43
|
+
that used to. Large surfaces are paged 80 symbols at a time: pass `query` with part of a
|
|
44
|
+
name to go straight to a symbol, or `offset` for the next page. `shallow: true` means the
|
|
45
|
+
API lives on an interface's members that are not listed (DefinitelyTyped's `export =`
|
|
46
|
+
shape, e.g. lodash); read its type declarations or use `resolve_surface`.
|
|
45
47
|
- **Check whether a symbol actually exists at runtime** → `resolve_surface` with the
|
|
46
48
|
package (and version, if you have one). `usage` reads the shipped `.d.ts`; this reads
|
|
47
49
|
the shipped JavaScript, and the difference matters: a removed *type* breaks `tsc`, a
|
|
@@ -82,16 +84,13 @@ reads like a guess.
|
|
|
82
84
|
can catch it, and the symptom is a malformed call that looks like a model mistake.
|
|
83
85
|
**Privilege widening** is a tool that stopped being read-only or started being
|
|
84
86
|
destructive; nothing breaks, which is what makes it worse than a break.
|
|
85
|
-
- **Build a whole project from a spec** → `plan` with the program description. Returns a
|
|
86
|
-
scored package per component plus a Mermaid roadmap. It recommends building blocks
|
|
87
|
-
slot-by-slot from the index; it does not invent an architecture from a bare prompt.
|
|
88
87
|
- **Visualize a stack you have already chosen** → `diagram` with the package names. A
|
|
89
88
|
labeled starting point by layer — not a validated architecture.
|
|
90
89
|
- **Unsure whether lurq covers the situation** → `capabilities` with what you are trying
|
|
91
90
|
to do, in plain words. Returns the matching tools and commands rather than prose, so a
|
|
92
91
|
capability you did not know about becomes a call you can make. Cheaper than guessing,
|
|
93
92
|
and far cheaper than skipping a check that exists.
|
|
94
|
-
- **After you act on a
|
|
93
|
+
- **After you act on lurq's evidence about a package** → `report_outcome` (optional) with whether you
|
|
95
94
|
used the package and whether it built. No source code, just the coarse decision and a
|
|
96
95
|
build signal. It is how lurq learns which packages agents actually succeed with.
|
|
97
96
|
|