lurqrun 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +311 -139
  2. package/dist/auditHandler-VWCXSDVO.js +24 -0
  3. package/dist/autopilotInit-Q62MX5M6.js +178 -0
  4. package/dist/bin/lurq.js +3255 -23319
  5. package/dist/browserAuth-J7APSD4P.js +96 -0
  6. package/dist/cache-AEAKCV4I.js +12 -0
  7. package/dist/check-2JTQDQA6.js +2613 -0
  8. package/dist/check-PQSQ2MMA.js +192 -0
  9. package/dist/checkUpgrade-5YW77OBL.js +24 -0
  10. package/dist/chunk-2GAYNIHG.js +40 -0
  11. package/dist/chunk-2O6Z37IT.js +423 -0
  12. package/dist/chunk-2WD4QAH4.js +116 -0
  13. package/dist/chunk-3676XOBU.js +2235 -0
  14. package/dist/chunk-3D2MPGOQ.js +181 -0
  15. package/dist/chunk-3GHJR7XR.js +2049 -0
  16. package/dist/chunk-4ESO33J6.js +34 -0
  17. package/dist/chunk-4JHDSVIN.js +1229 -0
  18. package/dist/chunk-4KCPOMG6.js +68 -0
  19. package/dist/chunk-53SG6XWA.js +141 -0
  20. package/dist/chunk-5ABNDB3I.js +37 -0
  21. package/dist/chunk-5ALIJFDA.js +114 -0
  22. package/dist/chunk-63MUJNZL.js +318 -0
  23. package/dist/chunk-64ZF7KO4.js +1571 -0
  24. package/dist/chunk-6DM6UQFD.js +318 -0
  25. package/dist/chunk-6EQ3ARXA.js +304 -0
  26. package/dist/chunk-6L67QMCP.js +92 -0
  27. package/dist/chunk-72Y2FDVS.js +172 -0
  28. package/dist/chunk-A3TYI2TF.js +288 -0
  29. package/dist/chunk-B2UUYRBX.js +536 -0
  30. package/dist/chunk-BJT2LHAR.js +320 -0
  31. package/dist/chunk-BM3LF5T6.js +132 -0
  32. package/dist/chunk-BN3NM47Q.js +214 -0
  33. package/dist/chunk-BUALU27S.js +123 -0
  34. package/dist/chunk-C6GLE626.js +160 -0
  35. package/dist/chunk-D3K6IZVR.js +12845 -0
  36. package/dist/chunk-D3VTZS7V.js +222 -0
  37. package/dist/chunk-DM37MTOO.js +636 -0
  38. package/dist/chunk-DONTW3NE.js +171 -0
  39. package/dist/chunk-DSROTZ3Z.js +38 -0
  40. package/dist/chunk-ELGCAM7P.js +184 -0
  41. package/dist/chunk-EQCXENKZ.js +130 -0
  42. package/dist/chunk-EYAKM6YN.js +96 -0
  43. package/dist/chunk-FDFPMBCA.js +112 -0
  44. package/dist/chunk-FVYFV5HA.js +154 -0
  45. package/dist/chunk-GE37NVLN.js +15 -0
  46. package/dist/chunk-GM5Y555O.js +143 -0
  47. package/dist/chunk-GRJXQBQZ.js +793 -0
  48. package/dist/chunk-HWFX4BC4.js +177 -0
  49. package/dist/chunk-I3M2KJXB.js +56 -0
  50. package/dist/chunk-IFNONGRQ.js +603 -0
  51. package/dist/chunk-J3U2CPSK.js +136 -0
  52. package/dist/chunk-J6XQ7OPZ.js +74 -0
  53. package/dist/chunk-KMV4Y6R3.js +127 -0
  54. package/dist/chunk-KP5ZDDPE.js +340 -0
  55. package/dist/chunk-KYKSZ3XZ.js +202 -0
  56. package/dist/chunk-LEGPB7DO.js +81 -0
  57. package/dist/chunk-LUAKDHLZ.js +40 -0
  58. package/dist/chunk-MHUEVBVO.js +35 -0
  59. package/dist/chunk-MYGSLK44.js +37 -0
  60. package/dist/chunk-NEZNAPPN.js +41 -0
  61. package/dist/chunk-NPVN2THM.js +197 -0
  62. package/dist/chunk-NYZU5NCW.js +23 -0
  63. package/dist/chunk-O4KHCV6I.js +320 -0
  64. package/dist/chunk-ONDVTXUO.js +240 -0
  65. package/dist/chunk-OTJFHESY.js +176 -0
  66. package/dist/chunk-P6MIKSPY.js +243 -0
  67. package/dist/chunk-Q5VPF4WI.js +26 -0
  68. package/dist/chunk-QCRBX3LV.js +165 -0
  69. package/dist/chunk-QKGYDMWB.js +7409 -0
  70. package/dist/chunk-QSL6QN5X.js +115 -0
  71. package/dist/chunk-QUIMQ7YL.js +73 -0
  72. package/dist/chunk-RG3YLU6E.js +49 -0
  73. package/dist/chunk-SHCEBP3J.js +107 -0
  74. package/dist/chunk-SHZFOSXC.js +462 -0
  75. package/dist/chunk-SOXFMMXC.js +151 -0
  76. package/dist/chunk-TDTYV6QI.js +119 -0
  77. package/dist/chunk-TNTXWSYA.js +19 -0
  78. package/dist/chunk-TUXQ32WE.js +2251 -0
  79. package/dist/chunk-VGCDRK3S.js +37 -0
  80. package/dist/chunk-VLRHFMGJ.js +58 -0
  81. package/dist/chunk-WHX2ZFCG.js +4048 -0
  82. package/dist/chunk-X4W64MHU.js +2005 -0
  83. package/dist/chunk-XBQA4I36.js +92 -0
  84. package/dist/chunk-XGOV6KV4.js +413 -0
  85. package/dist/chunk-XIFQIFSZ.js +940 -0
  86. package/dist/chunk-XLXPVN3Y.js +15393 -0
  87. package/dist/chunk-ZJMLQ37G.js +90 -0
  88. package/dist/client-MU4EUDZV.js +15 -0
  89. package/dist/commands-UOOTMBKA.js +1023 -0
  90. package/dist/compat-Q5DVPITN.js +201 -0
  91. package/dist/constants-DJFOFZ44.js +24 -0
  92. package/dist/dashboardIssue-KBKLQMGC.js +274 -0
  93. package/dist/diff-I4SNUHU3.js +13 -0
  94. package/dist/dist-4XXIXHHZ.js +12945 -0
  95. package/dist/domains-VRT4BRVZ.js +14 -0
  96. package/dist/e2b-FVPHDULZ.js +172 -0
  97. package/dist/env-UN6KGZ7S.js +15 -0
  98. package/dist/envCheck-KUPTORFQ.js +71 -0
  99. package/dist/extract-6WG265BL.js +455 -0
  100. package/dist/fetch-PJ3SC32M.js +22 -0
  101. package/dist/firstTouch-COJCMOB3.js +55 -0
  102. package/dist/fix-3EDWNKW3.js +220 -0
  103. package/dist/handlers-4Q37WIFT.js +55 -0
  104. package/dist/hook-NA66XJLC.js +412 -0
  105. package/dist/http-25GJ6SKK.js +6928 -0
  106. package/dist/ingestQueue-FSVJC3AA.js +37 -0
  107. package/dist/install-G2HHXYJ2.js +20 -0
  108. package/dist/installSkill-5TIMYIJZ.js +70 -0
  109. package/dist/inventory-5AWSLJYU.js +31 -0
  110. package/dist/local-XPZMRH5R.js +13 -0
  111. package/dist/manifest-ENMIC54B.js +13 -0
  112. package/dist/mcp-PENLL2PK.js +500 -0
  113. package/dist/mcpConfig-3LYPRY5Q.js +80 -0
  114. package/dist/mcpHandlers-PO7GENA7.js +22 -0
  115. package/dist/mcpScan-ULP626TQ.js +1735 -0
  116. package/dist/mcpScanWorkflow-27O44FOE.js +98 -0
  117. package/dist/mcpStack-ZNYIFXZ5.js +20 -0
  118. package/dist/model-ASMZWLM7.js +214 -0
  119. package/dist/packages-RWF2LXST.js +40 -0
  120. package/dist/plan-SDILIDZT.js +465 -0
  121. package/dist/planView-ZAKRTGVS.js +82 -0
  122. package/dist/policy-JAGNMQJI.js +115 -0
  123. package/dist/probe-3IK646WN.js +610 -0
  124. package/dist/publicUpgrades-WTBGLDIK.js +42 -0
  125. package/dist/references-I6Y4BSRR.js +16 -0
  126. package/dist/release-7IU2R4YG.js +128 -0
  127. package/dist/remote-FN6225AH.js +42 -0
  128. package/dist/rename-OS6JYBZQ.js +204 -0
  129. package/dist/reportRuns-O4X7ZFTX.js +77 -0
  130. package/dist/safeFetch-COERXGFN.js +19 -0
  131. package/dist/sandbox-SAPSRKEI.js +39 -0
  132. package/dist/sarif-WLVJFJ7U.js +125 -0
  133. package/dist/server-OLTY3NYT.js +59 -0
  134. package/dist/surface-7MHE3RL7.js +143 -0
  135. package/dist/surface-JS2XU3U3.js +38 -0
  136. package/dist/surfaceHandlers-4B6TMZ34.js +20 -0
  137. package/dist/typecheck-NGOKNAJY.js +282 -0
  138. package/dist/types-M5JP2W3D.js +10 -0
  139. package/dist/uninstall-I2IJP5JZ.js +200 -0
  140. package/dist/upgrade-FS26DJGG.js +650 -0
  141. package/dist/upgradePlan-ZS5IOVMZ.js +181 -0
  142. package/dist/upkeepHandler-VFGYXJKB.js +13 -0
  143. package/dist/userConfig-ICASHI47.js +20 -0
  144. package/dist/watch-OCNEUXG6.js +204 -0
  145. package/package.json +26 -20
  146. package/templates/agent-rules.md +4 -4
  147. package/templates/skill-instructions.md +35 -17
  148. package/dist/bin/lurq.js.map +0 -1
  149. package/dist/index.d.ts +0 -805
  150. package/dist/index.js +0 -23570
  151. package/dist/index.js.map +0 -1
  152. package/drizzle/0000_confused_fabian_cortez.sql +0 -54
  153. package/drizzle/0001_aspiring_timeslip.sql +0 -15
  154. package/drizzle/0002_lyrical_lila_cheney.sql +0 -14
  155. package/drizzle/0003_violet_giant_girl.sql +0 -14
  156. package/drizzle/0004_slim_valeria_richards.sql +0 -15
  157. package/drizzle/0005_petite_luke_cage.sql +0 -12
  158. package/drizzle/0006_calm_nighthawk.sql +0 -3
  159. package/drizzle/0007_slimy_naoko.sql +0 -1
  160. package/drizzle/0008_peaceful_tigra.sql +0 -1
  161. package/drizzle/0009_smooth_harrier.sql +0 -10
  162. package/drizzle/0010_curved_amphibian.sql +0 -2
  163. package/drizzle/0011_compat_provenance_closures.sql +0 -11
  164. package/drizzle/0012_api_surfaces.sql +0 -9
  165. package/drizzle/0013_nice_thanos.sql +0 -1
  166. package/drizzle/0014_luxuriant_malcolm_colcord.sql +0 -10
  167. package/drizzle/0015_past_fat_cobra.sql +0 -11
  168. package/drizzle/0016_futuristic_junta.sql +0 -50
  169. package/drizzle/0017_absent_grandmaster.sql +0 -20
  170. package/drizzle/0018_rainy_proemial_gods.sql +0 -1
  171. package/drizzle/0019_dashing_korvac.sql +0 -11
  172. package/drizzle/0020_normal_vulture.sql +0 -3
  173. package/drizzle/0021_dazzling_blue_shield.sql +0 -17
  174. package/drizzle/0022_massive_ghost_rider.sql +0 -24
  175. package/drizzle/0023_next_shatterstar.sql +0 -1
  176. package/drizzle/0024_dusty_maelstrom.sql +0 -15
  177. package/drizzle/0025_gifted_harpoon.sql +0 -5
  178. package/drizzle/0026_awesome_mordo.sql +0 -1
  179. package/drizzle/0027_charming_ulik.sql +0 -2
  180. package/drizzle/0028_romantic_loners.sql +0 -2
  181. package/drizzle/0029_busy_korvac.sql +0 -16
  182. package/drizzle/0030_steady_mathemanic.sql +0 -6
  183. package/drizzle/0031_redundant_maginty.sql +0 -2
  184. package/drizzle/0032_stack_resolutions.sql +0 -14
  185. package/drizzle/0033_graceful_tyger_tiger.sql +0 -3
  186. package/drizzle/0034_uneven_thunderbird.sql +0 -1
  187. package/drizzle/0035_api_key_scopes.sql +0 -1
  188. package/drizzle/0036_policy_audit.sql +0 -21
  189. package/drizzle/0037_subscription_seats.sql +0 -1
  190. package/drizzle/0038_symbol_offsets.sql +0 -2
  191. package/drizzle/0039_mcp_runtime_scans.sql +0 -80
  192. package/drizzle/0040_subscription_overage_and_interval.sql +0 -4
  193. package/drizzle/0041_account_email.sql +0 -38
  194. package/drizzle/0042_alert_channels.sql +0 -21
  195. package/drizzle/meta/0000_snapshot.json +0 -370
  196. package/drizzle/meta/0001_snapshot.json +0 -482
  197. package/drizzle/meta/0002_snapshot.json +0 -575
  198. package/drizzle/meta/0003_snapshot.json +0 -667
  199. package/drizzle/meta/0004_snapshot.json +0 -769
  200. package/drizzle/meta/0005_snapshot.json +0 -864
  201. package/drizzle/meta/0006_snapshot.json +0 -882
  202. package/drizzle/meta/0007_snapshot.json +0 -876
  203. package/drizzle/meta/0008_snapshot.json +0 -882
  204. package/drizzle/meta/0009_snapshot.json +0 -948
  205. package/drizzle/meta/0010_snapshot.json +0 -969
  206. package/drizzle/meta/0011_snapshot.json +0 -1049
  207. package/drizzle/meta/0012_snapshot.json +0 -1115
  208. package/drizzle/meta/0013_snapshot.json +0 -1121
  209. package/drizzle/meta/0014_snapshot.json +0 -1190
  210. package/drizzle/meta/0015_snapshot.json +0 -1280
  211. package/drizzle/meta/0016_snapshot.json +0 -1683
  212. package/drizzle/meta/0017_snapshot.json +0 -1834
  213. package/drizzle/meta/0018_snapshot.json +0 -1834
  214. package/drizzle/meta/0019_snapshot.json +0 -1909
  215. package/drizzle/meta/0020_snapshot.json +0 -1921
  216. package/drizzle/meta/0021_snapshot.json +0 -2045
  217. package/drizzle/meta/0022_snapshot.json +0 -2246
  218. package/drizzle/meta/0023_snapshot.json +0 -2252
  219. package/drizzle/meta/0024_snapshot.json +0 -2375
  220. package/drizzle/meta/0025_snapshot.json +0 -2407
  221. package/drizzle/meta/0026_snapshot.json +0 -2413
  222. package/drizzle/meta/0027_snapshot.json +0 -2425
  223. package/drizzle/meta/0028_snapshot.json +0 -2438
  224. package/drizzle/meta/0029_snapshot.json +0 -2546
  225. package/drizzle/meta/0030_snapshot.json +0 -2586
  226. package/drizzle/meta/0031_snapshot.json +0 -2598
  227. package/drizzle/meta/0032_snapshot.json +0 -2699
  228. package/drizzle/meta/0033_snapshot.json +0 -2712
  229. package/drizzle/meta/0034_snapshot.json +0 -2719
  230. package/drizzle/meta/0035_snapshot.json +0 -2726
  231. package/drizzle/meta/0036_snapshot.json +0 -2876
  232. package/drizzle/meta/0037_snapshot.json +0 -2883
  233. package/drizzle/meta/0038_snapshot.json +0 -2895
  234. package/drizzle/meta/0039_snapshot.json +0 -3501
  235. package/drizzle/meta/0040_snapshot.json +0 -3527
  236. package/drizzle/meta/0041_snapshot.json +0 -3824
  237. package/drizzle/meta/0042_snapshot.json +0 -3960
  238. package/drizzle/meta/_journal.json +0 -307
  239. package/src/data/seed.json +0 -253
@@ -0,0 +1,92 @@
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/fix/domains.ts
7
+ init_esm_shims();
8
+ var DOMAIN_SCAN_LIMIT = 2e4;
9
+ var DOMAINS = {
10
+ /** Variables the code reads that no .env file declares. No key, no network. */
11
+ env: async (root, opts) => {
12
+ const { envFindings } = await import("./env-UN6KGZ7S.js");
13
+ const plan = envFindings(root, { limit: opts.limit ?? DOMAIN_SCAN_LIMIT });
14
+ return { findings: plan.findings, truncated: plan.truncated };
15
+ },
16
+ /**
17
+ * Model identifiers the provider has retired or put an end date on.
18
+ *
19
+ * Reads source only — no network, no key, no arguments. That is why it runs
20
+ * by default: the check costs nothing the scan is not already paying, and
21
+ * the failure it catches is one nothing else in the toolchain can see.
22
+ */
23
+ model: async (root, opts) => {
24
+ const { modelFindings } = await import("./model-ASMZWLM7.js");
25
+ const plan = modelFindings(root, { limit: opts.limit ?? DOMAIN_SCAN_LIMIT });
26
+ return { findings: plan.findings, truncated: plan.truncated };
27
+ },
28
+ /**
29
+ * Renames the package itself proves, the manifest ranges an upgrade leaves
30
+ * stale, and a brief for everything that needs judgement.
31
+ *
32
+ * Reads the two published versions from npm, so it needs the network but no
33
+ * API key — the same contract `check-upgrade` advertises.
34
+ */
35
+ package: async (root, opts) => {
36
+ const targets = opts.upgrade ?? [];
37
+ if (targets.length === 0) {
38
+ return {
39
+ findings: [],
40
+ skipped: "no upgrades given. Pass `upgrade` with the versions to assess, or run `lurq fix` in the project to have them worked out from the index."
41
+ };
42
+ }
43
+ const { scanReferences } = await import("./references-I6Y4BSRR.js");
44
+ const { checkUpgrade } = await import("./upgrade-FS26DJGG.js");
45
+ const { renamePlan } = await import("./rename-OS6JYBZQ.js");
46
+ const { manifestFindings } = await import("./manifest-ENMIC54B.js");
47
+ const stats = { files: 0, truncated: false };
48
+ const refs = scanReferences(root, { limit: opts.limit ?? DOMAIN_SCAN_LIMIT, stats });
49
+ const report = await checkUpgrade(targets, refs, { rootDir: root });
50
+ return {
51
+ findings: [...renamePlan(report).findings, ...manifestFindings(root, targets).findings],
52
+ truncated: stats.truncated
53
+ };
54
+ }
55
+ };
56
+ var AVAILABLE = ["env", "model", "package"];
57
+ var SOURCE_DOMAINS = AVAILABLE.filter((d) => d !== "package");
58
+ async function runDomains(opts = {}) {
59
+ const root = opts.dir?.trim() || process.cwd();
60
+ const wanted = opts.domains?.length ? opts.domains : AVAILABLE;
61
+ const findings = [];
62
+ const ran = [];
63
+ const skipped = [];
64
+ let truncated = false;
65
+ for (const domain of wanted) {
66
+ const run = DOMAINS[domain];
67
+ if (!run) {
68
+ skipped.push({ domain, reason: `lurq has no detector for the ${domain} domain yet` });
69
+ continue;
70
+ }
71
+ try {
72
+ const result = await run(root, opts);
73
+ if (result.skipped) {
74
+ skipped.push({ domain, reason: result.skipped });
75
+ continue;
76
+ }
77
+ findings.push(...result.findings);
78
+ if (result.truncated) truncated = true;
79
+ ran.push(domain);
80
+ } catch (err) {
81
+ skipped.push({ domain, reason: err instanceof Error ? err.message : String(err) });
82
+ }
83
+ }
84
+ return { root, ran, skipped, findings, truncated };
85
+ }
86
+
87
+ export {
88
+ DOMAIN_SCAN_LIMIT,
89
+ AVAILABLE,
90
+ SOURCE_DOMAINS,
91
+ runDomains
92
+ };
@@ -0,0 +1,413 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ classifyServer,
4
+ mcpConfigPaths
5
+ } from "./chunk-63MUJNZL.js";
6
+ import {
7
+ init_esm_shims
8
+ } from "./chunk-I3M2KJXB.js";
9
+
10
+ // src/mcpScan/redact.ts
11
+ init_esm_shims();
12
+ var SHAPES = [
13
+ /\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g,
14
+ /\bgh[pousr]_[A-Za-z0-9]{20,}/g,
15
+ /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
16
+ /\bxox[abpors]-[A-Za-z0-9-]{10,}/g,
17
+ /\bAKIA[0-9A-Z]{16}\b/g,
18
+ /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g,
19
+ /\blurq_(?:live|test)_[A-Za-z0-9_-]{16,}/g,
20
+ /\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g
21
+ ];
22
+ var BEARER = /\b(Bearer|Basic|token)\s+[A-Za-z0-9._~+/=-]{12,}/gi;
23
+ var REDACTED = "[redacted]";
24
+ function looksLikeSecret(value) {
25
+ return SHAPES.some((re) => {
26
+ re.lastIndex = 0;
27
+ const m = re.exec(value);
28
+ return m !== null && m.index === 0 && m[0].length === value.length;
29
+ });
30
+ }
31
+ function scrub(text, secrets = []) {
32
+ let out = text;
33
+ for (const s of secrets) if (s && out.includes(s)) out = out.split(s).join(REDACTED);
34
+ for (const re of SHAPES) out = out.replace(re, REDACTED);
35
+ return out.replace(BEARER, `$1 ${REDACTED}`);
36
+ }
37
+ function scrubDeep(value, secrets = []) {
38
+ if (typeof value === "string") return scrub(value, secrets);
39
+ if (Array.isArray(value)) return value.map((v) => scrubDeep(v, secrets));
40
+ if (value && typeof value === "object") {
41
+ const out = {};
42
+ for (const [k, v] of Object.entries(value)) {
43
+ out[scrub(k, secrets)] = scrubDeep(v, secrets);
44
+ }
45
+ return out;
46
+ }
47
+ return value;
48
+ }
49
+
50
+ // src/mcpScan/config.ts
51
+ init_esm_shims();
52
+ import { createHash } from "crypto";
53
+ import { existsSync, readFileSync, realpathSync } from "fs";
54
+ import { homedir } from "os";
55
+ import { basename, isAbsolute, join, relative, resolve } from "path";
56
+ var MIN_SECRET_LENGTH = 6;
57
+ var SECRET_FLAG = /^--?(?:api[-_]?key|token|access[-_]?token|auth|password|secret|pat|key)$/i;
58
+ var SECRET_NAME = /(key|token|secret|password|passwd|auth|cookie|credential|session|pat)\b/i;
59
+ var strings = (v) => Array.isArray(v) ? v.filter((a) => typeof a === "string") : [];
60
+ var record = (v) => {
61
+ if (!v || typeof v !== "object" || Array.isArray(v)) return {};
62
+ const out = {};
63
+ for (const [k, val] of Object.entries(v)) {
64
+ if (typeof val === "string") out[k] = val;
65
+ else if (typeof val === "number" || typeof val === "boolean") out[k] = String(val);
66
+ }
67
+ return out;
68
+ };
69
+ function expandVars(value, env, missing) {
70
+ return value.replace(/\$\{([^}]+)\}/g, (whole, body) => {
71
+ if (body.startsWith("input:")) {
72
+ missing.add(body);
73
+ return whole;
74
+ }
75
+ const expr = body.startsWith("env:") ? body.slice(4) : body;
76
+ const [name, fallback] = expr.split(":-", 2);
77
+ const v = env[name.trim()];
78
+ if (v !== void 0 && v !== "") return v;
79
+ if (fallback !== void 0) return fallback;
80
+ missing.add(name.trim());
81
+ return "";
82
+ });
83
+ }
84
+ var sha = (s) => createHash("sha256").update(s).digest("hex");
85
+ function hostPath(url) {
86
+ try {
87
+ const u = new URL(url);
88
+ return `${u.host.toLowerCase()}${u.pathname.replace(/\/+$/, "")}`;
89
+ } catch {
90
+ return url.split("?")[0].slice(0, 200);
91
+ }
92
+ }
93
+ function splitPypi(spec) {
94
+ const m = /^([A-Za-z0-9][A-Za-z0-9._-]*)(?:\[[^\]]*\])?(?:(?:==|@)(\d[^\s,;]*))?/.exec(spec);
95
+ if (!m) return { name: spec, version: null };
96
+ return { name: m[1].toLowerCase().replace(/_/g, "-"), version: m[2] ?? null };
97
+ }
98
+ function splitImage(image) {
99
+ const noDigest = image.split("@")[0];
100
+ const lastColon = noDigest.lastIndexOf(":");
101
+ const hasTag = lastColon > noDigest.lastIndexOf("/");
102
+ const name = hasTag ? noDigest.slice(0, lastColon) : noDigest;
103
+ const tag = hasTag ? noDigest.slice(lastColon + 1) : null;
104
+ return { name: name.toLowerCase(), version: tag && /^v?\d/.test(tag) ? tag : null };
105
+ }
106
+ var DOCKER_VALUE_FLAGS = /* @__PURE__ */ new Set([
107
+ "-e",
108
+ "--env",
109
+ "-v",
110
+ "--volume",
111
+ "-p",
112
+ "--publish",
113
+ "--name",
114
+ "--network",
115
+ "-w",
116
+ "--workdir",
117
+ "--env-file",
118
+ "-u",
119
+ "--user",
120
+ "--mount",
121
+ "--entrypoint",
122
+ "--platform"
123
+ ]);
124
+ function identify(alias, command, args, url) {
125
+ if (url) return { kind: "remote", registry: "remote", packageName: null, pinnedVersion: null };
126
+ let cmd = command ?? "";
127
+ let rest = args;
128
+ if (/^cmd(\.exe)?$/i.test(basename(cmd)) && /^\/c$/i.test(rest[0] ?? "")) {
129
+ cmd = rest[1] ?? "";
130
+ rest = rest.slice(2);
131
+ }
132
+ const bin = basename(cmd).replace(/\.(cmd|exe)$/i, "");
133
+ const base = classifyServer(alias, { command: bin, args: rest });
134
+ if (base.kind === "npm-stdio" && base.packageName) {
135
+ return {
136
+ kind: base.kind,
137
+ registry: "npm",
138
+ packageName: base.packageName,
139
+ pinnedVersion: base.version
140
+ };
141
+ }
142
+ if (bin === "uvx" || bin === "pipx" || bin === "uv") {
143
+ let tokens = rest;
144
+ if (bin === "pipx" && tokens[0] === "run") tokens = tokens.slice(1);
145
+ if (bin === "uv" && tokens[0] === "tool" && tokens[1] === "run") tokens = tokens.slice(2);
146
+ const from = tokens.indexOf("--from");
147
+ const spec = from >= 0 ? tokens[from + 1] : tokens.find((t, i) => !t.startsWith("-") && tokens[i - 1] !== "--python");
148
+ if (spec) {
149
+ const { name, version } = splitPypi(spec);
150
+ return {
151
+ kind: "other-registry",
152
+ registry: "pypi",
153
+ packageName: name,
154
+ pinnedVersion: version
155
+ };
156
+ }
157
+ }
158
+ if ((bin === "docker" || bin === "podman") && rest[0] === "run") {
159
+ for (let i = 1; i < rest.length; i++) {
160
+ const a = rest[i];
161
+ if (DOCKER_VALUE_FLAGS.has(a)) {
162
+ i++;
163
+ continue;
164
+ }
165
+ if (a.startsWith("-")) continue;
166
+ const { name, version } = splitImage(a);
167
+ return {
168
+ kind: "other-registry",
169
+ registry: "docker",
170
+ packageName: name,
171
+ pinnedVersion: version
172
+ };
173
+ }
174
+ }
175
+ return { kind: base.kind, registry: "local", packageName: null, pinnedVersion: null };
176
+ }
177
+ function serverKeyFor(registry, packageName, url, alias) {
178
+ if (registry === "remote" && url) return `remote:${hostPath(url)}`;
179
+ if (packageName && registry !== "local" && registry !== "remote")
180
+ return `${registry}:${packageName}`;
181
+ return `local:${alias}`;
182
+ }
183
+ function collectSecrets(args, env, headers) {
184
+ const found = /* @__PURE__ */ new Set();
185
+ const add = (v) => {
186
+ if (!v || v.length < MIN_SECRET_LENGTH) return;
187
+ found.add(v);
188
+ const bearer = /^(?:bearer|token|basic)\s+(.+)$/i.exec(v);
189
+ if (bearer?.[1] && bearer[1].length >= MIN_SECRET_LENGTH) found.add(bearer[1]);
190
+ };
191
+ for (const [k, v] of Object.entries(env)) if (SECRET_NAME.test(k) || looksLikeSecret(v)) add(v);
192
+ for (const v of Object.values(headers)) add(v);
193
+ args.forEach((a, i) => {
194
+ if (looksLikeSecret(a)) add(a);
195
+ const eq = /^(--?[A-Za-z-_]+)=(.+)$/.exec(a);
196
+ if (eq && SECRET_FLAG.test(eq[1])) add(eq[2]);
197
+ if (SECRET_FLAG.test(a)) add(args[i + 1]);
198
+ const kv = /^([A-Z][A-Z0-9_]+)=(.+)$/.exec(a);
199
+ if (kv && SECRET_NAME.test(kv[1])) add(kv[2]);
200
+ });
201
+ return [...found].sort((a, b) => b.length - a.length);
202
+ }
203
+ function fingerprintConfig(spec, secrets, root, home) {
204
+ const normPath = (a) => {
205
+ let out = a;
206
+ if (root && out.startsWith(root)) out = `<project>${out.slice(root.length)}`;
207
+ if (home && out.startsWith(home)) out = `~${out.slice(home.length)}`;
208
+ return out;
209
+ };
210
+ const args = spec.args.map((a) => {
211
+ if (secrets.includes(a)) return "<secret>";
212
+ const kv = /^([A-Za-z-_][A-Za-z0-9-_]*)=(.*)$/.exec(a);
213
+ if (kv && secrets.includes(kv[2])) return `${kv[1]}=<secret>`;
214
+ if (spec.packageName && spec.registry === "npm" && a.startsWith(spec.packageName))
215
+ return spec.packageName;
216
+ if (spec.packageName && spec.registry === "pypi" && splitPypi(a).name === spec.packageName) {
217
+ return spec.packageName;
218
+ }
219
+ if (spec.packageName && spec.registry === "docker" && splitImage(a).name === spec.packageName) {
220
+ return spec.packageName;
221
+ }
222
+ return normPath(a);
223
+ });
224
+ const shape = {
225
+ t: spec.transport,
226
+ c: spec.command ? basename(spec.command) : null,
227
+ a: args,
228
+ e: Object.keys(spec.env).sort(),
229
+ h: Object.keys(spec.headers).map((h) => h.toLowerCase()).sort(),
230
+ u: spec.url ? hostPath(spec.url) : null
231
+ };
232
+ return sha(JSON.stringify(shape)).slice(0, 16);
233
+ }
234
+ function transportOf(raw, url, file) {
235
+ const declared = typeof raw.type === "string" ? raw.type : typeof raw.transport === "string" ? raw.transport : "";
236
+ const t = declared.toLowerCase().replace(/[-_]/g, "");
237
+ if (t === "stdio") return "stdio";
238
+ if (t === "sse") return "sse";
239
+ if (t === "http" || t === "streamablehttp") return "http";
240
+ if (typeof raw.httpUrl === "string") return "http";
241
+ if (url) {
242
+ return basename(file) === "settings.json" && file.includes(".gemini") ? "sse" : "auto";
243
+ }
244
+ return "stdio";
245
+ }
246
+ function readJson(path) {
247
+ try {
248
+ return JSON.parse(readFileSync(path, "utf8"));
249
+ } catch {
250
+ return null;
251
+ }
252
+ }
253
+ var canonicalPath = (p) => {
254
+ try {
255
+ return realpathSync(p);
256
+ } catch {
257
+ return resolve(p);
258
+ }
259
+ };
260
+ function claudeProject(home, root) {
261
+ const cfg = readJson(join(home, ".claude.json"));
262
+ const projects = cfg?.projects;
263
+ if (!projects) return null;
264
+ const want = canonicalPath(root);
265
+ for (const [path, state] of Object.entries(projects)) {
266
+ if (path === root || canonicalPath(path) === want) return state;
267
+ }
268
+ return null;
269
+ }
270
+ function readServerConfigs(root, opts = {}) {
271
+ const abs = resolve(root);
272
+ const home = opts.home ?? homedir();
273
+ const env = opts.env ?? process.env;
274
+ const filesRead = [];
275
+ const notes = [];
276
+ const rel = (p) => isAbsolute(p) && p.startsWith(abs) ? relative(abs, p) || "." : p.replace(home, "~");
277
+ const project = claudeProject(home, abs);
278
+ const approved = new Set(strings(project?.enabledMcpjsonServers));
279
+ const rejected = new Set(strings(project?.disabledMcpjsonServers));
280
+ const approveAll = project?.enableAllProjectMcpServers === true;
281
+ const entries = [];
282
+ for (const path of mcpConfigPaths(abs, home)) {
283
+ const inProject = path.startsWith(abs + "/") || path.startsWith(abs + "\\");
284
+ if (opts.projectOnly && !inProject) continue;
285
+ if (!existsSync(path)) continue;
286
+ const cfg = readJson(path);
287
+ if (!cfg || typeof cfg !== "object") {
288
+ notes.push(`could not parse ${rel(path)}`);
289
+ continue;
290
+ }
291
+ let found = 0;
292
+ for (const section of ["mcpServers", "servers"]) {
293
+ const block = cfg[section];
294
+ if (!block || typeof block !== "object") continue;
295
+ for (const [alias, raw] of Object.entries(block)) {
296
+ if (!raw || typeof raw !== "object") continue;
297
+ entries.push({
298
+ alias,
299
+ raw,
300
+ file: path,
301
+ section,
302
+ scope: inProject ? "project" : "user"
303
+ });
304
+ found++;
305
+ }
306
+ }
307
+ if (found) filesRead.push(rel(path));
308
+ }
309
+ if (!opts.projectOnly && project?.mcpServers && typeof project.mcpServers === "object") {
310
+ for (const [alias, raw] of Object.entries(project.mcpServers)) {
311
+ if (!raw || typeof raw !== "object") continue;
312
+ entries.push({
313
+ alias,
314
+ raw,
315
+ file: join(home, ".claude.json"),
316
+ section: `projects[${abs}].mcpServers`,
317
+ scope: "local"
318
+ });
319
+ }
320
+ }
321
+ const byKey = /* @__PURE__ */ new Map();
322
+ for (const { alias, raw, file, section, scope } of entries) {
323
+ const missing = /* @__PURE__ */ new Set();
324
+ const x = (v) => expandVars(v, env, missing);
325
+ const rawUrl = typeof raw.httpUrl === "string" ? raw.httpUrl : typeof raw.url === "string" ? raw.url : typeof raw.serverUrl === "string" ? raw.serverUrl : null;
326
+ const url = rawUrl ? x(rawUrl) : null;
327
+ const command = typeof raw.command === "string" ? x(raw.command) : null;
328
+ const args = strings(raw.args).map(x);
329
+ const envVars = Object.fromEntries(Object.entries(record(raw.env)).map(([k, v]) => [k, x(v)]));
330
+ const headers = Object.fromEntries(
331
+ Object.entries(record(raw.headers)).map(([k, v]) => [k, x(v)])
332
+ );
333
+ const cwd = typeof raw.cwd === "string" ? resolve(abs, x(raw.cwd)) : null;
334
+ const transport = transportOf(raw, url, file);
335
+ if (!url && !command) {
336
+ notes.push(`${rel(file)}: server "${alias}" has neither a command nor a url`);
337
+ continue;
338
+ }
339
+ const id = identify(alias, command, args, url);
340
+ const secrets = collectSecrets(args, envVars, headers);
341
+ const serverKey = serverKeyFor(id.registry, id.packageName, url, alias);
342
+ const configFingerprint = fingerprintConfig(
343
+ {
344
+ transport,
345
+ command,
346
+ args,
347
+ env: envVars,
348
+ headers,
349
+ url,
350
+ registry: id.registry,
351
+ packageName: id.packageName
352
+ },
353
+ secrets,
354
+ abs,
355
+ home
356
+ );
357
+ let trusted = true;
358
+ let trustReason = scope === "project" ? "approved" : "your own configuration";
359
+ if (scope === "project") {
360
+ const isMcpJson = basename(file) === ".mcp.json";
361
+ if (isMcpJson && rejected.has(alias)) {
362
+ trusted = false;
363
+ trustReason = "you declined this server in Claude Code";
364
+ } else if (opts.trustProject) {
365
+ trustReason = "trusted with --trust-project";
366
+ } else if (isMcpJson && (approveAll || approved.has(alias))) {
367
+ trustReason = "approved in Claude Code";
368
+ } else {
369
+ trusted = false;
370
+ trustReason = `committed to the repository (${rel(file)}) and not approved; pass --trust-project to launch it`;
371
+ }
372
+ }
373
+ const spec = {
374
+ alias,
375
+ transport,
376
+ command,
377
+ args,
378
+ env: envVars,
379
+ cwd,
380
+ url,
381
+ headers,
382
+ ...id,
383
+ serverKey,
384
+ configFingerprint,
385
+ scope,
386
+ trusted,
387
+ trustReason,
388
+ unresolved: [...missing].sort(),
389
+ disabled: raw.disabled === true || raw.enabled === false,
390
+ secrets,
391
+ sources: [{ file: rel(file), section }]
392
+ };
393
+ const key = `${serverKey}#${configFingerprint}`;
394
+ const seen = byKey.get(key);
395
+ if (seen) {
396
+ seen.sources.push(...spec.sources);
397
+ if (spec.trusted && !seen.trusted) {
398
+ seen.trusted = true;
399
+ seen.trustReason = spec.trustReason;
400
+ }
401
+ seen.disabled &&= spec.disabled;
402
+ continue;
403
+ }
404
+ byKey.set(key, spec);
405
+ }
406
+ return { root: abs, servers: [...byKey.values()], filesRead, notes };
407
+ }
408
+
409
+ export {
410
+ scrub,
411
+ scrubDeep,
412
+ readServerConfigs
413
+ };