@ax-llm/ax-tools 25.4.5 → 25.4.7

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/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BocRIvOZ.cjs");let t=require("node:child_process"),n=require("node:readline");n=e.t(n,1);var r=class{process;rl;pendingResponses=/* @__PURE__ */ new Map;closed=!1;closePromise;messageHandler;constructor(e){this.process=(0,t.spawn)(e.command,e.args??[],{env:e.env?{...process.env,...e.env}:process.env}),this.closePromise=new Promise(e=>{this.process.once(`close`,()=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process closed`)),e()})}),this.process.once(`error`,e=>this.closeWithError(e)),this.process.once(`exit`,(e,t)=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process exited${e===null?``:` with code ${e}`}${t?` (${t})`:``}`))}),this.process.stdin.on(`error`,e=>this.closeWithError(e)),this.rl=n.default.createInterface({input:this.process.stdout}),this.rl.on(`line`,e=>{try{let t=JSON.parse(e);if(`method`in t){this.messageHandler?.(t);return}let n=t,r=n.id===null?void 0:this.pendingResponses.get(n.id);r?(r.resolve(n),n.id!==null&&this.pendingResponses.delete(n.id)):this.messageHandler?.(t)}catch{console.warn(`Non-JSON output from MCP server:`,e)}})}async send(e){return new Promise((t,n)=>{if(this.closed){n(/* @__PURE__ */ Error(`MCP server process is not running`));return}this.pendingResponses.set(e.id,{resolve:e=>t(e),reject:n}),this.writeMessage(e).catch(t=>{this.pendingResponses.delete(e.id),n(t)})})}async sendNotification(e){await this.writeMessage(e)}async sendResponse(e){await this.writeMessage(e)}setMessageHandler(e){this.messageHandler=e}async connect(){return Promise.resolve()}async terminate(){this.closeWithError(/* @__PURE__ */ Error(`MCP server process terminated`)),this.rl.close(),this.process.exitCode===null&&this.process.signalCode===null&&this.process.kill(),await this.closePromise}async writeMessage(e){if(this.closed||this.process.stdin.destroyed)throw Error(`MCP server process is not running`);await new Promise((t,n)=>{this.process.stdin.write(`${JSON.stringify(e)}\n`,e=>{e?n(e):t()})})}closeWithError(e){if(!this.closed){this.closed=!0;for(let t of this.pendingResponses.values())t.reject(e);this.pendingResponses.clear()}}};function i(e){return new r(e)}exports.AxMCPStdioTransport=r,exports.axCreateMCPStdioTransport=i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BocRIvOZ.cjs");let t=require("node:child_process"),n=require("node:readline");n=e.t(n,1);let r=require("node:fs"),i=require("node:path");i=e.t(i,1);const a=/([()\][%!^"`<>&|;, *?])/g;function o(e,t){let n=Object.keys(e).sort().find(e=>e.toUpperCase()===t);return n===void 0?void 0:e[n]}function s(e){return e.replace(a,`^$1`)}function c(e,t){let n=``,r=0;for(let t of e){if(t===`\\`){r++;continue}let e=t===`"`?r*2+1:r;n+=`${`\\`.repeat(e)}${t}`,r=0}return n+=`\\`.repeat(r*2),n=`"${n}"`.replace(a,`^$1`),t?n.replace(a,`^$1`):n}function l(e,t){let n=/[\\/]/.test(e)?[``]:[process.cwd(),...(o(t,`PATH`)??``).split(`;`)],a=(o(t,`PATHEXT`)??`.EXE;.CMD;.BAT;.COM`).split(`;`);e.includes(`.`)&&a[0]!==``&&a.unshift(``);for(let t of n){let n=i.default.join(t.replace(/^"(.*)"$/,`$1`),e);for(let e of a){let t=n+e;if(a.some(e=>e!==``&&t.toLowerCase().endsWith(e.toLowerCase()))&&(0,r.statSync)(t,{throwIfNoEntry:!1})?.isFile())return i.default.resolve(t)}}}function u(e,t,n){let r=l(e,n);if(r&&/\.(?:com|exe)$/i.test(r))return;let a=r!==void 0&&/\.(?:bat|cmd)$/i.test(r),u=[s(i.default.normalize(e)),...t.map(e=>c(e,a))].join(` `);return{command:o(n,`COMSPEC`)??`cmd.exe`,args:[`/d`,`/s`,`/c`,`"${u}"`]}}var d=class{process;rl;pendingResponses=/* @__PURE__ */ new Map;closed=!1;closePromise;messageHandler;constructor(e){let r=e.env?{...process.env,...e.env}:process.env,i=process.platform===`win32`?u(e.command,e.args??[],r):void 0;this.process=i?(0,t.spawn)(i.command,i.args,{env:r,windowsVerbatimArguments:!0}):(0,t.spawn)(e.command,e.args??[],{env:r}),this.closePromise=new Promise(e=>{this.process.once(`close`,()=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process closed`)),e()})}),this.process.once(`error`,e=>this.closeWithError(e)),this.process.once(`exit`,(e,t)=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process exited${e===null?``:` with code ${e}`}${t?` (${t})`:``}`))}),this.process.stdin.on(`error`,e=>this.closeWithError(e)),this.rl=n.default.createInterface({input:this.process.stdout}),this.rl.on(`line`,e=>{try{let t=JSON.parse(e);if(`method`in t){this.messageHandler?.(t);return}let n=t,r=n.id===null?void 0:this.pendingResponses.get(n.id);r?(r.resolve(n),n.id!==null&&this.pendingResponses.delete(n.id)):this.messageHandler?.(t)}catch{console.warn(`Non-JSON output from MCP server:`,e)}})}async send(e){return new Promise((t,n)=>{if(this.closed){n(/* @__PURE__ */ Error(`MCP server process is not running`));return}this.pendingResponses.set(e.id,{resolve:e=>t(e),reject:n}),this.writeMessage(e).catch(t=>{this.pendingResponses.delete(e.id),n(t)})})}async sendNotification(e){await this.writeMessage(e)}async sendResponse(e){await this.writeMessage(e)}setMessageHandler(e){this.messageHandler=e}async connect(){return Promise.resolve()}async terminate(){this.closeWithError(/* @__PURE__ */ Error(`MCP server process terminated`)),this.rl.close(),this.process.exitCode===null&&this.process.signalCode===null&&this.process.kill(),await this.closePromise}async writeMessage(e){if(this.closed||this.process.stdin.destroyed)throw Error(`MCP server process is not running`);await new Promise((t,n)=>{this.process.stdin.write(`${JSON.stringify(e)}\n`,e=>{e?n(e):t()})})}closeWithError(e){if(!this.closed){this.closed=!0;for(let t of this.pendingResponses.values())t.reject(e);this.pendingResponses.clear()}}};function f(e){return new d(e)}exports.AxMCPStdioTransport=d,exports.axCreateMCPStdioTransport=f;
2
2
  //# sourceMappingURL=index.cjs.map
package/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["spawn","readline","require_rolldown_runtime","node_child_process","node_readline","AxMCPStdioTransport","config","resolve","error","code","signal","message","line","response","pending","reject","res","handler","axCreateMCPStdioTransport"],"sources":["../mcp/stdioTransport.ts"],"sourcesContent":["import { type ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport readline from 'node:readline';\n\nimport type {\n AxMCPJSONRPCMessage,\n AxMCPJSONRPCNotification,\n AxMCPJSONRPCRequest,\n AxMCPJSONRPCResponse,\n AxMCPTransport,\n} from '@ax-llm/ax';\n\nexport interface StdioTransportConfig {\n command: string;\n args?: string[];\n env?: NodeJS.ProcessEnv;\n}\n\nexport class AxMCPStdioTransport implements AxMCPTransport {\n private process: ChildProcessWithoutNullStreams;\n private rl: readline.Interface;\n private pendingResponses = new Map<\n string | number,\n {\n resolve: (res: AxMCPJSONRPCResponse) => void;\n reject: (error: Error) => void;\n }\n >();\n private closed = false;\n private closePromise: Promise<void>;\n private messageHandler?: (\n message: Readonly<AxMCPJSONRPCMessage>\n ) => void | Promise<void>;\n\n constructor(config: Readonly<StdioTransportConfig>) {\n this.process = spawn(config.command, config.args ?? [], {\n env: config.env ? { ...process.env, ...config.env } : process.env,\n });\n this.closePromise = new Promise((resolve) => {\n this.process.once('close', () => {\n this.closeWithError(new Error('MCP server process closed'));\n resolve();\n });\n });\n this.process.once('error', (error) => this.closeWithError(error));\n this.process.once('exit', (code, signal) => {\n this.closeWithError(\n new Error(\n `MCP server process exited${code === null ? '' : ` with code ${code}`}${signal ? ` (${signal})` : ''}`\n )\n );\n });\n this.process.stdin.on('error', (error) => this.closeWithError(error));\n this.rl = readline.createInterface({ input: this.process.stdout });\n this.rl.on('line', (line) => {\n try {\n const message: AxMCPJSONRPCMessage = JSON.parse(line);\n if ('method' in message) {\n void this.messageHandler?.(message);\n return;\n }\n const response = message as AxMCPJSONRPCResponse;\n const pending =\n response.id === null\n ? undefined\n : this.pendingResponses.get(response.id);\n if (pending) {\n pending.resolve(response);\n if (response.id !== null) this.pendingResponses.delete(response.id);\n } else {\n void this.messageHandler?.(message);\n }\n } catch (_error) {\n // Skip non-JSON lines (might be debug output from the MCP server)\n console.warn('Non-JSON output from MCP server:', line);\n }\n });\n }\n\n async send(\n message: Readonly<AxMCPJSONRPCRequest<unknown>>\n ): Promise<AxMCPJSONRPCResponse<unknown>> {\n return new Promise<AxMCPJSONRPCResponse<unknown>>((resolve, reject) => {\n if (this.closed) {\n reject(new Error('MCP server process is not running'));\n return;\n }\n this.pendingResponses.set(message.id, {\n resolve: (res) => resolve(res as AxMCPJSONRPCResponse<unknown>),\n reject,\n });\n void this.writeMessage(message).catch((error: Error) => {\n this.pendingResponses.delete(message.id);\n reject(error);\n });\n });\n }\n\n async sendNotification(\n message: Readonly<AxMCPJSONRPCNotification>\n ): Promise<void> {\n await this.writeMessage(message);\n }\n\n async sendResponse(message: Readonly<AxMCPJSONRPCResponse>): Promise<void> {\n await this.writeMessage(message);\n }\n\n setMessageHandler(\n handler: (message: Readonly<AxMCPJSONRPCMessage>) => void | Promise<void>\n ): void {\n this.messageHandler = handler;\n }\n\n async connect(): Promise<void> {\n // Connection is implicit when the process is spawned\n return Promise.resolve();\n }\n\n /**\n * Terminate the child process and clean up resources\n */\n async terminate(): Promise<void> {\n this.closeWithError(new Error('MCP server process terminated'));\n this.rl.close();\n // A failed stdin closes the transport without stopping the child.\n if (this.process.exitCode === null && this.process.signalCode === null) {\n this.process.kill();\n }\n await this.closePromise;\n }\n\n private async writeMessage(\n message: Readonly<AxMCPJSONRPCMessage>\n ): Promise<void> {\n if (this.closed || this.process.stdin.destroyed) {\n throw new Error('MCP server process is not running');\n }\n await new Promise<void>((resolve, reject) => {\n this.process.stdin.write(`${JSON.stringify(message)}\\n`, (error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n }\n\n private closeWithError(error: Error): void {\n if (this.closed) return;\n this.closed = true;\n for (const pending of this.pendingResponses.values()) {\n pending.reject(error);\n }\n this.pendingResponses.clear();\n }\n}\n\n/**\n * Create a new AxMCPStdioTransport instance\n * @param config Configuration for the stdio transport\n * @returns A new AxMCPStdioTransport instance\n */\nexport function axCreateMCPStdioTransport(\n config: Readonly<StdioTransportConfig>\n): AxMCPStdioTransport {\n return new AxMCPStdioTransport(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["path","statSync","spawn","readline","require_rolldown_runtime","node_child_process","node_readline","node_fs","node_path","metaCharsRegExp","windowsEnvValue","key","env","name","escapeCommand","command","escapeArgument","escaped","backslashes","char","arg","run","doubleEscape","resolveCommand","dirs","exts","dir","base","ext","file","windowsShellCommand","commandLine","args","AxMCPStdioTransport","config","shell","resolve","error","code","signal","message","line","response","pending","reject","res","handler","axCreateMCPStdioTransport"],"sources":["../mcp/windowsSpawn.ts","../mcp/stdioTransport.ts"],"sourcesContent":["// cspell:ignore PATHEXT COMSPEC\nimport { statSync } from 'node:fs';\nimport path from 'node:path';\n\n// Windows only runs .exe/.com directly; .cmd/.bat shims such as npx need\n// cmd.exe, and Node refuses to spawn them without a shell (CVE-2024-27980).\n// Lookup and escaping follow cross-spawn (lib/parse.js, lib/util/escape.js).\n\nconst metaCharsRegExp = /([()\\][%!^\"`<>&|;, *?])/g;\n\nfunction windowsEnvValue(\n env: NodeJS.ProcessEnv,\n name: string\n): string | undefined {\n // Node sorts keys and passes only the first case-insensitive match to the\n // child. Use the same value for lookup and escaping as the spawned process.\n const key = Object.keys(env)\n .sort()\n .find((key) => key.toUpperCase() === name);\n return key === undefined ? undefined : env[key];\n}\n\nexport function escapeCommand(command: string): string {\n return command.replace(metaCharsRegExp, '^$1');\n}\n\nexport function escapeArgument(arg: string, doubleEscape: boolean): string {\n // https://qntm.org/cmd: double the backslashes before a quote or the end.\n // cross-spawn 7.0.6's regex form doubles only the last one of a run.\n let escaped = '';\n let backslashes = 0;\n for (const char of arg) {\n if (char === '\\\\') {\n backslashes++;\n continue;\n }\n const run = char === '\"' ? backslashes * 2 + 1 : backslashes;\n escaped += `${'\\\\'.repeat(run)}${char}`;\n backslashes = 0;\n }\n escaped += '\\\\'.repeat(backslashes * 2);\n escaped = `\"${escaped}\"`.replace(metaCharsRegExp, '^$1');\n return doubleEscape ? escaped.replace(metaCharsRegExp, '^$1') : escaped;\n}\n\nfunction resolveCommand(\n command: string,\n env: NodeJS.ProcessEnv\n): string | undefined {\n const dirs = /[\\\\/]/.test(command)\n ? ['']\n : [process.cwd(), ...(windowsEnvValue(env, 'PATH') ?? '').split(';')];\n const exts = (windowsEnvValue(env, 'PATHEXT') ?? '.EXE;.CMD;.BAT;.COM').split(\n ';'\n );\n if (command.includes('.') && exts[0] !== '') exts.unshift('');\n for (const dir of dirs) {\n const base = path.join(dir.replace(/^\"(.*)\"$/, '$1'), command);\n for (const ext of exts) {\n const file = base + ext;\n const isExecutable = exts.some(\n (e) => e !== '' && file.toLowerCase().endsWith(e.toLowerCase())\n );\n if (isExecutable && statSync(file, { throwIfNoEntry: false })?.isFile()) {\n return path.resolve(file);\n }\n }\n }\n return undefined;\n}\n\n/**\n * Returns the cmd.exe invocation for a command Windows can't spawn directly,\n * or undefined when it resolves to an .exe/.com.\n */\nexport function windowsShellCommand(\n command: string,\n args: readonly string[],\n env: NodeJS.ProcessEnv\n): { command: string; args: string[] } | undefined {\n const file = resolveCommand(command, env);\n if (file && /\\.(?:com|exe)$/i.test(file)) return undefined;\n // Batch files expand %* and parse it again, so their arguments need a\n // second level of escaping (cross-spawn only does this under\n // node_modules\\.bin; npx.cmd and other shims live elsewhere).\n const doubleEscape = file !== undefined && /\\.(?:bat|cmd)$/i.test(file);\n const commandLine = [\n escapeCommand(path.normalize(command)),\n ...args.map((arg) => escapeArgument(arg, doubleEscape)),\n ].join(' ');\n return {\n command: windowsEnvValue(env, 'COMSPEC') ?? 'cmd.exe',\n args: ['/d', '/s', '/c', `\"${commandLine}\"`],\n };\n}\n","import { type ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport readline from 'node:readline';\n\nimport type {\n AxMCPJSONRPCMessage,\n AxMCPJSONRPCNotification,\n AxMCPJSONRPCRequest,\n AxMCPJSONRPCResponse,\n AxMCPTransport,\n} from '@ax-llm/ax';\n\nimport { windowsShellCommand } from './windowsSpawn.js';\n\nexport interface StdioTransportConfig {\n command: string;\n args?: string[];\n env?: NodeJS.ProcessEnv;\n}\n\nexport class AxMCPStdioTransport implements AxMCPTransport {\n private process: ChildProcessWithoutNullStreams;\n private rl: readline.Interface;\n private pendingResponses = new Map<\n string | number,\n {\n resolve: (res: AxMCPJSONRPCResponse) => void;\n reject: (error: Error) => void;\n }\n >();\n private closed = false;\n private closePromise: Promise<void>;\n private messageHandler?: (\n message: Readonly<AxMCPJSONRPCMessage>\n ) => void | Promise<void>;\n\n constructor(config: Readonly<StdioTransportConfig>) {\n const env = config.env ? { ...process.env, ...config.env } : process.env;\n const shell =\n process.platform === 'win32'\n ? windowsShellCommand(config.command, config.args ?? [], env)\n : undefined;\n this.process = shell\n ? spawn(shell.command, shell.args, {\n env,\n windowsVerbatimArguments: true,\n })\n : spawn(config.command, config.args ?? [], { env });\n this.closePromise = new Promise((resolve) => {\n this.process.once('close', () => {\n this.closeWithError(new Error('MCP server process closed'));\n resolve();\n });\n });\n this.process.once('error', (error) => this.closeWithError(error));\n this.process.once('exit', (code, signal) => {\n this.closeWithError(\n new Error(\n `MCP server process exited${code === null ? '' : ` with code ${code}`}${signal ? ` (${signal})` : ''}`\n )\n );\n });\n this.process.stdin.on('error', (error) => this.closeWithError(error));\n this.rl = readline.createInterface({ input: this.process.stdout });\n this.rl.on('line', (line) => {\n try {\n const message: AxMCPJSONRPCMessage = JSON.parse(line);\n if ('method' in message) {\n void this.messageHandler?.(message);\n return;\n }\n const response = message as AxMCPJSONRPCResponse;\n const pending =\n response.id === null\n ? undefined\n : this.pendingResponses.get(response.id);\n if (pending) {\n pending.resolve(response);\n if (response.id !== null) this.pendingResponses.delete(response.id);\n } else {\n void this.messageHandler?.(message);\n }\n } catch (_error) {\n // Skip non-JSON lines (might be debug output from the MCP server)\n console.warn('Non-JSON output from MCP server:', line);\n }\n });\n }\n\n async send(\n message: Readonly<AxMCPJSONRPCRequest<unknown>>\n ): Promise<AxMCPJSONRPCResponse<unknown>> {\n return new Promise<AxMCPJSONRPCResponse<unknown>>((resolve, reject) => {\n if (this.closed) {\n reject(new Error('MCP server process is not running'));\n return;\n }\n this.pendingResponses.set(message.id, {\n resolve: (res) => resolve(res as AxMCPJSONRPCResponse<unknown>),\n reject,\n });\n void this.writeMessage(message).catch((error: Error) => {\n this.pendingResponses.delete(message.id);\n reject(error);\n });\n });\n }\n\n async sendNotification(\n message: Readonly<AxMCPJSONRPCNotification>\n ): Promise<void> {\n await this.writeMessage(message);\n }\n\n async sendResponse(message: Readonly<AxMCPJSONRPCResponse>): Promise<void> {\n await this.writeMessage(message);\n }\n\n setMessageHandler(\n handler: (message: Readonly<AxMCPJSONRPCMessage>) => void | Promise<void>\n ): void {\n this.messageHandler = handler;\n }\n\n async connect(): Promise<void> {\n // Connection is implicit when the process is spawned\n return Promise.resolve();\n }\n\n /**\n * Terminate the child process and clean up resources\n */\n async terminate(): Promise<void> {\n this.closeWithError(new Error('MCP server process terminated'));\n this.rl.close();\n // A failed stdin closes the transport without stopping the child.\n if (this.process.exitCode === null && this.process.signalCode === null) {\n this.process.kill();\n }\n await this.closePromise;\n }\n\n private async writeMessage(\n message: Readonly<AxMCPJSONRPCMessage>\n ): Promise<void> {\n if (this.closed || this.process.stdin.destroyed) {\n throw new Error('MCP server process is not running');\n }\n await new Promise<void>((resolve, reject) => {\n this.process.stdin.write(`${JSON.stringify(message)}\\n`, (error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n }\n\n private closeWithError(error: Error): void {\n if (this.closed) return;\n this.closed = true;\n for (const pending of this.pendingResponses.values()) {\n pending.reject(error);\n }\n this.pendingResponses.clear();\n }\n}\n\n/**\n * Create a new AxMCPStdioTransport instance\n * @param config Configuration for the stdio transport\n * @returns A new AxMCPStdioTransport instance\n */\nexport function axCreateMCPStdioTransport(\n config: Readonly<StdioTransportConfig>\n): AxMCPStdioTransport {\n return new AxMCPStdioTransport(config);\n}\n"],"mappings":"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"}
package/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{spawn as e}from"node:child_process";import t from"node:readline";var n=class{process;rl;pendingResponses=/* @__PURE__ */ new Map;closed=!1;closePromise;messageHandler;constructor(n){this.process=e(n.command,n.args??[],{env:n.env?{...process.env,...n.env}:process.env}),this.closePromise=new Promise(e=>{this.process.once(`close`,()=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process closed`)),e()})}),this.process.once(`error`,e=>this.closeWithError(e)),this.process.once(`exit`,(e,t)=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process exited${e===null?``:` with code ${e}`}${t?` (${t})`:``}`))}),this.process.stdin.on(`error`,e=>this.closeWithError(e)),this.rl=t.createInterface({input:this.process.stdout}),this.rl.on(`line`,e=>{try{let t=JSON.parse(e);if(`method`in t){this.messageHandler?.(t);return}let n=t,r=n.id===null?void 0:this.pendingResponses.get(n.id);r?(r.resolve(n),n.id!==null&&this.pendingResponses.delete(n.id)):this.messageHandler?.(t)}catch{console.warn(`Non-JSON output from MCP server:`,e)}})}async send(e){return new Promise((t,n)=>{if(this.closed){n(/* @__PURE__ */ Error(`MCP server process is not running`));return}this.pendingResponses.set(e.id,{resolve:e=>t(e),reject:n}),this.writeMessage(e).catch(t=>{this.pendingResponses.delete(e.id),n(t)})})}async sendNotification(e){await this.writeMessage(e)}async sendResponse(e){await this.writeMessage(e)}setMessageHandler(e){this.messageHandler=e}async connect(){return Promise.resolve()}async terminate(){this.closeWithError(/* @__PURE__ */ Error(`MCP server process terminated`)),this.rl.close(),this.process.exitCode===null&&this.process.signalCode===null&&this.process.kill(),await this.closePromise}async writeMessage(e){if(this.closed||this.process.stdin.destroyed)throw Error(`MCP server process is not running`);await new Promise((t,n)=>{this.process.stdin.write(`${JSON.stringify(e)}\n`,e=>{e?n(e):t()})})}closeWithError(e){if(!this.closed){this.closed=!0;for(let t of this.pendingResponses.values())t.reject(e);this.pendingResponses.clear()}}};function r(e){return new n(e)}export{n as AxMCPStdioTransport,r as axCreateMCPStdioTransport};
1
+ import{spawn as e}from"node:child_process";import t from"node:readline";import{statSync as n}from"node:fs";import r from"node:path";const i=/([()\][%!^"`<>&|;, *?])/g;function a(e,t){let n=Object.keys(e).sort().find(e=>e.toUpperCase()===t);return n===void 0?void 0:e[n]}function o(e){return e.replace(i,`^$1`)}function s(e,t){let n=``,r=0;for(let t of e){if(t===`\\`){r++;continue}let e=t===`"`?r*2+1:r;n+=`${`\\`.repeat(e)}${t}`,r=0}return n+=`\\`.repeat(r*2),n=`"${n}"`.replace(i,`^$1`),t?n.replace(i,`^$1`):n}function c(e,t){let i=/[\\/]/.test(e)?[``]:[process.cwd(),...(a(t,`PATH`)??``).split(`;`)],o=(a(t,`PATHEXT`)??`.EXE;.CMD;.BAT;.COM`).split(`;`);e.includes(`.`)&&o[0]!==``&&o.unshift(``);for(let t of i){let i=r.join(t.replace(/^"(.*)"$/,`$1`),e);for(let e of o){let t=i+e;if(o.some(e=>e!==``&&t.toLowerCase().endsWith(e.toLowerCase()))&&n(t,{throwIfNoEntry:!1})?.isFile())return r.resolve(t)}}}function l(e,t,n){let i=c(e,n);if(i&&/\.(?:com|exe)$/i.test(i))return;let l=i!==void 0&&/\.(?:bat|cmd)$/i.test(i),u=[o(r.normalize(e)),...t.map(e=>s(e,l))].join(` `);return{command:a(n,`COMSPEC`)??`cmd.exe`,args:[`/d`,`/s`,`/c`,`"${u}"`]}}var u=class{process;rl;pendingResponses=/* @__PURE__ */ new Map;closed=!1;closePromise;messageHandler;constructor(n){let r=n.env?{...process.env,...n.env}:process.env,i=process.platform===`win32`?l(n.command,n.args??[],r):void 0;this.process=i?e(i.command,i.args,{env:r,windowsVerbatimArguments:!0}):e(n.command,n.args??[],{env:r}),this.closePromise=new Promise(e=>{this.process.once(`close`,()=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process closed`)),e()})}),this.process.once(`error`,e=>this.closeWithError(e)),this.process.once(`exit`,(e,t)=>{this.closeWithError(/* @__PURE__ */ Error(`MCP server process exited${e===null?``:` with code ${e}`}${t?` (${t})`:``}`))}),this.process.stdin.on(`error`,e=>this.closeWithError(e)),this.rl=t.createInterface({input:this.process.stdout}),this.rl.on(`line`,e=>{try{let t=JSON.parse(e);if(`method`in t){this.messageHandler?.(t);return}let n=t,r=n.id===null?void 0:this.pendingResponses.get(n.id);r?(r.resolve(n),n.id!==null&&this.pendingResponses.delete(n.id)):this.messageHandler?.(t)}catch{console.warn(`Non-JSON output from MCP server:`,e)}})}async send(e){return new Promise((t,n)=>{if(this.closed){n(/* @__PURE__ */ Error(`MCP server process is not running`));return}this.pendingResponses.set(e.id,{resolve:e=>t(e),reject:n}),this.writeMessage(e).catch(t=>{this.pendingResponses.delete(e.id),n(t)})})}async sendNotification(e){await this.writeMessage(e)}async sendResponse(e){await this.writeMessage(e)}setMessageHandler(e){this.messageHandler=e}async connect(){return Promise.resolve()}async terminate(){this.closeWithError(/* @__PURE__ */ Error(`MCP server process terminated`)),this.rl.close(),this.process.exitCode===null&&this.process.signalCode===null&&this.process.kill(),await this.closePromise}async writeMessage(e){if(this.closed||this.process.stdin.destroyed)throw Error(`MCP server process is not running`);await new Promise((t,n)=>{this.process.stdin.write(`${JSON.stringify(e)}\n`,e=>{e?n(e):t()})})}closeWithError(e){if(!this.closed){this.closed=!0;for(let t of this.pendingResponses.values())t.reject(e);this.pendingResponses.clear()}}};function d(e){return new u(e)}export{u as AxMCPStdioTransport,d as axCreateMCPStdioTransport};
2
2
  //# sourceMappingURL=index.js.map
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["readline","AxMCPStdioTransport","spawn","config","resolve","error","code","signal","message","line","response","pending","reject","res","handler","axCreateMCPStdioTransport"],"sources":["../mcp/stdioTransport.ts"],"sourcesContent":["import { type ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport readline from 'node:readline';\n\nimport type {\n AxMCPJSONRPCMessage,\n AxMCPJSONRPCNotification,\n AxMCPJSONRPCRequest,\n AxMCPJSONRPCResponse,\n AxMCPTransport,\n} from '@ax-llm/ax';\n\nexport interface StdioTransportConfig {\n command: string;\n args?: string[];\n env?: NodeJS.ProcessEnv;\n}\n\nexport class AxMCPStdioTransport implements AxMCPTransport {\n private process: ChildProcessWithoutNullStreams;\n private rl: readline.Interface;\n private pendingResponses = new Map<\n string | number,\n {\n resolve: (res: AxMCPJSONRPCResponse) => void;\n reject: (error: Error) => void;\n }\n >();\n private closed = false;\n private closePromise: Promise<void>;\n private messageHandler?: (\n message: Readonly<AxMCPJSONRPCMessage>\n ) => void | Promise<void>;\n\n constructor(config: Readonly<StdioTransportConfig>) {\n this.process = spawn(config.command, config.args ?? [], {\n env: config.env ? { ...process.env, ...config.env } : process.env,\n });\n this.closePromise = new Promise((resolve) => {\n this.process.once('close', () => {\n this.closeWithError(new Error('MCP server process closed'));\n resolve();\n });\n });\n this.process.once('error', (error) => this.closeWithError(error));\n this.process.once('exit', (code, signal) => {\n this.closeWithError(\n new Error(\n `MCP server process exited${code === null ? '' : ` with code ${code}`}${signal ? ` (${signal})` : ''}`\n )\n );\n });\n this.process.stdin.on('error', (error) => this.closeWithError(error));\n this.rl = readline.createInterface({ input: this.process.stdout });\n this.rl.on('line', (line) => {\n try {\n const message: AxMCPJSONRPCMessage = JSON.parse(line);\n if ('method' in message) {\n void this.messageHandler?.(message);\n return;\n }\n const response = message as AxMCPJSONRPCResponse;\n const pending =\n response.id === null\n ? undefined\n : this.pendingResponses.get(response.id);\n if (pending) {\n pending.resolve(response);\n if (response.id !== null) this.pendingResponses.delete(response.id);\n } else {\n void this.messageHandler?.(message);\n }\n } catch (_error) {\n // Skip non-JSON lines (might be debug output from the MCP server)\n console.warn('Non-JSON output from MCP server:', line);\n }\n });\n }\n\n async send(\n message: Readonly<AxMCPJSONRPCRequest<unknown>>\n ): Promise<AxMCPJSONRPCResponse<unknown>> {\n return new Promise<AxMCPJSONRPCResponse<unknown>>((resolve, reject) => {\n if (this.closed) {\n reject(new Error('MCP server process is not running'));\n return;\n }\n this.pendingResponses.set(message.id, {\n resolve: (res) => resolve(res as AxMCPJSONRPCResponse<unknown>),\n reject,\n });\n void this.writeMessage(message).catch((error: Error) => {\n this.pendingResponses.delete(message.id);\n reject(error);\n });\n });\n }\n\n async sendNotification(\n message: Readonly<AxMCPJSONRPCNotification>\n ): Promise<void> {\n await this.writeMessage(message);\n }\n\n async sendResponse(message: Readonly<AxMCPJSONRPCResponse>): Promise<void> {\n await this.writeMessage(message);\n }\n\n setMessageHandler(\n handler: (message: Readonly<AxMCPJSONRPCMessage>) => void | Promise<void>\n ): void {\n this.messageHandler = handler;\n }\n\n async connect(): Promise<void> {\n // Connection is implicit when the process is spawned\n return Promise.resolve();\n }\n\n /**\n * Terminate the child process and clean up resources\n */\n async terminate(): Promise<void> {\n this.closeWithError(new Error('MCP server process terminated'));\n this.rl.close();\n // A failed stdin closes the transport without stopping the child.\n if (this.process.exitCode === null && this.process.signalCode === null) {\n this.process.kill();\n }\n await this.closePromise;\n }\n\n private async writeMessage(\n message: Readonly<AxMCPJSONRPCMessage>\n ): Promise<void> {\n if (this.closed || this.process.stdin.destroyed) {\n throw new Error('MCP server process is not running');\n }\n await new Promise<void>((resolve, reject) => {\n this.process.stdin.write(`${JSON.stringify(message)}\\n`, (error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n }\n\n private closeWithError(error: Error): void {\n if (this.closed) return;\n this.closed = true;\n for (const pending of this.pendingResponses.values()) {\n pending.reject(error);\n }\n this.pendingResponses.clear();\n }\n}\n\n/**\n * Create a new AxMCPStdioTransport instance\n * @param config Configuration for the stdio transport\n * @returns A new AxMCPStdioTransport instance\n */\nexport function axCreateMCPStdioTransport(\n config: Readonly<StdioTransportConfig>\n): AxMCPStdioTransport {\n return new AxMCPStdioTransport(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["readline","path","metaCharsRegExp","windowsEnvValue","key","env","name","escapeCommand","command","escapeArgument","escaped","backslashes","char","arg","run","doubleEscape","resolveCommand","dirs","exts","dir","base","ext","file","statSync","windowsShellCommand","commandLine","args","AxMCPStdioTransport","config","shell","spawn","resolve","error","code","signal","message","line","response","pending","reject","res","handler","axCreateMCPStdioTransport"],"sources":["../mcp/windowsSpawn.ts","../mcp/stdioTransport.ts"],"sourcesContent":["// cspell:ignore PATHEXT COMSPEC\nimport { statSync } from 'node:fs';\nimport path from 'node:path';\n\n// Windows only runs .exe/.com directly; .cmd/.bat shims such as npx need\n// cmd.exe, and Node refuses to spawn them without a shell (CVE-2024-27980).\n// Lookup and escaping follow cross-spawn (lib/parse.js, lib/util/escape.js).\n\nconst metaCharsRegExp = /([()\\][%!^\"`<>&|;, *?])/g;\n\nfunction windowsEnvValue(\n env: NodeJS.ProcessEnv,\n name: string\n): string | undefined {\n // Node sorts keys and passes only the first case-insensitive match to the\n // child. Use the same value for lookup and escaping as the spawned process.\n const key = Object.keys(env)\n .sort()\n .find((key) => key.toUpperCase() === name);\n return key === undefined ? undefined : env[key];\n}\n\nexport function escapeCommand(command: string): string {\n return command.replace(metaCharsRegExp, '^$1');\n}\n\nexport function escapeArgument(arg: string, doubleEscape: boolean): string {\n // https://qntm.org/cmd: double the backslashes before a quote or the end.\n // cross-spawn 7.0.6's regex form doubles only the last one of a run.\n let escaped = '';\n let backslashes = 0;\n for (const char of arg) {\n if (char === '\\\\') {\n backslashes++;\n continue;\n }\n const run = char === '\"' ? backslashes * 2 + 1 : backslashes;\n escaped += `${'\\\\'.repeat(run)}${char}`;\n backslashes = 0;\n }\n escaped += '\\\\'.repeat(backslashes * 2);\n escaped = `\"${escaped}\"`.replace(metaCharsRegExp, '^$1');\n return doubleEscape ? escaped.replace(metaCharsRegExp, '^$1') : escaped;\n}\n\nfunction resolveCommand(\n command: string,\n env: NodeJS.ProcessEnv\n): string | undefined {\n const dirs = /[\\\\/]/.test(command)\n ? ['']\n : [process.cwd(), ...(windowsEnvValue(env, 'PATH') ?? '').split(';')];\n const exts = (windowsEnvValue(env, 'PATHEXT') ?? '.EXE;.CMD;.BAT;.COM').split(\n ';'\n );\n if (command.includes('.') && exts[0] !== '') exts.unshift('');\n for (const dir of dirs) {\n const base = path.join(dir.replace(/^\"(.*)\"$/, '$1'), command);\n for (const ext of exts) {\n const file = base + ext;\n const isExecutable = exts.some(\n (e) => e !== '' && file.toLowerCase().endsWith(e.toLowerCase())\n );\n if (isExecutable && statSync(file, { throwIfNoEntry: false })?.isFile()) {\n return path.resolve(file);\n }\n }\n }\n return undefined;\n}\n\n/**\n * Returns the cmd.exe invocation for a command Windows can't spawn directly,\n * or undefined when it resolves to an .exe/.com.\n */\nexport function windowsShellCommand(\n command: string,\n args: readonly string[],\n env: NodeJS.ProcessEnv\n): { command: string; args: string[] } | undefined {\n const file = resolveCommand(command, env);\n if (file && /\\.(?:com|exe)$/i.test(file)) return undefined;\n // Batch files expand %* and parse it again, so their arguments need a\n // second level of escaping (cross-spawn only does this under\n // node_modules\\.bin; npx.cmd and other shims live elsewhere).\n const doubleEscape = file !== undefined && /\\.(?:bat|cmd)$/i.test(file);\n const commandLine = [\n escapeCommand(path.normalize(command)),\n ...args.map((arg) => escapeArgument(arg, doubleEscape)),\n ].join(' ');\n return {\n command: windowsEnvValue(env, 'COMSPEC') ?? 'cmd.exe',\n args: ['/d', '/s', '/c', `\"${commandLine}\"`],\n };\n}\n","import { type ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport readline from 'node:readline';\n\nimport type {\n AxMCPJSONRPCMessage,\n AxMCPJSONRPCNotification,\n AxMCPJSONRPCRequest,\n AxMCPJSONRPCResponse,\n AxMCPTransport,\n} from '@ax-llm/ax';\n\nimport { windowsShellCommand } from './windowsSpawn.js';\n\nexport interface StdioTransportConfig {\n command: string;\n args?: string[];\n env?: NodeJS.ProcessEnv;\n}\n\nexport class AxMCPStdioTransport implements AxMCPTransport {\n private process: ChildProcessWithoutNullStreams;\n private rl: readline.Interface;\n private pendingResponses = new Map<\n string | number,\n {\n resolve: (res: AxMCPJSONRPCResponse) => void;\n reject: (error: Error) => void;\n }\n >();\n private closed = false;\n private closePromise: Promise<void>;\n private messageHandler?: (\n message: Readonly<AxMCPJSONRPCMessage>\n ) => void | Promise<void>;\n\n constructor(config: Readonly<StdioTransportConfig>) {\n const env = config.env ? { ...process.env, ...config.env } : process.env;\n const shell =\n process.platform === 'win32'\n ? windowsShellCommand(config.command, config.args ?? [], env)\n : undefined;\n this.process = shell\n ? spawn(shell.command, shell.args, {\n env,\n windowsVerbatimArguments: true,\n })\n : spawn(config.command, config.args ?? [], { env });\n this.closePromise = new Promise((resolve) => {\n this.process.once('close', () => {\n this.closeWithError(new Error('MCP server process closed'));\n resolve();\n });\n });\n this.process.once('error', (error) => this.closeWithError(error));\n this.process.once('exit', (code, signal) => {\n this.closeWithError(\n new Error(\n `MCP server process exited${code === null ? '' : ` with code ${code}`}${signal ? ` (${signal})` : ''}`\n )\n );\n });\n this.process.stdin.on('error', (error) => this.closeWithError(error));\n this.rl = readline.createInterface({ input: this.process.stdout });\n this.rl.on('line', (line) => {\n try {\n const message: AxMCPJSONRPCMessage = JSON.parse(line);\n if ('method' in message) {\n void this.messageHandler?.(message);\n return;\n }\n const response = message as AxMCPJSONRPCResponse;\n const pending =\n response.id === null\n ? undefined\n : this.pendingResponses.get(response.id);\n if (pending) {\n pending.resolve(response);\n if (response.id !== null) this.pendingResponses.delete(response.id);\n } else {\n void this.messageHandler?.(message);\n }\n } catch (_error) {\n // Skip non-JSON lines (might be debug output from the MCP server)\n console.warn('Non-JSON output from MCP server:', line);\n }\n });\n }\n\n async send(\n message: Readonly<AxMCPJSONRPCRequest<unknown>>\n ): Promise<AxMCPJSONRPCResponse<unknown>> {\n return new Promise<AxMCPJSONRPCResponse<unknown>>((resolve, reject) => {\n if (this.closed) {\n reject(new Error('MCP server process is not running'));\n return;\n }\n this.pendingResponses.set(message.id, {\n resolve: (res) => resolve(res as AxMCPJSONRPCResponse<unknown>),\n reject,\n });\n void this.writeMessage(message).catch((error: Error) => {\n this.pendingResponses.delete(message.id);\n reject(error);\n });\n });\n }\n\n async sendNotification(\n message: Readonly<AxMCPJSONRPCNotification>\n ): Promise<void> {\n await this.writeMessage(message);\n }\n\n async sendResponse(message: Readonly<AxMCPJSONRPCResponse>): Promise<void> {\n await this.writeMessage(message);\n }\n\n setMessageHandler(\n handler: (message: Readonly<AxMCPJSONRPCMessage>) => void | Promise<void>\n ): void {\n this.messageHandler = handler;\n }\n\n async connect(): Promise<void> {\n // Connection is implicit when the process is spawned\n return Promise.resolve();\n }\n\n /**\n * Terminate the child process and clean up resources\n */\n async terminate(): Promise<void> {\n this.closeWithError(new Error('MCP server process terminated'));\n this.rl.close();\n // A failed stdin closes the transport without stopping the child.\n if (this.process.exitCode === null && this.process.signalCode === null) {\n this.process.kill();\n }\n await this.closePromise;\n }\n\n private async writeMessage(\n message: Readonly<AxMCPJSONRPCMessage>\n ): Promise<void> {\n if (this.closed || this.process.stdin.destroyed) {\n throw new Error('MCP server process is not running');\n }\n await new Promise<void>((resolve, reject) => {\n this.process.stdin.write(`${JSON.stringify(message)}\\n`, (error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n }\n\n private closeWithError(error: Error): void {\n if (this.closed) return;\n this.closed = true;\n for (const pending of this.pendingResponses.values()) {\n pending.reject(error);\n }\n this.pendingResponses.clear();\n }\n}\n\n/**\n * Create a new AxMCPStdioTransport instance\n * @param config Configuration for the stdio transport\n * @returns A new AxMCPStdioTransport instance\n */\nexport function axCreateMCPStdioTransport(\n config: Readonly<StdioTransportConfig>\n): AxMCPStdioTransport {\n return new AxMCPStdioTransport(config);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ax-llm/ax-tools",
3
- "version": "25.4.5",
3
+ "version": "25.4.7",
4
4
  "type": "module",
5
5
  "description": "Ax tools package",
6
6
  "repository": {
@@ -13,7 +13,7 @@
13
13
  "license": "Apache-2.0",
14
14
  "keywords": [],
15
15
  "dependencies": {
16
- "@ax-llm/ax": "25.4.5",
16
+ "@ax-llm/ax": "25.4.7",
17
17
  "better-sqlite3": "^12.11.1"
18
18
  },
19
19
  "files": [