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.
Files changed (206) hide show
  1. package/README.md +18 -10
  2. package/dist/auditHandler-JCOJSUYW.js +23 -0
  3. package/dist/bin/lurq.js +3090 -23306
  4. package/dist/browserAuth-B6G27USY.js +95 -0
  5. package/dist/cache-DKI34SVS.js +12 -0
  6. package/dist/check-2FDGUOV7.js +192 -0
  7. package/dist/checkUpgrade-F2WESBPM.js +103 -0
  8. package/dist/chunk-2VMOWSRY.js +300 -0
  9. package/dist/chunk-3GHJR7XR.js +2049 -0
  10. package/dist/chunk-3N3Q3DSW.js +214 -0
  11. package/dist/chunk-4ESO33J6.js +34 -0
  12. package/dist/chunk-4F7ZESPO.js +132 -0
  13. package/dist/chunk-4KCPOMG6.js +68 -0
  14. package/dist/chunk-4ZYCIMY4.js +155 -0
  15. package/dist/chunk-63MUJNZL.js +318 -0
  16. package/dist/chunk-6AAEVQ7I.js +6336 -0
  17. package/dist/chunk-6EQ3ARXA.js +304 -0
  18. package/dist/chunk-6L3U7DZ5.js +23 -0
  19. package/dist/chunk-AHBP533R.js +220 -0
  20. package/dist/chunk-B43LCXBM.js +223 -0
  21. package/dist/chunk-BCANRN5B.js +33 -0
  22. package/dist/chunk-BUALU27S.js +123 -0
  23. package/dist/chunk-BULZAX2U.js +1554 -0
  24. package/dist/chunk-BV32UNLL.js +154 -0
  25. package/dist/chunk-C6GLE626.js +160 -0
  26. package/dist/chunk-CIDWNUAP.js +145 -0
  27. package/dist/chunk-CUP36ND3.js +2126 -0
  28. package/dist/chunk-CW5HJ3LX.js +96 -0
  29. package/dist/chunk-DB2VF5UD.js +315 -0
  30. package/dist/chunk-DWAGCNEL.js +210 -0
  31. package/dist/chunk-EA3DP5HG.js +293 -0
  32. package/dist/chunk-ELGCAM7P.js +184 -0
  33. package/dist/chunk-FW6BD2NO.js +1915 -0
  34. package/dist/chunk-GE37NVLN.js +15 -0
  35. package/dist/chunk-GPTKSNR6.js +171 -0
  36. package/dist/chunk-GRJXQBQZ.js +793 -0
  37. package/dist/chunk-HWBBVLOT.js +92 -0
  38. package/dist/chunk-I2JUKN6Z.js +24 -0
  39. package/dist/chunk-I3M2KJXB.js +56 -0
  40. package/dist/chunk-IQ4SDKKY.js +733 -0
  41. package/dist/chunk-J5FZYN4A.js +116 -0
  42. package/dist/chunk-L6N4JFW2.js +263 -0
  43. package/dist/chunk-LBFGSSF2.js +126 -0
  44. package/dist/chunk-LEGPB7DO.js +81 -0
  45. package/dist/chunk-LO35HLQZ.js +219 -0
  46. package/dist/chunk-LRD4GBYE.js +73 -0
  47. package/dist/chunk-LUAKDHLZ.js +40 -0
  48. package/dist/chunk-LYMPYETA.js +965 -0
  49. package/dist/chunk-M6NYEXCW.js +38 -0
  50. package/dist/chunk-MHUEVBVO.js +35 -0
  51. package/dist/chunk-MYGSLK44.js +37 -0
  52. package/dist/chunk-NH5I4KHH.js +201 -0
  53. package/dist/chunk-OQS4GUSI.js +1391 -0
  54. package/dist/chunk-PSX3GIAN.js +176 -0
  55. package/dist/chunk-Q5VPF4WI.js +26 -0
  56. package/dist/chunk-QKGYDMWB.js +7409 -0
  57. package/dist/chunk-QSL6QN5X.js +115 -0
  58. package/dist/chunk-SHCEBP3J.js +107 -0
  59. package/dist/chunk-SJOVFF7B.js +201 -0
  60. package/dist/chunk-ST2X2GYN.js +373 -0
  61. package/dist/chunk-TNTXWSYA.js +19 -0
  62. package/dist/chunk-U5AT3TD4.js +2128 -0
  63. package/dist/chunk-UDVNA7EA.js +483 -0
  64. package/dist/chunk-VL2E5T2A.js +109 -0
  65. package/dist/chunk-VLRHFMGJ.js +58 -0
  66. package/dist/chunk-WHX2ZFCG.js +4048 -0
  67. package/dist/chunk-WQ23REYT.js +37 -0
  68. package/dist/chunk-XBIDMHSK.js +15425 -0
  69. package/dist/chunk-Y5GI7RL3.js +66 -0
  70. package/dist/client-IRKAMDYZ.js +15 -0
  71. package/dist/commands-FIL5ET6P.js +911 -0
  72. package/dist/compat-R3UTFQ5Q.js +201 -0
  73. package/dist/dashboardIssue-WYYMBFIB.js +192 -0
  74. package/dist/diff-GZA2774U.js +13 -0
  75. package/dist/dist-4XXIXHHZ.js +12945 -0
  76. package/dist/e2b-FVPHDULZ.js +172 -0
  77. package/dist/extract-NKGKLIVT.js +444 -0
  78. package/dist/fetch-QYTUJVG2.js +22 -0
  79. package/dist/firstTouch-QQTJH4QX.js +55 -0
  80. package/dist/handlers-GEJAVZDK.js +53 -0
  81. package/dist/http-ETPYMBGD.js +5360 -0
  82. package/dist/ingestQueue-VKN4KBIF.js +35 -0
  83. package/dist/install-EK3W2COX.js +20 -0
  84. package/dist/installSkill-VQJWJVCL.js +52 -0
  85. package/dist/inventory-5AWSLJYU.js +31 -0
  86. package/dist/local-XPZMRH5R.js +13 -0
  87. package/dist/mcp-3JHD5SUZ.js +472 -0
  88. package/dist/mcpHandlers-QFN4MCFL.js +22 -0
  89. package/dist/mcpScan-QZHWENIP.js +1871 -0
  90. package/dist/mcpScanWorkflow-JPYCBGC4.js +81 -0
  91. package/dist/mcpStack-BYJCZNIV.js +20 -0
  92. package/dist/packages-THVFMWFP.js +42 -0
  93. package/dist/plan-V4OEI3J4.js +463 -0
  94. package/dist/planView-JRXGCG2N.js +79 -0
  95. package/dist/policy-3P6BGRDN.js +115 -0
  96. package/dist/references-6N7VEPHT.js +14 -0
  97. package/dist/release-4U4ABNSJ.js +128 -0
  98. package/dist/remote-YGCXYI4V.js +32 -0
  99. package/dist/reportRuns-CKQQYLY4.js +64 -0
  100. package/dist/sandbox-MEZLAODF.js +39 -0
  101. package/dist/server-KFUD5X57.js +55 -0
  102. package/dist/surface-V62GE554.js +141 -0
  103. package/dist/surface-YL6O67W3.js +36 -0
  104. package/dist/surfaceHandlers-X2IZKA3E.js +20 -0
  105. package/dist/typecheck-X7U5ELMR.js +268 -0
  106. package/dist/types-M5JP2W3D.js +10 -0
  107. package/dist/uninstall-P7RGBX6G.js +174 -0
  108. package/dist/upgrade-NQ5IWFZB.js +596 -0
  109. package/dist/upgradePlan-A4LRKLEG.js +146 -0
  110. package/dist/userConfig-Z3GQE776.js +20 -0
  111. package/dist/watch-DGFMWUDL.js +214 -0
  112. package/package.json +26 -21
  113. package/templates/agent-rules.md +4 -4
  114. package/templates/skill-instructions.md +13 -14
  115. package/dist/bin/lurq.js.map +0 -1
  116. package/dist/index.d.ts +0 -805
  117. package/dist/index.js +0 -23570
  118. package/dist/index.js.map +0 -1
  119. package/drizzle/0000_confused_fabian_cortez.sql +0 -54
  120. package/drizzle/0001_aspiring_timeslip.sql +0 -15
  121. package/drizzle/0002_lyrical_lila_cheney.sql +0 -14
  122. package/drizzle/0003_violet_giant_girl.sql +0 -14
  123. package/drizzle/0004_slim_valeria_richards.sql +0 -15
  124. package/drizzle/0005_petite_luke_cage.sql +0 -12
  125. package/drizzle/0006_calm_nighthawk.sql +0 -3
  126. package/drizzle/0007_slimy_naoko.sql +0 -1
  127. package/drizzle/0008_peaceful_tigra.sql +0 -1
  128. package/drizzle/0009_smooth_harrier.sql +0 -10
  129. package/drizzle/0010_curved_amphibian.sql +0 -2
  130. package/drizzle/0011_compat_provenance_closures.sql +0 -11
  131. package/drizzle/0012_api_surfaces.sql +0 -9
  132. package/drizzle/0013_nice_thanos.sql +0 -1
  133. package/drizzle/0014_luxuriant_malcolm_colcord.sql +0 -10
  134. package/drizzle/0015_past_fat_cobra.sql +0 -11
  135. package/drizzle/0016_futuristic_junta.sql +0 -50
  136. package/drizzle/0017_absent_grandmaster.sql +0 -20
  137. package/drizzle/0018_rainy_proemial_gods.sql +0 -1
  138. package/drizzle/0019_dashing_korvac.sql +0 -11
  139. package/drizzle/0020_normal_vulture.sql +0 -3
  140. package/drizzle/0021_dazzling_blue_shield.sql +0 -17
  141. package/drizzle/0022_massive_ghost_rider.sql +0 -24
  142. package/drizzle/0023_next_shatterstar.sql +0 -1
  143. package/drizzle/0024_dusty_maelstrom.sql +0 -15
  144. package/drizzle/0025_gifted_harpoon.sql +0 -5
  145. package/drizzle/0026_awesome_mordo.sql +0 -1
  146. package/drizzle/0027_charming_ulik.sql +0 -2
  147. package/drizzle/0028_romantic_loners.sql +0 -2
  148. package/drizzle/0029_busy_korvac.sql +0 -16
  149. package/drizzle/0030_steady_mathemanic.sql +0 -6
  150. package/drizzle/0031_redundant_maginty.sql +0 -2
  151. package/drizzle/0032_stack_resolutions.sql +0 -14
  152. package/drizzle/0033_graceful_tyger_tiger.sql +0 -3
  153. package/drizzle/0034_uneven_thunderbird.sql +0 -1
  154. package/drizzle/0035_api_key_scopes.sql +0 -1
  155. package/drizzle/0036_policy_audit.sql +0 -21
  156. package/drizzle/0037_subscription_seats.sql +0 -1
  157. package/drizzle/0038_symbol_offsets.sql +0 -2
  158. package/drizzle/0039_mcp_runtime_scans.sql +0 -80
  159. package/drizzle/0040_subscription_overage_and_interval.sql +0 -4
  160. package/drizzle/0041_account_email.sql +0 -38
  161. package/drizzle/0042_alert_channels.sql +0 -21
  162. package/drizzle/meta/0000_snapshot.json +0 -370
  163. package/drizzle/meta/0001_snapshot.json +0 -482
  164. package/drizzle/meta/0002_snapshot.json +0 -575
  165. package/drizzle/meta/0003_snapshot.json +0 -667
  166. package/drizzle/meta/0004_snapshot.json +0 -769
  167. package/drizzle/meta/0005_snapshot.json +0 -864
  168. package/drizzle/meta/0006_snapshot.json +0 -882
  169. package/drizzle/meta/0007_snapshot.json +0 -876
  170. package/drizzle/meta/0008_snapshot.json +0 -882
  171. package/drizzle/meta/0009_snapshot.json +0 -948
  172. package/drizzle/meta/0010_snapshot.json +0 -969
  173. package/drizzle/meta/0011_snapshot.json +0 -1049
  174. package/drizzle/meta/0012_snapshot.json +0 -1115
  175. package/drizzle/meta/0013_snapshot.json +0 -1121
  176. package/drizzle/meta/0014_snapshot.json +0 -1190
  177. package/drizzle/meta/0015_snapshot.json +0 -1280
  178. package/drizzle/meta/0016_snapshot.json +0 -1683
  179. package/drizzle/meta/0017_snapshot.json +0 -1834
  180. package/drizzle/meta/0018_snapshot.json +0 -1834
  181. package/drizzle/meta/0019_snapshot.json +0 -1909
  182. package/drizzle/meta/0020_snapshot.json +0 -1921
  183. package/drizzle/meta/0021_snapshot.json +0 -2045
  184. package/drizzle/meta/0022_snapshot.json +0 -2246
  185. package/drizzle/meta/0023_snapshot.json +0 -2252
  186. package/drizzle/meta/0024_snapshot.json +0 -2375
  187. package/drizzle/meta/0025_snapshot.json +0 -2407
  188. package/drizzle/meta/0026_snapshot.json +0 -2413
  189. package/drizzle/meta/0027_snapshot.json +0 -2425
  190. package/drizzle/meta/0028_snapshot.json +0 -2438
  191. package/drizzle/meta/0029_snapshot.json +0 -2546
  192. package/drizzle/meta/0030_snapshot.json +0 -2586
  193. package/drizzle/meta/0031_snapshot.json +0 -2598
  194. package/drizzle/meta/0032_snapshot.json +0 -2699
  195. package/drizzle/meta/0033_snapshot.json +0 -2712
  196. package/drizzle/meta/0034_snapshot.json +0 -2719
  197. package/drizzle/meta/0035_snapshot.json +0 -2726
  198. package/drizzle/meta/0036_snapshot.json +0 -2876
  199. package/drizzle/meta/0037_snapshot.json +0 -2883
  200. package/drizzle/meta/0038_snapshot.json +0 -2895
  201. package/drizzle/meta/0039_snapshot.json +0 -3501
  202. package/drizzle/meta/0040_snapshot.json +0 -3527
  203. package/drizzle/meta/0041_snapshot.json +0 -3824
  204. package/drizzle/meta/0042_snapshot.json +0 -3960
  205. package/drizzle/meta/_journal.json +0 -307
  206. 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
+ };