@codescene/codehealth-mcp 0.2.1
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.
- package/bin/cs-mcp.js +5 -0
- package/lib/download.js +248 -0
- package/lib/index.js +72 -0
- package/lib/platform.js +77 -0
- package/lib/run.js +59 -0
- package/package.json +47 -0
package/bin/cs-mcp.js
ADDED
package/lib/download.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Downloads and caches the cs-mcp binary from GitHub releases.
|
|
3
|
+
*
|
|
4
|
+
* The binary is cached inside the package's own directory under
|
|
5
|
+
* `.cache/{version}/` so it persists across runs but is cleaned
|
|
6
|
+
* up naturally when the package is reinstalled or upgraded.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createWriteStream, existsSync, readdirSync, mkdirSync, chmodSync } from "node:fs";
|
|
10
|
+
import { rename, rm } from "node:fs/promises";
|
|
11
|
+
import { join, dirname } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { execFileSync } from "node:child_process";
|
|
14
|
+
import https from "node:https";
|
|
15
|
+
import http from "node:http";
|
|
16
|
+
import { getPlatformInfo, getDownloadUrl } from "./platform.js";
|
|
17
|
+
|
|
18
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const PACKAGE_ROOT = join(__dirname, "..");
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the directory where binaries are cached for a given version.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} version
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
function getCacheDir(version) {
|
|
28
|
+
return join(PACKAGE_ROOT, ".cache", version);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the expected path of the cached binary for a given version.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} version
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
37
|
+
export function getCachedBinaryPath(version) {
|
|
38
|
+
const { binary } = getPlatformInfo();
|
|
39
|
+
return join(getCacheDir(version), binary);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Checks whether an HTTP response is a redirect with a location header.
|
|
44
|
+
*
|
|
45
|
+
* @param {import("node:http").IncomingMessage} response
|
|
46
|
+
* @returns {boolean}
|
|
47
|
+
*/
|
|
48
|
+
function isRedirect(response) {
|
|
49
|
+
const status = response.statusCode ?? 0;
|
|
50
|
+
return status >= 300 && status < 400 && Boolean(response.headers.location);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Reports download progress to stderr at 10% intervals.
|
|
55
|
+
*
|
|
56
|
+
* @param {number} downloadedBytes
|
|
57
|
+
* @param {number} totalBytes
|
|
58
|
+
* @param {number} lastPercent - The last reported percent value
|
|
59
|
+
* @returns {number} The updated lastPercent value
|
|
60
|
+
*/
|
|
61
|
+
function reportProgress(downloadedBytes, totalBytes, lastPercent) {
|
|
62
|
+
if (!totalBytes) return lastPercent;
|
|
63
|
+
|
|
64
|
+
const percent = Math.floor((downloadedBytes / totalBytes) * 100);
|
|
65
|
+
if (percent !== lastPercent && percent % 10 === 0) {
|
|
66
|
+
const mb = (downloadedBytes / 1024 / 1024).toFixed(1);
|
|
67
|
+
process.stderr.write(`\r Downloading... ${percent}% (${mb} MB)`);
|
|
68
|
+
return percent;
|
|
69
|
+
}
|
|
70
|
+
return lastPercent;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Downloads a file from a URL, following redirects (GitHub releases use 302s).
|
|
75
|
+
*
|
|
76
|
+
* @param {string} url
|
|
77
|
+
* @param {string} destPath
|
|
78
|
+
* @returns {Promise<void>}
|
|
79
|
+
*/
|
|
80
|
+
function downloadFile(url, destPath) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const proto = url.startsWith("https") ? https : http;
|
|
83
|
+
|
|
84
|
+
proto
|
|
85
|
+
.get(url, (response) => {
|
|
86
|
+
if (isRedirect(response)) {
|
|
87
|
+
downloadFile(response.headers.location, destPath)
|
|
88
|
+
.then(resolve)
|
|
89
|
+
.catch(reject);
|
|
90
|
+
response.resume();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (response.statusCode !== 200) {
|
|
95
|
+
response.resume();
|
|
96
|
+
reject(
|
|
97
|
+
new Error(
|
|
98
|
+
`Download failed: HTTP ${response.statusCode} from ${url}`
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const totalBytes = parseInt(response.headers["content-length"], 10);
|
|
105
|
+
let downloadedBytes = 0;
|
|
106
|
+
let lastPercent = -1;
|
|
107
|
+
|
|
108
|
+
const file = createWriteStream(destPath);
|
|
109
|
+
response.on("data", (chunk) => {
|
|
110
|
+
downloadedBytes += chunk.length;
|
|
111
|
+
lastPercent = reportProgress(downloadedBytes, totalBytes, lastPercent);
|
|
112
|
+
});
|
|
113
|
+
response.pipe(file);
|
|
114
|
+
file.on("finish", () => {
|
|
115
|
+
file.close();
|
|
116
|
+
if (totalBytes) {
|
|
117
|
+
process.stderr.write("\n");
|
|
118
|
+
}
|
|
119
|
+
resolve();
|
|
120
|
+
});
|
|
121
|
+
file.on("error", (err) => {
|
|
122
|
+
file.close();
|
|
123
|
+
reject(err);
|
|
124
|
+
});
|
|
125
|
+
})
|
|
126
|
+
.on("error", reject);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Extracts a zip file to a destination directory.
|
|
132
|
+
*
|
|
133
|
+
* Uses platform-native tools: `unzip` on Unix (available on macOS and
|
|
134
|
+
* most Linux distros) and PowerShell's Expand-Archive on Windows.
|
|
135
|
+
*
|
|
136
|
+
* @param {string} zipPath
|
|
137
|
+
* @param {string} destDir
|
|
138
|
+
* @returns {void}
|
|
139
|
+
*/
|
|
140
|
+
function extractZip(zipPath, destDir) {
|
|
141
|
+
if (process.platform === "win32") {
|
|
142
|
+
execFileSync(
|
|
143
|
+
"powershell",
|
|
144
|
+
[
|
|
145
|
+
"-NoProfile",
|
|
146
|
+
"-Command",
|
|
147
|
+
`Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force`,
|
|
148
|
+
],
|
|
149
|
+
{ stdio: "pipe" }
|
|
150
|
+
);
|
|
151
|
+
} else {
|
|
152
|
+
execFileSync("unzip", ["-o", "-q", zipPath, "-d", destDir], {
|
|
153
|
+
stdio: "pipe",
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Downloads and extracts a compressed binary, or downloads a bare binary.
|
|
160
|
+
*
|
|
161
|
+
* @param {string} url - The download URL
|
|
162
|
+
* @param {{ asset: string, compressed: boolean }} platformInfo
|
|
163
|
+
* @param {string} cacheDir - Directory to download into
|
|
164
|
+
* @param {string} binaryPath - Final expected binary path (for uncompressed)
|
|
165
|
+
* @returns {Promise<void>}
|
|
166
|
+
*/
|
|
167
|
+
async function downloadAsset(url, platformInfo, cacheDir, binaryPath) {
|
|
168
|
+
if (!platformInfo.compressed) {
|
|
169
|
+
await downloadFile(url, binaryPath);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const zipPath = join(cacheDir, platformInfo.asset);
|
|
174
|
+
try {
|
|
175
|
+
await downloadFile(url, zipPath);
|
|
176
|
+
process.stderr.write(" Extracting...\n");
|
|
177
|
+
extractZip(zipPath, cacheDir);
|
|
178
|
+
} finally {
|
|
179
|
+
await rm(zipPath, { force: true }).catch(() => {});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Finds and renames a platform-named binary to the canonical name.
|
|
185
|
+
*
|
|
186
|
+
* Zip files from GitHub releases contain binaries like "cs-mcp-linux-amd64"
|
|
187
|
+
* instead of plain "cs-mcp". This function locates such a candidate and
|
|
188
|
+
* renames it.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} cacheDir
|
|
191
|
+
* @param {string} binaryPath - The expected canonical binary path
|
|
192
|
+
* @returns {Promise<void>}
|
|
193
|
+
*/
|
|
194
|
+
async function renameExtractedBinary(cacheDir, binaryPath) {
|
|
195
|
+
if (existsSync(binaryPath)) return;
|
|
196
|
+
|
|
197
|
+
const files = readdirSync(cacheDir);
|
|
198
|
+
const candidate = files.find(
|
|
199
|
+
(f) => f.startsWith("cs-mcp") && !f.endsWith(".zip")
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
if (candidate) {
|
|
203
|
+
await rename(join(cacheDir, candidate), binaryPath);
|
|
204
|
+
} else {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Binary not found after download. Expected cs-mcp in ${cacheDir}. ` +
|
|
207
|
+
`Found: ${files.join(", ")}`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Ensures the cs-mcp binary is available for the given version.
|
|
214
|
+
*
|
|
215
|
+
* If the binary is already cached, returns its path immediately.
|
|
216
|
+
* Otherwise, downloads it from GitHub releases, extracts if needed,
|
|
217
|
+
* and caches it for future use.
|
|
218
|
+
*
|
|
219
|
+
* @param {string} version - The package version (e.g. "0.2.1")
|
|
220
|
+
* @returns {Promise<string>} Path to the binary
|
|
221
|
+
*/
|
|
222
|
+
export async function ensureBinary(version) {
|
|
223
|
+
const binaryPath = getCachedBinaryPath(version);
|
|
224
|
+
|
|
225
|
+
if (existsSync(binaryPath)) {
|
|
226
|
+
return binaryPath;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const platformInfo = getPlatformInfo();
|
|
230
|
+
const url = getDownloadUrl(version, platformInfo.asset);
|
|
231
|
+
const cacheDir = getCacheDir(version);
|
|
232
|
+
|
|
233
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
234
|
+
|
|
235
|
+
process.stderr.write(
|
|
236
|
+
`CodeScene MCP Server v${version} - downloading for ${process.platform}/${process.arch}...\n`
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
await downloadAsset(url, platformInfo, cacheDir, binaryPath);
|
|
240
|
+
await renameExtractedBinary(cacheDir, binaryPath);
|
|
241
|
+
|
|
242
|
+
if (process.platform !== "win32") {
|
|
243
|
+
chmodSync(binaryPath, 0o755);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
process.stderr.write(` Ready: ${binaryPath}\n`);
|
|
247
|
+
return binaryPath;
|
|
248
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main orchestrator for the npm wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the binary path (from CS_MCP_BINARY_PATH or by downloading
|
|
5
|
+
* from GitHub releases) and launches it.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
9
|
+
import { join, dirname, resolve } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { ensureBinary } from "./download.js";
|
|
12
|
+
import { runBinary } from "./run.js";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const PACKAGE_ROOT = join(__dirname, "..");
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Reads the package version from package.json.
|
|
19
|
+
*
|
|
20
|
+
* @returns {string}
|
|
21
|
+
*/
|
|
22
|
+
function getPackageVersion() {
|
|
23
|
+
const pkgPath = join(PACKAGE_ROOT, "package.json");
|
|
24
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
25
|
+
return pkg.version;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Main entry point.
|
|
30
|
+
*
|
|
31
|
+
* Resolution order:
|
|
32
|
+
* 1. CS_MCP_BINARY_PATH env var - use the specified binary directly
|
|
33
|
+
* 2. Cached binary for the current package version
|
|
34
|
+
* 3. Download from GitHub releases and cache
|
|
35
|
+
*
|
|
36
|
+
* All command-line arguments (except the node binary and script path)
|
|
37
|
+
* are forwarded to the cs-mcp binary.
|
|
38
|
+
*/
|
|
39
|
+
export async function main() {
|
|
40
|
+
const args = process.argv.slice(2);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const binaryPath = await resolveBinaryPath();
|
|
44
|
+
runBinary(binaryPath, args);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Resolves the path to the cs-mcp binary.
|
|
53
|
+
*
|
|
54
|
+
* @returns {Promise<string>}
|
|
55
|
+
*/
|
|
56
|
+
async function resolveBinaryPath() {
|
|
57
|
+
// 1. Check for explicit binary path override
|
|
58
|
+
const envPath = process.env.CS_MCP_BINARY_PATH;
|
|
59
|
+
if (envPath) {
|
|
60
|
+
const resolved = resolve(envPath);
|
|
61
|
+
if (!existsSync(resolved)) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`CS_MCP_BINARY_PATH is set to "${envPath}" but the file does not exist.`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
return resolved;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 2. Download or use cached binary matching this package version
|
|
70
|
+
const version = getPackageVersion();
|
|
71
|
+
return ensureBinary(version);
|
|
72
|
+
}
|
package/lib/platform.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform and architecture detection for downloading the correct binary.
|
|
3
|
+
*
|
|
4
|
+
* Maps Node.js platform/arch identifiers to the GitHub release asset names
|
|
5
|
+
* used by the codescene-mcp-server build pipeline.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const PLATFORM_MAP = {
|
|
9
|
+
"darwin-arm64": {
|
|
10
|
+
asset: "cs-mcp-macos-aarch64.zip",
|
|
11
|
+
binary: "cs-mcp",
|
|
12
|
+
compressed: true,
|
|
13
|
+
},
|
|
14
|
+
"darwin-x64": {
|
|
15
|
+
asset: "cs-mcp-macos-amd64.zip",
|
|
16
|
+
binary: "cs-mcp",
|
|
17
|
+
compressed: true,
|
|
18
|
+
},
|
|
19
|
+
"linux-arm64": {
|
|
20
|
+
asset: "cs-mcp-linux-aarch64.zip",
|
|
21
|
+
binary: "cs-mcp",
|
|
22
|
+
compressed: true,
|
|
23
|
+
},
|
|
24
|
+
"linux-x64": {
|
|
25
|
+
asset: "cs-mcp-linux-amd64.zip",
|
|
26
|
+
binary: "cs-mcp",
|
|
27
|
+
compressed: true,
|
|
28
|
+
},
|
|
29
|
+
"win32-x64": {
|
|
30
|
+
asset: "cs-mcp-windows-amd64.exe",
|
|
31
|
+
binary: "cs-mcp.exe",
|
|
32
|
+
compressed: false,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns the platform info for the current OS and architecture.
|
|
38
|
+
*
|
|
39
|
+
* @returns {{ asset: string, binary: string, compressed: boolean }}
|
|
40
|
+
* @throws {Error} If the current platform/arch combination is unsupported.
|
|
41
|
+
*/
|
|
42
|
+
export function getPlatformInfo() {
|
|
43
|
+
const key = `${process.platform}-${process.arch}`;
|
|
44
|
+
const info = PLATFORM_MAP[key];
|
|
45
|
+
|
|
46
|
+
if (!info) {
|
|
47
|
+
const supported = Object.keys(PLATFORM_MAP)
|
|
48
|
+
.map((k) => k.replace("-", "/"))
|
|
49
|
+
.join(", ");
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Unsupported platform: ${process.platform}/${process.arch}. ` +
|
|
52
|
+
`Supported platforms: ${supported}`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return info;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Constructs the download URL for a given version and asset.
|
|
61
|
+
*
|
|
62
|
+
* By default, downloads from GitHub releases. Set CS_MCP_DOWNLOAD_BASE_URL
|
|
63
|
+
* to override the base URL (useful for testing, mirrors, or air-gapped
|
|
64
|
+
* environments). The env var should include the full base up to the tag
|
|
65
|
+
* directory, e.g. "http://localhost:8080/releases/download".
|
|
66
|
+
*
|
|
67
|
+
* @param {string} version - The package version (e.g. "0.2.1")
|
|
68
|
+
* @param {string} asset - The asset filename (e.g. "cs-mcp-macos-aarch64.zip")
|
|
69
|
+
* @returns {string} The full download URL
|
|
70
|
+
*/
|
|
71
|
+
export function getDownloadUrl(version, asset) {
|
|
72
|
+
const tag = `MCP-${version}`;
|
|
73
|
+
const baseUrl =
|
|
74
|
+
process.env.CS_MCP_DOWNLOAD_BASE_URL ||
|
|
75
|
+
"https://github.com/codescene-oss/codescene-mcp-server/releases/download";
|
|
76
|
+
return `${baseUrl}/${tag}/${asset}`;
|
|
77
|
+
}
|
package/lib/run.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawns the cs-mcp binary as a child process.
|
|
3
|
+
*
|
|
4
|
+
* Uses `stdio: "inherit"` so that stdin, stdout, and stderr are passed
|
|
5
|
+
* directly through to the child process. This is critical for the MCP
|
|
6
|
+
* stdio transport where the MCP client communicates via JSON-RPC over
|
|
7
|
+
* the process's stdin/stdout.
|
|
8
|
+
*
|
|
9
|
+
* Signals are forwarded to the child process so that graceful shutdown
|
|
10
|
+
* works as expected.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Runs the cs-mcp binary, forwarding all stdio and signals.
|
|
17
|
+
*
|
|
18
|
+
* This function does not return until the binary exits.
|
|
19
|
+
* The current process exits with the same exit code as the binary.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} binaryPath - Absolute path to the cs-mcp binary
|
|
22
|
+
* @param {string[]} args - Command-line arguments to pass through
|
|
23
|
+
* @returns {never}
|
|
24
|
+
*/
|
|
25
|
+
export function runBinary(binaryPath, args) {
|
|
26
|
+
const result = spawnSync(binaryPath, args, {
|
|
27
|
+
stdio: "inherit",
|
|
28
|
+
env: process.env,
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (result.error) {
|
|
33
|
+
// Handle spawn errors (e.g. binary not found, permission denied)
|
|
34
|
+
if (result.error.code === "ENOENT") {
|
|
35
|
+
process.stderr.write(`Error: Binary not found at ${binaryPath}\n`);
|
|
36
|
+
process.exit(127);
|
|
37
|
+
}
|
|
38
|
+
if (result.error.code === "EACCES") {
|
|
39
|
+
process.stderr.write(
|
|
40
|
+
`Error: Permission denied executing ${binaryPath}\n`
|
|
41
|
+
);
|
|
42
|
+
process.exit(126);
|
|
43
|
+
}
|
|
44
|
+
throw result.error;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Exit with the same code as the child process.
|
|
48
|
+
// If the child was killed by a signal, use 128 + signal number convention.
|
|
49
|
+
if (result.status !== null) {
|
|
50
|
+
process.exit(result.status);
|
|
51
|
+
}
|
|
52
|
+
if (result.signal) {
|
|
53
|
+
// Convert signal name to number (e.g. SIGTERM -> 15)
|
|
54
|
+
const signalNumbers = { SIGTERM: 15, SIGINT: 2, SIGKILL: 9, SIGHUP: 1 };
|
|
55
|
+
const sigNum = signalNumbers[result.signal] || 1;
|
|
56
|
+
process.exit(128 + sigNum);
|
|
57
|
+
}
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codescene/codehealth-mcp",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "CodeScene MCP Server — Code Health analysis for AI coding agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"cs-mcp": "./bin/cs-mcp.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "c8 node --experimental-test-module-mocks --test tests/*.test.js",
|
|
11
|
+
"test:ci": "c8 --reporter=cobertura --reporter=text node --experimental-test-module-mocks --test tests/*.test.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin/",
|
|
15
|
+
"lib/"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"os": [
|
|
21
|
+
"darwin",
|
|
22
|
+
"linux",
|
|
23
|
+
"win32"
|
|
24
|
+
],
|
|
25
|
+
"cpu": [
|
|
26
|
+
"x64",
|
|
27
|
+
"arm64"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/codescene-oss/codescene-mcp-server.git",
|
|
33
|
+
"directory": "npm"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://codescene.com",
|
|
36
|
+
"keywords": [
|
|
37
|
+
"codescene",
|
|
38
|
+
"code-health",
|
|
39
|
+
"mcp",
|
|
40
|
+
"model-context-protocol",
|
|
41
|
+
"ai",
|
|
42
|
+
"code-quality"
|
|
43
|
+
],
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"c8": "^11.0.0"
|
|
46
|
+
}
|
|
47
|
+
}
|