@prmichaelsen/acp-mcp 0.4.1 → 0.5.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.
@@ -53,20 +53,127 @@ async function listRemoteFiles(ssh, dirPath, recursive) {
53
53
  const entries = await ssh.listFiles(dirPath);
54
54
  const files = [];
55
55
  for (const entry of entries) {
56
+ const fullPath = `${dirPath}/${entry.name}`.replace(/\/+/g, "/");
56
57
  if (entry.isDirectory) {
57
- files.push(`${entry.name}/`);
58
+ files.push(`${fullPath}/`);
58
59
  if (recursive) {
59
- const fullPath = `${dirPath}/${entry.name}`.replace(/\/+/g, "/");
60
60
  const subFiles = await listRemoteFiles(ssh, fullPath, recursive);
61
- files.push(...subFiles.map((f) => `${entry.name}/${f}`));
61
+ files.push(...subFiles);
62
62
  }
63
63
  } else {
64
- files.push(entry.name);
64
+ files.push(fullPath);
65
65
  }
66
66
  }
67
67
  return files.sort();
68
68
  }
69
69
 
70
+ // src/utils/logger.ts
71
+ var LOG_LEVELS = {
72
+ error: 0,
73
+ warn: 1,
74
+ info: 2,
75
+ debug: 3,
76
+ trace: 4
77
+ };
78
+ var Logger = class {
79
+ level;
80
+ enabled;
81
+ constructor() {
82
+ this.level = process.env.ACP_MCP_LOG_LEVEL || "info";
83
+ this.enabled = process.env.ACP_MCP_DEBUG === "true" || process.env.NODE_ENV === "development";
84
+ }
85
+ shouldLog(level) {
86
+ if (!this.enabled && level !== "error" && level !== "warn") {
87
+ return false;
88
+ }
89
+ return LOG_LEVELS[level] <= LOG_LEVELS[this.level];
90
+ }
91
+ formatMessage(level, message, data) {
92
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
93
+ const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
94
+ if (data !== void 0) {
95
+ const dataStr = typeof data === "object" ? JSON.stringify(data, null, 2) : String(data);
96
+ return `${prefix} ${message}
97
+ ${dataStr}`;
98
+ }
99
+ return `${prefix} ${message}`;
100
+ }
101
+ error(message, data) {
102
+ if (this.shouldLog("error")) {
103
+ console.error(this.formatMessage("error", message, data));
104
+ }
105
+ }
106
+ warn(message, data) {
107
+ if (this.shouldLog("warn")) {
108
+ console.error(this.formatMessage("warn", message, data));
109
+ }
110
+ }
111
+ info(message, data) {
112
+ if (this.shouldLog("info")) {
113
+ console.error(this.formatMessage("info", message, data));
114
+ }
115
+ }
116
+ debug(message, data) {
117
+ if (this.shouldLog("debug")) {
118
+ console.error(this.formatMessage("debug", message, data));
119
+ }
120
+ }
121
+ trace(message, data) {
122
+ if (this.shouldLog("trace")) {
123
+ console.error(this.formatMessage("trace", message, data));
124
+ }
125
+ }
126
+ /**
127
+ * Log tool invocation with parameters
128
+ */
129
+ toolInvoked(toolName, params, userId) {
130
+ this.info(`Tool invoked: ${toolName}`);
131
+ this.debug("Tool parameters", { tool: toolName, params, userId });
132
+ }
133
+ /**
134
+ * Log tool completion with result summary
135
+ */
136
+ toolCompleted(toolName, duration, resultSize) {
137
+ this.info(`Tool completed: ${toolName}`);
138
+ this.debug("Tool performance", { tool: toolName, duration: `${duration}ms`, resultSize });
139
+ }
140
+ /**
141
+ * Log tool failure with error details
142
+ */
143
+ toolFailed(toolName, error, params) {
144
+ this.error(`Tool execution failed: ${toolName}`, {
145
+ tool: toolName,
146
+ error: error.message,
147
+ stack: error.stack,
148
+ params
149
+ });
150
+ }
151
+ /**
152
+ * Log SSH command execution
153
+ */
154
+ sshCommand(command, cwd, timeout) {
155
+ this.debug("Executing SSH command", { command, cwd, timeout });
156
+ }
157
+ /**
158
+ * Log SSH command result
159
+ */
160
+ sshCommandResult(exitCode, duration, stdoutSize, stderrSize) {
161
+ this.debug("SSH command completed", {
162
+ exitCode,
163
+ duration: `${duration}ms`,
164
+ stdout: `${stdoutSize} bytes`,
165
+ stderr: `${stderrSize} bytes`
166
+ });
167
+ }
168
+ /**
169
+ * Log file operation
170
+ */
171
+ fileOperation(operation, path, details) {
172
+ this.info(`File operation: ${operation}`, { path, ...details });
173
+ }
174
+ };
175
+ var logger = new Logger();
176
+
70
177
  // src/tools/acp-remote-execute-command.ts
71
178
  var acpRemoteExecuteCommandTool = {
72
179
  name: "acp_remote_execute_command",
@@ -93,9 +200,16 @@ var acpRemoteExecuteCommandTool = {
93
200
  };
94
201
  async function handleAcpRemoteExecuteCommand(args, sshConnection) {
95
202
  const { command, cwd, timeout = 30 } = args;
203
+ logger.debug("Executing remote command", { command, cwd, timeout });
96
204
  try {
97
205
  const fullCommand = cwd ? `cd ${cwd} && ${command}` : command;
98
206
  const result = await sshConnection.execWithTimeout(fullCommand, timeout);
207
+ logger.debug("Command execution result", {
208
+ exitCode: result.exitCode,
209
+ timedOut: result.timedOut,
210
+ stdoutLength: result.stdout.length,
211
+ stderrLength: result.stderr.length
212
+ });
99
213
  const output = {
100
214
  stdout: result.stdout,
101
215
  stderr: result.stderr,
@@ -112,6 +226,7 @@ async function handleAcpRemoteExecuteCommand(args, sshConnection) {
112
226
  };
113
227
  } catch (error) {
114
228
  const errorMessage = error instanceof Error ? error.message : String(error);
229
+ logger.error("Command execution error", { command, error: errorMessage });
115
230
  return {
116
231
  content: [
117
232
  {
@@ -156,8 +271,10 @@ var acpRemoteReadFileTool = {
156
271
  };
157
272
  async function handleAcpRemoteReadFile(args, sshConnection) {
158
273
  const { path, encoding = "utf-8", maxSize = 1048576 } = args;
274
+ logger.debug("Reading remote file", { path, encoding, maxSize });
159
275
  try {
160
276
  const result = await sshConnection.readFile(path, encoding, maxSize);
277
+ logger.debug("File read successful", { path, size: result.size });
161
278
  const output = {
162
279
  content: result.content,
163
280
  size: result.size,
@@ -173,6 +290,7 @@ async function handleAcpRemoteReadFile(args, sshConnection) {
173
290
  };
174
291
  } catch (error) {
175
292
  const errorMessage = error instanceof Error ? error.message : String(error);
293
+ logger.error("File read error", { path, error: errorMessage });
176
294
  return {
177
295
  content: [
178
296
  {
@@ -225,12 +343,14 @@ var acpRemoteWriteFileTool = {
225
343
  };
226
344
  async function handleAcpRemoteWriteFile(args, sshConnection) {
227
345
  const { path, content, encoding = "utf-8", createDirs = false, backup = false } = args;
346
+ logger.debug("Writing remote file", { path, contentSize: content.length, encoding, createDirs, backup });
228
347
  try {
229
348
  const result = await sshConnection.writeFile(path, content, {
230
349
  encoding,
231
350
  createDirs,
232
351
  backup
233
352
  });
353
+ logger.debug("File write successful", { path, bytesWritten: result.bytesWritten, backupPath: result.backupPath });
234
354
  const output = {
235
355
  success: result.success,
236
356
  bytesWritten: result.bytesWritten,
@@ -246,6 +366,7 @@ async function handleAcpRemoteWriteFile(args, sshConnection) {
246
366
  };
247
367
  } catch (error) {
248
368
  const errorMessage = error instanceof Error ? error.message : String(error);
369
+ logger.error("File write error", { path, error: errorMessage });
249
370
  return {
250
371
  content: [
251
372
  {
@@ -276,13 +397,27 @@ var SSHConnectionManager = class {
276
397
  */
277
398
  async connect() {
278
399
  if (this.connected) {
400
+ logger.debug("SSH connection already established");
279
401
  return;
280
402
  }
403
+ logger.info("Connecting to SSH server", {
404
+ host: this.config.host,
405
+ port: this.config.port || 22,
406
+ username: this.config.username
407
+ });
281
408
  return new Promise((resolve, reject) => {
282
409
  this.client.on("ready", () => {
283
410
  this.connected = true;
411
+ logger.info("SSH connection established", {
412
+ host: this.config.host,
413
+ username: this.config.username
414
+ });
284
415
  resolve();
285
416
  }).on("error", (err) => {
417
+ logger.error("SSH connection failed", {
418
+ host: this.config.host,
419
+ error: err.message
420
+ });
286
421
  reject(err);
287
422
  }).connect({
288
423
  host: this.config.host,
@@ -328,6 +463,8 @@ var SSHConnectionManager = class {
328
463
  if (!this.connected) {
329
464
  await this.connect();
330
465
  }
466
+ const startTime = Date.now();
467
+ logger.sshCommand(command, void 0, timeoutSeconds);
331
468
  const execPromise = new Promise((resolve, reject) => {
332
469
  this.client.exec(command, (err, stream) => {
333
470
  if (err) {
@@ -337,6 +474,8 @@ var SSHConnectionManager = class {
337
474
  let stdout = "";
338
475
  let stderr = "";
339
476
  stream.on("close", (code) => {
477
+ const duration = Date.now() - startTime;
478
+ logger.sshCommandResult(code, duration, stdout.length, stderr.length);
340
479
  resolve({ stdout, stderr, exitCode: code });
341
480
  }).on("data", (data) => {
342
481
  stdout += data.toString();
@@ -355,6 +494,7 @@ var SSHConnectionManager = class {
355
494
  return { ...result, timedOut: false };
356
495
  } catch (error) {
357
496
  if (error instanceof Error && error.message === "Command execution timed out") {
497
+ logger.warn("SSH command timed out", { command, timeout: timeoutSeconds });
358
498
  return {
359
499
  stdout: "",
360
500
  stderr: "Command execution timed out",
@@ -362,6 +502,10 @@ var SSHConnectionManager = class {
362
502
  timedOut: true
363
503
  };
364
504
  }
505
+ logger.error("SSH command execution failed", {
506
+ command,
507
+ error: error instanceof Error ? error.message : String(error)
508
+ });
365
509
  throw error;
366
510
  }
367
511
  }
@@ -405,22 +549,30 @@ var SSHConnectionManager = class {
405
549
  * Read file contents from remote machine
406
550
  */
407
551
  async readFile(path, encoding = "utf-8", maxSize = 1048576) {
552
+ const startTime = Date.now();
553
+ logger.fileOperation("read", path, { encoding, maxSize });
408
554
  const sftp = await this.getSFTP();
409
555
  return new Promise((resolve, reject) => {
410
556
  sftp.stat(path, (err, stats) => {
411
557
  if (err) {
558
+ logger.error("File stat failed", { path, error: err.message });
412
559
  reject(new Error(`File not found or inaccessible: ${path}`));
413
560
  return;
414
561
  }
562
+ logger.debug("File stat retrieved", { path, size: stats.size });
415
563
  if (stats.size > maxSize) {
564
+ logger.warn("File too large", { path, size: stats.size, maxSize });
416
565
  reject(new Error(`File too large: ${stats.size} bytes (max: ${maxSize} bytes)`));
417
566
  return;
418
567
  }
419
568
  sftp.readFile(path, { encoding }, (err2, data) => {
420
569
  if (err2) {
570
+ logger.error("File read failed", { path, error: err2.message });
421
571
  reject(new Error(`Failed to read file: ${err2.message}`));
422
572
  return;
423
573
  }
574
+ const duration = Date.now() - startTime;
575
+ logger.debug("File read completed", { path, size: stats.size, duration: `${duration}ms` });
424
576
  resolve({
425
577
  content: data.toString(),
426
578
  size: stats.size,
@@ -435,6 +587,13 @@ var SSHConnectionManager = class {
435
587
  */
436
588
  async writeFile(path, content, options = {}) {
437
589
  const { encoding = "utf-8", createDirs = false, backup = false } = options;
590
+ const startTime = Date.now();
591
+ logger.fileOperation("write", path, {
592
+ contentSize: content.length,
593
+ encoding,
594
+ createDirs,
595
+ backup
596
+ });
438
597
  const sftp = await this.getSFTP();
439
598
  return new Promise((resolve, reject) => {
440
599
  const writeOperation = () => {
@@ -461,9 +620,17 @@ var SSHConnectionManager = class {
461
620
  }
462
621
  sftp.rename(tempPath, path, (err2) => {
463
622
  if (err2) {
623
+ logger.error("File rename failed", { tempPath, path, error: err2.message });
464
624
  reject(new Error(`Failed to rename temp file: ${err2.message}`));
465
625
  return;
466
626
  }
627
+ const duration = Date.now() - startTime;
628
+ logger.debug("File write completed", {
629
+ path,
630
+ bytesWritten: buffer.length,
631
+ duration: `${duration}ms`,
632
+ backupPath
633
+ });
467
634
  resolve({
468
635
  success: true,
469
636
  bytesWritten: buffer.length,
@@ -487,6 +654,10 @@ var SSHConnectionManager = class {
487
654
  */
488
655
  disconnect() {
489
656
  if (this.connected) {
657
+ logger.info("Disconnecting from SSH server", {
658
+ host: this.config.host,
659
+ username: this.config.username
660
+ });
490
661
  this.client.end();
491
662
  this.connected = false;
492
663
  }
@@ -501,8 +672,15 @@ var SSHConnectionManager = class {
501
672
 
502
673
  // src/server-factory.ts
503
674
  async function createServer(serverConfig) {
675
+ logger.info("Creating server instance", { userId: serverConfig.userId });
676
+ logger.debug("SSH configuration", {
677
+ host: serverConfig.ssh.host,
678
+ port: serverConfig.ssh.port,
679
+ username: serverConfig.ssh.username
680
+ });
504
681
  const sshConnection = new SSHConnectionManager(serverConfig.ssh);
505
682
  await sshConnection.connect();
683
+ logger.info("Server created successfully", { userId: serverConfig.userId });
506
684
  const server = new Server(
507
685
  {
508
686
  name: "acp-mcp",
@@ -514,29 +692,44 @@ async function createServer(serverConfig) {
514
692
  }
515
693
  }
516
694
  );
517
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
518
- tools: [acpRemoteListFilesTool, acpRemoteExecuteCommandTool, acpRemoteReadFileTool, acpRemoteWriteFileTool]
519
- }));
695
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
696
+ logger.debug("Tool discovery requested", { userId: serverConfig.userId });
697
+ const tools = [acpRemoteListFilesTool, acpRemoteExecuteCommandTool, acpRemoteReadFileTool, acpRemoteWriteFileTool];
698
+ logger.debug(`Returning ${tools.length} tools`, { tools: tools.map((t) => t.name), userId: serverConfig.userId });
699
+ return { tools };
700
+ });
520
701
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
521
- if (request.params.name === "acp_remote_list_files") {
522
- return await handleAcpRemoteListFiles(request.params.arguments, sshConnection);
523
- }
524
- if (request.params.name === "acp_remote_execute_command") {
525
- return await handleAcpRemoteExecuteCommand(request.params.arguments, sshConnection);
526
- }
527
- if (request.params.name === "acp_remote_read_file") {
528
- return await handleAcpRemoteReadFile(request.params.arguments, sshConnection);
529
- }
530
- if (request.params.name === "acp_remote_write_file") {
531
- return await handleAcpRemoteWriteFile(request.params.arguments, sshConnection);
702
+ const startTime = Date.now();
703
+ logger.toolInvoked(request.params.name, request.params.arguments, serverConfig.userId);
704
+ try {
705
+ let result;
706
+ if (request.params.name === "acp_remote_list_files") {
707
+ result = await handleAcpRemoteListFiles(request.params.arguments, sshConnection);
708
+ } else if (request.params.name === "acp_remote_execute_command") {
709
+ result = await handleAcpRemoteExecuteCommand(request.params.arguments, sshConnection);
710
+ } else if (request.params.name === "acp_remote_read_file") {
711
+ result = await handleAcpRemoteReadFile(request.params.arguments, sshConnection);
712
+ } else if (request.params.name === "acp_remote_write_file") {
713
+ result = await handleAcpRemoteWriteFile(request.params.arguments, sshConnection);
714
+ } else {
715
+ throw new Error(`Unknown tool: ${request.params.name}`);
716
+ }
717
+ const duration = Date.now() - startTime;
718
+ const resultSize = JSON.stringify(result).length;
719
+ logger.toolCompleted(request.params.name, duration, resultSize);
720
+ return result;
721
+ } catch (error) {
722
+ logger.toolFailed(request.params.name, error, request.params.arguments);
723
+ throw error;
532
724
  }
533
- throw new Error(`Unknown tool: ${request.params.name}`);
534
725
  });
535
726
  process.on("SIGINT", () => {
727
+ logger.info("Received SIGINT, shutting down", { userId: serverConfig.userId });
536
728
  sshConnection.disconnect();
537
729
  process.exit(0);
538
730
  });
539
731
  process.on("SIGTERM", () => {
732
+ logger.info("Received SIGTERM, shutting down", { userId: serverConfig.userId });
540
733
  sshConnection.disconnect();
541
734
  process.exit(0);
542
735
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/server-factory.ts", "../src/tools/acp-remote-list-files.ts", "../src/tools/acp-remote-execute-command.ts", "../src/tools/acp-remote-read-file.ts", "../src/tools/acp-remote-write-file.ts", "../src/utils/ssh-connection.ts"],
4
- "sourcesContent": ["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { config } from './config.js';\nimport { acpRemoteListFilesTool, handleAcpRemoteListFiles } from './tools/acp-remote-list-files.js';\nimport { acpRemoteExecuteCommandTool, handleAcpRemoteExecuteCommand } from './tools/acp-remote-execute-command.js';\nimport { acpRemoteReadFileTool, handleAcpRemoteReadFile } from './tools/acp-remote-read-file.js';\nimport { acpRemoteWriteFileTool, handleAcpRemoteWriteFile } from './tools/acp-remote-write-file.js';\nimport { ServerConfig } from './types/ssh-config.js';\nimport { SSHConnectionManager } from './utils/ssh-connection.js';\n\n/**\n * Create an MCP server instance for a specific user with SSH configuration\n * This factory function is used by mcp-auth for multi-tenant support\n * \n * @param serverConfig - Configuration including userId and SSH credentials\n * @returns Configured MCP Server instance\n */\nexport async function createServer(serverConfig: ServerConfig): Promise<Server> {\n // Create SSH connection manager\n const sshConnection = new SSHConnectionManager(serverConfig.ssh);\n \n // Connect to remote server\n await sshConnection.connect();\n\n const server = new Server(\n {\n name: 'acp-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Register tools with SSH connection context\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [acpRemoteListFilesTool, acpRemoteExecuteCommandTool, acpRemoteReadFileTool, acpRemoteWriteFileTool],\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (request.params.name === 'acp_remote_list_files') {\n // Pass SSH connection to handler for remote operations\n return await handleAcpRemoteListFiles(request.params.arguments, sshConnection);\n }\n if (request.params.name === 'acp_remote_execute_command') {\n return await handleAcpRemoteExecuteCommand(request.params.arguments, sshConnection);\n }\n if (request.params.name === 'acp_remote_read_file') {\n return await handleAcpRemoteReadFile(request.params.arguments, sshConnection);\n }\n if (request.params.name === 'acp_remote_write_file') {\n return await handleAcpRemoteWriteFile(request.params.arguments, sshConnection);\n }\n throw new Error(`Unknown tool: ${request.params.name}`);\n });\n\n // Handle server shutdown to cleanup SSH connection\n process.on('SIGINT', () => {\n sshConnection.disconnect();\n process.exit(0);\n });\n\n process.on('SIGTERM', () => {\n sshConnection.disconnect();\n process.exit(0);\n });\n\n return server;\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\n\nexport const acpRemoteListFilesTool: Tool = {\n name: 'acp_remote_list_files',\n description: 'List files and directories in a specified path on the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'The directory path to list files from',\n },\n recursive: {\n type: 'boolean',\n description: 'Whether to list files recursively',\n default: false,\n },\n },\n required: ['path'],\n },\n};\n\ninterface ListFilesArgs {\n path: string;\n recursive?: boolean;\n}\n\n/**\n * Handle the acp_remote_list_files tool invocation\n * Lists files and directories at the specified path on the remote machine via SSH\n * \n * @param args - Tool arguments containing path and recursive flag\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteListFiles(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, recursive = false } = args as ListFilesArgs;\n\n try {\n const files = await listRemoteFiles(sshConnection, path, recursive);\n \n return {\n content: [\n {\n type: 'text',\n text: files.join('\\n'),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Error listing remote files: ${errorMessage}`,\n },\n ],\n };\n }\n}\n\n/**\n * Recursively list files in a remote directory via SSH\n */\nasync function listRemoteFiles(\n ssh: SSHConnectionManager,\n dirPath: string,\n recursive: boolean\n): Promise<string[]> {\n const entries = await ssh.listFiles(dirPath);\n const files: string[] = [];\n\n for (const entry of entries) {\n if (entry.isDirectory) {\n files.push(`${entry.name}/`);\n if (recursive) {\n const fullPath = `${dirPath}/${entry.name}`.replace(/\\/+/g, '/');\n const subFiles = await listRemoteFiles(ssh, fullPath, recursive);\n files.push(...subFiles.map(f => `${entry.name}/${f}`));\n }\n } else {\n files.push(entry.name);\n }\n }\n\n return files.sort();\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\n\nexport const acpRemoteExecuteCommandTool: Tool = {\n name: 'acp_remote_execute_command',\n description: 'Execute a shell command on the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n description: 'Shell command to execute',\n },\n cwd: {\n type: 'string',\n description: 'Working directory for command execution (optional)',\n },\n timeout: {\n type: 'number',\n description: 'Timeout in seconds (default: 30)',\n default: 30,\n },\n },\n required: ['command'],\n },\n};\n\ninterface ExecuteCommandArgs {\n command: string;\n cwd?: string;\n timeout?: number;\n}\n\ninterface ExecuteCommandResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n timedOut: boolean;\n}\n\n/**\n * Handle the acp_remote_execute_command tool invocation\n * Executes a shell command on the remote machine via SSH\n * \n * @param args - Tool arguments containing command, cwd, and timeout\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteExecuteCommand(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { command, cwd, timeout = 30 } = args as ExecuteCommandArgs;\n\n try {\n // Build command with working directory if specified\n const fullCommand = cwd ? `cd ${cwd} && ${command}` : command;\n \n const result = await sshConnection.execWithTimeout(fullCommand, timeout);\n \n // Format output as JSON for structured response\n const output: ExecuteCommandResult = {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n stdout: '',\n stderr: errorMessage,\n exitCode: 1,\n timedOut: false,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\n\nexport const acpRemoteReadFileTool: Tool = {\n name: 'acp_remote_read_file',\n description: 'Read file contents from the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Absolute path to file',\n },\n encoding: {\n type: 'string',\n description: 'File encoding (default: utf-8)',\n default: 'utf-8',\n enum: ['utf-8', 'ascii', 'base64'],\n },\n maxSize: {\n type: 'number',\n description: 'Max file size in bytes (default: 1MB)',\n default: 1048576,\n },\n },\n required: ['path'],\n },\n};\n\ninterface ReadFileArgs {\n path: string;\n encoding?: string;\n maxSize?: number;\n}\n\ninterface ReadFileResult {\n content: string;\n size: number;\n encoding: string;\n}\n\n/**\n * Handle the acp_remote_read_file tool invocation\n * Reads file contents from the remote machine via SSH\n * \n * @param args - Tool arguments containing path, encoding, and maxSize\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteReadFile(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, encoding = 'utf-8', maxSize = 1048576 } = args as ReadFileArgs;\n\n try {\n const result = await sshConnection.readFile(path, encoding, maxSize);\n \n const output: ReadFileResult = {\n content: result.content,\n size: result.size,\n encoding: result.encoding,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n error: errorMessage,\n content: '',\n size: 0,\n encoding,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\n\nexport const acpRemoteWriteFileTool: Tool = {\n name: 'acp_remote_write_file',\n description: 'Write file contents to the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Absolute path to file',\n },\n content: {\n type: 'string',\n description: 'File contents to write',\n },\n encoding: {\n type: 'string',\n description: 'File encoding (default: utf-8)',\n default: 'utf-8',\n },\n createDirs: {\n type: 'boolean',\n description: 'Create parent directories if they don\\'t exist (default: false)',\n default: false,\n },\n backup: {\n type: 'boolean',\n description: 'Backup existing file before overwriting (default: false)',\n default: false,\n },\n },\n required: ['path', 'content'],\n },\n};\n\ninterface WriteFileArgs {\n path: string;\n content: string;\n encoding?: string;\n createDirs?: boolean;\n backup?: boolean;\n}\n\ninterface WriteFileResult {\n success: boolean;\n bytesWritten: number;\n backupPath?: string;\n}\n\n/**\n * Handle the acp_remote_write_file tool invocation\n * Writes file contents to the remote machine via SSH\n * \n * @param args - Tool arguments containing path, content, and options\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteWriteFile(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, content, encoding = 'utf-8', createDirs = false, backup = false } = args as WriteFileArgs;\n\n try {\n const result = await sshConnection.writeFile(path, content, {\n encoding,\n createDirs,\n backup,\n });\n \n const output: WriteFileResult = {\n success: result.success,\n bytesWritten: result.bytesWritten,\n backupPath: result.backupPath,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: false,\n bytesWritten: 0,\n error: errorMessage,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Client, SFTPWrapper } from 'ssh2';\nimport { SSHConfig } from '../types/ssh-config.js';\n\n/**\n * SSH Connection Manager\n * Manages SSH connections and provides SFTP access for remote file operations\n */\nexport class SSHConnectionManager {\n private client: Client;\n private config: SSHConfig;\n private connected: boolean = false;\n\n constructor(config: SSHConfig) {\n this.config = config;\n this.client = new Client();\n }\n\n /**\n * Connect to the remote SSH server\n */\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.client\n .on('ready', () => {\n this.connected = true;\n resolve();\n })\n .on('error', (err) => {\n reject(err);\n })\n .connect({\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n privateKey: this.config.privateKey,\n });\n });\n }\n\n /**\n * Execute a command on the remote server\n */\n async exec(command: string): Promise<string> {\n if (!this.connected) {\n await this.connect();\n }\n\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n if (code !== 0) {\n reject(new Error(`Command failed with code ${code}: ${stderr}`));\n } else {\n resolve(stdout);\n }\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Execute a command on the remote server with timeout support\n */\n async execWithTimeout(\n command: string,\n timeoutSeconds: number = 30\n ): Promise<{ stdout: string; stderr: string; exitCode: number; timedOut: boolean }> {\n if (!this.connected) {\n await this.connect();\n }\n\n const execPromise = new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve, reject) => {\n this.client.exec(command, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n resolve({ stdout, stderr, exitCode: code });\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error('Command execution timed out'));\n }, timeoutSeconds * 1000);\n });\n\n try {\n const result = await Promise.race([execPromise, timeoutPromise]);\n return { ...result, timedOut: false };\n } catch (error) {\n if (error instanceof Error && error.message === 'Command execution timed out') {\n return {\n stdout: '',\n stderr: 'Command execution timed out',\n exitCode: 124,\n timedOut: true,\n };\n }\n throw error;\n }\n }\n\n /**\n * Get SFTP wrapper for file operations\n */\n async getSFTP(): Promise<SFTPWrapper> {\n if (!this.connected) {\n await this.connect();\n }\n\n return new Promise((resolve, reject) => {\n this.client.sftp((err, sftp) => {\n if (err) {\n reject(err);\n } else {\n resolve(sftp);\n }\n });\n });\n }\n\n /**\n * List files in a directory using SFTP\n */\n async listFiles(path: string): Promise<Array<{ name: string; isDirectory: boolean }>> {\n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n sftp.readdir(path, (err, list) => {\n if (err) {\n reject(err);\n return;\n }\n\n const files = list.map((item) => ({\n name: item.filename,\n isDirectory: item.attrs.isDirectory(),\n }));\n\n resolve(files);\n });\n });\n }\n\n /**\n * Read file contents from remote machine\n */\n async readFile(\n path: string,\n encoding: string = 'utf-8',\n maxSize: number = 1048576\n ): Promise<{ content: string; size: number; encoding: string }> {\n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n // First, get file stats to check size\n sftp.stat(path, (err, stats) => {\n if (err) {\n reject(new Error(`File not found or inaccessible: ${path}`));\n return;\n }\n\n if (stats.size > maxSize) {\n reject(new Error(`File too large: ${stats.size} bytes (max: ${maxSize} bytes)`));\n return;\n }\n\n // Read file contents\n sftp.readFile(path, { encoding: encoding as BufferEncoding }, (err, data) => {\n if (err) {\n reject(new Error(`Failed to read file: ${err.message}`));\n return;\n }\n\n resolve({\n content: data.toString(),\n size: stats.size,\n encoding,\n });\n });\n });\n });\n }\n\n /**\n * Write file contents to remote machine\n */\n async writeFile(\n path: string,\n content: string,\n options: {\n encoding?: string;\n createDirs?: boolean;\n backup?: boolean;\n } = {}\n ): Promise<{ success: boolean; bytesWritten: number; backupPath?: string }> {\n const { encoding = 'utf-8', createDirs = false, backup = false } = options;\n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n const writeOperation = () => {\n // Create backup if requested\n if (backup) {\n const backupPath = `${path}.backup`;\n sftp.rename(path, backupPath, (err) => {\n if (err && err.message !== 'No such file') {\n // Ignore \"no such file\" error (file doesn't exist yet)\n reject(new Error(`Failed to create backup: ${err.message}`));\n return;\n }\n \n // Write file\n performWrite(backupPath);\n });\n } else {\n performWrite();\n }\n };\n\n const performWrite = (backupPath?: string) => {\n const buffer = Buffer.from(content, encoding as BufferEncoding);\n const tempPath = `${path}.tmp`;\n\n // Write to temp file first (atomic write)\n sftp.writeFile(tempPath, buffer, (err) => {\n if (err) {\n reject(new Error(`Failed to write file: ${err.message}`));\n return;\n }\n\n // Rename temp file to target (atomic operation)\n sftp.rename(tempPath, path, (err) => {\n if (err) {\n reject(new Error(`Failed to rename temp file: ${err.message}`));\n return;\n }\n\n resolve({\n success: true,\n bytesWritten: buffer.length,\n backupPath,\n });\n });\n });\n };\n\n // Create parent directories if requested\n if (createDirs) {\n const dirPath = path.substring(0, path.lastIndexOf('/'));\n this.exec(`mkdir -p ${dirPath}`).then(() => {\n writeOperation();\n }).catch(reject);\n } else {\n writeOperation();\n }\n });\n }\n\n /**\n * Disconnect from the SSH server\n */\n disconnect(): void {\n if (this.connected) {\n this.client.end();\n this.connected = false;\n }\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connected;\n }\n}\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/server-factory.ts", "../src/tools/acp-remote-list-files.ts", "../src/utils/logger.ts", "../src/tools/acp-remote-execute-command.ts", "../src/tools/acp-remote-read-file.ts", "../src/tools/acp-remote-write-file.ts", "../src/utils/ssh-connection.ts"],
4
+ "sourcesContent": ["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { config } from './config.js';\nimport { acpRemoteListFilesTool, handleAcpRemoteListFiles } from './tools/acp-remote-list-files.js';\nimport { acpRemoteExecuteCommandTool, handleAcpRemoteExecuteCommand } from './tools/acp-remote-execute-command.js';\nimport { acpRemoteReadFileTool, handleAcpRemoteReadFile } from './tools/acp-remote-read-file.js';\nimport { acpRemoteWriteFileTool, handleAcpRemoteWriteFile } from './tools/acp-remote-write-file.js';\nimport { ServerConfig } from './types/ssh-config.js';\nimport { SSHConnectionManager } from './utils/ssh-connection.js';\nimport { logger } from './utils/logger.js';\n\n/**\n * Create an MCP server instance for a specific user with SSH configuration\n * This factory function is used by mcp-auth for multi-tenant support\n * \n * @param serverConfig - Configuration including userId and SSH credentials\n * @returns Configured MCP Server instance\n */\nexport async function createServer(serverConfig: ServerConfig): Promise<Server> {\n logger.info('Creating server instance', { userId: serverConfig.userId });\n logger.debug('SSH configuration', {\n host: serverConfig.ssh.host,\n port: serverConfig.ssh.port,\n username: serverConfig.ssh.username,\n });\n \n // Create SSH connection manager\n const sshConnection = new SSHConnectionManager(serverConfig.ssh);\n \n // Connect to remote server\n await sshConnection.connect();\n \n logger.info('Server created successfully', { userId: serverConfig.userId });\n\n const server = new Server(\n {\n name: 'acp-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Register tools with SSH connection context\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n logger.debug('Tool discovery requested', { userId: serverConfig.userId });\n const tools = [acpRemoteListFilesTool, acpRemoteExecuteCommandTool, acpRemoteReadFileTool, acpRemoteWriteFileTool];\n logger.debug(`Returning ${tools.length} tools`, { tools: tools.map(t => t.name), userId: serverConfig.userId });\n return { tools };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const startTime = Date.now();\n logger.toolInvoked(request.params.name, request.params.arguments, serverConfig.userId);\n \n try {\n let result;\n \n if (request.params.name === 'acp_remote_list_files') {\n // Pass SSH connection to handler for remote operations\n result = await handleAcpRemoteListFiles(request.params.arguments, sshConnection);\n } else if (request.params.name === 'acp_remote_execute_command') {\n result = await handleAcpRemoteExecuteCommand(request.params.arguments, sshConnection);\n } else if (request.params.name === 'acp_remote_read_file') {\n result = await handleAcpRemoteReadFile(request.params.arguments, sshConnection);\n } else if (request.params.name === 'acp_remote_write_file') {\n result = await handleAcpRemoteWriteFile(request.params.arguments, sshConnection);\n } else {\n throw new Error(`Unknown tool: ${request.params.name}`);\n }\n \n const duration = Date.now() - startTime;\n const resultSize = JSON.stringify(result).length;\n logger.toolCompleted(request.params.name, duration, resultSize);\n \n return result;\n } catch (error) {\n logger.toolFailed(request.params.name, error as Error, request.params.arguments);\n throw error;\n }\n });\n\n // Handle server shutdown to cleanup SSH connection\n process.on('SIGINT', () => {\n logger.info('Received SIGINT, shutting down', { userId: serverConfig.userId });\n sshConnection.disconnect();\n process.exit(0);\n });\n\n process.on('SIGTERM', () => {\n logger.info('Received SIGTERM, shutting down', { userId: serverConfig.userId });\n sshConnection.disconnect();\n process.exit(0);\n });\n\n return server;\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\n\nexport const acpRemoteListFilesTool: Tool = {\n name: 'acp_remote_list_files',\n description: 'List files and directories in a specified path on the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'The directory path to list files from',\n },\n recursive: {\n type: 'boolean',\n description: 'Whether to list files recursively',\n default: false,\n },\n },\n required: ['path'],\n },\n};\n\ninterface ListFilesArgs {\n path: string;\n recursive?: boolean;\n}\n\n/**\n * Handle the acp_remote_list_files tool invocation\n * Lists files and directories at the specified path on the remote machine via SSH\n * \n * @param args - Tool arguments containing path and recursive flag\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteListFiles(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, recursive = false } = args as ListFilesArgs;\n\n try {\n const files = await listRemoteFiles(sshConnection, path, recursive);\n \n return {\n content: [\n {\n type: 'text',\n text: files.join('\\n'),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Error listing remote files: ${errorMessage}`,\n },\n ],\n };\n }\n}\n\n/**\n * Recursively list files in a remote directory via SSH\n * Returns absolute paths for compatibility with acp_remote_read_file\n */\nasync function listRemoteFiles(\n ssh: SSHConnectionManager,\n dirPath: string,\n recursive: boolean\n): Promise<string[]> {\n const entries = await ssh.listFiles(dirPath);\n const files: string[] = [];\n\n for (const entry of entries) {\n // Construct absolute path by combining dirPath with entry name\n const fullPath = `${dirPath}/${entry.name}`.replace(/\\/+/g, '/');\n \n if (entry.isDirectory) {\n files.push(`${fullPath}/`); // Return absolute path with trailing slash\n if (recursive) {\n const subFiles = await listRemoteFiles(ssh, fullPath, recursive);\n files.push(...subFiles); // Sub-files already have absolute paths\n }\n } else {\n files.push(fullPath); // Return absolute path\n }\n }\n\n return files.sort();\n}\n", "/**\n * Logger utility for ACP MCP Server\n * Provides structured logging with configurable log levels\n */\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\nclass Logger {\n private level: LogLevel;\n private enabled: boolean;\n\n constructor() {\n // Read configuration from environment variables\n this.level = (process.env.ACP_MCP_LOG_LEVEL as LogLevel) || 'info';\n this.enabled = process.env.ACP_MCP_DEBUG === 'true' || process.env.NODE_ENV === 'development';\n }\n\n private shouldLog(level: LogLevel): boolean {\n if (!this.enabled && level !== 'error' && level !== 'warn') {\n return false;\n }\n return LOG_LEVELS[level] <= LOG_LEVELS[this.level];\n }\n\n private formatMessage(level: LogLevel, message: string, data?: any): string {\n const timestamp = new Date().toISOString();\n const prefix = `[${timestamp}] [${level.toUpperCase()}]`;\n \n if (data !== undefined) {\n const dataStr = typeof data === 'object' ? JSON.stringify(data, null, 2) : String(data);\n return `${prefix} ${message}\\n${dataStr}`;\n }\n \n return `${prefix} ${message}`;\n }\n\n error(message: string, data?: any): void {\n if (this.shouldLog('error')) {\n console.error(this.formatMessage('error', message, data));\n }\n }\n\n warn(message: string, data?: any): void {\n if (this.shouldLog('warn')) {\n console.error(this.formatMessage('warn', message, data));\n }\n }\n\n info(message: string, data?: any): void {\n if (this.shouldLog('info')) {\n console.error(this.formatMessage('info', message, data));\n }\n }\n\n debug(message: string, data?: any): void {\n if (this.shouldLog('debug')) {\n console.error(this.formatMessage('debug', message, data));\n }\n }\n\n trace(message: string, data?: any): void {\n if (this.shouldLog('trace')) {\n console.error(this.formatMessage('trace', message, data));\n }\n }\n\n /**\n * Log tool invocation with parameters\n */\n toolInvoked(toolName: string, params: any, userId?: string): void {\n this.info(`Tool invoked: ${toolName}`);\n this.debug('Tool parameters', { tool: toolName, params, userId });\n }\n\n /**\n * Log tool completion with result summary\n */\n toolCompleted(toolName: string, duration: number, resultSize?: number): void {\n this.info(`Tool completed: ${toolName}`);\n this.debug('Tool performance', { tool: toolName, duration: `${duration}ms`, resultSize });\n }\n\n /**\n * Log tool failure with error details\n */\n toolFailed(toolName: string, error: Error, params?: any): void {\n this.error(`Tool execution failed: ${toolName}`, {\n tool: toolName,\n error: error.message,\n stack: error.stack,\n params,\n });\n }\n\n /**\n * Log SSH command execution\n */\n sshCommand(command: string, cwd?: string, timeout?: number): void {\n this.debug('Executing SSH command', { command, cwd, timeout });\n }\n\n /**\n * Log SSH command result\n */\n sshCommandResult(exitCode: number, duration: number, stdoutSize: number, stderrSize: number): void {\n this.debug('SSH command completed', {\n exitCode,\n duration: `${duration}ms`,\n stdout: `${stdoutSize} bytes`,\n stderr: `${stderrSize} bytes`,\n });\n }\n\n /**\n * Log file operation\n */\n fileOperation(operation: string, path: string, details?: any): void {\n this.info(`File operation: ${operation}`, { path, ...details });\n }\n}\n\n// Export singleton instance\nexport const logger = new Logger();\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { logger } from '../utils/logger.js';\n\nexport const acpRemoteExecuteCommandTool: Tool = {\n name: 'acp_remote_execute_command',\n description: 'Execute a shell command on the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n description: 'Shell command to execute',\n },\n cwd: {\n type: 'string',\n description: 'Working directory for command execution (optional)',\n },\n timeout: {\n type: 'number',\n description: 'Timeout in seconds (default: 30)',\n default: 30,\n },\n },\n required: ['command'],\n },\n};\n\ninterface ExecuteCommandArgs {\n command: string;\n cwd?: string;\n timeout?: number;\n}\n\ninterface ExecuteCommandResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n timedOut: boolean;\n}\n\n/**\n * Handle the acp_remote_execute_command tool invocation\n * Executes a shell command on the remote machine via SSH\n * \n * @param args - Tool arguments containing command, cwd, and timeout\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteExecuteCommand(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { command, cwd, timeout = 30 } = args as ExecuteCommandArgs;\n\n logger.debug('Executing remote command', { command, cwd, timeout });\n\n try {\n // Build command with working directory if specified\n const fullCommand = cwd ? `cd ${cwd} && ${command}` : command;\n \n const result = await sshConnection.execWithTimeout(fullCommand, timeout);\n \n logger.debug('Command execution result', {\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n stdoutLength: result.stdout.length,\n stderrLength: result.stderr.length,\n });\n \n // Format output as JSON for structured response\n const output: ExecuteCommandResult = {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error('Command execution error', { command, error: errorMessage });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n stdout: '',\n stderr: errorMessage,\n exitCode: 1,\n timedOut: false,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { logger } from '../utils/logger.js';\n\nexport const acpRemoteReadFileTool: Tool = {\n name: 'acp_remote_read_file',\n description: 'Read file contents from the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Absolute path to file',\n },\n encoding: {\n type: 'string',\n description: 'File encoding (default: utf-8)',\n default: 'utf-8',\n enum: ['utf-8', 'ascii', 'base64'],\n },\n maxSize: {\n type: 'number',\n description: 'Max file size in bytes (default: 1MB)',\n default: 1048576,\n },\n },\n required: ['path'],\n },\n};\n\ninterface ReadFileArgs {\n path: string;\n encoding?: string;\n maxSize?: number;\n}\n\ninterface ReadFileResult {\n content: string;\n size: number;\n encoding: string;\n}\n\n/**\n * Handle the acp_remote_read_file tool invocation\n * Reads file contents from the remote machine via SSH\n * \n * @param args - Tool arguments containing path, encoding, and maxSize\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteReadFile(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, encoding = 'utf-8', maxSize = 1048576 } = args as ReadFileArgs;\n\n logger.debug('Reading remote file', { path, encoding, maxSize });\n\n try {\n const result = await sshConnection.readFile(path, encoding, maxSize);\n \n logger.debug('File read successful', { path, size: result.size });\n \n const output: ReadFileResult = {\n content: result.content,\n size: result.size,\n encoding: result.encoding,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error('File read error', { path, error: errorMessage });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n error: errorMessage,\n content: '',\n size: 0,\n encoding,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { logger } from '../utils/logger.js';\n\nexport const acpRemoteWriteFileTool: Tool = {\n name: 'acp_remote_write_file',\n description: 'Write file contents to the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Absolute path to file',\n },\n content: {\n type: 'string',\n description: 'File contents to write',\n },\n encoding: {\n type: 'string',\n description: 'File encoding (default: utf-8)',\n default: 'utf-8',\n },\n createDirs: {\n type: 'boolean',\n description: 'Create parent directories if they don\\'t exist (default: false)',\n default: false,\n },\n backup: {\n type: 'boolean',\n description: 'Backup existing file before overwriting (default: false)',\n default: false,\n },\n },\n required: ['path', 'content'],\n },\n};\n\ninterface WriteFileArgs {\n path: string;\n content: string;\n encoding?: string;\n createDirs?: boolean;\n backup?: boolean;\n}\n\ninterface WriteFileResult {\n success: boolean;\n bytesWritten: number;\n backupPath?: string;\n}\n\n/**\n * Handle the acp_remote_write_file tool invocation\n * Writes file contents to the remote machine via SSH\n * \n * @param args - Tool arguments containing path, content, and options\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteWriteFile(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, content, encoding = 'utf-8', createDirs = false, backup = false } = args as WriteFileArgs;\n\n logger.debug('Writing remote file', { path, contentSize: content.length, encoding, createDirs, backup });\n\n try {\n const result = await sshConnection.writeFile(path, content, {\n encoding,\n createDirs,\n backup,\n });\n \n logger.debug('File write successful', { path, bytesWritten: result.bytesWritten, backupPath: result.backupPath });\n \n const output: WriteFileResult = {\n success: result.success,\n bytesWritten: result.bytesWritten,\n backupPath: result.backupPath,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error('File write error', { path, error: errorMessage });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: false,\n bytesWritten: 0,\n error: errorMessage,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Client, SFTPWrapper } from 'ssh2';\nimport { SSHConfig } from '../types/ssh-config.js';\nimport { logger } from './logger.js';\n\n/**\n * SSH Connection Manager\n * Manages SSH connections and provides SFTP access for remote file operations\n */\nexport class SSHConnectionManager {\n private client: Client;\n private config: SSHConfig;\n private connected: boolean = false;\n\n constructor(config: SSHConfig) {\n this.config = config;\n this.client = new Client();\n }\n\n /**\n * Connect to the remote SSH server\n */\n async connect(): Promise<void> {\n if (this.connected) {\n logger.debug('SSH connection already established');\n return;\n }\n\n logger.info('Connecting to SSH server', {\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n });\n\n return new Promise((resolve, reject) => {\n this.client\n .on('ready', () => {\n this.connected = true;\n logger.info('SSH connection established', {\n host: this.config.host,\n username: this.config.username,\n });\n resolve();\n })\n .on('error', (err) => {\n logger.error('SSH connection failed', {\n host: this.config.host,\n error: err.message,\n });\n reject(err);\n })\n .connect({\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n privateKey: this.config.privateKey,\n });\n });\n }\n\n /**\n * Execute a command on the remote server\n */\n async exec(command: string): Promise<string> {\n if (!this.connected) {\n await this.connect();\n }\n\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n if (code !== 0) {\n reject(new Error(`Command failed with code ${code}: ${stderr}`));\n } else {\n resolve(stdout);\n }\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Execute a command on the remote server with timeout support\n */\n async execWithTimeout(\n command: string,\n timeoutSeconds: number = 30\n ): Promise<{ stdout: string; stderr: string; exitCode: number; timedOut: boolean }> {\n if (!this.connected) {\n await this.connect();\n }\n\n const startTime = Date.now();\n logger.sshCommand(command, undefined, timeoutSeconds);\n\n const execPromise = new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve, reject) => {\n this.client.exec(command, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n const duration = Date.now() - startTime;\n logger.sshCommandResult(code, duration, stdout.length, stderr.length);\n resolve({ stdout, stderr, exitCode: code });\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error('Command execution timed out'));\n }, timeoutSeconds * 1000);\n });\n\n try {\n const result = await Promise.race([execPromise, timeoutPromise]);\n return { ...result, timedOut: false };\n } catch (error) {\n if (error instanceof Error && error.message === 'Command execution timed out') {\n logger.warn('SSH command timed out', { command, timeout: timeoutSeconds });\n return {\n stdout: '',\n stderr: 'Command execution timed out',\n exitCode: 124,\n timedOut: true,\n };\n }\n logger.error('SSH command execution failed', {\n command,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Get SFTP wrapper for file operations\n */\n async getSFTP(): Promise<SFTPWrapper> {\n if (!this.connected) {\n await this.connect();\n }\n\n return new Promise((resolve, reject) => {\n this.client.sftp((err, sftp) => {\n if (err) {\n reject(err);\n } else {\n resolve(sftp);\n }\n });\n });\n }\n\n /**\n * List files in a directory using SFTP\n */\n async listFiles(path: string): Promise<Array<{ name: string; isDirectory: boolean }>> {\n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n sftp.readdir(path, (err, list) => {\n if (err) {\n reject(err);\n return;\n }\n\n const files = list.map((item) => ({\n name: item.filename,\n isDirectory: item.attrs.isDirectory(),\n }));\n\n resolve(files);\n });\n });\n }\n\n /**\n * Read file contents from remote machine\n */\n async readFile(\n path: string,\n encoding: string = 'utf-8',\n maxSize: number = 1048576\n ): Promise<{ content: string; size: number; encoding: string }> {\n const startTime = Date.now();\n logger.fileOperation('read', path, { encoding, maxSize });\n \n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n // First, get file stats to check size\n sftp.stat(path, (err, stats) => {\n if (err) {\n logger.error('File stat failed', { path, error: err.message });\n reject(new Error(`File not found or inaccessible: ${path}`));\n return;\n }\n\n logger.debug('File stat retrieved', { path, size: stats.size });\n\n if (stats.size > maxSize) {\n logger.warn('File too large', { path, size: stats.size, maxSize });\n reject(new Error(`File too large: ${stats.size} bytes (max: ${maxSize} bytes)`));\n return;\n }\n\n // Read file contents\n sftp.readFile(path, { encoding: encoding as BufferEncoding }, (err, data) => {\n if (err) {\n logger.error('File read failed', { path, error: err.message });\n reject(new Error(`Failed to read file: ${err.message}`));\n return;\n }\n\n const duration = Date.now() - startTime;\n logger.debug('File read completed', { path, size: stats.size, duration: `${duration}ms` });\n\n resolve({\n content: data.toString(),\n size: stats.size,\n encoding,\n });\n });\n });\n });\n }\n\n /**\n * Write file contents to remote machine\n */\n async writeFile(\n path: string,\n content: string,\n options: {\n encoding?: string;\n createDirs?: boolean;\n backup?: boolean;\n } = {}\n ): Promise<{ success: boolean; bytesWritten: number; backupPath?: string }> {\n const { encoding = 'utf-8', createDirs = false, backup = false } = options;\n const startTime = Date.now();\n \n logger.fileOperation('write', path, {\n contentSize: content.length,\n encoding,\n createDirs,\n backup,\n });\n \n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n const writeOperation = () => {\n // Create backup if requested\n if (backup) {\n const backupPath = `${path}.backup`;\n sftp.rename(path, backupPath, (err) => {\n if (err && err.message !== 'No such file') {\n // Ignore \"no such file\" error (file doesn't exist yet)\n reject(new Error(`Failed to create backup: ${err.message}`));\n return;\n }\n \n // Write file\n performWrite(backupPath);\n });\n } else {\n performWrite();\n }\n };\n\n const performWrite = (backupPath?: string) => {\n const buffer = Buffer.from(content, encoding as BufferEncoding);\n const tempPath = `${path}.tmp`;\n\n // Write to temp file first (atomic write)\n sftp.writeFile(tempPath, buffer, (err) => {\n if (err) {\n reject(new Error(`Failed to write file: ${err.message}`));\n return;\n }\n\n // Rename temp file to target (atomic operation)\n sftp.rename(tempPath, path, (err) => {\n if (err) {\n logger.error('File rename failed', { tempPath, path, error: err.message });\n reject(new Error(`Failed to rename temp file: ${err.message}`));\n return;\n }\n\n const duration = Date.now() - startTime;\n logger.debug('File write completed', {\n path,\n bytesWritten: buffer.length,\n duration: `${duration}ms`,\n backupPath,\n });\n\n resolve({\n success: true,\n bytesWritten: buffer.length,\n backupPath,\n });\n });\n });\n };\n\n // Create parent directories if requested\n if (createDirs) {\n const dirPath = path.substring(0, path.lastIndexOf('/'));\n this.exec(`mkdir -p ${dirPath}`).then(() => {\n writeOperation();\n }).catch(reject);\n } else {\n writeOperation();\n }\n });\n }\n\n /**\n * Disconnect from the SSH server\n */\n disconnect(): void {\n if (this.connected) {\n logger.info('Disconnecting from SSH server', {\n host: this.config.host,\n username: this.config.username,\n });\n this.client.end();\n this.connected = false;\n }\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connected;\n }\n}\n"],
5
+ "mappings": ";AAAA,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,OACK;;;ACDA,IAAM,yBAA+B;AAAA,EAC1C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,WAAW;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,UAAU,CAAC,MAAM;AAAA,EACnB;AACF;AAcA,eAAsB,yBACpB,MACA,eAC6D;AAC7D,QAAM,EAAE,MAAM,YAAY,MAAM,IAAI;AAEpC,MAAI;AACF,UAAM,QAAQ,MAAM,gBAAgB,eAAe,MAAM,SAAS;AAElE,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,MAAM,KAAK,IAAI;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,+BAA+B,YAAY;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAMA,eAAe,gBACb,KACA,SACA,WACmB;AACnB,QAAM,UAAU,MAAM,IAAI,UAAU,OAAO;AAC3C,QAAM,QAAkB,CAAC;AAEzB,aAAW,SAAS,SAAS;AAE3B,UAAM,WAAW,GAAG,OAAO,IAAI,MAAM,IAAI,GAAG,QAAQ,QAAQ,GAAG;AAE/D,QAAI,MAAM,aAAa;AACrB,YAAM,KAAK,GAAG,QAAQ,GAAG;AACzB,UAAI,WAAW;AACb,cAAM,WAAW,MAAM,gBAAgB,KAAK,UAAU,SAAS;AAC/D,cAAM,KAAK,GAAG,QAAQ;AAAA,MACxB;AAAA,IACF,OAAO;AACL,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,MAAM,KAAK;AACpB;;;ACtFA,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AACT;AAEA,IAAM,SAAN,MAAa;AAAA,EACH;AAAA,EACA;AAAA,EAER,cAAc;AAEZ,SAAK,QAAS,QAAQ,IAAI,qBAAkC;AAC5D,SAAK,UAAU,QAAQ,IAAI,kBAAkB,UAAU,QAAQ,IAAI,aAAa;AAAA,EAClF;AAAA,EAEQ,UAAU,OAA0B;AAC1C,QAAI,CAAC,KAAK,WAAW,UAAU,WAAW,UAAU,QAAQ;AAC1D,aAAO;AAAA,IACT;AACA,WAAO,WAAW,KAAK,KAAK,WAAW,KAAK,KAAK;AAAA,EACnD;AAAA,EAEQ,cAAc,OAAiB,SAAiB,MAAoB;AAC1E,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAM,SAAS,IAAI,SAAS,MAAM,MAAM,YAAY,CAAC;AAErD,QAAI,SAAS,QAAW;AACtB,YAAM,UAAU,OAAO,SAAS,WAAW,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,OAAO,IAAI;AACtF,aAAO,GAAG,MAAM,IAAI,OAAO;AAAA,EAAK,OAAO;AAAA,IACzC;AAEA,WAAO,GAAG,MAAM,IAAI,OAAO;AAAA,EAC7B;AAAA,EAEA,MAAM,SAAiB,MAAkB;AACvC,QAAI,KAAK,UAAU,OAAO,GAAG;AAC3B,cAAQ,MAAM,KAAK,cAAc,SAAS,SAAS,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA,EAEA,KAAK,SAAiB,MAAkB;AACtC,QAAI,KAAK,UAAU,MAAM,GAAG;AAC1B,cAAQ,MAAM,KAAK,cAAc,QAAQ,SAAS,IAAI,CAAC;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,KAAK,SAAiB,MAAkB;AACtC,QAAI,KAAK,UAAU,MAAM,GAAG;AAC1B,cAAQ,MAAM,KAAK,cAAc,QAAQ,SAAS,IAAI,CAAC;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,MAAM,SAAiB,MAAkB;AACvC,QAAI,KAAK,UAAU,OAAO,GAAG;AAC3B,cAAQ,MAAM,KAAK,cAAc,SAAS,SAAS,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA,EAEA,MAAM,SAAiB,MAAkB;AACvC,QAAI,KAAK,UAAU,OAAO,GAAG;AAC3B,cAAQ,MAAM,KAAK,cAAc,SAAS,SAAS,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAAkB,QAAa,QAAuB;AAChE,SAAK,KAAK,iBAAiB,QAAQ,EAAE;AACrC,SAAK,MAAM,mBAAmB,EAAE,MAAM,UAAU,QAAQ,OAAO,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,UAAkB,UAAkB,YAA2B;AAC3E,SAAK,KAAK,mBAAmB,QAAQ,EAAE;AACvC,SAAK,MAAM,oBAAoB,EAAE,MAAM,UAAU,UAAU,GAAG,QAAQ,MAAM,WAAW,CAAC;AAAA,EAC1F;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,UAAkB,OAAc,QAAoB;AAC7D,SAAK,MAAM,0BAA0B,QAAQ,IAAI;AAAA,MAC/C,MAAM;AAAA,MACN,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,SAAiB,KAAc,SAAwB;AAChE,SAAK,MAAM,yBAAyB,EAAE,SAAS,KAAK,QAAQ,CAAC;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,UAAkB,UAAkB,YAAoB,YAA0B;AACjG,SAAK,MAAM,yBAAyB;AAAA,MAClC;AAAA,MACA,UAAU,GAAG,QAAQ;AAAA,MACrB,QAAQ,GAAG,UAAU;AAAA,MACrB,QAAQ,GAAG,UAAU;AAAA,IACvB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,WAAmB,MAAc,SAAqB;AAClE,SAAK,KAAK,mBAAmB,SAAS,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;AAAA,EAChE;AACF;AAGO,IAAM,SAAS,IAAI,OAAO;;;AC9H1B,IAAM,8BAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,UAAU,CAAC,SAAS;AAAA,EACtB;AACF;AAsBA,eAAsB,8BACpB,MACA,eAC6D;AAC7D,QAAM,EAAE,SAAS,KAAK,UAAU,GAAG,IAAI;AAEvC,SAAO,MAAM,4BAA4B,EAAE,SAAS,KAAK,QAAQ,CAAC;AAElE,MAAI;AAEF,UAAM,cAAc,MAAM,MAAM,GAAG,OAAO,OAAO,KAAK;AAEtD,UAAM,SAAS,MAAM,cAAc,gBAAgB,aAAa,OAAO;AAEvE,WAAO,MAAM,4BAA4B;AAAA,MACvC,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,cAAc,OAAO,OAAO;AAAA,MAC5B,cAAc,OAAO,OAAO;AAAA,IAC9B,CAAC;AAGD,UAAM,SAA+B;AAAA,MACnC,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,IACnB;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO,MAAM,2BAA2B,EAAE,SAAS,OAAO,aAAa,CAAC;AACxE,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,UAAU;AAAA,UACZ,GAAG,MAAM,CAAC;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AClGO,IAAM,wBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,UAAU;AAAA,QACR,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,QACT,MAAM,CAAC,SAAS,SAAS,QAAQ;AAAA,MACnC;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,UAAU,CAAC,MAAM;AAAA,EACnB;AACF;AAqBA,eAAsB,wBACpB,MACA,eAC6D;AAC7D,QAAM,EAAE,MAAM,WAAW,SAAS,UAAU,QAAQ,IAAI;AAExD,SAAO,MAAM,uBAAuB,EAAE,MAAM,UAAU,QAAQ,CAAC;AAE/D,MAAI;AACF,UAAM,SAAS,MAAM,cAAc,SAAS,MAAM,UAAU,OAAO;AAEnE,WAAO,MAAM,wBAAwB,EAAE,MAAM,MAAM,OAAO,KAAK,CAAC;AAEhE,UAAM,SAAyB;AAAA,MAC7B,SAAS,OAAO;AAAA,MAChB,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,IACnB;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO,MAAM,mBAAmB,EAAE,MAAM,OAAO,aAAa,CAAC;AAC7D,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB,OAAO;AAAA,YACP,SAAS;AAAA,YACT,MAAM;AAAA,YACN;AAAA,UACF,GAAG,MAAM,CAAC;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACzFO,IAAM,yBAA+B;AAAA,EAC1C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,UAAU;AAAA,QACR,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,YAAY;AAAA,QACV,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,UAAU,CAAC,QAAQ,SAAS;AAAA,EAC9B;AACF;AAuBA,eAAsB,yBACpB,MACA,eAC6D;AAC7D,QAAM,EAAE,MAAM,SAAS,WAAW,SAAS,aAAa,OAAO,SAAS,MAAM,IAAI;AAElF,SAAO,MAAM,uBAAuB,EAAE,MAAM,aAAa,QAAQ,QAAQ,UAAU,YAAY,OAAO,CAAC;AAEvG,MAAI;AACF,UAAM,SAAS,MAAM,cAAc,UAAU,MAAM,SAAS;AAAA,MAC1D;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO,MAAM,yBAAyB,EAAE,MAAM,cAAc,OAAO,cAAc,YAAY,OAAO,WAAW,CAAC;AAEhH,UAAM,SAA0B;AAAA,MAC9B,SAAS,OAAO;AAAA,MAChB,cAAc,OAAO;AAAA,MACrB,YAAY,OAAO;AAAA,IACrB;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO,MAAM,oBAAoB,EAAE,MAAM,OAAO,aAAa,CAAC;AAC9D,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB,SAAS;AAAA,YACT,cAAc;AAAA,YACd,OAAO;AAAA,UACT,GAAG,MAAM,CAAC;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC1GA,SAAS,cAA2B;AAQ7B,IAAM,uBAAN,MAA2B;AAAA,EACxB;AAAA,EACA;AAAA,EACA,YAAqB;AAAA,EAE7B,YAAY,QAAmB;AAC7B,SAAK,SAAS;AACd,SAAK,SAAS,IAAI,OAAO;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,QAAI,KAAK,WAAW;AAClB,aAAO,MAAM,oCAAoC;AACjD;AAAA,IACF;AAEA,WAAO,KAAK,4BAA4B;AAAA,MACtC,MAAM,KAAK,OAAO;AAAA,MAClB,MAAM,KAAK,OAAO,QAAQ;AAAA,MAC1B,UAAU,KAAK,OAAO;AAAA,IACxB,CAAC;AAED,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OACF,GAAG,SAAS,MAAM;AACjB,aAAK,YAAY;AACjB,eAAO,KAAK,8BAA8B;AAAA,UACxC,MAAM,KAAK,OAAO;AAAA,UAClB,UAAU,KAAK,OAAO;AAAA,QACxB,CAAC;AACD,gBAAQ;AAAA,MACV,CAAC,EACA,GAAG,SAAS,CAAC,QAAQ;AACpB,eAAO,MAAM,yBAAyB;AAAA,UACpC,MAAM,KAAK,OAAO;AAAA,UAClB,OAAO,IAAI;AAAA,QACb,CAAC;AACD,eAAO,GAAG;AAAA,MACZ,CAAC,EACA,QAAQ;AAAA,QACP,MAAM,KAAK,OAAO;AAAA,QAClB,MAAM,KAAK,OAAO,QAAQ;AAAA,QAC1B,UAAU,KAAK,OAAO;AAAA,QACtB,YAAY,KAAK,OAAO;AAAA,MAC1B,CAAC;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,SAAkC;AAC3C,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,KAAK,QAAQ;AAAA,IACrB;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,KAAK,SAAS,CAAC,KAAK,WAAW;AACzC,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAEA,YAAI,SAAS;AACb,YAAI,SAAS;AAEb,eACG,GAAG,SAAS,CAAC,SAAiB;AAC7B,cAAI,SAAS,GAAG;AACd,mBAAO,IAAI,MAAM,4BAA4B,IAAI,KAAK,MAAM,EAAE,CAAC;AAAA,UACjE,OAAO;AACL,oBAAQ,MAAM;AAAA,UAChB;AAAA,QACF,CAAC,EACA,GAAG,QAAQ,CAAC,SAAiB;AAC5B,oBAAU,KAAK,SAAS;AAAA,QAC1B,CAAC,EACA,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACnC,oBAAU,KAAK,SAAS;AAAA,QAC1B,CAAC;AAAA,MACL,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACJ,SACA,iBAAyB,IACyD;AAClF,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,KAAK,QAAQ;AAAA,IACrB;AAEA,UAAM,YAAY,KAAK,IAAI;AAC3B,WAAO,WAAW,SAAS,QAAW,cAAc;AAEpD,UAAM,cAAc,IAAI,QAA8D,CAAC,SAAS,WAAW;AACzG,WAAK,OAAO,KAAK,SAAS,CAAC,KAAK,WAAW;AACzC,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAEA,YAAI,SAAS;AACb,YAAI,SAAS;AAEb,eACG,GAAG,SAAS,CAAC,SAAiB;AAC7B,gBAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,iBAAO,iBAAiB,MAAM,UAAU,OAAO,QAAQ,OAAO,MAAM;AACpE,kBAAQ,EAAE,QAAQ,QAAQ,UAAU,KAAK,CAAC;AAAA,QAC5C,CAAC,EACA,GAAG,QAAQ,CAAC,SAAiB;AAC5B,oBAAU,KAAK,SAAS;AAAA,QAC1B,CAAC,EACA,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACnC,oBAAU,KAAK,SAAS;AAAA,QAC1B,CAAC;AAAA,MACL,CAAC;AAAA,IACH,CAAC;AAED,UAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,iBAAW,MAAM;AACf,eAAO,IAAI,MAAM,6BAA6B,CAAC;AAAA,MACjD,GAAG,iBAAiB,GAAI;AAAA,IAC1B,CAAC;AAED,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,KAAK,CAAC,aAAa,cAAc,CAAC;AAC/D,aAAO,EAAE,GAAG,QAAQ,UAAU,MAAM;AAAA,IACtC,SAAS,OAAO;AACd,UAAI,iBAAiB,SAAS,MAAM,YAAY,+BAA+B;AAC7E,eAAO,KAAK,yBAAyB,EAAE,SAAS,SAAS,eAAe,CAAC;AACzE,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,UAAU;AAAA,QACZ;AAAA,MACF;AACA,aAAO,MAAM,gCAAgC;AAAA,QAC3C;AAAA,QACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAgC;AACpC,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,KAAK,QAAQ;AAAA,IACrB;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,KAAK,CAAC,KAAK,SAAS;AAC9B,YAAI,KAAK;AACP,iBAAO,GAAG;AAAA,QACZ,OAAO;AACL,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,MAAsE;AACpF,UAAM,OAAO,MAAM,KAAK,QAAQ;AAEhC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,QAAQ,MAAM,CAAC,KAAK,SAAS;AAChC,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAEA,cAAM,QAAQ,KAAK,IAAI,CAAC,UAAU;AAAA,UAChC,MAAM,KAAK;AAAA,UACX,aAAa,KAAK,MAAM,YAAY;AAAA,QACtC,EAAE;AAEF,gBAAQ,KAAK;AAAA,MACf,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SACJ,MACA,WAAmB,SACnB,UAAkB,SAC4C;AAC9D,UAAM,YAAY,KAAK,IAAI;AAC3B,WAAO,cAAc,QAAQ,MAAM,EAAE,UAAU,QAAQ,CAAC;AAExD,UAAM,OAAO,MAAM,KAAK,QAAQ;AAEhC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,WAAK,KAAK,MAAM,CAAC,KAAK,UAAU;AAC9B,YAAI,KAAK;AACP,iBAAO,MAAM,oBAAoB,EAAE,MAAM,OAAO,IAAI,QAAQ,CAAC;AAC7D,iBAAO,IAAI,MAAM,mCAAmC,IAAI,EAAE,CAAC;AAC3D;AAAA,QACF;AAEA,eAAO,MAAM,uBAAuB,EAAE,MAAM,MAAM,MAAM,KAAK,CAAC;AAE9D,YAAI,MAAM,OAAO,SAAS;AACxB,iBAAO,KAAK,kBAAkB,EAAE,MAAM,MAAM,MAAM,MAAM,QAAQ,CAAC;AACjE,iBAAO,IAAI,MAAM,mBAAmB,MAAM,IAAI,gBAAgB,OAAO,SAAS,CAAC;AAC/E;AAAA,QACF;AAGA,aAAK,SAAS,MAAM,EAAE,SAAqC,GAAG,CAACA,MAAK,SAAS;AAC3E,cAAIA,MAAK;AACP,mBAAO,MAAM,oBAAoB,EAAE,MAAM,OAAOA,KAAI,QAAQ,CAAC;AAC7D,mBAAO,IAAI,MAAM,wBAAwBA,KAAI,OAAO,EAAE,CAAC;AACvD;AAAA,UACF;AAEA,gBAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,iBAAO,MAAM,uBAAuB,EAAE,MAAM,MAAM,MAAM,MAAM,UAAU,GAAG,QAAQ,KAAK,CAAC;AAEzF,kBAAQ;AAAA,YACN,SAAS,KAAK,SAAS;AAAA,YACvB,MAAM,MAAM;AAAA,YACZ;AAAA,UACF,CAAC;AAAA,QACH,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UACJ,MACA,SACA,UAII,CAAC,GACqE;AAC1E,UAAM,EAAE,WAAW,SAAS,aAAa,OAAO,SAAS,MAAM,IAAI;AACnE,UAAM,YAAY,KAAK,IAAI;AAE3B,WAAO,cAAc,SAAS,MAAM;AAAA,MAClC,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,OAAO,MAAM,KAAK,QAAQ;AAEhC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,iBAAiB,MAAM;AAE3B,YAAI,QAAQ;AACV,gBAAM,aAAa,GAAG,IAAI;AAC1B,eAAK,OAAO,MAAM,YAAY,CAAC,QAAQ;AACrC,gBAAI,OAAO,IAAI,YAAY,gBAAgB;AAEzC,qBAAO,IAAI,MAAM,4BAA4B,IAAI,OAAO,EAAE,CAAC;AAC3D;AAAA,YACF;AAGA,yBAAa,UAAU;AAAA,UACzB,CAAC;AAAA,QACH,OAAO;AACL,uBAAa;AAAA,QACf;AAAA,MACF;AAEA,YAAM,eAAe,CAAC,eAAwB;AAC5C,cAAM,SAAS,OAAO,KAAK,SAAS,QAA0B;AAC9D,cAAM,WAAW,GAAG,IAAI;AAGxB,aAAK,UAAU,UAAU,QAAQ,CAAC,QAAQ;AACxC,cAAI,KAAK;AACP,mBAAO,IAAI,MAAM,yBAAyB,IAAI,OAAO,EAAE,CAAC;AACxD;AAAA,UACF;AAGA,eAAK,OAAO,UAAU,MAAM,CAACA,SAAQ;AACnC,gBAAIA,MAAK;AACP,qBAAO,MAAM,sBAAsB,EAAE,UAAU,MAAM,OAAOA,KAAI,QAAQ,CAAC;AACzE,qBAAO,IAAI,MAAM,+BAA+BA,KAAI,OAAO,EAAE,CAAC;AAC9D;AAAA,YACF;AAEA,kBAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,mBAAO,MAAM,wBAAwB;AAAA,cACnC;AAAA,cACA,cAAc,OAAO;AAAA,cACrB,UAAU,GAAG,QAAQ;AAAA,cACrB;AAAA,YACF,CAAC;AAED,oBAAQ;AAAA,cACN,SAAS;AAAA,cACT,cAAc,OAAO;AAAA,cACrB;AAAA,YACF,CAAC;AAAA,UACH,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAGA,UAAI,YAAY;AACd,cAAM,UAAU,KAAK,UAAU,GAAG,KAAK,YAAY,GAAG,CAAC;AACvD,aAAK,KAAK,YAAY,OAAO,EAAE,EAAE,KAAK,MAAM;AAC1C,yBAAe;AAAA,QACjB,CAAC,EAAE,MAAM,MAAM;AAAA,MACjB,OAAO;AACL,uBAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,QAAI,KAAK,WAAW;AAClB,aAAO,KAAK,iCAAiC;AAAA,QAC3C,MAAM,KAAK,OAAO;AAAA,QAClB,UAAU,KAAK,OAAO;AAAA,MACxB,CAAC;AACD,WAAK,OAAO,IAAI;AAChB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AACF;;;ANzVA,eAAsB,aAAa,cAA6C;AAC9E,SAAO,KAAK,4BAA4B,EAAE,QAAQ,aAAa,OAAO,CAAC;AACvE,SAAO,MAAM,qBAAqB;AAAA,IAChC,MAAM,aAAa,IAAI;AAAA,IACvB,MAAM,aAAa,IAAI;AAAA,IACvB,UAAU,aAAa,IAAI;AAAA,EAC7B,CAAC;AAGD,QAAM,gBAAgB,IAAI,qBAAqB,aAAa,GAAG;AAG/D,QAAM,cAAc,QAAQ;AAE5B,SAAO,KAAK,+BAA+B,EAAE,QAAQ,aAAa,OAAO,CAAC;AAE1E,QAAM,SAAS,IAAI;AAAA,IACjB;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,cAAc;AAAA,QACZ,OAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,SAAO,kBAAkB,wBAAwB,YAAY;AAC3D,WAAO,MAAM,4BAA4B,EAAE,QAAQ,aAAa,OAAO,CAAC;AACxE,UAAM,QAAQ,CAAC,wBAAwB,6BAA6B,uBAAuB,sBAAsB;AACjH,WAAO,MAAM,aAAa,MAAM,MAAM,UAAU,EAAE,OAAO,MAAM,IAAI,OAAK,EAAE,IAAI,GAAG,QAAQ,aAAa,OAAO,CAAC;AAC9G,WAAO,EAAE,MAAM;AAAA,EACjB,CAAC;AAED,SAAO,kBAAkB,uBAAuB,OAAO,YAAY;AACjE,UAAM,YAAY,KAAK,IAAI;AAC3B,WAAO,YAAY,QAAQ,OAAO,MAAM,QAAQ,OAAO,WAAW,aAAa,MAAM;AAErF,QAAI;AACF,UAAI;AAEJ,UAAI,QAAQ,OAAO,SAAS,yBAAyB;AAEnD,iBAAS,MAAM,yBAAyB,QAAQ,OAAO,WAAW,aAAa;AAAA,MACjF,WAAW,QAAQ,OAAO,SAAS,8BAA8B;AAC/D,iBAAS,MAAM,8BAA8B,QAAQ,OAAO,WAAW,aAAa;AAAA,MACtF,WAAW,QAAQ,OAAO,SAAS,wBAAwB;AACzD,iBAAS,MAAM,wBAAwB,QAAQ,OAAO,WAAW,aAAa;AAAA,MAChF,WAAW,QAAQ,OAAO,SAAS,yBAAyB;AAC1D,iBAAS,MAAM,yBAAyB,QAAQ,OAAO,WAAW,aAAa;AAAA,MACjF,OAAO;AACL,cAAM,IAAI,MAAM,iBAAiB,QAAQ,OAAO,IAAI,EAAE;AAAA,MACxD;AAEA,YAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,YAAM,aAAa,KAAK,UAAU,MAAM,EAAE;AAC1C,aAAO,cAAc,QAAQ,OAAO,MAAM,UAAU,UAAU;AAE9D,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO,WAAW,QAAQ,OAAO,MAAM,OAAgB,QAAQ,OAAO,SAAS;AAC/E,YAAM;AAAA,IACR;AAAA,EACF,CAAC;AAGD,UAAQ,GAAG,UAAU,MAAM;AACzB,WAAO,KAAK,kCAAkC,EAAE,QAAQ,aAAa,OAAO,CAAC;AAC7E,kBAAc,WAAW;AACzB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,UAAQ,GAAG,WAAW,MAAM;AAC1B,WAAO,KAAK,mCAAmC,EAAE,QAAQ,aAAa,OAAO,CAAC;AAC9E,kBAAc,WAAW;AACzB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,SAAO;AACT;",
6
6
  "names": ["err"]
7
7
  }