semantic-js-mcp 0.8.0

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.
@@ -0,0 +1,54 @@
1
+ # Distribution
2
+
3
+ The package manifest defines an explicit public file allowlist and exposes the `semantic-js-mcp` executable. Codex installs the package through the public `elnonathan` marketplace; other MCP hosts can use the executable directly.
4
+
5
+ ## Codex
6
+
7
+ ```bash
8
+ codex plugin marketplace add elnonathan/semantic-js-mcp
9
+ codex plugin add semantic-js-mcp@elnonathan
10
+ ```
11
+
12
+ The marketplace entry pins a concrete npm package version. A release updates the package version, plugin manifest, and marketplace entry together.
13
+
14
+ ## Executable
15
+
16
+ ```bash
17
+ semantic-js-mcp serve
18
+ semantic-js-mcp doctor
19
+ semantic-js-mcp doctor --yaml
20
+ ```
21
+
22
+ `serve` starts the MCP server over stdio. `doctor` creates isolated TypeScript and Vue fixtures and reports `pass`, `fail`, `untrusted`, or `blocked` with exit codes `0`, `1`, `2`, or `3`.
23
+
24
+ ## Package Artifact
25
+
26
+ ```bash
27
+ npm run smoke:distribution
28
+ ```
29
+
30
+ The distribution smoke performs these checks:
31
+
32
+ 1. creates an npm tarball from the declared `files` allowlist;
33
+ 2. verifies required runtime, plugin, and skill files are present;
34
+ 3. rejects every tarball entry outside the package's declared public allowlist;
35
+ 4. installs the tarball in a temporary consumer project;
36
+ 5. runs `semantic-js-mcp doctor` from that installed copy;
37
+ 6. verifies that language-server components resolve within the consumer dependency tree and never from the source checkout.
38
+
39
+ The temporary installation uses an isolated npm cache and may resolve dependencies from the registry. Once installed, normal semantic analysis requires no network access.
40
+
41
+ ## Source Validation
42
+
43
+ Run the complete local validation sequence before reviewing a distribution change:
44
+
45
+ ```bash
46
+ npm run check
47
+ npm run check:runtime
48
+ npm run smoke:ci
49
+ npm run smoke
50
+ npm run smoke:vue
51
+ npm run smoke:distribution
52
+ ```
53
+
54
+ Run `npm run doctor` separately when the structured installation evidence is part of the review. Exit `2` is an explicit untrusted diagnostic result and must not be described as a clean semantic pass.
package/lib/doctor.mjs ADDED
@@ -0,0 +1,319 @@
1
+ import path from "node:path";
2
+ import {mkdtemp, mkdir, realpath, rm, writeFile} from "node:fs/promises";
3
+ import {tmpdir} from "node:os";
4
+ import {Client} from "@modelcontextprotocol/sdk/client/index.js";
5
+ import {StdioClientTransport} from "@modelcontextprotocol/sdk/client/stdio.js";
6
+ import {
7
+ ACCOUNTING_STATUS,
8
+ CI_EXIT_CODE,
9
+ CI_STATUS,
10
+ CLI_ARGUMENT,
11
+ CLI_COMMAND,
12
+ CONFIGURATION_FILE,
13
+ COLLECTION_STATUS,
14
+ DEFINITION_MATCH,
15
+ DOCTOR_CHECK,
16
+ DOCTOR_REASON,
17
+ DOCTOR_STATUS_PRIORITY,
18
+ EVIDENCE_STATUS,
19
+ PACKAGE_PATH,
20
+ PRODUCT,
21
+ RUNTIME_COMMAND,
22
+ SERVER_VERSION,
23
+ TOOL,
24
+ TOOL_ORDER,
25
+ } from "../protocol.mjs";
26
+ import {PACKAGE_ROOT, inspectExternalCommand, inspectNodeRuntime, inspectRuntimeComponents} from "./runtime.mjs";
27
+
28
+ const STATUS_EXIT_CODE = Object.freeze({
29
+ [CI_STATUS.PASS]: CI_EXIT_CODE.PASS,
30
+ [CI_STATUS.FAIL]: CI_EXIT_CODE.FAIL,
31
+ [CI_STATUS.UNTRUSTED]: CI_EXIT_CODE.UNTRUSTED,
32
+ [CI_STATUS.BLOCKED]: CI_EXIT_CODE.BLOCKED,
33
+ });
34
+
35
+ function check(name, status, reason, details) {
36
+ return {name, status, reason, ...(details === undefined ? {} : {details})};
37
+ }
38
+
39
+ function aggregateStatus(checks) {
40
+ return checks.reduce(
41
+ (current, item) => (DOCTOR_STATUS_PRIORITY[item.status] > DOCTOR_STATUS_PRIORITY[current] ? item.status : current),
42
+ CI_STATUS.PASS,
43
+ );
44
+ }
45
+
46
+ function doctorResult(packageRoot, checks, runtime) {
47
+ const status = aggregateStatus(checks);
48
+ return {
49
+ product: {name: PRODUCT.NAME, version: SERVER_VERSION},
50
+ command: CLI_COMMAND.DOCTOR,
51
+ status,
52
+ exitCode: STATUS_EXIT_CODE[status],
53
+ installationRoot: packageRoot,
54
+ runtime,
55
+ checks,
56
+ };
57
+ }
58
+
59
+ function assertToolResult(response, tool) {
60
+ if (response.isError) throw new Error(response.content?.[0]?.text || `${tool} failed`);
61
+ if (response.structuredContent?.tool !== tool) throw new Error(`${tool} returned a different canonical tool name`);
62
+ return response.structuredContent;
63
+ }
64
+
65
+ async function createDoctorFixture() {
66
+ const workspace = await mkdtemp(path.join(tmpdir(), `${PRODUCT.NAME}-doctor-`));
67
+ const src = path.join(workspace, "src");
68
+ await mkdir(src, {recursive: true});
69
+ await writeFile(path.join(workspace, CONFIGURATION_FILE.PACKAGE), JSON.stringify({private: true, type: "module"}));
70
+ await writeFile(
71
+ path.join(workspace, CONFIGURATION_FILE.TYPESCRIPT),
72
+ JSON.stringify({
73
+ compilerOptions: {strict: true, target: "ES2022", module: "ESNext", moduleResolution: "Bundler"},
74
+ include: ["src/**/*.ts", "src/**/*.vue"],
75
+ }),
76
+ );
77
+
78
+ const target = path.join(src, "target.ts");
79
+ const usage = path.join(src, "usage.ts");
80
+ const unresolved = path.join(src, "unresolved.ts");
81
+ const child = path.join(src, "DoctorChild.vue");
82
+ const component = path.join(src, "DoctorPanel.vue");
83
+ await writeFile(target, "export function doctorTarget(value: number): number { return value + 1; }\n");
84
+ await writeFile(usage, 'import {doctorTarget} from "./target.js";\nexport const doctorValue = doctorTarget(1);\n');
85
+ await writeFile(unresolved, 'export const unresolvedDoctorText = "doctorTarget";\n');
86
+ await writeFile(
87
+ child,
88
+ '<script setup lang="ts">\ndefineProps<{label: string}>();\n</script>\n<template><span>{{ label }}</span></template>\n',
89
+ );
90
+ await writeFile(
91
+ component,
92
+ [
93
+ '<script setup lang="ts">',
94
+ 'import DoctorChild from "./DoctorChild.vue";',
95
+ "const doctorVueValue = 1;",
96
+ "</script>",
97
+ "<template>",
98
+ ' <DoctorChild label="Doctor" />',
99
+ " <span>{{ doctorVueValue }}</span>",
100
+ "</template>",
101
+ ].join("\n"),
102
+ );
103
+ return {workspace, target, component, child};
104
+ }
105
+
106
+ function failedCheck(name, error) {
107
+ return check(name, CI_STATUS.FAIL, DOCTOR_REASON.CHECK_FAILED, {message: error.message});
108
+ }
109
+
110
+ export async function runDoctor({packageRoot = PACKAGE_ROOT} = {}) {
111
+ const checks = [];
112
+ const node = inspectNodeRuntime();
113
+ checks.push(
114
+ check(
115
+ DOCTOR_CHECK.NODE_RUNTIME,
116
+ node.supported ? CI_STATUS.PASS : CI_STATUS.BLOCKED,
117
+ node.supported ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.UNSUPPORTED_NODE_RUNTIME,
118
+ node,
119
+ ),
120
+ );
121
+
122
+ const components = inspectRuntimeComponents(packageRoot);
123
+ const missingComponents = components.filter((component) => !component.available);
124
+ checks.push(
125
+ check(
126
+ DOCTOR_CHECK.RUNTIME_COMPONENTS,
127
+ missingComponents.length === 0 ? CI_STATUS.PASS : CI_STATUS.BLOCKED,
128
+ missingComponents.length === 0 ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.RUNTIME_COMPONENT_MISSING,
129
+ {components, missingComponents},
130
+ ),
131
+ );
132
+
133
+ const ripgrep = await inspectExternalCommand(RUNTIME_COMMAND.RIPGREP, [CLI_ARGUMENT.VERSION]);
134
+ checks.push(
135
+ check(
136
+ DOCTOR_CHECK.RIPGREP,
137
+ ripgrep.available ? CI_STATUS.PASS : CI_STATUS.BLOCKED,
138
+ ripgrep.available ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.RIPGREP_UNAVAILABLE,
139
+ ripgrep,
140
+ ),
141
+ );
142
+
143
+ const runtime = {node, components, externalCommands: [ripgrep]};
144
+ if (aggregateStatus(checks) === CI_STATUS.BLOCKED) return doctorResult(packageRoot, checks, runtime);
145
+
146
+ const fixture = await createDoctorFixture();
147
+ const client = new Client({name: `${PRODUCT.NAME}-doctor`, version: SERVER_VERSION});
148
+ const serverFile = path.join(packageRoot, PACKAGE_PATH.SERVER);
149
+ const transport = new StdioClientTransport({command: process.execPath, args: [serverFile], cwd: packageRoot});
150
+
151
+ try {
152
+ try {
153
+ await client.connect(transport);
154
+ checks.push(check(DOCTOR_CHECK.MCP_STARTUP, CI_STATUS.PASS, DOCTOR_REASON.CHECK_COMPLETED, {serverFile}));
155
+ } catch (error) {
156
+ checks.push(
157
+ check(DOCTOR_CHECK.MCP_STARTUP, CI_STATUS.BLOCKED, DOCTOR_REASON.MCP_STARTUP_FAILED, {message: error.message, serverFile}),
158
+ );
159
+ return doctorResult(packageRoot, checks, runtime);
160
+ }
161
+
162
+ try {
163
+ const listed = await client.listTools();
164
+ const actualTools = listed.tools.map((tool) => tool.name);
165
+ const matchesProtocol = JSON.stringify(actualTools) === JSON.stringify(TOOL_ORDER);
166
+ checks.push(
167
+ check(
168
+ DOCTOR_CHECK.TOOL_DISCOVERY,
169
+ matchesProtocol ? CI_STATUS.PASS : CI_STATUS.FAIL,
170
+ matchesProtocol ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.TOOL_SET_DIFFERENT,
171
+ {expectedTools: TOOL_ORDER, actualTools},
172
+ ),
173
+ );
174
+ if (!matchesProtocol) return doctorResult(packageRoot, checks, runtime);
175
+ } catch (error) {
176
+ checks.push(failedCheck(DOCTOR_CHECK.TOOL_DISCOVERY, error));
177
+ return doctorResult(packageRoot, checks, runtime);
178
+ }
179
+
180
+ try {
181
+ const symbols = assertToolResult(
182
+ await client.callTool({
183
+ name: TOOL.DOCUMENT_SYMBOLS,
184
+ arguments: {file: fixture.target, root: fixture.workspace},
185
+ }),
186
+ TOOL.DOCUMENT_SYMBOLS,
187
+ );
188
+ const found = symbols.result.symbols.some((symbol) => symbol.name === "doctorTarget");
189
+ checks.push(
190
+ check(
191
+ DOCTOR_CHECK.TYPESCRIPT_SYMBOLS,
192
+ found ? CI_STATUS.PASS : CI_STATUS.FAIL,
193
+ found ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.TYPESCRIPT_SYMBOL_NOT_FOUND,
194
+ {symbolsFound: symbols.result.symbols.length},
195
+ ),
196
+ );
197
+ } catch (error) {
198
+ checks.push(failedCheck(DOCTOR_CHECK.TYPESCRIPT_SYMBOLS, error));
199
+ }
200
+
201
+ try {
202
+ const references = assertToolResult(
203
+ await client.callTool({
204
+ name: TOOL.COUNT_NAMED_SYMBOL,
205
+ arguments: {root: fixture.workspace, symbol: "doctorTarget", fileHint: "target.ts"},
206
+ }),
207
+ TOOL.COUNT_NAMED_SYMBOL,
208
+ );
209
+ const definition = references.result.definitions[0];
210
+ const accountingComplete = definition?.textSearch?.accountingStatus === ACCOUNTING_STATUS.COMPLETE;
211
+ const unresolvedReported = definition?.textSearch?.matchesWhoseDefinitionCouldNotBeResolved === 1;
212
+ const partial = references.collection.status === COLLECTION_STATUS.PARTIAL;
213
+ const verified = accountingComplete && unresolvedReported && partial;
214
+ checks.push(
215
+ check(
216
+ DOCTOR_CHECK.TYPESCRIPT_REFERENCES,
217
+ verified ? CI_STATUS.PASS : CI_STATUS.FAIL,
218
+ verified ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.TYPESCRIPT_REFERENCE_ACCOUNTING_INCOMPLETE,
219
+ {
220
+ collectionStatus: references.collection.status,
221
+ accountingStatus: definition?.textSearch?.accountingStatus,
222
+ unresolvedCandidates: definition?.textSearch?.matchesWhoseDefinitionCouldNotBeResolved,
223
+ verifiedReferences: definition?.references?.verifiedTotal,
224
+ },
225
+ ),
226
+ );
227
+ } catch (error) {
228
+ checks.push(failedCheck(DOCTOR_CHECK.TYPESCRIPT_REFERENCES, error));
229
+ }
230
+
231
+ try {
232
+ const diagnostics = assertToolResult(
233
+ await client.callTool({
234
+ name: TOOL.DIAGNOSTICS,
235
+ arguments: {file: fixture.target, root: fixture.workspace},
236
+ }),
237
+ TOOL.DIAGNOSTICS,
238
+ );
239
+ const verified =
240
+ diagnostics.result.evidence.status === EVIDENCE_STATUS.VERIFIED && diagnostics.result.diagnosticsForCurrentDocument !== null;
241
+ checks.push(
242
+ check(
243
+ DOCTOR_CHECK.DIAGNOSTIC_FRESHNESS,
244
+ verified ? CI_STATUS.PASS : CI_STATUS.UNTRUSTED,
245
+ verified ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.DIAGNOSTICS_NOT_CONFIRMED,
246
+ {
247
+ evidenceStatus: diagnostics.result.evidence.status,
248
+ evidenceReason: diagnostics.result.evidence.reason,
249
+ collectionStatus: diagnostics.collection.status,
250
+ document: diagnostics.result.document,
251
+ },
252
+ ),
253
+ );
254
+ } catch (error) {
255
+ checks.push(failedCheck(DOCTOR_CHECK.DIAGNOSTIC_FRESHNESS, error));
256
+ }
257
+
258
+ try {
259
+ const symbols = assertToolResult(
260
+ await client.callTool({
261
+ name: TOOL.DOCUMENT_SYMBOLS,
262
+ arguments: {file: fixture.component, root: fixture.workspace},
263
+ }),
264
+ TOOL.DOCUMENT_SYMBOLS,
265
+ );
266
+ const found = symbols.result.symbols.some((symbol) => symbol.name === "doctorVueValue");
267
+ checks.push(
268
+ check(
269
+ DOCTOR_CHECK.VUE_SYMBOLS,
270
+ found ? CI_STATUS.PASS : CI_STATUS.FAIL,
271
+ found ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.VUE_SYMBOL_NOT_FOUND,
272
+ {symbolsFound: symbols.result.symbols.length},
273
+ ),
274
+ );
275
+ } catch (error) {
276
+ checks.push(failedCheck(DOCTOR_CHECK.VUE_SYMBOLS, error));
277
+ }
278
+
279
+ try {
280
+ const definition = assertToolResult(
281
+ await client.callTool({
282
+ name: TOOL.DEFINITION,
283
+ arguments: {file: fixture.component, root: fixture.workspace, line: 6, column: 4},
284
+ }),
285
+ TOOL.DEFINITION,
286
+ );
287
+ const expectedFile = await realpath(fixture.child);
288
+ const resolvedDefinitions = await Promise.all(
289
+ definition.result.definitions.map(async (item) => ({
290
+ ...item,
291
+ canonicalFile: await realpath(item.file).catch(() => path.resolve(item.file)),
292
+ })),
293
+ );
294
+ const resolved =
295
+ definition.result.definitionMatch === DEFINITION_MATCH.RESOLVED &&
296
+ resolvedDefinitions.some((item) => item.canonicalFile === expectedFile);
297
+ checks.push(
298
+ check(
299
+ DOCTOR_CHECK.VUE_TEMPLATE_DEFINITION,
300
+ resolved ? CI_STATUS.PASS : CI_STATUS.FAIL,
301
+ resolved ? DOCTOR_REASON.CHECK_COMPLETED : DOCTOR_REASON.VUE_TEMPLATE_DEFINITION_UNRESOLVED,
302
+ {
303
+ definitionMatch: definition.result.definitionMatch,
304
+ resolutionMethod: definition.result.resolutionMethod,
305
+ definitions: resolvedDefinitions,
306
+ expectedFile,
307
+ },
308
+ ),
309
+ );
310
+ } catch (error) {
311
+ checks.push(failedCheck(DOCTOR_CHECK.VUE_TEMPLATE_DEFINITION, error));
312
+ }
313
+ } finally {
314
+ await client.close().catch(() => undefined);
315
+ await rm(fixture.workspace, {recursive: true, force: true});
316
+ }
317
+
318
+ return doctorResult(packageRoot, checks, runtime);
319
+ }
@@ -0,0 +1,69 @@
1
+ import {spawn} from "node:child_process";
2
+ import {existsSync} from "node:fs";
3
+ import {createRequire} from "node:module";
4
+ import path from "node:path";
5
+ import {fileURLToPath} from "node:url";
6
+ import {CONFIGURATION_FILE, NODE_EVENT, PROCESS_EXIT_CODE, REQUIRED_RUNTIME_COMPONENT, RUNTIME_REQUIREMENT} from "../protocol.mjs";
7
+
8
+ export const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
9
+
10
+ export function inspectNodeRuntime() {
11
+ const major = Number.parseInt(process.versions.node.split(".")[0], 10);
12
+ return {
13
+ version: process.versions.node,
14
+ major,
15
+ minimumMajor: RUNTIME_REQUIREMENT.MINIMUM_NODE_MAJOR,
16
+ supported: Number.isInteger(major) && major >= RUNTIME_REQUIREMENT.MINIMUM_NODE_MAJOR,
17
+ };
18
+ }
19
+
20
+ export function inspectRuntimeComponents(packageRoot = PACKAGE_ROOT) {
21
+ const resolveFromPackage = createRequire(path.join(packageRoot, CONFIGURATION_FILE.PACKAGE));
22
+ return Object.entries(REQUIRED_RUNTIME_COMPONENT).map(([component, moduleSpecifier]) => {
23
+ let file;
24
+ let resolutionError;
25
+ try {
26
+ file = resolveFromPackage.resolve(moduleSpecifier);
27
+ } catch (error) {
28
+ resolutionError = error.message;
29
+ }
30
+ return {component, moduleSpecifier, file, available: Boolean(file && existsSync(file)), ...(resolutionError ? {resolutionError} : {})};
31
+ });
32
+ }
33
+
34
+ export function resolveRuntimeComponent(moduleSpecifier, packageRoot = PACKAGE_ROOT) {
35
+ return createRequire(path.join(packageRoot, CONFIGURATION_FILE.PACKAGE)).resolve(moduleSpecifier);
36
+ }
37
+
38
+ export function runtimeDependencyRoot(moduleSpecifier, packageRoot = PACKAGE_ROOT) {
39
+ let current = path.dirname(resolveRuntimeComponent(moduleSpecifier, packageRoot));
40
+ while (path.basename(current) !== "node_modules") {
41
+ const parent = path.dirname(current);
42
+ if (parent === current) throw new Error(`Resolved runtime component is outside a node_modules tree: ${moduleSpecifier}`);
43
+ current = parent;
44
+ }
45
+ return current;
46
+ }
47
+
48
+ export function inspectExternalCommand(command, args) {
49
+ return new Promise((resolve) => {
50
+ const child = spawn(command, args, {stdio: ["ignore", "pipe", "pipe"]});
51
+ let stdout = "";
52
+ let stderr = "";
53
+ child.stdout.on("data", (chunk) => {
54
+ stdout += chunk;
55
+ });
56
+ child.stderr.on("data", (chunk) => {
57
+ stderr += chunk;
58
+ });
59
+ child.on(NODE_EVENT.ERROR, (error) => resolve({command, available: false, error: error.message}));
60
+ child.on(NODE_EVENT.CLOSE, (exitCode) =>
61
+ resolve({
62
+ command,
63
+ available: exitCode === PROCESS_EXIT_CODE.SUCCESS,
64
+ exitCode,
65
+ versionOutput: (stdout || stderr).trim().split("\n")[0] || undefined,
66
+ }),
67
+ );
68
+ });
69
+ }
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "semantic-js-mcp",
3
+ "version": "0.8.0",
4
+ "description": "Semantic understanding of JavaScript codebases for AI agents",
5
+ "author": {
6
+ "name": "Jonathan Muñoz Lucas",
7
+ "email": "git@jonathanmunoz.dev",
8
+ "url": "https://mx.linkedin.com/in/nonathan"
9
+ },
10
+ "license": "MIT",
11
+ "type": "module",
12
+ "bin": {
13
+ "semantic-js-mcp": "cli.mjs"
14
+ },
15
+ "files": [
16
+ ".codex-plugin/",
17
+ ".mcp.json",
18
+ ".prettierrc.json",
19
+ "CHANGELOG.md",
20
+ "CONTRIBUTING.md",
21
+ "ROADMAP.md",
22
+ "SECURITY.md",
23
+ "cli.mjs",
24
+ "docs/",
25
+ "lib/",
26
+ "protocol.mjs",
27
+ "scripts/",
28
+ "server.mjs",
29
+ "skills/"
30
+ ],
31
+ "engines": {
32
+ "node": ">=22"
33
+ },
34
+ "scripts": {
35
+ "check": "npm run format:check && node --check protocol.mjs && node --check server.mjs && node --check cli.mjs && node --check lib/runtime.mjs && node --check lib/doctor.mjs && node --check scripts/generate-protocol-reference.mjs && node --check scripts/check-protocol-literals.mjs && node --check scripts/check-runtime.mjs && node --check scripts/semantic-js-mcp-ci.mjs && node --check scripts/ci-smoke.mjs && node --check scripts/smoke.mjs && node --check scripts/vue-smoke.mjs && node --check scripts/benchmark.mjs && node --check scripts/distribution-policy.mjs && node --check scripts/distribution-smoke.mjs && node scripts/generate-protocol-reference.mjs --check && node scripts/check-protocol-literals.mjs",
36
+ "check:runtime": "node scripts/check-runtime.mjs",
37
+ "doctor": "node cli.mjs doctor",
38
+ "ci:evaluate": "node scripts/semantic-js-mcp-ci.mjs",
39
+ "smoke": "node scripts/smoke.mjs",
40
+ "smoke:ci": "node scripts/ci-smoke.mjs",
41
+ "smoke:vue": "node scripts/vue-smoke.mjs",
42
+ "smoke:distribution": "node scripts/distribution-smoke.mjs",
43
+ "benchmark": "node scripts/benchmark.mjs",
44
+ "format": "prettier --write \".codex-plugin/**/*.json\" \".agents/plugins/marketplace.json\" \".mcp.json\" \".prettierrc.json\" \"package.json\" \"package-lock.json\" \"CHANGELOG.md\" \"CONTRIBUTING.md\" \"README.md\" \"ROADMAP.md\" \"SECURITY.md\" \"*.mjs\" \"docs/**/*.md\" \"lib/**/*.mjs\" \"scripts/**/*.mjs\" \"skills/**/SKILL.md\" \"skills/**/agents/*.yaml\"",
45
+ "format:check": "prettier --check \".codex-plugin/**/*.json\" \".agents/plugins/marketplace.json\" \".mcp.json\" \".prettierrc.json\" \"package.json\" \"package-lock.json\" \"CHANGELOG.md\" \"CONTRIBUTING.md\" \"README.md\" \"ROADMAP.md\" \"SECURITY.md\" \"*.mjs\" \"docs/**/*.md\" \"lib/**/*.mjs\" \"scripts/**/*.mjs\" \"skills/**/SKILL.md\" \"skills/**/agents/*.yaml\""
46
+ },
47
+ "dependencies": {
48
+ "@modelcontextprotocol/sdk": "1.27.1",
49
+ "@vue/compiler-sfc": "3.5.39",
50
+ "@vue/language-server": "3.0.8",
51
+ "typescript": "6.0.3",
52
+ "typescript-language-server": "5.1.3",
53
+ "yaml": "2.9.0",
54
+ "zod": "4.1.5"
55
+ },
56
+ "devDependencies": {
57
+ "prettier": "3.9.5"
58
+ },
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/elnonathan/semantic-js-mcp.git"
62
+ },
63
+ "homepage": "https://github.com/elnonathan/semantic-js-mcp#readme",
64
+ "bugs": {
65
+ "url": "https://github.com/elnonathan/semantic-js-mcp/issues"
66
+ },
67
+ "publishConfig": {
68
+ "access": "public"
69
+ }
70
+ }