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,483 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ packageRoot
4
+ } from "./chunk-LUAKDHLZ.js";
5
+ import {
6
+ logger
7
+ } from "./chunk-MYGSLK44.js";
8
+ import {
9
+ lurqHome,
10
+ resolveApiKey
11
+ } from "./chunk-Y5GI7RL3.js";
12
+ import {
13
+ DEFAULT_ENDPOINT,
14
+ PACKAGE_NAME
15
+ } from "./chunk-GPTKSNR6.js";
16
+ import {
17
+ init_esm_shims
18
+ } from "./chunk-I3M2KJXB.js";
19
+
20
+ // src/cli/installSkill.ts
21
+ init_esm_shims();
22
+ import {
23
+ accessSync,
24
+ chmodSync,
25
+ constants,
26
+ existsSync,
27
+ mkdirSync,
28
+ readFileSync,
29
+ realpathSync,
30
+ renameSync,
31
+ rmSync,
32
+ statSync,
33
+ writeFileSync
34
+ } from "fs";
35
+ import { copyFileSync } from "fs";
36
+ import { homedir } from "os";
37
+ import { delimiter, dirname, join } from "path";
38
+ var ENV_KEYS = [
39
+ "DATABASE_URL",
40
+ "GITHUB_TOKEN",
41
+ "EMBEDDING_PROVIDER",
42
+ "EMBEDDING_API_KEY",
43
+ "EMBEDDING_MODEL",
44
+ "SUMMARY_PROVIDER",
45
+ "SUMMARY_API_KEY",
46
+ "SUMMARY_MODEL"
47
+ ];
48
+ function home(...p) {
49
+ return join(homedir(), ...p);
50
+ }
51
+ function vscodeUserDir() {
52
+ if (process.platform === "darwin") return home("Library", "Application Support", "Code", "User");
53
+ if (process.platform === "win32") {
54
+ return join(process.env.APPDATA ?? home("AppData", "Roaming"), "Code", "User");
55
+ }
56
+ return join(process.env.XDG_CONFIG_HOME || home(".config"), "Code", "User");
57
+ }
58
+ function agentSpecs() {
59
+ return [
60
+ {
61
+ id: "claude-code",
62
+ label: "Claude Code",
63
+ format: "mcpServers",
64
+ path: home(".claude.json"),
65
+ detected: existsSync(home(".claude.json")) || existsSync(home(".claude")),
66
+ // Personal skills are read from ~/.claude/skills/<name>/SKILL.md and apply
67
+ // across every project, which is exactly the scope a global install wants.
68
+ instructions: { kind: "skill", path: home(".claude", "skills", "lurq", "SKILL.md") }
69
+ },
70
+ {
71
+ // No instructions target: Cursor's user-level rules live in its settings
72
+ // UI, not a file on disk, and its `.cursor/rules/*.mdc` files are
73
+ // per-project, so there is nothing a machine-wide install can write once.
74
+ // The MCP tool descriptions carry the guidance here.
75
+ id: "cursor",
76
+ label: "Cursor",
77
+ format: "mcpServers",
78
+ path: home(".cursor", "mcp.json"),
79
+ detected: existsSync(home(".cursor"))
80
+ },
81
+ {
82
+ id: "windsurf",
83
+ label: "Windsurf",
84
+ format: "mcpServers",
85
+ path: home(".codeium", "windsurf", "mcp_config.json"),
86
+ detected: existsSync(home(".codeium")),
87
+ instructions: {
88
+ kind: "shared",
89
+ path: home(".codeium", "windsurf", "memories", "global_rules.md")
90
+ }
91
+ },
92
+ {
93
+ // No instructions target, for two reasons that compound. A
94
+ // `.instructions.md` file is only applied automatically when its
95
+ // frontmatter carries an `applyTo` glob; without one, VS Code requires the
96
+ // user to attach it to a request by hand. And the user-profile directory
97
+ // that gets scanned is not a documented default at all: the workspace
98
+ // default is `.github/instructions`, and profile-level folders come from
99
+ // the `chat.instructionsFilesLocations` setting. Guessing the path would
100
+ // write a file nobody reads while reporting success, which is the same
101
+ // mistake the hardcoded macOS config path made above.
102
+ id: "copilot",
103
+ label: "VS Code / GitHub Copilot",
104
+ format: "servers",
105
+ path: join(vscodeUserDir(), "mcp.json"),
106
+ detected: existsSync(vscodeUserDir())
107
+ },
108
+ {
109
+ id: "codex",
110
+ label: "OpenAI Codex CLI",
111
+ format: "toml",
112
+ path: home(".codex", "config.toml"),
113
+ detected: existsSync(home(".codex")),
114
+ instructions: { kind: "shared", path: home(".codex", "AGENTS.md") }
115
+ },
116
+ {
117
+ id: "gemini-cli",
118
+ label: "Gemini CLI",
119
+ format: "mcpServers",
120
+ path: home(".gemini", "settings.json"),
121
+ detected: existsSync(home(".gemini", "settings.json")),
122
+ // ~/.gemini/GEMINI.md is the global tier of the context hierarchy, loaded
123
+ // ahead of any workspace file.
124
+ instructions: { kind: "shared", path: home(".gemini", "GEMINI.md") }
125
+ },
126
+ {
127
+ // Shares the ~/.gemini root with the Gemini CLI but keeps its own file, so
128
+ // detection has to look at the file rather than at the directory. It reads
129
+ // the same global GEMINI.md; upserting the block twice is a no-op, so
130
+ // having both selected is harmless.
131
+ id: "antigravity",
132
+ label: "Google Antigravity",
133
+ format: "mcpServers",
134
+ path: home(".gemini", "config", "mcp_config.json"),
135
+ detected: existsSync(home(".gemini", "config")),
136
+ instructions: { kind: "shared", path: home(".gemini", "GEMINI.md") }
137
+ },
138
+ {
139
+ id: "kiro",
140
+ label: "Kiro",
141
+ format: "mcpServers",
142
+ path: home(".kiro", "settings", "mcp.json"),
143
+ detected: existsSync(home(".kiro")),
144
+ // Steering files in ~/.kiro/steering apply to every workspace and are
145
+ // always included.
146
+ instructions: { kind: "file", path: home(".kiro", "steering", "lurq.md") }
147
+ }
148
+ ];
149
+ }
150
+ var SUPPORTED_AGENTS = [
151
+ "claude-code",
152
+ "cursor",
153
+ "windsurf",
154
+ "copilot",
155
+ "codex",
156
+ "gemini-cli",
157
+ "antigravity",
158
+ "kiro"
159
+ ];
160
+ function collectEnv() {
161
+ const env = {};
162
+ for (const key of ENV_KEYS) {
163
+ const value = process.env[key];
164
+ if (value) env[key] = value;
165
+ }
166
+ return env;
167
+ }
168
+ function readJsonObject(path) {
169
+ if (!existsSync(path)) return {};
170
+ const text = readFileSync(path, "utf8").trim();
171
+ if (!text) return {};
172
+ try {
173
+ return JSON.parse(text);
174
+ } catch (err) {
175
+ throw new Error(
176
+ `${path} is not plain JSON (${err instanceof Error ? err.message : String(err)}). If it has comments or trailing commas, lurq will not rewrite it and lose them: remove them and re-run, or edit the "lurq" server entry by hand.`
177
+ );
178
+ }
179
+ }
180
+ var KEY_FILE_MODE = 384;
181
+ function writeFileAtomic(path, contents, newFileMode = KEY_FILE_MODE) {
182
+ let target = path;
183
+ let mode = newFileMode;
184
+ try {
185
+ target = realpathSync(path);
186
+ mode = statSync(target).mode & 511;
187
+ } catch {
188
+ }
189
+ mkdirSync(dirname(target), { recursive: true });
190
+ const tmp = `${target}.lurq-${process.pid}.tmp`;
191
+ try {
192
+ writeFileSync(tmp, contents, { encoding: "utf8", mode });
193
+ chmodSync(tmp, mode);
194
+ renameSync(tmp, target);
195
+ } catch (err) {
196
+ try {
197
+ rmSync(tmp, { force: true });
198
+ } catch {
199
+ }
200
+ throw err;
201
+ }
202
+ }
203
+ function writeJson(path, obj) {
204
+ writeFileAtomic(path, JSON.stringify(obj, null, 2) + "\n");
205
+ }
206
+ function buildServerEntry(env, withType) {
207
+ const entry = { command: "npx", args: ["-y", PACKAGE_NAME, "serve"] };
208
+ if (withType) entry.type = "stdio";
209
+ if (Object.keys(env).length) entry.env = env;
210
+ return entry;
211
+ }
212
+ function buildRemoteServerEntry(agentId, opts) {
213
+ const headers = { Authorization: `Bearer ${opts.apiKey}` };
214
+ switch (agentId) {
215
+ case "cursor":
216
+ case "kiro":
217
+ return { url: opts.url, headers };
218
+ case "windsurf":
219
+ case "antigravity":
220
+ return { serverUrl: opts.url, headers };
221
+ case "gemini-cli":
222
+ return { httpUrl: opts.url, headers };
223
+ case "claude-code":
224
+ case "copilot":
225
+ default:
226
+ return { type: "http", url: opts.url, headers };
227
+ }
228
+ }
229
+ function buildTomlBlock(env) {
230
+ const lines = ["[mcp_servers.lurq]", 'command = "npx"', `args = ["-y", "${PACKAGE_NAME}", "serve"]`];
231
+ if (Object.keys(env).length) {
232
+ lines.push("", "[mcp_servers.lurq.env]");
233
+ for (const [k, v] of Object.entries(env)) lines.push(`${k} = ${JSON.stringify(v)}`);
234
+ }
235
+ return lines.join("\n") + "\n";
236
+ }
237
+ function buildRemoteTomlBlock(opts) {
238
+ return [
239
+ "[mcp_servers.lurq]",
240
+ `url = ${JSON.stringify(opts.url)}`,
241
+ `http_headers = { Authorization = ${JSON.stringify(`Bearer ${opts.apiKey}`)} }`
242
+ ].join("\n") + "\n";
243
+ }
244
+ function installJsonEntry(spec, entry) {
245
+ const key = spec.format === "servers" ? "servers" : "mcpServers";
246
+ const config = readJsonObject(spec.path);
247
+ if (typeof config[key] !== "object" || config[key] === null) config[key] = {};
248
+ config[key].lurq = entry;
249
+ writeJson(spec.path, config);
250
+ return { agent: spec.id, path: spec.path, status: "installed" };
251
+ }
252
+ function stripTomlBlock(text, header = "[mcp_servers.lurq]") {
253
+ const lines = text.split("\n");
254
+ const start = lines.findIndex((l) => l.trim() === header);
255
+ if (start === -1) return text;
256
+ let end = start + 1;
257
+ while (end < lines.length) {
258
+ const t = lines[end].trim();
259
+ if (t.startsWith("[") && !t.startsWith(`${header.slice(0, -1)}.`)) break;
260
+ end++;
261
+ }
262
+ return [...lines.slice(0, start), ...lines.slice(end)].join("\n").replace(/\n{3,}/g, "\n\n");
263
+ }
264
+ function installTomlBlock(spec, block) {
265
+ const current = existsSync(spec.path) ? readFileSync(spec.path, "utf8") : "";
266
+ const existing = stripTomlBlock(current).replace(/\s+$/, "");
267
+ const sep = existing ? "\n\n" : "";
268
+ writeFileAtomic(spec.path, existing + sep + block);
269
+ return {
270
+ agent: spec.id,
271
+ path: spec.path,
272
+ status: "installed",
273
+ message: current.includes("[mcp_servers.lurq]") ? "replaced the existing lurq entry" : void 0
274
+ };
275
+ }
276
+ var BLOCK_START = "<!-- lurq:start -->";
277
+ var BLOCK_END = "<!-- lurq:end -->";
278
+ var SKILL_DESCRIPTION = "Get current, evidence-scored facts about npm packages instead of recalling them. Use before adding, choosing, comparing, or upgrading any JS/TS dependency, before hand-rolling something a package may already do, and before writing code against a package API that may have moved since training. Covers hallucinated and typosquatted package names, advisories, version-exact export surfaces, and stack compatibility.";
279
+ function template(name) {
280
+ const src = join(packageRoot(), "templates", name);
281
+ return existsSync(src) ? readFileSync(src, "utf8") : null;
282
+ }
283
+ function upsertMarkedBlock(text, block) {
284
+ const wrapped = `${BLOCK_START}
285
+ ${block.trim()}
286
+ ${BLOCK_END}`;
287
+ const start = text.indexOf(BLOCK_START);
288
+ if (start === -1) {
289
+ const existing = text.replace(/\s+$/, "");
290
+ return existing ? `${existing}
291
+
292
+ ${wrapped}
293
+ ` : `${wrapped}
294
+ `;
295
+ }
296
+ const endAt = text.indexOf(BLOCK_END, start);
297
+ const after = endAt === -1 ? "" : text.slice(endAt + BLOCK_END.length);
298
+ return `${text.slice(0, start)}${wrapped}${after.replace(/^\n*/, "\n")}`;
299
+ }
300
+ function removeMarkedBlock(text) {
301
+ const start = text.indexOf(BLOCK_START);
302
+ if (start === -1) return text;
303
+ const endAt = text.indexOf(BLOCK_END, start);
304
+ const before = text.slice(0, start).replace(/\s+$/, "");
305
+ const after = endAt === -1 ? "" : text.slice(endAt + BLOCK_END.length).replace(/^\s+/, "");
306
+ const joined = [before, after].filter(Boolean).join("\n\n");
307
+ return joined ? joined.replace(/\s*$/, "\n") : "";
308
+ }
309
+ function buildSkillFile(guide) {
310
+ return [
311
+ "---",
312
+ "name: lurq",
313
+ `description: ${SKILL_DESCRIPTION}`,
314
+ "---",
315
+ "",
316
+ guide.trim(),
317
+ ""
318
+ ].join("\n");
319
+ }
320
+ function installInstructions(spec) {
321
+ const target = spec.instructions;
322
+ if (!target) return null;
323
+ if (target.kind === "shared") {
324
+ const brief = template("agent-rules.md");
325
+ if (!brief) return null;
326
+ const current = existsSync(target.path) ? readFileSync(target.path, "utf8") : "";
327
+ writeFileAtomic(target.path, upsertMarkedBlock(current, brief), 420);
328
+ return target.path;
329
+ }
330
+ const guide = template("skill-instructions.md");
331
+ if (!guide) return null;
332
+ writeFileAtomic(target.path, target.kind === "skill" ? buildSkillFile(guide) : guide, 420);
333
+ return target.path;
334
+ }
335
+ function installAgent(spec, mode) {
336
+ try {
337
+ const result = spec.format === "toml" ? installTomlBlock(
338
+ spec,
339
+ mode.kind === "remote" ? buildRemoteTomlBlock(mode) : buildTomlBlock(mode.env)
340
+ ) : installJsonEntry(
341
+ spec,
342
+ mode.kind === "remote" ? buildRemoteServerEntry(spec.id, mode) : buildServerEntry(mode.env, spec.format === "servers")
343
+ );
344
+ try {
345
+ result.instructionsPath = installInstructions(spec) ?? void 0;
346
+ } catch (err) {
347
+ result.message = `MCP entry written; instructions file failed: ${err instanceof Error ? err.message : String(err)}`;
348
+ }
349
+ return result;
350
+ } catch (err) {
351
+ return {
352
+ agent: spec.id,
353
+ path: spec.path,
354
+ status: "error",
355
+ message: err instanceof Error ? err.message : String(err)
356
+ };
357
+ }
358
+ }
359
+ function installInstructionsFile() {
360
+ const src = join(packageRoot(), "templates", "skill-instructions.md");
361
+ if (!existsSync(src)) return null;
362
+ const destDir = lurqHome();
363
+ const dest = join(destDir, "skill-instructions.md");
364
+ mkdirSync(destDir, { recursive: true });
365
+ copyFileSync(src, dest);
366
+ return dest;
367
+ }
368
+ function resolveAgents(target) {
369
+ const specs = agentSpecs();
370
+ if (target === "all") return specs.filter((s) => s.detected);
371
+ const spec = specs.find((s) => s.id === target);
372
+ if (!spec) {
373
+ throw new Error(`Unknown agent "${target}". Supported: ${SUPPORTED_AGENTS.join(", ")}, all.`);
374
+ }
375
+ return [spec];
376
+ }
377
+ function lurqInvocation() {
378
+ const candidates = process.platform === "win32" ? [".cmd", ".exe", ""] : [""];
379
+ for (const dir of (process.env.PATH ?? "").split(delimiter)) {
380
+ if (!dir) continue;
381
+ for (const ext of candidates) {
382
+ try {
383
+ accessSync(join(dir, `lurq${ext}`), constants.X_OK);
384
+ return { command: "lurq", onPath: true };
385
+ } catch {
386
+ }
387
+ }
388
+ }
389
+ return { command: `npx ${PACKAGE_NAME}`, onPath: false };
390
+ }
391
+ function printInstallReport(results, instructionsPath, mode) {
392
+ const specs = agentSpecs();
393
+ const short = (p) => p.startsWith(homedir()) ? `~${p.slice(homedir().length)}` : p;
394
+ console.log("lurq MCP server registration:");
395
+ for (const r of results) {
396
+ const spec = specs.find((s) => s.id === r.agent);
397
+ const mark = r.status === "installed" ? "\u2713" : r.status === "skipped" ? "\u2022" : "\u2717";
398
+ console.log(
399
+ ` ${mark} ${spec.label.padEnd(26)} ${short(r.path)}${r.message ? ` (${r.message})` : ""}`
400
+ );
401
+ }
402
+ const withSkills = results.filter((r) => r.instructionsPath);
403
+ if (withSkills.length) {
404
+ console.log("\nAgent instructions (so it reaches for lurq on its own):");
405
+ for (const r of withSkills) {
406
+ const spec = specs.find((s) => s.id === r.agent);
407
+ console.log(` \u2713 ${spec.label.padEnd(26)} ${short(r.instructionsPath)}`);
408
+ }
409
+ }
410
+ if (instructionsPath) console.log(`
411
+ Full guide: ${short(instructionsPath)}`);
412
+ console.log("\nNext steps:");
413
+ if (mode.kind === "local") {
414
+ console.log(" 1. Ensure DATABASE_URL (and any API keys) are set in the config env above.");
415
+ console.log(" 2. Restart the agent so it picks up the new MCP server.");
416
+ } else {
417
+ console.log(" 1. Restart the agent so it picks up the new MCP server.");
418
+ }
419
+ console.log(" \u2022 Ask it to add a package. It should check the package with lurq first.");
420
+ const { command, onPath } = lurqInvocation();
421
+ console.log(` \u2022 Or use the terminal directly: \`${command} verify zod\`.`);
422
+ if (!onPath) {
423
+ console.log(`
424
+ There is no \`lurq\` command on this machine yet. Everything above`);
425
+ console.log(" worked and your agents are wired up; only the terminal shortcut is");
426
+ console.log(` missing, so use \`npx ${PACKAGE_NAME} <command>\`. To get \`lurq\` itself:`);
427
+ console.log(` npm install -g ${PACKAGE_NAME}`);
428
+ }
429
+ }
430
+ async function runInstallSkill(opts) {
431
+ const selected = resolveAgents(opts.agent ?? "claude-code");
432
+ if (selected.length === 0) {
433
+ console.log("No supported agents detected on this machine.");
434
+ return;
435
+ }
436
+ const remote = !opts.local;
437
+ let mode;
438
+ if (remote) {
439
+ const apiKey = resolveApiKey(opts.apiKey);
440
+ if (!apiKey) {
441
+ throw new Error(
442
+ "An API key is required for a hosted install. Pass --api-key <key> (or set LURQ_API_KEY), or run `lurq setup` for the guided setup, or --local to self-host."
443
+ );
444
+ }
445
+ const url = opts.url ?? process.env.LURQ_ENDPOINT ?? DEFAULT_ENDPOINT;
446
+ mode = { kind: "remote", url, apiKey };
447
+ } else {
448
+ const env = collectEnv();
449
+ if (!env.DATABASE_URL) {
450
+ logger.warn(
451
+ "DATABASE_URL is not set, the local server entry will have no DATABASE_URL. Set it (in .env) and re-run, or edit the config."
452
+ );
453
+ }
454
+ mode = { kind: "local", env };
455
+ }
456
+ const results = selected.map((spec) => installAgent(spec, mode));
457
+ const instructionsPath = installInstructionsFile();
458
+ printInstallReport(results, instructionsPath, mode);
459
+ }
460
+
461
+ export {
462
+ agentSpecs,
463
+ SUPPORTED_AGENTS,
464
+ readJsonObject,
465
+ writeFileAtomic,
466
+ writeJson,
467
+ buildServerEntry,
468
+ buildRemoteServerEntry,
469
+ buildTomlBlock,
470
+ buildRemoteTomlBlock,
471
+ stripTomlBlock,
472
+ BLOCK_START,
473
+ upsertMarkedBlock,
474
+ removeMarkedBlock,
475
+ buildSkillFile,
476
+ installInstructions,
477
+ installAgent,
478
+ installInstructionsFile,
479
+ resolveAgents,
480
+ lurqInvocation,
481
+ printInstallReport,
482
+ runInstallSkill
483
+ };
@@ -0,0 +1,109 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ MCP_TIER,
4
+ contractOf,
5
+ resolveAnnotations
6
+ } from "./chunk-6EQ3ARXA.js";
7
+ import {
8
+ init_esm_shims
9
+ } from "./chunk-I3M2KJXB.js";
10
+
11
+ // src/compat/mcpStack.ts
12
+ init_esm_shims();
13
+ var TOKENS_PER_TOOL = 250;
14
+ var CROWDED_TOOL_COUNT = 60;
15
+ var NPM_NAME = /^(?:@[a-z0-9-][a-z0-9-._]*\/)?[a-z0-9-][a-z0-9-._]*$/;
16
+ async function loadStackMembers(db, servers, tenantId = 0) {
17
+ const out = [];
18
+ for (const s of servers) {
19
+ if (s.tools) {
20
+ out.push({
21
+ server: s.server,
22
+ version: s.version,
23
+ tools: s.tools.map((t) => ({ name: t.name, annotations: resolveAnnotations(t.annotations) }))
24
+ });
25
+ continue;
26
+ }
27
+ const [{ enqueueSurface }, { loadStored, rowsToSurface }] = await Promise.all([
28
+ import("./surface-YL6O67W3.js"),
29
+ import("./surfaceHandlers-X2IZKA3E.js")
30
+ ]);
31
+ const stored = await loadStored(db, s.server, s.version, tenantId, "mcp_server");
32
+ if (!stored || stored.rows.length === 0 || stored.verdict === "verified_false") {
33
+ if (stored?.verdict !== "verified_false" && NPM_NAME.test(s.server)) {
34
+ await enqueueSurface(db, s.server, s.version, "mcp_server").catch(() => {
35
+ });
36
+ }
37
+ out.push({ server: s.server, version: s.version, tools: null });
38
+ continue;
39
+ }
40
+ const surface = rowsToSurface(s.server, s.version, stored.rows, MCP_TIER);
41
+ out.push({
42
+ server: s.server,
43
+ version: s.version,
44
+ // A symbol written by an older extractor has no contract; the spec
45
+ // defaults (writes, destroys) are the honest reading of "we don't know".
46
+ tools: surface.symbols.map((sym) => ({
47
+ name: sym.path,
48
+ annotations: contractOf(sym)?.annotations ?? resolveAnnotations(null)
49
+ }))
50
+ });
51
+ }
52
+ return out;
53
+ }
54
+ function analyzeStack(inputs) {
55
+ const members = [];
56
+ const unread = [];
57
+ const byTool = /* @__PURE__ */ new Map();
58
+ for (const m of inputs) {
59
+ if (!m.tools) {
60
+ unread.push(m.server);
61
+ members.push({ server: m.server, version: m.version, tools: null, writes: 0, destroys: 0 });
62
+ continue;
63
+ }
64
+ let writes = 0;
65
+ let destroys = 0;
66
+ for (const t of m.tools) {
67
+ const canWrite = !t.annotations.readOnlyHint;
68
+ if (canWrite) writes++;
69
+ if (t.annotations.destructiveHint) destroys++;
70
+ const seen = byTool.get(t.name);
71
+ if (seen) {
72
+ if (!seen.servers.includes(m.server)) seen.servers.push(m.server);
73
+ seen.writes ||= canWrite;
74
+ } else {
75
+ byTool.set(t.name, { servers: [m.server], writes: canWrite });
76
+ }
77
+ }
78
+ members.push({ server: m.server, version: m.version, tools: m.tools.length, writes, destroys });
79
+ }
80
+ const collisions = [...byTool.entries()].filter(([, v]) => v.servers.length > 1).map(([tool, v]) => ({ tool, servers: v.servers, writes: v.writes })).sort((a, b) => a.tool < b.tool ? -1 : 1);
81
+ const readMembers = members.filter((m) => m.tools !== null);
82
+ const totalTools = unread.length ? null : readMembers.reduce((n, m) => n + (m.tools ?? 0), 0);
83
+ const overall = collisions.length > 0 ? "conflict" : unread.length > 0 ? "unknown" : "compatible";
84
+ const note = collisions.length > 0 ? `${collisions.length} tool name(s) are exposed by more than one server; the agent has no way to say which one it means` : unread.length > 0 ? `${unread.length} server(s) have not been probed, so the namespace was only partly assembled \u2014 this is NOT a clean bill` : `${totalTools} tool(s) across ${readMembers.length} server(s), no name collisions`;
85
+ return {
86
+ overall,
87
+ members,
88
+ collisions,
89
+ totalTools,
90
+ estimatedContextTokens: totalTools === null ? null : totalTools * TOKENS_PER_TOOL,
91
+ unread,
92
+ note
93
+ };
94
+ }
95
+ async function checkMcpStack(db, servers, tenantId = 0) {
96
+ return analyzeStack(await loadStackMembers(db, servers, tenantId));
97
+ }
98
+ function isCrowded(report) {
99
+ return (report.totalTools ?? 0) >= CROWDED_TOOL_COUNT;
100
+ }
101
+
102
+ export {
103
+ TOKENS_PER_TOOL,
104
+ CROWDED_TOOL_COUNT,
105
+ loadStackMembers,
106
+ analyzeStack,
107
+ checkMcpStack,
108
+ isCrowded
109
+ };
@@ -0,0 +1,58 @@
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/types.ts
7
+ init_esm_shims();
8
+ var DEFAULT_ECOSYSTEM = "npm";
9
+ var CATEGORIES = [
10
+ "framework",
11
+ "meta-framework",
12
+ "state-management",
13
+ "routing",
14
+ "orm",
15
+ "database-client",
16
+ "ui-component-library",
17
+ "styling",
18
+ "forms",
19
+ "validation",
20
+ "data-fetching",
21
+ "http-client",
22
+ "auth",
23
+ "testing",
24
+ "build-tool",
25
+ "bundler",
26
+ "linting",
27
+ "date-time",
28
+ "animation",
29
+ "charts",
30
+ "i18n",
31
+ "utility",
32
+ "other"
33
+ ];
34
+ function isCategory(value) {
35
+ return CATEGORIES.includes(value);
36
+ }
37
+ var FRONTEND_CATEGORIES = [
38
+ "ui-component-library",
39
+ "styling",
40
+ "state-management",
41
+ "forms",
42
+ "validation",
43
+ "data-fetching",
44
+ "charts",
45
+ "animation",
46
+ "date-time",
47
+ "utility"
48
+ ];
49
+ function isFrontendCategory(category) {
50
+ return category != null && FRONTEND_CATEGORIES.includes(category);
51
+ }
52
+
53
+ export {
54
+ DEFAULT_ECOSYSTEM,
55
+ CATEGORIES,
56
+ isCategory,
57
+ isFrontendCategory
58
+ };