@atlassian/mcp-compressor 0.31.5 → 0.31.6
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/dist/cli.js +77 -4
- package/native/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command, Option } from "commander";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
4
|
+
import { accessSync, closeSync, constants, existsSync, openSync, readSync } from "node:fs";
|
|
5
|
+
import { delimiter, dirname, join } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { VERSION } from "./version.js";
|
|
8
8
|
function parseBackendArg(backendArgs) {
|
|
@@ -121,12 +121,85 @@ function parseClearOAuthArgs(args) {
|
|
|
121
121
|
const options = clearProgram.opts();
|
|
122
122
|
return { ...(target ? { target } : {}), all: options.all ?? false };
|
|
123
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Resolve a bare binary name to an absolute path using the PATH environment
|
|
126
|
+
* variable. Returns null when the name cannot be found in any PATH directory.
|
|
127
|
+
*/
|
|
128
|
+
function resolveFromPath(name) {
|
|
129
|
+
const pathEnv = process.env.PATH ?? "";
|
|
130
|
+
const dirs = pathEnv.split(delimiter);
|
|
131
|
+
const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";") : [""];
|
|
132
|
+
for (const dir of dirs) {
|
|
133
|
+
for (const ext of exts) {
|
|
134
|
+
const candidate = join(dir, name + ext);
|
|
135
|
+
try {
|
|
136
|
+
accessSync(candidate, constants.X_OK);
|
|
137
|
+
return candidate;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// not executable or not found — try next
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Return true when the file at `filePath` begins with a native-executable
|
|
148
|
+
* magic number (ELF, Mach-O, or PE). A JS shim that starts with a `#!`
|
|
149
|
+
* shebang (or any other non-native header) returns false.
|
|
150
|
+
*
|
|
151
|
+
* This guards against the fork-bomb that occurs when the npm-installed
|
|
152
|
+
* `mcp-compressor` bin shim is the only entry on PATH: spawning it would
|
|
153
|
+
* re-invoke this very script rather than the Rust binary.
|
|
154
|
+
*/
|
|
155
|
+
function isNativeExecutable(filePath) {
|
|
156
|
+
let fd;
|
|
157
|
+
try {
|
|
158
|
+
fd = openSync(filePath, "r");
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const buf = Buffer.alloc(4);
|
|
165
|
+
const n = readSync(fd, buf, 0, 4, 0);
|
|
166
|
+
if (n < 4)
|
|
167
|
+
return false;
|
|
168
|
+
// ELF (Linux/BSD): \x7fELF
|
|
169
|
+
if (buf[0] === 0x7f && buf[1] === 0x45 && buf[2] === 0x4c && buf[3] === 0x46)
|
|
170
|
+
return true;
|
|
171
|
+
// PE (Windows): MZ
|
|
172
|
+
if (buf[0] === 0x4d && buf[1] === 0x5a)
|
|
173
|
+
return true;
|
|
174
|
+
// Mach-O (macOS) — big-endian and little-endian variants, including fat/universal
|
|
175
|
+
const be = buf.readUInt32BE(0);
|
|
176
|
+
if (be === 0xfeedface || // Mach-O 32-bit BE
|
|
177
|
+
be === 0xfeedfacf || // Mach-O 64-bit BE
|
|
178
|
+
be === 0xcefaedfe || // Mach-O 32-bit LE
|
|
179
|
+
be === 0xcffaedfe || // Mach-O 64-bit LE
|
|
180
|
+
be === 0xcafebabe || // Mach-O fat binary
|
|
181
|
+
be === 0xbebafeca // Mach-O fat binary LE
|
|
182
|
+
)
|
|
183
|
+
return true;
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
closeSync(fd);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
124
190
|
function candidateCoreBinaries() {
|
|
125
191
|
const candidates = [];
|
|
126
192
|
if (process.env.MCP_COMPRESSOR_BINARY) {
|
|
127
193
|
candidates.push(process.env.MCP_COMPRESSOR_BINARY);
|
|
128
194
|
}
|
|
129
|
-
|
|
195
|
+
// Resolve the bare name from PATH and only include it when the resolved
|
|
196
|
+
// file is a native binary, not a JS shim. Without this check the npm bin
|
|
197
|
+
// shim (which maps `mcp-compressor` back to this very script) would be
|
|
198
|
+
// spawned indefinitely, creating a fork bomb.
|
|
199
|
+
const resolved = resolveFromPath("mcp-compressor");
|
|
200
|
+
if (resolved !== null && isNativeExecutable(resolved)) {
|
|
201
|
+
candidates.push(resolved);
|
|
202
|
+
}
|
|
130
203
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
131
204
|
candidates.push(join(here, "..", "..", "target", "debug", process.platform === "win32" ? "mcp-compressor.exe" : "mcp-compressor"));
|
|
132
205
|
candidates.push(join(process.cwd(), "..", "target", "debug", process.platform === "win32" ? "mcp-compressor.exe" : "mcp-compressor"));
|
|
@@ -141,7 +214,7 @@ function translateArgsForRust(args) {
|
|
|
141
214
|
}
|
|
142
215
|
async function runRustCoreCli(args) {
|
|
143
216
|
for (const binary of candidateCoreBinaries()) {
|
|
144
|
-
if (
|
|
217
|
+
if (!existsSync(binary)) {
|
|
145
218
|
continue;
|
|
146
219
|
}
|
|
147
220
|
const child = spawn(binary, translateArgsForRust(args), { stdio: "inherit" });
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlassian/mcp-compressor",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.6",
|
|
4
4
|
"description": "TypeScript MCP server wrapper for reducing tokens consumed by MCP tools.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/atlassian-labs/mcp-compressor",
|