Sign In

@paretools/shared

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@paretools/shared - npm Package Compare versions

Comparing version
0.2.0
to
0.3.0
+8
dist/validation.d.ts
/**
* Validates that a string argument is safe to pass as a positional argument to a CLI tool.
* Prevents flag injection attacks (e.g., passing "--output=/etc/passwd" as a ref name).
* See: CVE-2025-68144, CVE-2025-68145
*/
export declare function assertNoFlagInjection(value: string, paramName: string): void;
export declare function assertAllowedCommand(command: string): void;
//# sourceMappingURL=validation.d.ts.map
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAM5E;AAiCD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAe1D"}
/**
* Validates that a string argument is safe to pass as a positional argument to a CLI tool.
* Prevents flag injection attacks (e.g., passing "--output=/etc/passwd" as a ref name).
* See: CVE-2025-68144, CVE-2025-68145
*/
export function assertNoFlagInjection(value, paramName) {
if (value.startsWith("-")) {
throw new Error(`Invalid ${paramName}: "${value}". Values must not start with "-" to prevent argument injection.`);
}
}
/**
* Allowlist of known safe build commands.
* Prevents arbitrary command execution via the build tool's command parameter.
*/
const ALLOWED_BUILD_COMMANDS = new Set([
"npm",
"npx",
"pnpm",
"yarn",
"bun",
"bunx",
"make",
"cmake",
"gradle",
"gradlew",
"mvn",
"ant",
"cargo",
"go",
"dotnet",
"msbuild",
"tsc",
"esbuild",
"vite",
"webpack",
"rollup",
"turbo",
"nx",
"bazel",
]);
export function assertAllowedCommand(command) {
// Extract the base command name (handle paths like /usr/bin/npm or C:\npm.cmd)
const base = command
.replace(/\\/g, "/")
.split("/")
.pop()
?.replace(/\.(cmd|exe|bat|sh)$/i, "") ?? "";
if (!ALLOWED_BUILD_COMMANDS.has(base)) {
throw new Error(`Command "${command}" is not in the allowed build commands list. ` +
`Allowed: ${[...ALLOWED_BUILD_COMMANDS].sort().join(", ")}`);
}
}
//# sourceMappingURL=validation.js.map
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa,EAAE,SAAiB;IACpE,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,WAAW,SAAS,MAAM,KAAK,kEAAkE,CAClG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,OAAO;IACP,QAAQ;IACR,SAAS;IACT,KAAK;IACL,KAAK;IACL,OAAO;IACP,IAAI;IACJ,QAAQ;IACR,SAAS;IACT,KAAK;IACL,SAAS;IACT,MAAM;IACN,SAAS;IACT,QAAQ;IACR,OAAO;IACP,IAAI;IACJ,OAAO;CACR,CAAC,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,+EAA+E;IAC/E,MAAM,IAAI,GACR,OAAO;SACJ,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,EAAE;QACN,EAAE,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IAEhD,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CACb,YAAY,OAAO,+CAA+C;YAChE,YAAY,CAAC,GAAG,sBAAsB,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9D,CAAC;IACJ,CAAC;AACH,CAAC"}
# @paretools/shared
Shared utilities for Pare MCP servers.
## Exports
- **`run(command, args, options)`** — Executes a CLI command via `execFile` (no shell injection) and returns `{ stdout, stderr, exitCode }`
- **`dualOutput(data, formatter)`** — Returns both `structuredContent` (typed JSON) and `content` (human-readable text) for MCP tool responses
- **`stripAnsi(text)`** — Removes ANSI escape codes from CLI output
## Usage
This package is used internally by all `@paretools/*` server packages. You generally don't need to install it directly unless you're building a custom Pare server.
```typescript
import { run, dualOutput, stripAnsi } from "@paretools/shared";
```
## Links
- [Pare monorepo](https://github.com/Dave-London/pare)
## License
[MIT](https://github.com/Dave-London/pare/blob/main/LICENSE)
+1
-0
export { dualOutput } from "./output.js";
export { run, type RunResult, type RunOptions } from "./runner.js";
export { stripAnsi } from "./ansi.js";
export { assertNoFlagInjection, assertAllowedCommand } from "./validation.js";
export type { ToolOutput } from "./types.js";
//# sourceMappingURL=index.d.ts.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
export { dualOutput } from "./output.js";
export { run } from "./runner.js";
export { stripAnsi } from "./ansi.js";
export { assertNoFlagInjection, assertAllowedCommand } from "./validation.js";
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,GAAG,EAAmC,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,GAAG,EAAmC,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC"}

@@ -16,4 +16,7 @@ export interface RunOptions {

* still passed as an array so they remain properly escaped.
*
* Throws on system-level errors (command not found, permission denied).
* Normal non-zero exit codes are returned in the result, not thrown.
*/
export declare function run(cmd: string, args: string[], opts?: RunOptions): Promise<RunResult>;
//# sourceMappingURL=runner.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAqBtF"}
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAkDtF"}

@@ -8,5 +8,8 @@ import { execFile } from "node:child_process";

* still passed as an array so they remain properly escaped.
*
* Throws on system-level errors (command not found, permission denied).
* Normal non-zero exit codes are returned in the result, not thrown.
*/
export function run(cmd, args, opts) {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
execFile(cmd, args, {

@@ -19,4 +22,22 @@ cwd: opts?.cwd,

}, (error, stdout, stderr) => {
if (error) {
const errno = error;
// Unix: direct ENOENT from execFile (no shell wrapping)
if (errno.code === "ENOENT") {
reject(new Error(`Command not found: "${cmd}". Ensure it is installed and available in your PATH.`));
return;
}
if (errno.code === "EACCES" || errno.code === "EPERM") {
reject(new Error(`Permission denied executing "${cmd}": ${errno.message}`));
return;
}
// Windows: cmd.exe masks ENOENT — detect via stderr message
const cleanStderr = stripAnsi(stderr);
if (cleanStderr.includes("is not recognized")) {
reject(new Error(`Command not found: "${cmd}". Ensure it is installed and available in your PATH.`));
return;
}
}
resolve({
exitCode: error && "code" in error ? error.code : error ? 1 : 0,
exitCode: error ? (typeof error.code === "number" ? error.code : 1) : 0,
stdout: stripAnsi(stdout),

@@ -23,0 +44,0 @@ stderr: stripAnsi(stderr),

@@ -1,1 +0,1 @@

{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AActC;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,IAAc,EAAE,IAAiB;IAChE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CACN,GAAG,EACH,IAAI,EACJ;YACE,GAAG,EAAE,IAAI,EAAE,GAAG;YACd,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,MAAM;YAChC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;YAC5D,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,QAAQ;YACrC,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;SACpC,EACD,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACxB,OAAO,CAAC;gBACN,QAAQ,EAAE,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAE,KAAK,CAAC,IAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3E,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;gBACzB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;aAC1B,CAAC,CAAC;QACL,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AActC;;;;;;;;GAQG;AACH,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,IAAc,EAAE,IAAiB;IAChE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,QAAQ,CACN,GAAG,EACH,IAAI,EACJ;YACE,GAAG,EAAE,IAAI,EAAE,GAAG;YACd,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,MAAM;YAChC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;YAC5D,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,QAAQ;YACrC,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;SACpC,EACD,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACxB,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,KAAK,GAAG,KAA8B,CAAC;gBAE7C,wDAAwD;gBACxD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC5B,MAAM,CACJ,IAAI,KAAK,CACP,uBAAuB,GAAG,uDAAuD,CAClF,CACF,CAAC;oBACF,OAAO;gBACT,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACtD,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBAC5E,OAAO;gBACT,CAAC;gBAED,4DAA4D;gBAC5D,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;gBACtC,IAAI,WAAW,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBAC9C,MAAM,CACJ,IAAI,KAAK,CACP,uBAAuB,GAAG,uDAAuD,CAClF,CACF,CAAC;oBACF,OAAO;gBACT,CAAC;YACH,CAAC;YAED,OAAO,CAAC;gBACN,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;gBACzB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;aAC1B,CAAC,CAAC;QACL,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
{
"name": "@paretools/shared",
"version": "0.2.0",
"description": "Shared utilities for pare MCP servers",
"version": "0.3.0",
"description": "Shared utilities for Pare MCP servers",
"license": "MIT",
"keywords": [
"mcp",
"mcp-server",
"model-context-protocol",
"structured-output"
],
"homepage": "https://github.com/Dave-London/pare/tree/main/packages/shared",
"engines": {
"node": ">=18"
},
"type": "module",

@@ -7,0 +17,0 @@ "exports": {