@creeperhost/modlens-mcp 1.6.20 → 1.6.22

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 (116) hide show
  1. package/ATTRIBUTION.md +8 -1
  2. package/README.md +77 -2
  3. package/RUNTIME.md +262 -0
  4. package/TESTING.md +8 -0
  5. package/dist/hosted-mod-license.d.ts +36 -0
  6. package/dist/hosted-mod-license.d.ts.map +1 -0
  7. package/dist/hosted-mod-license.js +65 -0
  8. package/dist/hosted-mod-license.js.map +1 -0
  9. package/dist/hosted-oauth.d.ts +36 -0
  10. package/dist/hosted-oauth.d.ts.map +1 -0
  11. package/dist/hosted-oauth.js +522 -0
  12. package/dist/hosted-oauth.js.map +1 -0
  13. package/dist/hosted-policy.d.ts +36 -0
  14. package/dist/hosted-policy.d.ts.map +1 -0
  15. package/dist/hosted-policy.js +354 -0
  16. package/dist/hosted-policy.js.map +1 -0
  17. package/dist/launcher.js +104 -89
  18. package/dist/launcher.js.map +1 -1
  19. package/dist/license-notices.d.ts +8 -0
  20. package/dist/license-notices.d.ts.map +1 -0
  21. package/dist/license-notices.js +10 -0
  22. package/dist/license-notices.js.map +1 -0
  23. package/dist/license-source-references.d.ts +12 -0
  24. package/dist/license-source-references.d.ts.map +1 -0
  25. package/dist/license-source-references.js +18 -0
  26. package/dist/license-source-references.js.map +1 -0
  27. package/dist/license-templates.d.ts +6 -0
  28. package/dist/license-templates.d.ts.map +1 -0
  29. package/dist/license-templates.js +55 -0
  30. package/dist/license-templates.js.map +1 -0
  31. package/dist/local-mod.d.ts +31 -0
  32. package/dist/local-mod.d.ts.map +1 -0
  33. package/dist/local-mod.js +71 -0
  34. package/dist/local-mod.js.map +1 -0
  35. package/dist/minecraft.d.ts +2 -0
  36. package/dist/minecraft.d.ts.map +1 -1
  37. package/dist/minecraft.js +16 -0
  38. package/dist/minecraft.js.map +1 -1
  39. package/dist/mod-license.d.ts +53 -0
  40. package/dist/mod-license.d.ts.map +1 -0
  41. package/dist/mod-license.js +617 -0
  42. package/dist/mod-license.js.map +1 -0
  43. package/dist/repositories/mcVersion.d.ts +1 -0
  44. package/dist/repositories/mcVersion.d.ts.map +1 -1
  45. package/dist/repositories/mcVersion.js +11 -0
  46. package/dist/repositories/mcVersion.js.map +1 -1
  47. package/dist/runtime/cli.d.ts +2 -0
  48. package/dist/runtime/cli.d.ts.map +1 -0
  49. package/dist/runtime/cli.js +163 -0
  50. package/dist/runtime/cli.js.map +1 -0
  51. package/dist/runtime/companion.d.ts +32 -0
  52. package/dist/runtime/companion.d.ts.map +1 -0
  53. package/dist/runtime/companion.js +135 -0
  54. package/dist/runtime/companion.js.map +1 -0
  55. package/dist/runtime/guidance.d.ts +73 -0
  56. package/dist/runtime/guidance.d.ts.map +1 -0
  57. package/dist/runtime/guidance.js +40 -0
  58. package/dist/runtime/guidance.js.map +1 -0
  59. package/dist/runtime/hub.d.ts +150 -0
  60. package/dist/runtime/hub.d.ts.map +1 -0
  61. package/dist/runtime/hub.js +561 -0
  62. package/dist/runtime/hub.js.map +1 -0
  63. package/dist/runtime/modlens-agent.jar +0 -0
  64. package/dist/runtime/protocol.d.ts +202 -0
  65. package/dist/runtime/protocol.d.ts.map +1 -0
  66. package/dist/runtime/protocol.js +91 -0
  67. package/dist/runtime/protocol.js.map +1 -0
  68. package/dist/runtime/requests.d.ts +367 -0
  69. package/dist/runtime/requests.d.ts.map +1 -0
  70. package/dist/runtime/requests.js +57 -0
  71. package/dist/runtime/requests.js.map +1 -0
  72. package/dist/server.js +186 -39
  73. package/dist/server.js.map +1 -1
  74. package/dist/tools/hosted-mc-index.d.ts +8 -0
  75. package/dist/tools/hosted-mc-index.d.ts.map +1 -0
  76. package/dist/tools/hosted-mc-index.js +92 -0
  77. package/dist/tools/hosted-mc-index.js.map +1 -0
  78. package/dist/tools/mc-fts.d.ts +2 -0
  79. package/dist/tools/mc-fts.d.ts.map +1 -1
  80. package/dist/tools/mc-fts.js +8 -0
  81. package/dist/tools/mc-fts.js.map +1 -1
  82. package/dist/tools/project.d.ts +7 -3
  83. package/dist/tools/project.d.ts.map +1 -1
  84. package/dist/tools/project.js +45 -3
  85. package/dist/tools/project.js.map +1 -1
  86. package/dist/tools/report-issue.d.ts +77 -0
  87. package/dist/tools/report-issue.d.ts.map +1 -0
  88. package/dist/tools/report-issue.js +92 -0
  89. package/dist/tools/report-issue.js.map +1 -0
  90. package/dist/tools/runtime.d.ts +6 -0
  91. package/dist/tools/runtime.d.ts.map +1 -0
  92. package/dist/tools/runtime.js +18 -0
  93. package/dist/tools/runtime.js.map +1 -0
  94. package/dist/tools/source.d.ts +1 -1
  95. package/dist/tools/source.d.ts.map +1 -1
  96. package/dist/tools/source.js +5 -1
  97. package/dist/tools/source.js.map +1 -1
  98. package/dist/tools/vanilla.d.ts +30 -1
  99. package/dist/tools/vanilla.d.ts.map +1 -1
  100. package/dist/tools/vanilla.js +184 -25
  101. package/dist/tools/vanilla.js.map +1 -1
  102. package/package.json +5 -1
  103. package/scripts/build-runtime-agent.mjs +64 -0
  104. package/scripts/fixtures/mod-license-corpus.json +154 -0
  105. package/scripts/gradle/modlens-runtime.init.gradle +17 -0
  106. package/scripts/runtime-test-client.mjs +36 -0
  107. package/scripts/test-hosted-oauth.mjs +186 -0
  108. package/scripts/test-hosted-policy.mjs +182 -0
  109. package/scripts/test-mod-licenses-live.mjs +86 -0
  110. package/scripts/test-package.mjs +44 -0
  111. package/scripts/test-project-http.mjs +46 -3
  112. package/scripts/test-runtime-gradle.mjs +107 -0
  113. package/scripts/test-runtime-minecraft.mjs +190 -0
  114. package/scripts/test-runtime-native.mjs +120 -0
  115. package/scripts/test-runtime-remote.mjs +209 -0
  116. package/scripts/update-license-templates.mjs +14 -0
@@ -0,0 +1,354 @@
1
+ import { createHash, timingSafeEqual } from "node:crypto";
2
+ import { getDb } from "./db.js";
3
+ import { guardHostedMod, attachLicenseNotices } from "./hosted-mod-license.js";
4
+ export function hostedLimits(env = process.env) {
5
+ const number = (key, fallback) => {
6
+ if (env[key] === undefined)
7
+ return fallback;
8
+ const value = Number(env[key]);
9
+ if (!Number.isSafeInteger(value) || value < 1 || value > 1_000_000_000) {
10
+ throw new Error(`${key} must be a positive integer no larger than 1000000000`);
11
+ }
12
+ return value;
13
+ };
14
+ return {
15
+ lines: number("MODLENS_HOSTED_SOURCE_LINES", 200),
16
+ responseBytes: number("MODLENS_HOSTED_RESPONSE_BYTES", 128 * 1024),
17
+ dailyBytes: number("MODLENS_HOSTED_DAILY_BYTES", 5 * 1024 * 1024),
18
+ periodBytes: number("MODLENS_HOSTED_PERIOD_BYTES", 50 * 1024 * 1024),
19
+ dailyRequests: number("MODLENS_HOSTED_DAILY_REQUESTS", 1000),
20
+ minuteRequests: number("MODLENS_HOSTED_MINUTE_REQUESTS", 120),
21
+ };
22
+ }
23
+ export class HostedPolicyError extends Error {
24
+ }
25
+ /** Only an authenticated gateway may choose the stable account identifier. */
26
+ export function hostedPrincipal(headers, secret) {
27
+ if (!secret)
28
+ return "shared"; // Never trust user-supplied IDs, bearer tokens, IPs or session IDs.
29
+ const provided = headers["x-modlens-proxy-secret"];
30
+ const user = headers["x-modlens-user-id"];
31
+ const digest = (value) => createHash("sha256").update(value).digest();
32
+ if (typeof provided !== "string" || !timingSafeEqual(digest(provided), digest(secret))
33
+ || typeof user !== "string" || !user.trim() || user.length > 256 || /[\r\n\x00]/.test(user)) {
34
+ throw new HostedPolicyError("Authenticated gateway identity required.");
35
+ }
36
+ return digest(user).toString("hex");
37
+ }
38
+ /** Team claims are accepted only from the authenticated gateway. */
39
+ export function hostedMinecraftSourceTeams(env = process.env, secret) {
40
+ if (env.MODLENS_HOSTED_MC_SOURCE !== "1")
41
+ return new Set();
42
+ if (!secret || secret.length < 32)
43
+ throw new Error("MODLENS_HOSTED_MC_SOURCE requires MODLENS_HOSTED_PROXY_SECRET");
44
+ const teams = (env.MODLENS_HOSTED_MC_SOURCE_TEAMS ?? "").split(",").map(value => value.trim()).filter(Boolean);
45
+ if (!teams.length || teams.some(value => !/^[a-zA-Z0-9._:-]{1,128}$/.test(value))) {
46
+ throw new Error("MODLENS_HOSTED_MC_SOURCE_TEAMS requires valid comma-separated team IDs");
47
+ }
48
+ return new Set(teams);
49
+ }
50
+ export function hostedMinecraftSourceAccess(headers, teams) {
51
+ const team = headers["x-modlens-team-id"];
52
+ return typeof team === "string" && teams.has(team);
53
+ }
54
+ // Fail closed: new tools/actions must be reviewed before becoming remotely available.
55
+ // Cache population and filesystem/registry administration stay on the operator's local interface.
56
+ export const HOSTED_ACTIONS = {
57
+ report_issue: ["help", "prepare"],
58
+ runtime: ["help", "setup", "status", "sessions", "launch", "events", "command", "artifact"],
59
+ mod_license: ["check", "local_plan"],
60
+ mod: ["get", "search", "dependencies", "dep_graph", "version_conflicts", "source_urls", "decompile_class", "source", "search_source", "search_indexed", "search_semantic", "graph_query", "graph_report"],
61
+ mod_bytecode: ["search_class", "class_members", "bytecode", "find_refs", "cross_refs", "inheritance", "diff", "diff_detailed", "find_implementors", "scan_registrations", "annotated_by", "event_listeners", "optional_integrations", "network_payloads", "config_schema"],
62
+ mod_mixins: ["targets", "resolve", "conflicts", "targets_in_package", "at_conflicts", "at_entries", "aw_entries"],
63
+ platform: ["search", "check_updates", "batch_check_updates"],
64
+ modpacks_ch: ["search", "featured", "info", "manifest", "resolve_pack", "list_versions", "search_mods", "mod_info", "search_ftb_mods", "ftb_mod_info", "list_pack_versions", "list_pack_files", "find_mod_in_packs"],
65
+ mc_versions: ["list_mc", "list_neoforge", "list_forge", "list_fabric"],
66
+ mc_source: ["search_class", "source_info", "index_status", "get_source", "bytecode", "class_members", "find_refs", "inheritance", "diff", "diff_detailed", "search_code", "search_indexed", "search_events", "validate_aw", "analyze_mixin", "search_semantic"],
67
+ mappings: ["find", "parchment", "list_parchment", "parchment_summary"],
68
+ docs: ["get", "search", "list", "semantic_search"],
69
+ primers: ["get", "by_version", "search", "list", "semantic_search"],
70
+ mc_registry: ["blocks", "commands", "registries", "sounds", "item_components", "registry_entries", "mcmeta_versions"],
71
+ mc_data: ["tags", "find_tags_for", "recipes", "get_recipe", "find_recipes_for", "loot_tables", "get_loot_table", "lang", "blockstate", "model", "model_tree", "biomes", "get_biome", "damage_types", "enchantments", "get_enchantment", "advancements", "get_advancement", "structures", "get_structure", "particles", "get_particle", "entity_attributes"],
72
+ mc_files: ["get_data", "get_asset", "list_files", "diff", "atlas", "compare", "changelog"],
73
+ mod_jar: ["lang", "sounds", "atlas", "registry_entries", "manifest", "list_configs", "get_config"],
74
+ mod_data: ["list", "get", "diff", "trace_item"],
75
+ mod_tags: ["namespaces", "contributors", "expand", "mod_list", "find_conflicts", "search"],
76
+ mixin_scan: ["list_mods", "conflict_matrix", "class_detail", "hotspots"],
77
+ gradle: ["get_files", "search", "compare_deps"],
78
+ project: ["upload_begin", "upload_chunk", "upload_finish", "upload_abort", "list", "info", "classes", "source", "search", "members", "bytecode"],
79
+ reports: [""],
80
+ pack_tools: ["asset_conflicts", "vanilla_overrides", "sidedness", "pack_sidedness", "complexity", "pack_changelog", "data_conflicts", "health"],
81
+ analyze_crash_log: [""],
82
+ find_missing_deps: [""],
83
+ };
84
+ export function hostedActions(tool, allowMinecraftSource = false) {
85
+ const actions = HOSTED_ACTIONS[tool];
86
+ if (tool !== "mc_source" || allowMinecraftSource)
87
+ return actions;
88
+ return actions.filter(action => action !== "bytecode");
89
+ }
90
+ const rawSource = (tool, action) => (tool === "mc_source" && ["get_source", "bytecode"].includes(String(action)))
91
+ || (tool === "mod" && ["source", "decompile_class"].includes(String(action)))
92
+ || (tool === "mod_bytecode" && action === "bytecode")
93
+ || (tool === "project" && ["source", "bytecode"].includes(String(action)));
94
+ export function prepareHostedArgs(tool, input, limits, allowMinecraftSource = false) {
95
+ const args = { ...input };
96
+ if (!hostedActions(tool, allowMinecraftSource)?.includes(String(args.action ?? ""))) {
97
+ throw new HostedPolicyError("This operation is available only to the server operator locally.");
98
+ }
99
+ if (tool === "project" && !allowMinecraftSource && ["source", "bytecode"].includes(String(args.action))
100
+ && /^net[./]minecraft[./]/i.test(String(args.className ?? ""))) {
101
+ throw new HostedPolicyError("Minecraft source is unavailable on public hosted access.");
102
+ }
103
+ if (args.savePath !== undefined || args.scriptsDir !== undefined || args.configDir !== undefined) {
104
+ throw new HostedPolicyError("Host filesystem operations are unavailable remotely.");
105
+ }
106
+ if (tool === "mod_jar" && args.action === "get_config" && !/\.(?:json|json5|toml|cfg|conf|properties|ya?ml)$/i.test(String(args.path ?? ""))) {
107
+ throw new HostedPolicyError("Specify a configuration file path.");
108
+ }
109
+ if (tool === "mc_files" && args.branch !== undefined && !["data", "assets", "registries", "summary", "diff", "atlas"].includes(String(args.branch))) {
110
+ throw new HostedPolicyError("Unsupported data branch.");
111
+ }
112
+ for (const key of ["limit", "top", "budget"]) {
113
+ if (args[key] !== undefined) {
114
+ if (!Number.isSafeInteger(args[key]) || Number(args[key]) < 1)
115
+ throw new HostedPolicyError(`${key} must be a positive integer.`);
116
+ args[key] = Math.min(Number(args[key]), key === "budget" ? 2000 : 50);
117
+ }
118
+ }
119
+ if (rawSource(tool, args.action)) {
120
+ for (const key of ["startLine", "endLine", "maxLines"]) {
121
+ if (args[key] !== undefined && (!Number.isSafeInteger(args[key]) || Number(args[key]) < 1)) {
122
+ throw new HostedPolicyError(`${key} must be a positive integer.`);
123
+ }
124
+ }
125
+ const start = Number(args.startLine ?? 1);
126
+ if (start > Number.MAX_SAFE_INTEGER - limits.lines)
127
+ throw new HostedPolicyError("Invalid source range.");
128
+ if (args.endLine !== undefined && Number(args.endLine) < start)
129
+ throw new HostedPolicyError("Invalid source range.");
130
+ args.startLine = start;
131
+ args.maxLines = Math.min(Number(args.maxLines ?? limits.lines), limits.lines);
132
+ if (args.endLine !== undefined)
133
+ args.endLine = Math.min(Number(args.endLine), start + Number(args.maxLines) - 1);
134
+ }
135
+ // Keep exploration useful without unbounded empty searches / directory listings.
136
+ if (tool === "mod" && args.action === "source" && !args.path)
137
+ throw new HostedPolicyError("Specify a source file path or use a class search.");
138
+ if ((String(args.action).startsWith("search") || args.action === "classes")
139
+ && !(typeof args.query === "string" && args.query.trim())
140
+ && !(typeof args.className === "string" && args.className.trim())) {
141
+ throw new HostedPolicyError("Provide a focused search query.");
142
+ }
143
+ return args;
144
+ }
145
+ /** Atomic shared-database accounting: session churn, parallel calls and restarts do not reset it. */
146
+ export class HostedBudget {
147
+ database;
148
+ now;
149
+ ready;
150
+ constructor(database = getDb, now = Date.now) {
151
+ this.database = database;
152
+ this.now = now;
153
+ }
154
+ async charge(subject, limits, requests, bytes) {
155
+ const db = await this.database();
156
+ if (!this.ready)
157
+ this.ready = db.$executeRawUnsafe(`CREATE TABLE IF NOT EXISTS hosted_usage (
158
+ subject TEXT PRIMARY KEY, minute BIGINT NOT NULL, minute_requests BIGINT NOT NULL,
159
+ day BIGINT NOT NULL, daily_requests BIGINT NOT NULL, daily_bytes BIGINT NOT NULL,
160
+ period BIGINT NOT NULL, period_bytes BIGINT NOT NULL
161
+ )`).then(() => { }).catch(e => { this.ready = undefined; throw e; });
162
+ await this.ready;
163
+ const time = this.now();
164
+ const minute = Math.floor(time / 60_000), day = Math.floor(time / 86_400_000), period = Math.floor(day / 30);
165
+ // A single conditional UPSERT serializes checks and updates on every supported backend.
166
+ const rows = await db.$queryRawUnsafe(`
167
+ INSERT INTO hosted_usage (subject, minute, minute_requests, day, daily_requests, daily_bytes, period, period_bytes)
168
+ SELECT CAST($1 AS TEXT), CAST($2 AS BIGINT), CAST($5 AS BIGINT), CAST($3 AS BIGINT),
169
+ CAST($5 AS BIGINT), CAST($6 AS BIGINT), CAST($4 AS BIGINT), CAST($6 AS BIGINT)
170
+ WHERE $5 <= $7 AND $5 <= $8 AND $6 <= $9 AND $6 <= $10
171
+ ON CONFLICT (subject) DO UPDATE SET
172
+ minute = $2, minute_requests = CASE WHEN hosted_usage.minute = $2 THEN hosted_usage.minute_requests ELSE 0 END + $5,
173
+ day = $3, daily_requests = CASE WHEN hosted_usage.day = $3 THEN hosted_usage.daily_requests ELSE 0 END + $5,
174
+ daily_bytes = CASE WHEN hosted_usage.day = $3 THEN hosted_usage.daily_bytes ELSE 0 END + $6,
175
+ period = $4, period_bytes = CASE WHEN hosted_usage.period = $4 THEN hosted_usage.period_bytes ELSE 0 END + $6
176
+ WHERE (CASE WHEN hosted_usage.minute = $2 THEN hosted_usage.minute_requests ELSE 0 END) + $5 <= $7
177
+ AND (CASE WHEN hosted_usage.day = $3 THEN hosted_usage.daily_requests ELSE 0 END) + $5 <= $8
178
+ AND (CASE WHEN hosted_usage.day = $3 THEN hosted_usage.daily_bytes ELSE 0 END) + $6 <= $9
179
+ AND (CASE WHEN hosted_usage.period = $4 THEN hosted_usage.period_bytes ELSE 0 END) + $6 <= $10
180
+ RETURNING subject`, subject, minute, day, period, requests, bytes, limits.minuteRequests, limits.dailyRequests, limits.dailyBytes, limits.periodBytes);
181
+ if (!rows.length)
182
+ throw new HostedPolicyError("Hosted analysis allowance reached. Try again later or contact the operator for a higher allowance.");
183
+ }
184
+ }
185
+ const privateKeys = /^(?:jarPath|decompPath|sourcePath|graphPath|cacheRoot|indexPath|cachedAt|outDir|outputDir|savedTo|decompiled|indexed|embeddedCount|embedSource|embedUpdatedAt)$/i;
186
+ const sourceKeys = /^(?:source|content|text|snippet|answer|bytecode|result|raw)$/i;
187
+ export function boundHostedResult(tool, args, result, limits, allowMinecraftSource = false) {
188
+ if (result.isError)
189
+ return failure("Request failed. Check the arguments or ask the operator to inspect the server log.");
190
+ if (tool === "mc_source" && !allowMinecraftSource && args.action === "get_source") {
191
+ result = { content: result.content.map(block => {
192
+ if (block.type !== "text")
193
+ throw new HostedPolicyError("This response format is unavailable remotely.");
194
+ let value;
195
+ try {
196
+ value = JSON.parse(block.text);
197
+ }
198
+ catch {
199
+ throw new HostedPolicyError("Minecraft source preparation unavailable.");
200
+ }
201
+ if (!value || typeof value !== "object")
202
+ throw new HostedPolicyError("Minecraft source preparation unavailable.");
203
+ const info = value;
204
+ if (typeof info.version !== "string" || typeof info.className !== "string" || typeof info.cached !== "boolean"
205
+ || typeof info.indexed !== "boolean" || !(info.totalLines === null || Number.isSafeInteger(info.totalLines))
206
+ || !["ready", "preparing", "busy", "failed"].includes(String(info.status))) {
207
+ throw new HostedPolicyError("Minecraft source preparation unavailable.");
208
+ }
209
+ return { type: "text", text: JSON.stringify({ version: info.version, className: info.className,
210
+ cached: info.cached, indexed: info.indexed, totalLines: info.totalLines, status: info.status }) };
211
+ }) };
212
+ }
213
+ if (tool === "mc_source" && !allowMinecraftSource && ["search_code", "search_indexed"].includes(String(args.action))) {
214
+ result = { content: result.content.map(block => {
215
+ if (block.type !== "text")
216
+ throw new HostedPolicyError("This response format is unavailable remotely.");
217
+ let rows;
218
+ try {
219
+ rows = JSON.parse(block.text);
220
+ }
221
+ catch {
222
+ throw new HostedPolicyError("Minecraft search response unavailable.");
223
+ }
224
+ if (!Array.isArray(rows))
225
+ throw new HostedPolicyError("Minecraft search response unavailable.");
226
+ const projected = rows.map(row => {
227
+ if (!row || typeof row !== "object")
228
+ throw new HostedPolicyError("Minecraft search response unavailable.");
229
+ const item = row;
230
+ if (args.action === "search_indexed") {
231
+ if (typeof item.className !== "string")
232
+ throw new HostedPolicyError("Minecraft search response unavailable.");
233
+ return { className: item.className };
234
+ }
235
+ if (typeof item.file !== "string" || typeof item.line !== "number")
236
+ throw new HostedPolicyError("Minecraft search response unavailable.");
237
+ return { file: item.file.replace(/\\/g, "/"), line: item.line };
238
+ });
239
+ return { type: "text", text: JSON.stringify(projected) };
240
+ }) };
241
+ }
242
+ if (tool === "project" && !allowMinecraftSource && args.action === "search") {
243
+ result = { content: result.content.map(block => {
244
+ if (block.type !== "text")
245
+ throw new HostedPolicyError("This response format is unavailable remotely.");
246
+ let value;
247
+ try {
248
+ value = JSON.parse(block.text);
249
+ }
250
+ catch {
251
+ throw new HostedPolicyError("Project search response unavailable.");
252
+ }
253
+ if (!value || typeof value !== "object" || !Array.isArray(value.results))
254
+ throw new HostedPolicyError("Project search response unavailable.");
255
+ const data = value;
256
+ return { type: "text", text: JSON.stringify({ ...data,
257
+ results: data.results.filter(row => typeof row?.className === "string" && !/^net[./]minecraft[./]/i.test(row.className)),
258
+ }) };
259
+ }) };
260
+ }
261
+ let truncated = false;
262
+ let remainingLines = limits.lines;
263
+ const clip = (text) => {
264
+ const lines = text.split(/\r\n|\n|\r/);
265
+ let value = lines.slice(0, remainingLines).join("\n");
266
+ if (lines.length > remainingLines)
267
+ truncated = true;
268
+ remainingLines = Math.max(0, remainingLines - lines.length);
269
+ // Byte caps also handle generated/minified one-line classes and multibyte Unicode.
270
+ const bytes = Buffer.from(value);
271
+ const stringBytes = Math.min(32 * 1024, Math.floor(limits.responseBytes / 2));
272
+ if (bytes.length > stringBytes) {
273
+ let end = stringBytes;
274
+ while (end > 0 && (bytes[end] & 0xc0) === 0x80)
275
+ end--;
276
+ value = bytes.subarray(0, end).toString("utf8");
277
+ truncated = true;
278
+ }
279
+ return value;
280
+ };
281
+ const clean = (value, key = "", depth = 0) => {
282
+ if (depth > 20) {
283
+ truncated = true;
284
+ return null;
285
+ }
286
+ if (typeof value === "string") {
287
+ if (tool === "project" && args.action === "bytecode" && key === "result") {
288
+ value = value.split(/\r\n|\n|\r/).slice(Number(args.startLine ?? 1) - 1, Number(args.startLine ?? 1) - 1 + Number(args.maxLines ?? limits.lines)).join("\n");
289
+ }
290
+ return sourceKeys.test(key) ? clip(value) : value;
291
+ }
292
+ if (Array.isArray(value))
293
+ return value.map(v => clean(v, key, depth + 1));
294
+ if (value && typeof value === "object")
295
+ return Object.fromEntries(Object.entries(value)
296
+ .filter(([k]) => !privateKeys.test(k)).map(([k, v]) => [k, clean(v, k, depth + 1)]));
297
+ return value;
298
+ };
299
+ const content = [];
300
+ for (const block of result.content) {
301
+ // No file/resource links, binary payloads, hidden structuredContent or metadata bypasses.
302
+ if (block.type !== "text")
303
+ throw new HostedPolicyError("This response format is unavailable remotely.");
304
+ let value;
305
+ // Source text must not evade line limits by happening to parse as JSON.
306
+ try {
307
+ value = rawSource(tool, args.action) && tool !== "project" ? undefined : JSON.parse(block.text);
308
+ }
309
+ catch {
310
+ value = undefined;
311
+ }
312
+ let text;
313
+ // Bytecode/mod source implementations that lack pagination are sliced before clipping.
314
+ if (rawSource(tool, args.action) && value === undefined && !(tool === "mc_source" && args.action === "get_source") && !(tool === "mod" && args.action === "source")) {
315
+ text = clip(block.text.split(/\r\n|\n|\r/).slice(Number(args.startLine ?? 1) - 1, Number(args.startLine ?? 1) - 1 + Number(args.maxLines ?? limits.lines)).join("\n"));
316
+ }
317
+ else
318
+ text = value === undefined ? clip(block.text) : JSON.stringify(clean(value));
319
+ content.push({ type: "text", text });
320
+ }
321
+ if (truncated)
322
+ content.push({ type: "text", text: "Response limited. Narrow the query or request a specific source range." });
323
+ if (Buffer.byteLength(JSON.stringify(content)) > limits.responseBytes) {
324
+ throw new HostedPolicyError("Response too large. Narrow the query or request a smaller source range.");
325
+ }
326
+ return { content };
327
+ }
328
+ function failure(text) {
329
+ return { isError: true, content: [{ type: "text", text }] };
330
+ }
331
+ export async function runHostedTool(tool, input, subject, limits, budget, run, allowMinecraftSource = false) {
332
+ try {
333
+ await budget.charge(subject, limits, 1, 0);
334
+ const args = prepareHostedArgs(tool, input, limits, allowMinecraftSource);
335
+ const review = await guardHostedMod(tool, args);
336
+ const result = review.blocked
337
+ ? boundHostedResult("mod_license", { action: "check" }, review.blocked, limits)
338
+ : attachLicenseNotices(boundHostedResult(tool, args, await run(args), limits, allowMinecraftSource), review.notices ?? []);
339
+ // License notices must remain complete even when all 200 source lines are
340
+ // used. Reject the whole response if source plus notices exceeds the cap.
341
+ if (Buffer.byteLength(JSON.stringify(result.content)) > limits.responseBytes) {
342
+ throw new HostedPolicyError("Source and required license notices exceed the response limit. Request a smaller source range or use the local workflow.");
343
+ }
344
+ // Charge before release, atomically, including search snippets, bytecode and alternate routes.
345
+ await budget.charge(subject, limits, 0, Buffer.byteLength(JSON.stringify(result.content)));
346
+ return result;
347
+ }
348
+ catch (error) {
349
+ if (!(error instanceof HostedPolicyError))
350
+ console.error("[modlens] hosted policy failure", error);
351
+ return failure(error instanceof HostedPolicyError ? error.message : "Hosted request unavailable. Contact the operator.");
352
+ }
353
+ }
354
+ //# sourceMappingURL=hosted-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted-policy.js","sourceRoot":"","sources":["../src/hosted-policy.ts"],"names":[],"mappings":"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"}
package/dist/launcher.js CHANGED
@@ -19,105 +19,120 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from
19
19
  import { join, dirname } from "path";
20
20
  import { fileURLToPath } from "url";
21
21
  import { spawnSync } from "child_process";
22
- const __dirname = dirname(fileURLToPath(import.meta.url));
23
- // ── Resolve paths (mirrors env-path.ts but without importing it so we can
24
- // load the .env before any other imports trigger DB connections) ──────────
25
- const PKG_ROOT = join(__dirname, "..");
26
- const IS_INSTALLED = !existsSync(join(PKG_ROOT, ".git"));
27
22
  import { homedir } from "os";
28
- const MODLENS_HOME = process.env.MODLENS_HOME ?? (IS_INSTALLED ? join(homedir(), ".modlens") : PKG_ROOT);
29
- const ENV_FILE = IS_INSTALLED ? join(MODLENS_HOME, ".env") : join(PKG_ROOT, ".env");
30
- const VERSION_FILE = join(MODLENS_HOME, "version");
31
- // ── Load .env early so DB connection picks up DATABASE_URL ───────────────────
32
- for (const ep of [ENV_FILE, join(PKG_ROOT, ".env")]) {
33
- if (existsSync(ep)) {
34
- for (const line of readFileSync(ep, "utf8").split("\n")) {
35
- const m = line.match(/^([^#=]+)=(.*)$/);
36
- if (m)
37
- process.env[m[1].trim()] ??= m[2].trim().replace(/^["']|["']$/g, "");
38
- }
39
- break;
40
- }
41
- }
42
- const args = process.argv.slice(2);
43
- // Project utilities do not need a database or first-run bootstrap.
44
- if (args[0] === "--gradle-init-script") {
45
- console.log(join(PKG_ROOT, "scripts", "gradle", "modlens.init.gradle"));
46
- process.exit(0);
47
- }
48
- if (args[0] === "--project-upload") {
49
- process.argv = [process.argv[0], join(PKG_ROOT, "scripts", "project-upload.mjs"), ...args.slice(1)];
50
- await import(new URL("../scripts/project-upload.mjs", import.meta.url).href);
51
- process.exit(process.exitCode ?? 0);
52
- }
53
- if (args[0] === "--project") {
54
- process.argv = [process.argv[0], join(PKG_ROOT, "dist", "cli.js"), "project", ...args.slice(1)];
55
- await import("./cli.js");
56
- process.exit(process.exitCode ?? 0);
23
+ const __dirname = dirname(fileURLToPath(import.meta.url));
24
+ // Runtime-only local helper: no DB bootstrap, server .env, or MCP configuration.
25
+ if (process.argv[2] === "--local-mod") {
26
+ delete process.env.MCP_PORT;
27
+ const { localModCli } = await import("./local-mod.js");
28
+ process.exitCode = await localModCli(process.argv.slice(3));
57
29
  }
58
- const wantSetup = args.includes("--setup");
59
- // Bootstrap embedded SQLite only when nothing else is configured. A
60
- // pre-supplied DATABASE_URL (e.g. Postgres via a container env var) opts out, so
61
- // `docker run -e DATABASE_URL=postgresql://…` works without a stray SQLite db.
62
- const isFirstRun = IS_INSTALLED && !existsSync(ENV_FILE) && !process.env.DATABASE_URL;
63
- // ── Explicit setup wizard (--setup) ─────────────────────────────────────────
64
- // Opt-in interactive configuration (Postgres, semantic search, MCP client, …).
65
- if (wantSetup) {
66
- mkdirSync(MODLENS_HOME, { recursive: true });
67
- const result = spawnSync(process.execPath, [join(PKG_ROOT, "dist", "setup.js")], {
68
- stdio: "inherit",
69
- env: { ...process.env, MODLENS_HOME },
70
- });
71
- process.exit(result.status ?? 0);
30
+ else if (process.argv[2] === "--runtime") {
31
+ delete process.env.MCP_PORT;
32
+ const { runtimeCli } = await import("./runtime/cli.js");
33
+ process.exitCode = await runtimeCli(process.argv.slice(3));
72
34
  }
73
- // ── Zero-config first run: bootstrap embedded SQLite ─────────────────────────
74
- // No interactive wizard — copy the prebuilt schema'd template database into
75
- // ~/.modlens/data so the server can start immediately with no external services.
76
- // Power users can switch to Postgres/semantic search any time with `--setup`.
77
- if (isFirstRun) {
78
- mkdirSync(MODLENS_HOME, { recursive: true });
79
- const dataDir = join(MODLENS_HOME, "data");
80
- mkdirSync(dataDir, { recursive: true });
81
- const dbPath = join(dataDir, "modlens.db");
82
- if (!existsSync(dbPath)) {
83
- const template = join(PKG_ROOT, "prisma", "backends", "template.db");
84
- if (!existsSync(template)) {
85
- console.error("[modlens] template.db is missing from the package — cannot bootstrap SQLite.\n[modlens] Run `npx @creeperhost/modlens-mcp --setup` to configure a database manually.");
86
- process.exit(1);
35
+ else
36
+ await startMcp();
37
+ async function startMcp() {
38
+ // ── Resolve paths (mirrors env-path.ts but without importing it so we can
39
+ // load the .env before any other imports trigger DB connections) ──────────
40
+ const PKG_ROOT = join(__dirname, "..");
41
+ const IS_INSTALLED = !existsSync(join(PKG_ROOT, ".git"));
42
+ const MODLENS_HOME = process.env.MODLENS_HOME ?? (IS_INSTALLED ? join(homedir(), ".modlens") : PKG_ROOT);
43
+ const ENV_FILE = IS_INSTALLED ? join(MODLENS_HOME, ".env") : join(PKG_ROOT, ".env");
44
+ const VERSION_FILE = join(MODLENS_HOME, "version");
45
+ // ── Load .env early so DB connection picks up DATABASE_URL ───────────────────
46
+ for (const ep of [ENV_FILE, join(PKG_ROOT, ".env")]) {
47
+ if (existsSync(ep)) {
48
+ for (const line of readFileSync(ep, "utf8").split("\n")) {
49
+ const m = line.match(/^([^#=]+)=(.*)$/);
50
+ if (m)
51
+ process.env[m[1].trim()] ??= m[2].trim().replace(/^["']|["']$/g, "");
52
+ }
53
+ break;
87
54
  }
88
- copyFileSync(template, dbPath);
89
55
  }
90
- const dbUrl = `file:${dbPath}`;
91
- writeFileSync(ENV_FILE, `MODLENS_PROFILE=lightweight\nDATABASE_URL=${dbUrl}\n`);
92
- process.env.DATABASE_URL ??= dbUrl;
93
- // Record the current version so the migration step below treats this fresh
94
- // install as already up to date (template.db already has the right schema).
95
- const freshVersion = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8")).version;
96
- writeFileSync(VERSION_FILE, freshVersion + "\n");
97
- console.error(`[modlens] First run — initialized embedded SQLite database at ${dbPath}`);
98
- console.error("[modlens] Run `npx @creeperhost/modlens-mcp --setup` to switch to Postgres or enable semantic search.");
99
- }
100
- // ── Version check + auto-migrate (installed mode only) ───────────────────────
101
- if (IS_INSTALLED) {
102
- const pkgVersion = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8")).version;
103
- const storedVersion = existsSync(VERSION_FILE) ? readFileSync(VERSION_FILE, "utf8").trim() : null;
104
- if (storedVersion !== pkgVersion) {
105
- console.error(`[modlens] Version changed (${storedVersion ?? "none"} → ${pkgVersion}), running migrations...`);
106
- const result = spawnSync(process.execPath, [join(PKG_ROOT, "scripts", "post-update.mjs")], {
56
+ const args = process.argv.slice(2);
57
+ // Project utilities do not need a database or first-run bootstrap.
58
+ if (args[0] === "--gradle-init-script") {
59
+ console.log(join(PKG_ROOT, "scripts", "gradle", "modlens.init.gradle"));
60
+ process.exit(0);
61
+ }
62
+ if (args[0] === "--project-upload") {
63
+ process.argv = [process.argv[0], join(PKG_ROOT, "scripts", "project-upload.mjs"), ...args.slice(1)];
64
+ await import(new URL("../scripts/project-upload.mjs", import.meta.url).href);
65
+ process.exit(process.exitCode ?? 0);
66
+ }
67
+ if (args[0] === "--project") {
68
+ process.argv = [process.argv[0], join(PKG_ROOT, "dist", "cli.js"), "project", ...args.slice(1)];
69
+ await import("./cli.js");
70
+ process.exit(process.exitCode ?? 0);
71
+ }
72
+ const wantSetup = args.includes("--setup");
73
+ // Bootstrap embedded SQLite only when nothing else is configured. A
74
+ // pre-supplied DATABASE_URL (e.g. Postgres via a container env var) opts out, so
75
+ // `docker run -e DATABASE_URL=postgresql://…` works without a stray SQLite db.
76
+ const isFirstRun = IS_INSTALLED && !existsSync(ENV_FILE) && !process.env.DATABASE_URL;
77
+ // ── Explicit setup wizard (--setup) ─────────────────────────────────────────
78
+ // Opt-in interactive configuration (Postgres, semantic search, MCP client, …).
79
+ if (wantSetup) {
80
+ mkdirSync(MODLENS_HOME, { recursive: true });
81
+ const result = spawnSync(process.execPath, [join(PKG_ROOT, "dist", "setup.js")], {
107
82
  stdio: "inherit",
108
83
  env: { ...process.env, MODLENS_HOME },
109
84
  });
110
- if (result.status === 0) {
111
- mkdirSync(MODLENS_HOME, { recursive: true });
112
- writeFileSync(VERSION_FILE, pkgVersion + "\n");
85
+ process.exit(result.status ?? 0);
86
+ }
87
+ // ── Zero-config first run: bootstrap embedded SQLite ─────────────────────────
88
+ // No interactive wizard — copy the prebuilt schema'd template database into
89
+ // ~/.modlens/data so the server can start immediately with no external services.
90
+ // Power users can switch to Postgres/semantic search any time with `--setup`.
91
+ if (isFirstRun) {
92
+ mkdirSync(MODLENS_HOME, { recursive: true });
93
+ const dataDir = join(MODLENS_HOME, "data");
94
+ mkdirSync(dataDir, { recursive: true });
95
+ const dbPath = join(dataDir, "modlens.db");
96
+ if (!existsSync(dbPath)) {
97
+ const template = join(PKG_ROOT, "prisma", "backends", "template.db");
98
+ if (!existsSync(template)) {
99
+ console.error("[modlens] template.db is missing from the package — cannot bootstrap SQLite.\n[modlens] Run `npx @creeperhost/modlens-mcp --setup` to configure a database manually.");
100
+ process.exit(1);
101
+ }
102
+ copyFileSync(template, dbPath);
113
103
  }
114
- else {
115
- console.error("[modlens] Migration had errors — server may not start correctly.");
104
+ const dbUrl = `file:${dbPath}`;
105
+ writeFileSync(ENV_FILE, `MODLENS_PROFILE=lightweight\nDATABASE_URL=${dbUrl}\n`);
106
+ process.env.DATABASE_URL ??= dbUrl;
107
+ // Record the current version so the migration step below treats this fresh
108
+ // install as already up to date (template.db already has the right schema).
109
+ const freshVersion = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8")).version;
110
+ writeFileSync(VERSION_FILE, freshVersion + "\n");
111
+ console.error(`[modlens] First run — initialized embedded SQLite database at ${dbPath}`);
112
+ console.error("[modlens] Run `npx @creeperhost/modlens-mcp --setup` to switch to Postgres or enable semantic search.");
113
+ }
114
+ // ── Version check + auto-migrate (installed mode only) ───────────────────────
115
+ if (IS_INSTALLED) {
116
+ const pkgVersion = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8")).version;
117
+ const storedVersion = existsSync(VERSION_FILE) ? readFileSync(VERSION_FILE, "utf8").trim() : null;
118
+ if (storedVersion !== pkgVersion) {
119
+ console.error(`[modlens] Version changed (${storedVersion ?? "none"} → ${pkgVersion}), running migrations...`);
120
+ const result = spawnSync(process.execPath, [join(PKG_ROOT, "scripts", "post-update.mjs")], {
121
+ stdio: "inherit",
122
+ env: { ...process.env, MODLENS_HOME },
123
+ });
124
+ if (result.status === 0) {
125
+ mkdirSync(MODLENS_HOME, { recursive: true });
126
+ writeFileSync(VERSION_FILE, pkgVersion + "\n");
127
+ }
128
+ else {
129
+ console.error("[modlens] Migration had errors — server may not start correctly.");
130
+ }
116
131
  }
117
132
  }
133
+ // ── Start server ──────────────────────────────────────────────────────────────
134
+ // Dynamic import so all the above env-loading completes before any module
135
+ // that reads process.env at import time (e.g. db.ts) is evaluated.
136
+ await import("./server.js");
118
137
  }
119
- // ── Start server ──────────────────────────────────────────────────────────────
120
- // Dynamic import so all the above env-loading completes before any module
121
- // that reads process.env at import time (e.g. db.ts) is evaluated.
122
- await import("./server.js");
123
138
  //# sourceMappingURL=launcher.js.map