@flemist/mcp-project-tools 1.0.2 → 1.0.3

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/build/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Command } from "commander";
2
- import { S as SERVER_VERSION, s as startMcpServer, a as SERVER_NAME, A as AUTH_TOKEN } from "./startMcpServer-B-xjEzCx.js";
2
+ import { S as SERVER_VERSION, s as startMcpServer, a as SERVER_NAME, A as AUTH_TOKEN } from "./startMcpServer-CN6Th9Zn.js";
3
3
  import * as path from "path";
4
4
  const program = new Command();
5
5
  program.name("mcp-project-tools").description("MCP project tools server").version(SERVER_VERSION);
package/build/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { s } from "./startMcpServer-B-xjEzCx.js";
1
+ import { s } from "./startMcpServer-CN6Th9Zn.js";
2
2
  export {
3
3
  s as startMcpServer
4
4
  };
@@ -763,10 +763,13 @@ function _walkPaths(options) {
763
763
  abortSignal: abortSignalCombined
764
764
  });
765
765
  }
766
- async function processItem(itemPath, index, matchResult) {
766
+ async function processItem(resolvedItemPath, index, matchResult, originalItemPath) {
767
+ if (!originalItemPath) {
768
+ originalItemPath = resolvedItemPath;
769
+ }
767
770
  const stat = await poolRunWait({
768
771
  pool,
769
- func: () => fs__default.promises.lstat(itemPath).catch(_handleError),
772
+ func: () => fs__default.promises.lstat(resolvedItemPath).catch(_handleError),
770
773
  count: 1,
771
774
  priority: priorityCreate(index, priorityCreate(1, priority)),
772
775
  abortSignal: abortSignalCombined
@@ -777,7 +780,7 @@ function _walkPaths(options) {
777
780
  if (!matchResult && stat.isFile()) {
778
781
  return null;
779
782
  }
780
- const itemId = getFileId(itemPath, stat);
783
+ const itemId = getFileId(resolvedItemPath, stat);
781
784
  if (walkedIds.has(itemId)) {
782
785
  return null;
783
786
  }
@@ -797,13 +800,14 @@ function _walkPaths(options) {
797
800
  if (walkLinks) {
798
801
  const link = await poolRunWait({
799
802
  pool,
800
- func: () => fs__default.promises.readlink(itemPath).catch(_handleError).then((link2) => link2 ?? null),
803
+ func: () => fs__default.promises.readlink(resolvedItemPath).catch(_handleError).then((link2) => link2 ?? null),
801
804
  count: 1,
802
805
  priority: _priority,
803
806
  abortSignal: abortSignalCombined
804
807
  });
805
808
  if (link) {
806
- const linkedItemStat = await processItem(link, index, matchResult);
809
+ const resolvedLink = path.isAbsolute(link) ? link : path.resolve(path.dirname(originalItemPath), link);
810
+ const linkedItemStat = await processItem(resolvedLink, index, matchResult, originalItemPath);
807
811
  if (linkedItemStat) {
808
812
  itemStat = linkedItemStat;
809
813
  }
@@ -812,28 +816,28 @@ function _walkPaths(options) {
812
816
  itemStat.countLinks = 1;
813
817
  if (matchResult || itemStat.countFiles + itemStat.countDirs + itemStat.countLinks > 1) {
814
818
  const shouldInclude = await _handlePath(
815
- itemPath,
819
+ originalItemPath,
816
820
  stat,
817
821
  itemStat,
818
822
  _priority
819
823
  );
820
824
  if (shouldInclude) {
821
825
  addStats(totalStat, itemStat);
822
- logItem(itemPath, itemStat);
826
+ logItem(originalItemPath, itemStat);
823
827
  }
824
828
  }
825
829
  return itemStat;
826
830
  } else if (stat.isDirectory()) {
827
831
  const dirItems = await poolRunWait({
828
832
  pool,
829
- func: () => fs__default.promises.readdir(itemPath).catch(_handleError),
833
+ func: () => fs__default.promises.readdir(resolvedItemPath).catch(_handleError),
830
834
  count: 1,
831
835
  priority,
832
836
  abortSignal: abortSignalCombined
833
837
  });
834
838
  if (dirItems) {
835
839
  for (let i = 0, len = dirItems.length; i < len; i++) {
836
- dirItems[i] = path.join(itemPath, dirItems[i]);
840
+ dirItems[i] = path.join(originalItemPath, dirItems[i]);
837
841
  }
838
842
  itemStat = await _walkPaths({
839
843
  ...options,
@@ -850,14 +854,14 @@ function _walkPaths(options) {
850
854
  }
851
855
  if (matchResult || itemStat.countFiles + itemStat.countDirs + itemStat.countLinks > 1) {
852
856
  const shouldInclude = await _handlePath(
853
- itemPath,
857
+ originalItemPath,
854
858
  stat,
855
859
  itemStat,
856
860
  _priority
857
861
  );
858
862
  if (shouldInclude) {
859
863
  addStats(totalStat, itemStat);
860
- logItem(itemPath, itemStat);
864
+ logItem(originalItemPath, itemStat);
861
865
  }
862
866
  }
863
867
  return itemStat;
@@ -1689,4 +1693,4 @@ export {
1689
1693
  SERVER_NAME as a,
1690
1694
  startMcpServer as s
1691
1695
  };
1692
- //# sourceMappingURL=startMcpServer-B-xjEzCx.js.map
1696
+ //# sourceMappingURL=startMcpServer-CN6Th9Zn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startMcpServer-CN6Th9Zn.js","sources":["../src/server/createAuthMiddleware.ts","../src/helpers/logToFile.ts","../src/server/transport/streamable-http/StreamableHttpHandler.ts","../src/tools/process/helpers/extractCommand.ts","../src/tools/process/common.ts","../src/tools/process/helpers/cleanupOldProcesses.ts","../src/tools/process/helpers/updateProcessOutput.ts","../src/helpers/cropText.ts","../src/tools/process/methods/status.ts","../src/helpers/killProcessById.ts","../src/tools/process/methods/wait.ts","../src/tools/process/methods/run.ts","../src/tools/process/methods/list.ts","../src/tools/process/methods/kill.ts","../src/tools/process/index.ts","../src/server/createMcpRegisterToolFunc.ts","../src/tools/fs/walkPaths/helpers.ts","../src/tools/fs/pools.ts","../src/tools/fs/walkPaths/walkPaths.ts","../src/tools/fs/globToRelative.ts","../src/tools/fs/globGitIgnoreToPicomatch.ts","../src/tools/fs/loadGlobs.ts","../src/tools/fs/walkPaths/createMatchPath.ts","../src/tools/fs/getPathList.ts","../src/tools/fs/pathListToString.ts","../src/config/constants.ts","../src/tools/fs/methods/list.ts","../src/tools/fs/index.ts","../src/server/createErrorMiddleware.ts","../src/server/startMcpServer.ts"],"sourcesContent":["import { NextFunction, Request, Response } from 'express'\n\nexport interface CreateAuthMiddlewareOptions {\n authToken: string\n}\n\n/**\n * Token validation middleware\n */\nexport function createAuthMiddleware(options: CreateAuthMiddlewareOptions) {\n const { authToken } = options\n return function authMiddleware(\n req: Request,\n res: Response,\n next: NextFunction,\n ): void {\n const token =\n (req.query.token as string) ||\n req.headers.authorization?.replace('Bearer ', '')\n\n if (token !== authToken) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n next()\n }\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\n\nexport interface LogOptions {\n logFilePath: string\n message: string\n data: any\n}\n\nexport async function logToFile(options: LogOptions): Promise<void> {\n const { logFilePath, message, data } = options\n try {\n const timestamp = new Date().toISOString().replace(/[TZ]/g, ' ').trim()\n const dataStr =\n typeof data === 'string' ? data : JSON.stringify(data, null, 2)\n const logData = `[${timestamp}] ${message}\\n${dataStr}\\n\\n`\n await fs.promises.mkdir(path.dirname(logFilePath), { recursive: true })\n await fs.promises.appendFile(logFilePath, logData)\n } catch (err) {\n console.error(`Failed to log \"${message}\":`, err)\n }\n}\n","import { randomBytes } from 'crypto'\nimport { Request, Response } from 'express'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'\nimport { logToFile } from 'src/helpers/logToFile'\n\nexport type StreamableHttpHandlerOptions = {\n logFilePath: string\n enableJsonResponse?: boolean | null\n}\n\n/**\n * HTTP session storage (old name: streamableTransports)\n * WHY: Stores active HTTP transport sessions for session management and reuse\n */\nexport const sessionsTransports = new Map<\n string,\n StreamableHTTPServerTransport\n>()\n\n/**\n * MCP over HTTP handler\n * WHY: Handles MCP protocol over HTTP transport, creates and manages HTTP sessions\n */\nexport function createStreamableHttpHandler(\n mcpServer: McpServer,\n options: StreamableHttpHandlerOptions,\n) {\n return async function streamableHttpHandler(\n req: Request,\n res: Response,\n ): Promise<void> {\n const sessionId =\n (req.headers['mcp-session-id'] as string) ||\n (req.headers['x-session-id'] as string) ||\n (req.query.token as string) // Use token as fallback session ID\n let transport: StreamableHTTPServerTransport\n\n if (req.method === 'POST') {\n await logToFile({\n logFilePath: options.logFilePath,\n message: 'REQUEST',\n data: req.body,\n })\n\n if (sessionId && sessionsTransports.has(sessionId)) {\n transport = sessionsTransports.get(sessionId)!\n } else {\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () =>\n sessionId || randomBytes(16).toString('hex'),\n onsessioninitialized: (id: string) => {\n sessionsTransports.set(id, transport)\n console.log(`Session initialized: ${id}`)\n },\n enableJsonResponse: options.enableJsonResponse || false,\n })\n\n transport.onclose = () => {\n if (transport.sessionId) {\n sessionsTransports.delete(transport.sessionId)\n console.log(`Session closed: ${transport.sessionId}`)\n }\n }\n\n await mcpServer.connect(transport)\n\n // Store the transport immediately using the session ID\n if (sessionId) {\n sessionsTransports.set(sessionId, transport)\n }\n }\n\n const response = await transport.handleRequest(req, res, req.body)\n } else if (req.method === 'GET') {\n if (sessionId && sessionsTransports.has(sessionId)) {\n transport = sessionsTransports.get(sessionId)!\n await transport.handleRequest(req, res)\n } else {\n res.status(400).json({ error: 'No valid session' })\n }\n } else {\n res.status(405).json({ error: 'Method not allowed' })\n }\n }\n}\n","export interface ExtractCommandOptions {\n commandLine: string\n}\n\n/**\n * Parse command from command line\n * WHY: Extracts base command from command line for security validation\n */\nexport function extractCommand(options: ExtractCommandOptions): string {\n const { commandLine } = options\n // Extract command from command line considering quotes\n const match = commandLine.match(/^\"([^\"]+)\"|^(\\S+)/)\n return match ? match[1] || match[2] : commandLine.split(' ')[0]\n}\n","import type { ProcessInfo } from './types'\nimport { extractCommand } from './helpers/extractCommand'\nimport treeKill from 'tree-kill'\n\n/**\n * All process tracking data\n * WHY: Central storage for all active and completed processes\n */\nexport const processes = new Map<number, ProcessInfo>()\n\n/**\n * Incremental ID generator (old name: processCounter)\n * WHY: Generates unique process IDs for tracking\n */\nexport let nextProcessId = 0\n\n/**\n * Limit concurrent processes constant\n * WHY: Prevents resource exhaustion by limiting concurrent processes\n */\nexport const MAX_PROCESSES = 10\n\n/**\n * 30min cleanup interval constant\n * WHY: Defines when to remove completed processes from memory\n */\nexport const PROCESS_CLEANUP_TIME = 30 * 60 * 1000 // 30 minutes\n\n/**\n * 2000 char limit constant\n * WHY: Prevents memory issues from excessive process output\n */\nexport const OUTPUT_LIMIT = 2000\n\n/**\n * 500ms throttle constant\n * WHY: Reduces CPU usage by throttling output updates\n */\nexport const OUTPUT_THROTTLE_TIME = 500\n\n/**\n * 5s wait between signals constant\n * WHY: Gives processes time to gracefully exit before force kill\n */\nexport const KILL_TIMEOUT = 5000\n\nexport interface IsCommandAllowedOptions {\n commandLine: string\n allowedCommands: string[]\n}\n\n/**\n * Validate against whitelist\n * WHY: Security function to prevent execution of unauthorized commands\n */\nexport function isCommandAllowed(options: IsCommandAllowedOptions): boolean {\n const { commandLine, allowedCommands } = options\n const command = extractCommand({ commandLine })\n return allowedCommands.some(\n allowed =>\n command === allowed || command.toLowerCase() === allowed.toLowerCase(),\n )\n}\n\n/**\n * Increment process ID counter\n * WHY: Provides thread-safe way to get next unique process ID\n */\nexport function getNextProcessId(): number {\n return ++nextProcessId\n}\n\nlet autoKillInitialized = false\n\nexport function autoKillChildProcesses(): void {\n if (autoKillInitialized) {\n return\n }\n autoKillInitialized = true\n\n const kill = (): void => {\n console.log('Auto-killing all child processes...')\n\n for (const [id, process] of Array.from(processes.entries())) {\n if (process.isRunning && process.pid) {\n try {\n treeKill(process.pid, 'SIGKILL')\n } catch (err) {\n console.error(`Error killing process ${id}:`, err)\n }\n }\n }\n\n process.exit(0)\n }\n\n process.on('SIGINT', kill)\n process.on('SIGTERM', kill)\n}\n","import { processes, PROCESS_CLEANUP_TIME } from '../common'\n\n/**\n * Remove old completed processes\n * WHY: Prevents memory leaks by removing old process data\n */\nexport function cleanupOldProcesses(): void {\n const now = Date.now()\n const toRemove: number[] = []\n\n for (const [id, process] of Array.from(processes.entries())) {\n if (!process.isRunning && process.endTime) {\n const timeSinceEnd = now - process.endTime.getTime()\n if (timeSinceEnd > PROCESS_CLEANUP_TIME) {\n toRemove.push(id)\n }\n }\n }\n\n for (const id of toRemove) {\n processes.delete(id)\n }\n}\n","import type { ProcessInfo } from '../types'\nimport { OUTPUT_THROTTLE_TIME, OUTPUT_LIMIT } from '../common'\n\nexport interface UpdateProcessOutputOptions {\n process: ProcessInfo\n}\n\n/**\n * Throttle output updates\n * WHY: Manages process output buffering and throttling to prevent performance issues\n */\nexport function updateProcessOutput(options: UpdateProcessOutputOptions): void {\n const { process } = options\n const now = Date.now()\n const timeSinceLastUpdate = now - process.lastOutputTime.getTime()\n\n if (timeSinceLastUpdate >= OUTPUT_THROTTLE_TIME) {\n process.output += process.localOutput\n process.localOutput = ''\n process.lastOutputTime = new Date(now)\n\n // Trim output if it exceeds limit\n if (process.output.length > OUTPUT_LIMIT) {\n const removed = process.output.length - OUTPUT_LIMIT\n const trimMessage = `\\n... [${removed} characters trimmed] ...\\n`\n const availableSpace = OUTPUT_LIMIT - trimMessage.length\n\n if (availableSpace > 0) {\n const half = Math.floor(availableSpace / 2)\n process.output =\n process.output.substring(0, half) +\n trimMessage +\n process.output.substring(\n process.output.length - (availableSpace - half),\n )\n } else {\n process.output = process.output.substring(0, OUTPUT_LIMIT)\n }\n }\n }\n}\n","export interface CropTextOptions {\n limit: number\n}\n\n/** Crops text to a specified limit by removing extra text from the middle */\nexport function cropText(text: string, options: CropTextOptions): string {\n const limit = options.limit - 35 // 35 - is trim message length\n if (text.length <= limit) return text\n\n const removedLength = text.length - limit\n const trimMessage = `\\n... [${removedLength} characters trimmed] ...\\n`\n const availableLength = limit - trimMessage.length\n\n if (availableLength <= 0) {\n return text.substring(0, limit)\n }\n\n const half = Math.floor(availableLength / 2)\n return (\n text.substring(0, half) +\n trimMessage +\n text.substring(text.length - (availableLength - half))\n )\n}\n","import { z } from 'zod'\nimport { OUTPUT_LIMIT, processes } from '../common'\nimport { cleanupOldProcesses } from '../helpers/cleanupOldProcesses'\nimport { updateProcessOutput } from '../helpers/updateProcessOutput'\nimport { cropText } from 'src/helpers/cropText'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\n/**\n * Get process status and latest output requests\n */\nexport const StatusSchema = z.object({\n id: z\n .number()\n .describe(\n 'Process ID to get detailed status information for. Get process IDs using process-list. Works for both running and completed processes. Examples: 1, 42, 123.',\n ),\n outputLimit: z\n .number()\n .max(OUTPUT_LIMIT)\n .default(OUTPUT_LIMIT)\n .describe(\n `Maximum number of output characters to return from the process. Output exceeding this limit will be cropped with beginning/end preserved. Maximum: ${OUTPUT_LIMIT} characters. Default: ${OUTPUT_LIMIT}.`,\n ),\n})\n\nexport type ProcessManagerStatusOptions = {\n workingDir?: string | null\n}\n\n/**\n * Get process status and latest output\n */\nexport async function commandStatus(\n args: z.infer<typeof StatusSchema>,\n options: ProcessManagerStatusOptions,\n): Promise<Record<string, any>> {\n cleanupOldProcesses()\n\n const parsedArgs = StatusSchema.parse(args)\n const { id, outputLimit } = parsedArgs\n const process = processes.get(id)\n\n if (!process) {\n return {\n error: `Process ${id} not found. The process may have already completed and been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`,\n }\n }\n\n updateProcessOutput({ process })\n\n const fullOutput = process.output + process.localOutput\n const formattedOutput = cropText(fullOutput, { limit: outputLimit })\n\n // Clear output after retrieval to avoid duplication\n process.output = ''\n process.localOutput = ''\n\n return {\n id: process.id,\n cwd: path.relative(options.workingDir || '', process.cwd),\n commandLine: process.commandLine,\n pid: process.pid,\n startTime: process.startTime.toISOString().replace(/[TZ]/g, ' ').trim(),\n endTime: process.endTime?.toISOString().replace(/[TZ]/g, ' ').trim(),\n exitCode: process.exitCode,\n isRunning: process.isRunning,\n output: formattedOutput,\n error: process.error,\n }\n}\n\nexport function mcpRegisterToolProcessStatus(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerStatusOptions,\n): void {\n mcpRegisterTool(\n 'process-status',\n {\n title: 'Get Host Machine Process Status',\n description:\n 'Get detailed status information about a process on the host machine, including execution details, captured output, exit code, and runtime status. Returns comprehensive process information for both running and completed processes. The output is cleared after retrieval to prevent duplication in subsequent calls. Useful for checking command execution results and monitoring process progress.',\n inputSchema: StatusSchema.shape,\n },\n async args => {\n const result = await commandStatus(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-status(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import treeKill from 'tree-kill'\nimport { KILL_TIMEOUT } from 'src/tools/process/common'\n\n/** Safe kill process by ID */\nexport function killProcessById(pid: number): void {\n // First try soft kill\n treeKill(pid, 'SIGTERM', (err?: Error) => {\n if (err && !err.message.includes('not found')) {\n console.error(`Error sending SIGTERM to process ${pid}:`, err)\n }\n })\n\n // Force kill after timeout\n setTimeout(() => {\n treeKill(pid, 'SIGKILL', (err?: Error) => {\n if (err && !err.message.includes('not found')) {\n console.error(`Error sending SIGKILL to process ${pid}:`, err)\n }\n })\n }, KILL_TIMEOUT)\n}\n","import { z } from 'zod'\nimport { OUTPUT_LIMIT, processes } from '../common'\nimport { commandStatus } from './status'\nimport { killProcessById } from 'src/helpers/killProcessById'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\n\n/**\n * Wait for process completion with timeout operation requests\n */\nexport const WaitSchema = z.object({\n id: z\n .number()\n .describe(\n 'Process ID to wait for completion. Get process IDs using process-list. The process can be running or already completed. Examples: 1, 42, 123.',\n ),\n waitTime: z\n .number()\n .optional()\n .describe(\n 'Maximum time to wait in seconds for process completion. If omitted, waits indefinitely until process completes. If process is already completed, returns immediately. Examples: 30 (wait up to 30 seconds), 300 (wait up to 5 minutes).',\n ),\n autoKill: z\n .boolean()\n .default(false)\n .describe(\n 'Automatically terminate the process if waitTime expires and it is still running. Only applies when waitTime is specified. Default: false (let process continue running after timeout). Set to true for processes that should not run indefinitely.',\n ),\n outputLimit: z\n .number()\n .max(OUTPUT_LIMIT)\n .default(OUTPUT_LIMIT)\n .describe(\n `Maximum number of output characters to capture and return from the process. Output exceeding this limit will be trimmed. Maximum: ${OUTPUT_LIMIT} characters. Default: ${OUTPUT_LIMIT}.`,\n ),\n})\n\nexport type ProcessManagerWaitOptions = {\n workingDir?: string | null\n}\n\n/**\n * Wait for process completion with timeout\n */\nexport async function commandWait(\n args: z.infer<typeof WaitSchema>,\n options: ProcessManagerWaitOptions,\n): Promise<Record<string, any>> {\n const parsedArgs = WaitSchema.parse(args)\n const { id, waitTime, autoKill, outputLimit } = parsedArgs\n const process = processes.get(id)\n\n if (!process) {\n return {\n error: `Process ${id} not found. The process may have already completed and been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`,\n }\n }\n\n const startWait = Date.now()\n let waitTimeExceeded = false\n let autoKillExecuted = false\n\n if (waitTime !== undefined) {\n const waitPromise = new Promise<void>(resolve => {\n const checkInterval = setInterval(() => {\n if (!process.isRunning) {\n clearInterval(checkInterval)\n resolve()\n } else if (Date.now() - startWait >= waitTime * 1000) {\n clearInterval(checkInterval)\n waitTimeExceeded = true\n\n if (autoKill && process.pid) {\n killProcessById(process.pid)\n autoKillExecuted = true\n }\n\n resolve()\n }\n }, 100)\n })\n\n await waitPromise\n }\n\n const waitDuration = (Date.now() - startWait) / 1000\n const status = await commandStatus(\n { id, outputLimit },\n { workingDir: options.workingDir },\n )\n\n return {\n ...status,\n waitDuration,\n waitTimeExceeded,\n autoKillExecuted,\n }\n}\n\nexport function mcpRegisterToolProcessWait(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerWaitOptions,\n): void {\n mcpRegisterTool(\n 'process-wait',\n {\n title: 'Wait for Host Machine Process',\n description:\n 'Wait for a host machine process to complete execution, with optional timeout and auto-kill functionality. Useful for long-running commands like builds, installs, or tests where you need to wait for completion. Returns the final process status along with wait duration and timeout information. Can automatically terminate processes that exceed the wait time limit.',\n inputSchema: WaitSchema.shape,\n },\n async args => {\n const result = await commandWait(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-wait(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import { spawn } from 'child_process'\nimport { z } from 'zod'\nimport type { ProcessInfo } from '../types'\nimport {\n getNextProcessId,\n isCommandAllowed,\n MAX_PROCESSES,\n OUTPUT_LIMIT,\n processes,\n} from '../common'\nimport { cleanupOldProcesses } from '../helpers/cleanupOldProcesses'\nimport { updateProcessOutput } from '../helpers/updateProcessOutput'\nimport { extractCommand } from '../helpers/extractCommand'\nimport { commandWait } from './wait'\nimport { commandStatus } from './status'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\n/**\n * Validates command execution requests\n * WHY: Ensures command execution requests have valid parameters\n */\nexport const RunSchema = z.object({\n cwd: z\n .string()\n .optional()\n .describe(\n 'Working directory for command execution, resolved relative to the current working directory. Leave empty to use current directory. Examples: \"src\" (run in src/ subdirectory), \"../parent\" (run in parent directory), \"build/output\" (run in nested subdirectory). Directory must exist.',\n ),\n commandLine: z\n .string()\n .describe(\n 'Complete command line to execute on the host machine. Include all arguments and options. Examples: \"npm install\", \"pnpm build\", \"node script.js --verbose\", \"git status\". Command must be in the allowed commands list for security.',\n ),\n waitTime: z\n .number()\n .optional()\n .describe(\n 'Time to wait in seconds for process completion before returning results. If specified, will wait this long then return final status. If omitted, returns immediately with initial status. Use process-wait or process-status to check progress later. Examples: 30 (wait 30 seconds), 120 (wait 2 minutes).',\n ),\n autoKill: z\n .boolean()\n .default(false)\n .describe(\n 'Automatically kill the process if waitTime expires and it is still running. Only applies when waitTime is specified. Default: false (let process continue running). Set to true for commands that should not run indefinitely.',\n ),\n outputLimit: z\n .number()\n .max(OUTPUT_LIMIT)\n .default(OUTPUT_LIMIT)\n .describe(\n `Maximum number of output characters to capture and return from the process. Output exceeding this limit will be trimmed with beginning/end preserved and middle removed. Maximum: ${OUTPUT_LIMIT} characters. Default: ${OUTPUT_LIMIT}.`,\n ),\n})\n\nexport type ProcessManagerRunOptions = {\n workingDir?: string | null\n allowedCommands: string[]\n}\n\n/**\n * Execute commands on host\n */\nexport async function commandRun(\n args: z.infer<typeof RunSchema>,\n options: ProcessManagerRunOptions,\n): Promise<Record<string, any>> {\n cleanupOldProcesses()\n\n const parsedArgs = RunSchema.parse(args)\n const { commandLine, waitTime, autoKill, outputLimit } = parsedArgs\n const { allowedCommands } = options\n\n const cwd = path.resolve(options.workingDir || '', parsedArgs.cwd || '')\n\n if (!isCommandAllowed({ commandLine, allowedCommands })) {\n return {\n error: `Command not allowed: \"${commandLine}\". For security, only whitelisted commands can be executed on the host machine. Allowed commands: ${allowedCommands.join(', ')}. The command \"${extractCommand({ commandLine })}\" is not in the allowed list. To use this command, ask the user to add it to the allowedCommands configuration.`,\n }\n }\n\n const activeProcesses = Array.from(processes.values()).filter(\n o => o.isRunning,\n )\n if (activeProcesses.length >= MAX_PROCESSES) {\n return {\n error: `Maximum concurrent process limit reached (${MAX_PROCESSES} processes). Cannot start new process until existing processes complete. Use process-list to see active processes, or process-kill to terminate unnecessary processes.`,\n }\n }\n\n const id = getNextProcessId()\n const processInfo: ProcessInfo = {\n id,\n cwd,\n commandLine,\n startTime: new Date(),\n isRunning: true,\n output: '',\n localOutput: '',\n lastOutputTime: new Date(),\n }\n\n processes.set(id, processInfo)\n\n try {\n const child = spawn(commandLine, [], {\n shell: true,\n cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n processInfo.pid = child.pid\n\n const handleOutput = (data: Buffer): void => {\n const text = data.toString()\n processInfo.localOutput += text\n updateProcessOutput({ process: processInfo })\n console.log(text)\n }\n\n child.stdout?.on('data', handleOutput)\n child.stderr?.on('data', handleOutput)\n\n child.on('close', code => {\n processInfo.isRunning = false\n processInfo.endTime = new Date()\n processInfo.exitCode = code !== null ? code : undefined\n\n // Final output update\n processInfo.output += processInfo.localOutput\n processInfo.localOutput = ''\n\n if (processInfo.output.length > OUTPUT_LIMIT) {\n const removed = processInfo.output.length - OUTPUT_LIMIT\n const trimMessage = `\\n... [${removed} characters trimmed] ...\\n`\n const availableSpace = OUTPUT_LIMIT - trimMessage.length\n\n if (availableSpace > 0) {\n const half = Math.floor(availableSpace / 2)\n processInfo.output =\n processInfo.output.substring(0, half) +\n trimMessage +\n processInfo.output.substring(\n processInfo.output.length - (availableSpace - half),\n )\n } else {\n processInfo.output = processInfo.output.substring(0, OUTPUT_LIMIT)\n }\n }\n\n console.log(`Process ${id} (${commandLine}) exited with code ${code}`)\n })\n\n child.on('error', err => {\n processInfo.isRunning = false\n processInfo.endTime = new Date()\n processInfo.error = err.message\n console.error(`Process ${id} error:`, err.message)\n })\n\n // Wait if requested\n if (waitTime !== undefined) {\n return commandWait(\n { id, waitTime, autoKill, outputLimit },\n { workingDir: options.workingDir },\n )\n }\n\n return commandStatus(\n { id, outputLimit },\n { workingDir: options.workingDir },\n )\n } catch (err) {\n processInfo.isRunning = false\n processInfo.endTime = new Date()\n processInfo.error = err instanceof Error ? err.message : 'Unknown error'\n return { error: processInfo.error }\n }\n}\n\nexport function mcpRegisterToolProcessRun(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerRunOptions,\n): void {\n mcpRegisterTool(\n 'process-run',\n {\n title: 'Execute Command on Host Machine',\n description: `Execute commands on the host machine. This tool allows running system commands that require host environment access, such as package managers (npm, pnpm, yarn), build tools, git operations, and other system utilities. Commands are executed in shell with full argument support. Returns process status and captured output. If waitTime is specified, waits for completion; otherwise returns immediately and you can check progress with process-wait or process-status. Security: Only whitelisted commands are allowed. Current allowed commands: ${options.allowedCommands.join(', ')}.`,\n inputSchema: RunSchema.shape,\n },\n async args => {\n const result = await commandRun(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-run(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import { z } from 'zod'\nimport { processes } from '../common'\nimport { cleanupOldProcesses } from '../helpers/cleanupOldProcesses'\nimport { updateProcessOutput } from '../helpers/updateProcessOutput'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport path from 'path'\n\n/**\n * Load filtered list of processes requests\n */\nexport const ListSchema = z.object({\n minOpenDateTime: z\n .string()\n .optional()\n .describe(\n 'Filter to processes started after this datetime. Accepts ISO format or space-separated format. Examples: \"2024-01-15T10:30:00Z\", \"2024-01-15 10:30:00\". Underscores and spaces are converted to standard ISO format internally.',\n ),\n minCloseDateTime: z\n .string()\n .optional()\n .describe(\n 'Filter to processes that finished after this datetime. Only applies to completed processes. Accepts ISO format or space-separated format. Examples: \"2024-01-15T14:30:00Z\", \"2024-01-15 14:30:00\". Useful for finding recently completed processes.',\n ),\n activeOnly: z\n .boolean()\n .default(false)\n .describe(\n 'Show only currently running processes. Set to true to exclude completed processes, false to show all processes (running and completed). Default: false (show all).',\n ),\n fields: z\n .array(z.string())\n .optional()\n .describe(\n 'Specific process data fields to include in the response. If omitted, returns all available fields. Available fields: id, cwd, commandLine, pid, startTime, endTime, exitCode, isRunning, output, error. Examples: [\"id\", \"commandLine\", \"isRunning\"] for minimal info, [\"id\", \"output\", \"exitCode\"] for execution results.',\n ),\n})\n\nexport type ProcessManagerListOptions = {\n workingDir?: string | null\n}\n\n/**\n * Load filtered list of processes\n */\nexport async function commandList(\n args: z.infer<typeof ListSchema>,\n options: ProcessManagerListOptions,\n): Promise<Record<string, any>> {\n cleanupOldProcesses()\n\n const parsedArgs = ListSchema.parse(args)\n const { minOpenDateTime, minCloseDateTime, activeOnly, fields } = parsedArgs\n\n let processList = Array.from(processes.values())\n\n if (minOpenDateTime) {\n const minDate = new Date(minOpenDateTime.replace(/[_\\s]/g, 'T'))\n processList = processList.filter(p => p.startTime >= minDate)\n }\n\n if (minCloseDateTime) {\n const minDate = new Date(minCloseDateTime.replace(/[_\\s]/g, 'T'))\n processList = processList.filter(p => p.endTime && p.endTime >= minDate)\n }\n\n if (activeOnly) {\n processList = processList.filter(p => p.isRunning)\n }\n\n const result = processList.map(process => {\n updateProcessOutput({ process })\n\n let processData: Record<string, any> = {\n id: process.id,\n cwd: path.relative(options.workingDir || '', process.cwd),\n commandLine: process.commandLine,\n pid: process.pid,\n startTime: process.startTime.toISOString().replace(/[TZ]/g, ' ').trim(),\n endTime: process.endTime?.toISOString().replace(/[TZ]/g, ' ').trim(),\n exitCode: process.exitCode,\n isRunning: process.isRunning,\n output: process.output + process.localOutput,\n error: process.error,\n }\n\n if (fields) {\n const filtered: Record<string, any> = {}\n for (const field of fields) {\n if (field in processData) {\n filtered[field] = processData[field]\n }\n }\n processData = filtered\n }\n\n return processData\n })\n\n return { processes: result }\n}\n\nexport function mcpRegisterToolProcessList(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerListOptions,\n): void {\n mcpRegisterTool(\n 'process-list',\n {\n title: 'List Host Machine Processes',\n description:\n 'List all processes that have been executed on the host machine with filtering and field selection options. Shows both currently running and completed processes with their execution details, output, and status. Useful for monitoring command execution history, checking active processes, and retrieving results from completed commands. Supports datetime filtering to find processes within specific time ranges.',\n inputSchema: ListSchema.shape,\n },\n async args => {\n const result = await commandList(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-list(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import { z } from 'zod'\nimport { processes } from '../common'\nimport { killProcessById } from 'src/helpers/killProcessById'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\n\n/**\n * Kill process requests\n */\nexport const KillSchema = z.object({\n id: z\n .number()\n .describe(\n 'Process ID of the process to terminate. Get process IDs using process-list. The process must be currently running. Examples: 1, 42, 123.',\n ),\n})\n\n/**\n * Internal kill process with SIGTERM/SIGKILL\n */\nexport function commandKill(\n args: z.infer<typeof KillSchema>,\n): Record<string, any> {\n const parsedArgs = KillSchema.parse(args)\n const { id } = parsedArgs\n const process = processes.get(id)\n\n if (!process) {\n return {\n error: `Process ${id} not found. The process may have already completed, been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`,\n }\n }\n\n if (!process.isRunning) {\n return {\n error: `Process ${id} is not currently running. The process has already completed or was previously terminated. Use process-list to see the process status and process-status to get final execution details.`,\n }\n }\n\n if (!process.pid) {\n return {\n error: `Process ${id} has no system process ID (PID). This indicates the process failed to start properly or the system was unable to assign a PID. Check process-status for error details.`,\n }\n }\n\n try {\n killProcessById(process.pid)\n return { success: true, message: `Kill signal sent to process ${id}` }\n } catch (err) {\n return {\n error: `Failed to terminate process ${id}: ${err instanceof Error ? err.message : 'Unknown error'}. The process may have already exited, be protected by the system, or there may be insufficient permissions. Use process-status to check current process state.`,\n }\n }\n}\n\nexport function mcpRegisterToolProcessKill(\n mcpRegisterTool: McpRegisterToolFunc,\n): void {\n mcpRegisterTool(\n 'process-kill',\n {\n title: 'Kill Host Machine Process',\n description:\n 'Forcibly terminate a running process on the host machine. Sends SIGTERM signal first for graceful shutdown, then SIGKILL after 5 seconds if the process is still running. Use this to stop runaway processes, hung commands, or long-running tasks that need to be cancelled. The process must be currently running to be terminated.',\n inputSchema: KillSchema.shape,\n },\n async args => {\n const result = commandKill(args)\n const output = result.output || ''\n delete result.output\n return `Method: process-kill(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import {\n mcpRegisterToolProcessRun,\n type ProcessManagerRunOptions,\n} from 'src/tools/process/methods/run'\nimport { mcpRegisterToolProcessStatus } from 'src/tools/process/methods/status'\nimport { mcpRegisterToolProcessWait } from 'src/tools/process/methods/wait'\nimport { mcpRegisterToolProcessList } from 'src/tools/process/methods/list'\nimport { mcpRegisterToolProcessKill } from 'src/tools/process/methods/kill'\nimport { autoKillChildProcesses } from 'src/tools/process/common'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\nexport type ProcessManagerOptions = {\n workingDir?: string | null\n run: Omit<ProcessManagerRunOptions, 'workingDir'>\n}\n\nexport function mcpRegisterProcessManager(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerOptions,\n): void {\n autoKillChildProcesses()\n\n mcpRegisterToolProcessRun(mcpRegisterTool, {\n workingDir: options.workingDir,\n ...options.run,\n })\n mcpRegisterToolProcessStatus(mcpRegisterTool, {\n workingDir: options.workingDir,\n })\n mcpRegisterToolProcessWait(mcpRegisterTool, {\n workingDir: options.workingDir,\n })\n mcpRegisterToolProcessList(mcpRegisterTool, {\n workingDir: options.workingDir,\n })\n mcpRegisterToolProcessKill(mcpRegisterTool)\n\n console.log(\n `Process manager:\n- Working directory: ${path.resolve(options.workingDir || '')}\n- Allowed commands: ${options.run.allowedCommands.join(', ')}\n`,\n )\n}\n","import { ZodRawShape } from 'zod'\nimport type { PromiseOrValue } from '@flemist/async-utils'\nimport { logToFile } from 'src/helpers/logToFile'\nimport {\n McpServer,\n ToolCallback,\n RegisteredTool,\n} from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\n\nexport type CreateMcpRegisterToolFuncOptions = {\n logFilePath: string\n}\nexport type ToolCallbackExt<InputArgs extends ZodRawShape> = (\n ...args: Parameters<ToolCallback<InputArgs>>\n) => PromiseOrValue<string>\nexport type McpRegisterToolFunc = <\n InputArgs extends ZodRawShape,\n OutputArgs extends ZodRawShape,\n>(\n name: string,\n config: {\n title?: string\n description?: string\n inputSchema?: InputArgs\n outputSchema?: OutputArgs\n annotations?: ToolAnnotations\n },\n cb: ToolCallbackExt<InputArgs>,\n) => RegisteredTool\n\nexport function createMcpRegisterToolFunc(\n server: McpServer,\n options: CreateMcpRegisterToolFuncOptions,\n): McpRegisterToolFunc {\n return function mcpRegisterTool<\n InputArgs extends ZodRawShape,\n OutputArgs extends ZodRawShape,\n >(name, config, callback) {\n const callbackNative = (async (...args) => {\n await logToFile({\n logFilePath: options.logFilePath,\n message: 'REQUEST',\n data: { name, args },\n })\n\n const result = await callback(...args)\n\n await logToFile({\n logFilePath: options.logFilePath,\n message: 'RESPONSE',\n data: result,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: result,\n },\n ],\n }\n }) as ToolCallback<InputArgs>\n\n return server.registerTool<InputArgs, OutputArgs>(\n name,\n config,\n callbackNative,\n )\n }\n}\n","import fs from 'fs'\nimport * as path from 'path'\n\nexport function getDrive(path: string): string {\n return path.match(/^[/\\\\]?[^/\\\\]+/)![0]\n}\n\nexport function getFileId(path: string, stat: fs.Stats): string {\n return getDrive(path) + '|' + stat.ino\n}\n\nexport function pathResolve(_path: string): string {\n if (_path.endsWith(':')) {\n // если этого не сделать path.resolve заменит \"D:\" на \".\", а потом на текущую папку\n _path += '/'\n }\n return path.resolve(_path)\n}\n","import { IPool, Pool } from '@flemist/time-limits'\nimport os from 'node:os'\n\nexport const poolFs: IPool = new Pool(os.cpus().length)\n","import { IPool, poolRunWait } from '@flemist/time-limits'\nimport { Priority, priorityCreate } from '@flemist/priority-queue'\nimport { IAbortSignalFast } from '@flemist/abort-controller-fast'\nimport fs from 'fs'\nimport {\n combineAbortSignals,\n type PromiseOrValue,\n useAbortController,\n} from '@flemist/async-utils'\nimport * as path from 'path'\nimport { getFileId, pathResolve } from './helpers'\nimport { poolFs } from 'src/tools/fs/pools'\nimport type { MatchPath } from 'src/tools/fs/walkPaths/createMatchPath'\n\ntype WalkPathOptionsCommon = {\n paths: string[]\n walkLinks?: null | boolean\n abortSignal?: null | IAbortSignalFast\n pool?: null | IPool\n priority?: null | Priority\n log?: null | WalkPathLogOptions\n handlePath?: null | WalkPathHandlePath\n handleError?: null | WalkPathHandleError\n matchPath?: null | MatchPath\n}\n\n/** @internal */\ntype WalkPathPrivate = WalkPathOptionsCommon & {\n level?: null | number\n walkedIds?: null | Set<string>\n}\n\nexport type WalkPathOptions = WalkPathOptionsCommon\n\n/** @returns true if the error is handled */\nexport type WalkPathHandleError = (\n err: any,\n) => PromiseOrValue<boolean | null | undefined | void>\n\nexport type WalkPathStat = {\n totalSize: number\n countFiles: number\n countDirs: number\n countLinks: number\n maxFileDateModified: number\n}\n\nexport type WalkPathHandlePathArg = {\n level: number\n path: string\n stat: fs.Stats\n itemStat: WalkPathStat\n totalStat: WalkPathStat\n abortSignal: IAbortSignalFast\n}\n\n/**\n * Handler function for processing each discovered path.\n * @param arg - The path processing arguments\n * @returns boolean - true to include this item in totalStat, false to exclude it\n */\nexport type WalkPathHandlePath = (\n arg: WalkPathHandlePathArg,\n) => PromiseOrValue<boolean>\n\nexport type WalkPathLogOptions = {\n /** Don't log paths deeper than this level */\n maxNestedLevel?: null | number\n /** Don't log paths with total size less than this size */\n minTotalContentSize?: null | number\n handleLog?: null | WalkPathLogFunc\n}\n\nexport type WalkPathLogFunc = (message: string) => PromiseOrValue<void>\n\nfunction addStats(totalStat: WalkPathStat, itemStat: WalkPathStat) {\n totalStat.totalSize += itemStat.totalSize\n totalStat.maxFileDateModified = Math.max(\n totalStat.maxFileDateModified,\n itemStat.maxFileDateModified,\n )\n totalStat.countFiles += itemStat.countFiles\n totalStat.countDirs += itemStat.countDirs\n totalStat.countLinks += itemStat.countLinks\n}\n\nexport const walkPathHandleErrorDefault: WalkPathHandleError =\n function walkPathHandleErrorDefault(err: any) {\n if (err.code === 'ENOENT') {\n return true\n }\n return false\n }\n\n/** @internal */\nfunction _walkPaths(options: WalkPathPrivate): Promise<WalkPathStat> {\n const items = options.paths\n if (!items || items.length === 0) {\n return Promise.resolve({\n totalSize: 0,\n maxFileDateModified: 0,\n countFiles: 0,\n countDirs: 0,\n countLinks: 0,\n })\n }\n const level = options.level ?? 0\n const walkedIds = options.walkedIds ?? new Set<string>()\n const abortSignal = options.abortSignal\n const pool = options.pool ?? poolFs\n const handleError = options.handleError\n const priority = options.priority ?? priorityCreate(0)\n const walkLinks = options.walkLinks ?? false\n const logOptions = options.log\n const handlePath = options.handlePath\n const matchPath = options.matchPath\n\n async function _handleError(err: any) {\n if (handleError) {\n if (await handleError(err)) {\n return undefined\n }\n }\n if (walkPathHandleErrorDefault(err)) {\n return undefined\n }\n throw err\n }\n\n function canLog(itemSize: number) {\n if (!logOptions) {\n return false\n }\n if (\n logOptions.minTotalContentSize != null &&\n itemSize < logOptions.minTotalContentSize\n ) {\n return false\n }\n if (\n logOptions.maxNestedLevel != null &&\n level > logOptions.maxNestedLevel\n ) {\n return false\n }\n return true\n }\n\n return useAbortController(async _abortSignal => {\n const abortSignalCombined = combineAbortSignals(abortSignal, _abortSignal)\n\n const totalStat: WalkPathStat = {\n totalSize: 0,\n maxFileDateModified: 0,\n countFiles: 0,\n countDirs: 0,\n countLinks: 0,\n }\n\n function logItem(itemPath: string, itemStat: WalkPathStat) {\n if (canLog(itemStat.totalSize)) {\n // size to string with spaces between thousands\n const sizeStr = itemStat.totalSize\n .toLocaleString('en-US')\n .replace(/,/g, ' ')\n .padStart(19)\n const message = `${sizeStr}: ${itemPath}`\n if (logOptions?.handleLog) {\n logOptions.handleLog(message)\n } else {\n console.log(message)\n }\n }\n }\n\n async function _handlePath(\n itemPath: string,\n stat: fs.Stats,\n itemStat: WalkPathStat,\n priority: Priority,\n ): Promise<boolean> {\n if (!handlePath) {\n return true\n }\n return await poolRunWait({\n pool,\n func: async () => {\n try {\n return await handlePath({\n level,\n path: itemPath,\n stat,\n itemStat,\n totalStat: totalStat,\n abortSignal: abortSignalCombined,\n })\n } catch (err) {\n await _handleError(err)\n return false\n }\n },\n count: 1,\n priority,\n abortSignal: abortSignalCombined,\n })\n }\n\n async function processItem(\n /** Original or Symbolic link resolved path */\n resolvedItemPath: string,\n index: number,\n matchResult: boolean | null | undefined,\n /** Original item path before resolving symbolic links */\n originalItemPath?: string | null,\n ): Promise<WalkPathStat | null> {\n if (!originalItemPath) {\n originalItemPath = resolvedItemPath\n }\n\n const stat = await poolRunWait({\n pool,\n func: () => fs.promises.lstat(resolvedItemPath).catch(_handleError),\n count: 1,\n priority: priorityCreate(index, priorityCreate(1, priority)),\n abortSignal: abortSignalCombined,\n })\n\n if (!stat) {\n return null\n }\n\n if (!matchResult && stat.isFile()) {\n return null\n }\n\n // Check if the file has been walked already\n const itemId = getFileId(resolvedItemPath, stat)\n if (walkedIds.has(itemId)) {\n return null\n }\n walkedIds.add(itemId)\n\n let itemStat: WalkPathStat = {\n totalSize: stat.size,\n maxFileDateModified: stat.isDirectory() ? 0 : stat.mtimeMs,\n countFiles: 0,\n countDirs: 0,\n countLinks: 0,\n }\n\n const _priority = priorityCreate(\n index,\n priorityCreate(stat.isDirectory() ? 2 : 3, priority),\n )\n\n if (stat.isSymbolicLink()) {\n if (walkLinks) {\n const link: string = (await poolRunWait({\n pool,\n func: () =>\n fs.promises\n .readlink(resolvedItemPath)\n .catch(_handleError)\n .then(link => link ?? null),\n count: 1,\n priority: _priority,\n abortSignal: abortSignalCombined,\n })) as string\n\n if (link) {\n const resolvedLink = path.isAbsolute(link) ? link : path.resolve(path.dirname(originalItemPath), link)\n const linkedItemStat = await processItem(resolvedLink, index, matchResult, originalItemPath)\n if (linkedItemStat) {\n itemStat = linkedItemStat\n }\n }\n }\n itemStat.countLinks = 1\n\n if (\n matchResult ||\n itemStat.countFiles + itemStat.countDirs + itemStat.countLinks > 1\n ) {\n const shouldInclude = await _handlePath(\n originalItemPath,\n stat,\n itemStat,\n _priority,\n )\n if (shouldInclude) {\n addStats(totalStat, itemStat)\n logItem(originalItemPath, itemStat)\n }\n }\n\n return itemStat\n } else if (stat.isDirectory()) {\n // Get items from the directory\n const dirItems = await poolRunWait({\n pool,\n func: () => fs.promises.readdir(resolvedItemPath).catch(_handleError),\n count: 1,\n priority,\n abortSignal: abortSignalCombined,\n })\n\n if (dirItems) {\n for (let i = 0, len = dirItems.length; i < len; i++) {\n dirItems[i] = path.join(originalItemPath, dirItems[i])\n }\n itemStat = await _walkPaths({\n ...options,\n paths: dirItems,\n abortSignal: abortSignalCombined,\n priority: _priority,\n level: level + 1,\n walkedIds,\n })\n }\n itemStat.countDirs += 1\n } else if (stat.isFile()) {\n itemStat.countFiles += 1\n }\n\n if (\n matchResult ||\n itemStat.countFiles + itemStat.countDirs + itemStat.countLinks > 1\n ) {\n const shouldInclude = await _handlePath(\n originalItemPath,\n stat,\n itemStat,\n _priority,\n )\n if (shouldInclude) {\n addStats(totalStat, itemStat)\n logItem(originalItemPath, itemStat)\n }\n }\n\n return itemStat\n }\n\n const promises: Promise<WalkPathStat | null>[] = []\n for (let i = 0, len = items.length; i < len; i++) {\n const itemPath = pathResolve(items[i])\n const matchResult = matchPath ? matchPath(itemPath) : true\n if (matchResult === false) {\n continue\n }\n promises.push(processItem(itemPath, i, matchResult))\n }\n\n await Promise.all(promises)\n\n return totalStat\n })\n}\n\nexport function walkPaths(options: WalkPathOptions): Promise<WalkPathStat> {\n return _walkPaths(options)\n}\n","import * as path from 'path'\n\n// /glob => <relativePath>/glob\n// ./dir/glob => <relativePath>/dir/glob\n// ../glob => <relativePath>/../glob\n// **/glob => <relativePath>/**/glob\n// *.glob => <relativePath>/**/*.glob\n// glob => <relativePath>/**/glob\n/**\n * @param glob - .gitignore glob pattern\n * @param relativePath - relative path from the directory where the glob should be applied\n * @return - glob pattern relative to the given path\n */\nexport function globToRelative(glob: string, relativePath: string): string {\n if (!relativePath || relativePath === '.') {\n return glob\n }\n const exclude = glob.startsWith('^')\n if (exclude) {\n glob = glob.substring(1)\n }\n const negative = glob.startsWith('!')\n if (negative) {\n glob = glob.substring(1)\n }\n\n if (glob.startsWith('/')) {\n if (relativePath.endsWith('/')) {\n relativePath = relativePath.substring(0, relativePath.length - 1)\n }\n glob = relativePath + glob\n } else {\n if (!relativePath.endsWith('/')) {\n relativePath += '/'\n }\n if (glob.startsWith('./')) {\n glob = relativePath + glob.substring(2)\n } else if (glob.startsWith('../')) {\n glob = relativePath + glob\n } else {\n if (relativePath.startsWith('..')) {\n relativePath = ''\n }\n if (glob.startsWith('**')) {\n glob = relativePath + glob\n } else {\n glob = relativePath + '**/' + glob\n }\n }\n }\n\n glob = path.normalize(glob).replace(/\\\\/g, '/')\n\n if (negative) {\n glob = '!' + glob\n }\n if (exclude) {\n glob = '^' + glob\n }\n return glob\n}\n","export function globGitIgnoreToPicomatch(glob: string): string {\n const negative = glob.startsWith('!')\n if (negative) {\n glob = glob.substring(1)\n }\n // Convert glob from .gitignore to picomatch format\n // Because AI agents understands picomatch format better\n if (glob.startsWith('/')) {\n glob = glob.substring(1)\n } else if (!glob.startsWith('**') && !glob.startsWith('../')) {\n glob = `**/${glob}`\n }\n if (negative) {\n glob = '!' + glob\n }\n return glob\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport { globToRelative } from './globToRelative'\nimport { poolRunWait } from '@flemist/time-limits'\nimport { poolFs } from './pools'\nimport { globGitIgnoreToPicomatch } from 'src/tools/fs/globGitIgnoreToPicomatch'\n\n/**\n * @import {CreateMatchPathOptions} from \"./walkPaths/createMatchPath\"\n */\n\n// see CreateMatchPathOptions['globs'] for glob syntax\nexport type Glob = {\n value: string\n valueType: 'file-contains-patterns' | 'pattern'\n /**\n * exclude like .gitignore by adding ^ prefix to glob.\n * @see CreateMatchPathOptions\n */\n exclude: boolean\n}\nexport type LoadGlobsOptions = {\n /** default: cwd */\n rootDir?: string | null\n globs?: Glob[] | null\n}\n\nfunction globExclude(glob: string): string {\n return '^' + glob\n}\n\nexport async function loadGlobsFromFile(filePath: string): Promise<string[]> {\n const content = await fs.promises.readFile(filePath, 'utf-8')\n const lines = content.split('\\n')\n const globs: string[] = []\n lines.forEach(line => {\n line = line.trim()\n if (!line || line.startsWith('#')) {\n return\n }\n globs.push(line)\n })\n return globs\n}\n\nexport async function loadGlobs(options: LoadGlobsOptions): Promise<string[]> {\n const rootDir = options.rootDir ?? '.'\n const result: string[] = []\n if (!options.globs?.length) {\n return result\n }\n const filesContainsGlobs: Glob[] = []\n options.globs.forEach(glob => {\n if (!glob.value) {\n return\n }\n if (glob.valueType === 'file-contains-patterns') {\n filesContainsGlobs.push(glob)\n } else if (glob.valueType === 'pattern') {\n result.push(glob.exclude ? globExclude(glob.value) : glob.value)\n }\n })\n if (filesContainsGlobs.length) {\n await Promise.all(\n filesContainsGlobs.map(async glob => {\n await poolRunWait({\n pool: poolFs,\n count: 1,\n func: async () => {\n const filePath = path.resolve(rootDir, glob.value)\n const globs = await loadGlobsFromFile(filePath)\n const relativePath = path.relative(rootDir, path.dirname(filePath))\n globs.forEach(globValue => {\n globValue = globGitIgnoreToPicomatch(globValue)\n globValue = globToRelative(globValue, relativePath)\n result.push(glob.exclude ? globExclude(globValue) : globValue)\n })\n },\n })\n }),\n )\n }\n return result\n}\n","import picomatch from 'picomatch'\nimport * as path from 'path'\n\n/**\n * true - include the path\n * false - exclude the path\n * null - no match, do default action\n */\nexport type MatchPath = (path: string) => boolean | null\nexport type CreateMatchPathOptions = {\n /**\n * Behavior:\n * let include = false\n * let exclude = false\n *\n * for each glob:\n * if glob matched\n * if pattern is `glob` then include = true; exclude = false\n * if pattern is `!glob` then include = false; exclude = false\n * if pattern is `^glob` then exclude = true\n * if pattern is `^!glob` then exclude = false\n * if pattern is `!^glob` then incorrect should throw error\n *\n * result = include && !exclude\n */\n globs: string[]\n rootDir?: string | null\n noCase?: null | boolean\n}\n\n/** .gitignore-like path matching function */\nexport function createMatchPath({\n globs,\n rootDir,\n noCase,\n}: CreateMatchPathOptions): MatchPath {\n type Condition = {\n exclude: boolean\n negative: boolean\n debugInfo: string\n match: (path: string) => boolean\n }\n\n const conditions: Condition[] = []\n globs.forEach(glob => {\n glob = glob.replace(/\\\\/g, '/').trim()\n const exclude = glob.startsWith('^')\n if (exclude) {\n glob = glob.substring(1).trim()\n }\n const negative = glob.startsWith('!')\n if (negative) {\n glob = glob.substring(1).trim()\n }\n if (glob.startsWith('!') || glob.startsWith('^')) {\n throw new Error(\n `Invalid glob pattern: \"${glob}\". The syntax '${glob.substring(0, 2)}' is not supported. Valid glob patterns use: * (match any characters), ** (match any directories), ? (match single character), [abc] (character class), ! (negate pattern), ^ (exclude if included). Examples of valid patterns: \"*.js\", \"src/**/*.ts\", \"!node_modules\", \"^dist\". Avoid starting with '!' after '^' or multiple special prefixes.`,\n )\n }\n if (glob.startsWith('/')) {\n glob = '.' + glob\n }\n\n const globAbsolute = rootDir\n ? path.resolve(rootDir, glob).replace(/\\\\/g, '/')\n : glob\n\n if (!globAbsolute) {\n return\n }\n\n let matcher: (path: string) => boolean\n try {\n matcher = picomatch(globAbsolute, {\n nocase: noCase ?? false,\n dot: true,\n strictBrackets: true, // Validate bracket balance for patterns like \"[\"\n })\n } catch (error) {\n throw new Error(\n `Invalid glob pattern: \"${glob}\". ${error instanceof Error ? error.message : 'Unknown error'}. Valid glob patterns use: * (match any characters), ** (match any directories), ? (match single character), [abc] (character class with balanced brackets), ! (negate pattern), ^ (exclude if included). Examples: \"*.js\", \"src/**/*.ts\", \"!node_modules\", \"[abc]def.txt\". Ensure all brackets [ ] are properly closed and balanced.`,\n )\n }\n\n conditions.push({\n exclude,\n negative,\n debugInfo: globAbsolute,\n match: matcher,\n })\n })\n\n return function matchPath(_path: string) {\n _path = _path.replace(/\\\\/g, '/')\n let include: boolean | null = null\n let exclude = false\n for (let i = 0, len = conditions.length; i < len; i++) {\n const condition = conditions[i]\n const conditionResult = condition.match(_path)\n if (conditionResult) {\n if (condition.exclude) {\n exclude = !condition.negative\n } else {\n include = !condition.negative\n exclude = false\n }\n }\n }\n return exclude ? false : include\n }\n}\n","import { walkPaths } from 'src/tools/fs/walkPaths/walkPaths'\nimport type { Glob } from 'src/tools/fs/loadGlobs'\nimport { loadGlobs } from 'src/tools/fs/loadGlobs'\nimport * as path from 'path'\nimport { createMatchPath } from 'src/tools/fs/walkPaths/createMatchPath'\nimport { NumberRangeOptional } from 'src/helpers/types'\n\nexport type PathType = 'dir' | 'file'\n\nexport type PathListOptionsResult = {\n dirs?: boolean | null\n files?: boolean | null\n dateModified?: boolean | null\n size?: boolean | null\n countFiles?: boolean | null\n}\n\nexport type PathListOptions = {\n /** default: cwd */\n rootDir?: string | null\n /** prepend all globs from gitIgnore files */\n globs?: Glob[] | null\n result: PathListOptionsResult\n dateModified?: null | NumberRangeOptional\n totalSize?: null | NumberRangeOptional\n}\n\nexport type PathListStats = {\n /** Unix timestamp. Dir path should be calculated as max nested files dateModified */\n dateModified?: number | null\n /** File size in bytes */\n size?: number | null\n /** Total files count for dirs: WalkPathStat.countFiles */\n countFiles?: number | null\n}\n\nexport type PathListItem = PathListStats & {\n /** path relative to rootDir */\n path: string\n type: PathType\n}\n\nexport type PathListResult = {\n items: PathListItem[]\n totals: PathListStats\n}\n\nexport async function getPathList(\n options: PathListOptions,\n): Promise<PathListResult> {\n const rootDir = options.rootDir ?? '.'\n const items: PathListItem[] = []\n const totals: PathListStats = {}\n if (options.result.countFiles) {\n totals.countFiles = 0\n }\n if (options.result.size) {\n totals.size = 0\n }\n\n // Load and process globs with revert logic\n const globs = await loadGlobs({\n rootDir,\n globs: options.globs,\n })\n\n await walkPaths({\n paths: [rootDir],\n walkLinks: true,\n matchPath: createMatchPath({\n globs,\n rootDir,\n noCase: true,\n }),\n handlePath: async ({ path: itemPath, stat, itemStat }) => {\n const relativePath = path.relative(rootDir, itemPath)\n\n const isDir = stat.isDirectory()\n const isFile = stat.isFile()\n if (!isDir && !isFile) {\n // Skip unsupported types but add referenced items to statistics\n return true\n }\n\n const _path = (relativePath || '.').replace(/\\\\/g, '/')\n const type = isDir ? 'dir' : 'file'\n const dateModified = isDir\n ? itemStat.maxFileDateModified || null\n : stat.mtimeMs\n const size = isDir ? itemStat.totalSize : stat.size\n const countFiles = isDir ? itemStat.countFiles : null\n\n const item: PathListItem = {\n path: _path,\n type: type,\n }\n if (options.result.dateModified) {\n item.dateModified = dateModified\n }\n if (options.result.size) {\n item.size = size\n }\n if (options.result.countFiles) {\n item.countFiles = countFiles\n }\n\n // Apply date filters if specified\n if (options.dateModified && dateModified != null) {\n const [minDate, maxDate] = options.dateModified\n if (\n (minDate != null && dateModified < minDate) ||\n (maxDate != null && dateModified > maxDate)\n ) {\n return false // Skip this item due to date filter - exclude from totals and items\n }\n }\n\n // Apply size filters if specified\n if (options.totalSize && size != null) {\n const [minSize, maxSize] = options.totalSize\n if (\n (minSize != null && size < minSize) ||\n (maxSize != null && size > maxSize)\n ) {\n return false // Skip this item due to size filter - exclude from totals and items\n }\n }\n\n // Calculate totals for items that pass date/size filters\n // Note: totals include all files/dirs that pass filters, regardless of show options\n if (type === 'file') {\n // Count files only not the same files from directory statistics\n totals.countFiles = (totals.countFiles ?? 0) + 1\n }\n\n if (type === 'file' && size != null) {\n totals.size = (totals.size ?? 0) + size\n }\n\n if (\n dateModified != null &&\n (totals.dateModified == null || dateModified > totals.dateModified)\n ) {\n totals.dateModified = dateModified\n }\n\n // Filter based on result options for what to show in table\n if (isDir && !options.result.dirs) {\n return true // Include in totals but not in items list\n }\n if (isFile && !options.result.files) {\n return true // Include in totals but not in items list\n }\n\n items.push(item)\n return true // Include in totals and items list\n },\n })\n\n return { items, totals }\n}\n","import type { PathListItem, PathListResult } from 'src/tools/fs/getPathList'\n\nexport type PathListToStringField =\n | 'type'\n | 'path'\n | 'dateModified'\n | 'size'\n | 'countFiles'\nexport type PathListToStringSort = {\n field: PathListToStringField\n desc?: boolean | null\n}\nexport type PathListToStringOptions = {\n sort?: PathListToStringSort[] | null\n fields?: PathListToStringField[] | null\n totals?: boolean | null\n}\n\n/**\n Example of output (with headers):\n Date modified (UTC) | Type | Path \n 2025-12-31 23:59:59 | dir | path/to/dir/ \n 2025-12-31 23:59:59 | file | path/to/dir/file.txt\n 2025-12-31 23:59:59 | dir | path/to/dir/subdir/\n 2025-12-31 23:59:59 | file | path/to/dir/subdir/file.txt\n */\nconst UNITS = ['B', 'KB', 'MB', 'GB', 'TB']\nconst UNIT_SIZE = 1024\n\nfunction fileSizeFormat(bytes: number | null | undefined): string {\n if (bytes == null) return '-'\n\n let value = bytes ?? 0\n let unitIndex = 0\n\n while (value >= UNIT_SIZE && unitIndex < UNITS.length - 1) {\n value /= UNIT_SIZE\n unitIndex++\n }\n\n const formatted = unitIndex === 0 ? value.toString() : value.toFixed(2)\n return `${formatted}${UNITS[unitIndex]}`\n}\n\nfunction timeAgoFormat(timestamp: number): string {\n const now = Date.now()\n const diffMs = now - timestamp\n\n if (diffMs < 0) return '0s' // Future dates\n\n const diffSeconds = Math.floor(diffMs / 1000)\n const diffMinutes = Math.floor(diffSeconds / 60)\n const diffHours = Math.floor(diffMinutes / 60)\n const diffDays = Math.floor(diffHours / 24)\n const diffWeeks = Math.floor(diffDays / 7)\n const diffMonths = Math.floor(diffDays / 30)\n const diffYears = Math.floor(diffDays / 365)\n\n if (diffYears > 0) return `${diffYears}Y`\n if (diffMonths > 0) return `${diffMonths}M`\n if (diffWeeks > 0) return `${diffWeeks}w`\n if (diffDays > 0) return `${diffDays}d`\n if (diffHours > 0) return `${diffHours}h`\n if (diffMinutes > 0) return `${diffMinutes}m`\n return `${diffSeconds}s`\n}\n\nfunction pathListSort(\n pathList: PathListItem[],\n sort: PathListToStringSort[],\n): PathListItem[] {\n if (!sort?.length) return pathList\n\n return [...pathList].sort((a, b) => {\n for (let i = 0, len = sort.length; i < len; i++) {\n const sortConfig = sort[i]\n let aValue: string | number | null | undefined\n let bValue: string | number | null | undefined\n\n switch (sortConfig.field) {\n case 'type':\n aValue = a.type\n bValue = b.type\n break\n case 'path':\n aValue = a.path\n bValue = b.path\n break\n case 'dateModified':\n aValue = a.dateModified\n bValue = b.dateModified\n break\n case 'size':\n aValue = a.size\n bValue = b.size\n break\n case 'countFiles':\n aValue = a.countFiles\n bValue = b.countFiles\n break\n }\n\n if (aValue == null) {\n if (bValue == null) {\n continue\n }\n return 1\n }\n if (bValue == null) {\n return -1\n }\n\n const comparison = aValue > bValue ? 1 : aValue < bValue ? -1 : 0\n if (comparison !== 0) {\n return sortConfig.desc ? -comparison : comparison\n }\n }\n return 0\n })\n}\n\nexport function pathListToString(\n pathListResult: PathListResult,\n options: PathListToStringOptions,\n): string {\n const sortedList = pathListSort(pathListResult.items, options.sort ?? [])\n const fields =\n options.fields && options.fields.length > 0 ? options.fields : []\n\n let result = ''\n\n // Only write table if fields are specified\n if (sortedList.length > 0 && fields.length > 0) {\n // Header row\n for (let i = 0, len = fields.length; i < len; i++) {\n const field = fields[i]\n if (i > 0) result += ' | '\n switch (field) {\n case 'dateModified':\n result += 'Time ago (s/m/h/d/w/M/Y)'\n break\n case 'size':\n result += 'Size (B/KB/MB/TB)'\n break\n case 'type':\n result += 'Type'\n break\n case 'path':\n result += 'Path'\n break\n case 'countFiles':\n result += 'Files Count'\n break\n }\n }\n\n // Data rows\n for (let i = 0, len = sortedList.length; i < len; i++) {\n const item = sortedList[i]\n result += '\\n'\n\n for (let j = 0, fieldsLen = fields.length; j < fieldsLen; j++) {\n const field = fields[j]\n if (j > 0) result += ' | '\n\n switch (field) {\n case 'dateModified':\n result += item.dateModified ? timeAgoFormat(item.dateModified) : '-'\n break\n case 'size':\n result += fileSizeFormat(item.size)\n break\n case 'type':\n result += item.type\n break\n case 'path':\n result += item.type === 'dir' ? `${item.path}/` : item.path\n break\n case 'countFiles':\n if (item.type === 'dir') {\n result +=\n item.countFiles != null ? item.countFiles.toString() : '-'\n } else {\n result += '-'\n }\n break\n }\n }\n }\n }\n\n // Add totals if requested\n if (options.totals) {\n if (result.length > 0) {\n result += '\\n---\\n'\n }\n\n const totalSizeFormatted = fileSizeFormat(pathListResult.totals.size ?? 0)\n const lastModifiedPart = pathListResult.totals.dateModified\n ? `, last modified ${timeAgoFormat(pathListResult.totals.dateModified)} ago`\n : ''\n\n result += `Totals: ${pathListResult.totals.countFiles ?? 0} files in dirs, ${totalSizeFormatted}${lastModifiedPart}`\n }\n\n return result\n}\n","export const SERVER_NAME = 'project-tools'\nexport const SERVER_VERSION = '1.0.0'\nexport const AUTH_TOKEN =\n 'd00f70240703039df14c76176a055bce6b5484d2b552ba2c89820f03b8e5e60d'\n\nexport const MAX_FS_LIST_PATHS = 25000\n","import { z } from 'zod'\nimport { getPathList, type PathListOptionsResult } from '../getPathList'\nimport {\n pathListToString,\n type PathListToStringField,\n type PathListToStringSort,\n} from '../pathListToString'\nimport type { Glob } from '../loadGlobs'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport { MAX_FS_LIST_PATHS } from 'src/config/constants'\nimport * as path from 'path'\nimport * as fs from 'fs'\nimport { NumberRangeOptional } from 'src/helpers/types'\n\n/**\n * Parse time ago format like \"59s\", \"23h\", \"12M\", \"123Y\" to milliseconds\n */\nfunction parseTimeAgo(timeAgoStr: string): number {\n const match = timeAgoStr.match(\n /^\\s*(\\d+(?:\\.\\d+)?)\\s*([smhdwMY]|sec(onds?)?|min(utes?)?|hours?|days?|weeks?|months?|years?)\\s*$/i,\n )\n if (!match) {\n throw new Error(\n `Invalid time ago format: \"${timeAgoStr}\". Must be a number followed by a time unit. Valid units: s/sec/seconds (seconds), m/min/minutes (minutes), h/hours (hours), d/days (days), w/weeks (weeks), M/months (months), Y/years (years). Examples: \"30s\", \"0.5h\", \"1.5d\", \"7d\", \"3w\", \"6M\", \"1Y\". Format is case-insensitive except M (months) must be uppercase to distinguish from m (minutes).`,\n )\n }\n\n const value = parseFloat(match[1])\n let unit = match[2]\n if (unit !== 'M') {\n unit = unit.toLowerCase()\n if (unit.startsWith('month')) {\n unit = 'M'\n } else if (unit.length > 1) {\n unit = unit[0]\n }\n }\n\n switch (unit) {\n case 's':\n return value * 1000\n case 'm':\n return value * 60 * 1000\n case 'h':\n return value * 60 * 60 * 1000\n case 'd':\n return value * 24 * 60 * 60 * 1000\n case 'w':\n return value * 7 * 24 * 60 * 60 * 1000\n case 'M':\n return value * 30 * 24 * 60 * 60 * 1000\n case 'y':\n return value * 365 * 24 * 60 * 60 * 1000\n default:\n throw new Error(\n `Unknown time unit: \"${unit}\". Valid time units are: s (seconds), m (minutes), h (hours), d (days), w (weeks), M (months), Y (years). Use uppercase M for months to distinguish from lowercase m for minutes. Examples: \"30s\", \"5m\", \"2h\", \"7d\", \"3w\", \"6M\", \"1Y\".`,\n )\n }\n}\n\n/**\n * Parse size format like \"1B\", \"2KB\", \"5MB\" to bytes\n */\nfunction parseSize(sizeStr: string): number {\n const match = sizeStr.match(/^\\s*(\\d+(?:\\.\\d+)?)\\s*(B|KB|MB|GB|TB)\\s*$/i)\n if (!match) {\n throw new Error(\n `Invalid size format: \"${sizeStr}\". Must be a number (integer or decimal) followed by a size unit. Valid units: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary units (1024-based). Examples: \"1B\", \"2.5KB\", \"100MB\", \"1.2GB\", \"0.5TB\". Units are case-insensitive.`,\n )\n }\n\n const value = parseFloat(match[1])\n const unit = match[2].toUpperCase()\n\n switch (unit) {\n case 'B':\n return value\n case 'KB':\n return value * 1024\n case 'MB':\n return value * 1024 * 1024\n case 'GB':\n return value * 1024 * 1024 * 1024\n case 'TB':\n return value * 1024 * 1024 * 1024 * 1024\n default:\n throw new Error(\n `Unknown size unit: \"${unit}\". Valid size units are: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary calculation (1KB = 1024 bytes). Examples: \"500B\", \"2KB\", \"100MB\", \"1.5GB\", \"2TB\". Units are case-insensitive.`,\n )\n }\n}\n\n/**\n * Validates filesystem list requests\n * WHY: Ensures filesystem list requests have valid parameters\n */\nexport const ListSchema = z.object({\n rootDir: z\n .string()\n .optional()\n .describe(\n 'Root directory to list files from, resolved relative to the current working directory. Leave empty to use current directory. Examples: \"src\" (list src/ subdirectory), \"../parent\" (list parent directory), \"docs/api\" (list nested subdirectory). Path must exist and be accessible.',\n ),\n globs: z\n .array(z.string())\n .optional()\n .describe(\n 'Glob patterns to filter which files/directories to include. Add leading ** to match files and dirs in subdirectories. Examples: [\"**/*.js\"] (JavaScript files), [\"src/**/*.ts\"] (TypeScript files in src), [\"**/dir/\"] (all directories named \"dir\"), [\"!node_modules\"] (exclude {rootDir}/node_modules). If omitted, includes all files matching other criteria. Supports standard glob syntax: * (any chars), ** (any dirs), ? (single char), [abc] (char class).',\n ),\n showFiles: z\n .boolean()\n .optional()\n .describe(\n 'Whether to show regular files in the report table. Set to true to show files, false to hide them from the table. When both showFiles and showDirs are false, nothing will be shown in the table. It Does not affect totals. Default is false (do not show files in the table).',\n ),\n showDirs: z\n .boolean()\n .optional()\n .describe(\n 'Whether to show directories in the report table. Set to true to show directories, false to hide them from the table. When both showFiles and showDirs are false, nothing will be shown in the table. It Does not affect totals. Default is true (show directories in the table).',\n ),\n sortBy: z\n .array(\n z.object({\n field: z\n .enum(['type', 'path', 'lastModified', 'size', 'totalCountFiles'])\n .describe(\n 'Field to sort results by. \"type\" sorts files before directories. \"path\" sorts alphabetically by file/directory name. \"lastModified\" sorts by modification time (newest first when desc=true). \"size\" sorts by file/directory size (largest first when desc=true). \"totalCountFiles\" sorts by total files count (highest first when desc=true, directories only).',\n ),\n desc: z\n .boolean()\n .optional()\n .describe('Sort in descending order (largest/newest first).'),\n }),\n )\n .optional()\n .describe(\n 'Multi-level sorting configuration. Sorts are applied in array order - first sort is primary, second is secondary, etc. Example: [{field: \"type\", desc: false}, {field: \"size\", desc: true}] sorts by type ascending, then by size descending within each type.',\n ),\n fields: z\n .array(z.enum(['type', 'path', 'lastModified', 'size', 'totalCountFiles']))\n .optional()\n .describe(\n 'Which data fields to include in the formatted table output. \"type\" shows file/directory indicator. \"path\" shows relative file/directory path. \"lastModified\" shows last modification time as time-ago format (5m, 2h, 3d, etc). \"size\" shows file/directory size in human-readable format (KB, MB, GB). \"totalCountFiles\" shows total files count for directories (displays \"-\" for files). Adding lastModified, size, or totalCountFiles fields increases processing time. Do not set fields if you want to show only totals summary.',\n ),\n minTimeAgo: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories modified at least this long ago. Only items older than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: \"1h\" (modified more than 1 hour ago), \"7d\" (modified more than 7 days ago), \"6M\" (modified more than 6 months ago).',\n ),\n maxTimeAgo: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories modified at most this long ago. Only items newer than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: \"1h\" (modified within last hour), \"7d\" (modified within last 7 days), \"1M\" (modified within last month). Combine with minTimeAgo for date ranges.',\n ),\n minTotalSize: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories with total size at least this large. Only items with size >= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: \"1KB\" (at least 1 kilobyte), \"100MB\" (at least 100 megabytes), \"1.5GB\" (at least 1.5 gigabytes).',\n ),\n maxTotalSize: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories with total size at most this large. Only items with size <= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: \"1MB\" (up to 1 megabyte), \"500KB\" (up to 500 kilobytes), \"10GB\" (up to 10 gigabytes). Combine with minTotalSize for size ranges.',\n ),\n})\n\nexport type FsManagerListOptions = {\n workingDir?: string | null\n globsExclude?: Glob[]\n}\n\n/**\n * List filesystem paths\n */\nexport async function commandList(\n args: z.infer<typeof ListSchema>,\n options: FsManagerListOptions,\n): Promise<Record<string, any>> {\n const parsedArgs = ListSchema.parse(args)\n const {\n globs,\n showFiles,\n showDirs,\n sortBy,\n minTimeAgo,\n maxTimeAgo,\n minTotalSize,\n maxTotalSize,\n } = parsedArgs\n\n // Validate fields: if provided, must include 'path'\n if (\n parsedArgs.fields &&\n parsedArgs.fields.length > 0 &&\n !parsedArgs.fields.includes('path')\n ) {\n return {\n error:\n 'Fields array must include \"path\" field when fields are specified. The \"path\" field is required to identify files and directories in the output.',\n }\n }\n\n const fields = parsedArgs.fields\n ? parsedArgs.fields.map(o => {\n if (o === 'totalCountFiles') {\n return 'countFiles' // Convert to internal field name\n }\n if (o === 'lastModified') {\n return 'dateModified' // Convert to internal field name\n }\n return o // Keep other fields as is\n })\n : []\n\n let sort: PathListToStringSort[] | null =\n parsedArgs.sortBy?.map(o => {\n let field = o.field as string\n if (field === 'totalCountFiles') {\n field = 'countFiles' // Convert to internal field name\n }\n if (field === 'lastModified') {\n field = 'dateModified' // Convert to internal field name\n }\n return {\n field: field as PathListToStringField,\n desc: o.desc ?? false, // Default to ascending if not specified\n }\n }) || null\n if (!sort || sort.length === 0) {\n // Default sort by path ascending if no sort specified\n sort = [{ field: 'path', desc: false }]\n }\n\n const sortFields = sort?.map(o => o.field) || []\n\n const rootDir = path.resolve(\n options.workingDir || '',\n parsedArgs.rootDir || '',\n )\n\n try {\n // Check if rootDir exists\n try {\n await fs.promises.access(rootDir, fs.constants.F_OK)\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n return {\n error: `Directory does not exist: \"${rootDir}\". Verify the path is correct and accessible. If using rootDir parameter, ensure it exists relative to the current working directory. Use fs-list without rootDir to list the current directory, or check parent directories first.`,\n }\n }\n throw err\n }\n\n // Convert globs to internal format\n const userGlobs: Glob[] =\n globs && globs.length > 0\n ? globs.map(g => ({\n value: g,\n valueType: 'pattern' as const,\n exclude: false,\n }))\n : [{ value: '**', valueType: 'pattern', exclude: false }]\n const excludeGlobs = options.globsExclude || []\n const globsConverted: Glob[] = [...userGlobs, ...excludeGlobs]\n\n // Build result options based on fields and sorting requirements\n const result: PathListOptionsResult = {\n files: showFiles ?? false,\n dirs: showDirs ?? false,\n dateModified:\n fields.includes('dateModified') || sortFields.includes('dateModified'),\n size: fields.includes('size') || sortFields.includes('size'),\n countFiles:\n fields.includes('countFiles') || sortFields.includes('countFiles'),\n }\n\n // Parse time and size filters\n let dateModifiedRange: NumberRangeOptional | null = null\n let totalSizeRange: NumberRangeOptional | null = null\n\n if (minTimeAgo || maxTimeAgo) {\n try {\n const now = Date.now()\n const minDate = maxTimeAgo ? now - parseTimeAgo(maxTimeAgo) : null\n const maxDate = minTimeAgo ? now - parseTimeAgo(minTimeAgo) : null\n dateModifiedRange = [minDate, maxDate]\n } catch (err) {\n return {\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error parsing time ago filter',\n }\n }\n }\n\n if (minTotalSize || maxTotalSize) {\n try {\n const minTotalSizeBytes = minTotalSize ? parseSize(minTotalSize) : null\n const maxTotalSizeBytes = maxTotalSize ? parseSize(maxTotalSize) : null\n totalSizeRange = [minTotalSizeBytes, maxTotalSizeBytes]\n } catch (err) {\n return {\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error parsing size filter',\n }\n }\n }\n\n // Get path list with filters\n const pathListResult = await getPathList({\n rootDir: rootDir || null,\n globs: globsConverted,\n result,\n dateModified: dateModifiedRange,\n totalSize: totalSizeRange,\n })\n\n // Check if the number of paths exceeds the maximum allowed\n if (pathListResult.items.length > MAX_FS_LIST_PATHS) {\n throw new Error(\n `Number of paths (${pathListResult.items.length}) exceeds maximum allowed (${MAX_FS_LIST_PATHS}). Consider using more specific glob patterns or filters to reduce the result set.`,\n )\n }\n\n // Format as string\n const formattedOutput = pathListToString(pathListResult, {\n sort,\n fields: fields as PathListToStringField[],\n totals: true,\n })\n\n return {\n output: formattedOutput,\n }\n } catch (err) {\n return { error: err instanceof Error ? err.message : 'Unknown error' }\n }\n}\n\nexport function mcpRegisterToolFsList(\n mcpRegisterTool: McpRegisterToolFunc,\n options: FsManagerListOptions,\n): void {\n mcpRegisterTool(\n 'fs-list',\n {\n title: 'List Filesystem Paths',\n description: `List files and directories with advanced filtering, sorting and formatting options. Features include: glob pattern filtering (gitignore-style syntax), date modification filters (modified within/before time ranges), size filters (binary units B/KB/MB/GB/TB), multi-field sorting (type/path/date/size/totalCountFiles), custom field selection, and formatted table output. Returns structured table text with pipe-separated columns. Use showFiles/showDirs to control what types are shown in report table. The totalCountFiles field shows total files count for directories. Supports complex queries like \"all TypeScript files larger than 1KB modified in the last week\".`,\n inputSchema: ListSchema.shape,\n },\n async args => {\n const result = await commandList(args, options)\n if (result.error) {\n return `Method: fs-list(${JSON.stringify(args)})\\nError: ${result.error}`\n }\n return `Method: fs-list(${JSON.stringify(args)})\\n${result.output || JSON.stringify(result, null, 2)}`\n },\n )\n}\n","import {\n type FsManagerListOptions,\n mcpRegisterToolFsList,\n} from 'src/tools/fs/methods/list'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\nexport type FsManagerOptions = {\n workingDir?: string | null\n list?: Omit<FsManagerListOptions, 'workingDir'> | null\n}\n\nexport function mcpRegisterFsManager(\n mcpRegisterTool: McpRegisterToolFunc,\n options: FsManagerOptions,\n): void {\n mcpRegisterToolFsList(mcpRegisterTool, {\n workingDir: options.workingDir || null,\n ...options.list,\n })\n\n console.log(\n `File manager:\n- Working directory: ${path.resolve(options.workingDir || '')}\n`,\n )\n}\n","import type { Request, Response } from 'express'\nimport { logToFile } from 'src/helpers/logToFile'\n\nexport type ErrorMiddlewareOptions = {\n logFilePath: string\n}\n\nexport function createErrorMiddleware(options: ErrorMiddlewareOptions) {\n const { logFilePath } = options\n\n return async function errorErrorMiddleware(\n err: Error,\n req: Request,\n res: Response,\n next: () => void,\n ) {\n await logToFile({\n logFilePath,\n message: 'ERROR',\n data: {\n request: {\n url: req.url,\n method: req.method,\n headers: req.headers,\n body: req.body,\n },\n error: err.message,\n stack: err.stack,\n },\n })\n res.status(500).send({\n error: 'Internal Server Error',\n message: err.stack || err.message || err.toString(),\n })\n }\n}\n","import express, { type Express, type Router } from 'express'\nimport * as cors from 'cors'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { Server } from 'http'\nimport { createAuthMiddleware } from './createAuthMiddleware'\nimport { createStreamableHttpHandler } from 'src/server/transport/streamable-http/StreamableHttpHandler'\nimport * as path from 'path'\nimport {\n mcpRegisterProcessManager,\n type ProcessManagerOptions,\n} from 'src/tools/process'\nimport { createMcpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport { type FsManagerOptions, mcpRegisterFsManager } from 'src/tools/fs'\nimport { createErrorMiddleware } from 'src/server/createErrorMiddleware'\n\n/**\n * Get timestamped log file name\n */\nfunction createLogFileName(): string {\n const timestamp = new Date()\n .toISOString()\n .substring(0, 19)\n .replace(/T/, '_')\n .replace(/:/g, '-')\n return `mcp_${timestamp}.log`\n}\n\nexport type CreateServerOptions = {\n logFilePath: string\n}\n\nexport function createServer(options: CreateServerOptions): Express {\n const app = express()\n const baseRouter = createBaseRouter({\n logFilePath: options.logFilePath,\n })\n app.use(baseRouter)\n return app\n}\n\nexport type McpServerOptions = {\n name: string\n version: string\n authToken: string\n logFilePath: string\n enableJsonResponse?: boolean | null\n}\n\nexport function createMcpServer(options: McpServerOptions): {\n mcpServer: McpServer\n mcpRouter: Router\n} {\n const mcpServer = new McpServer({\n name: options.name,\n version: options.version,\n title: 'Project Tools',\n })\n\n const mcpRouter = createMcpRouter(mcpServer, options)\n\n return {\n mcpServer,\n mcpRouter,\n }\n}\n\nexport type CreateBaseRouterOptions = {\n logFilePath: string\n}\n\nexport function createBaseRouter(options: CreateBaseRouterOptions): Router {\n const router = express.Router()\n\n router.use(\n cors.default({\n origin: '*',\n credentials: true,\n allowedHeaders: [\n 'Content-Type',\n 'Authorization',\n 'X-Session-Id',\n 'mcp-session-id',\n ],\n exposedHeaders: ['mcp-session-id'],\n }),\n )\n router.use(express.json())\n // router.use(createRequestLoggerMiddleware({ logFilePath: options.logFilePath }))\n\n return router\n}\n\nexport function createMcpRouter(\n mcpServer: McpServer,\n options: McpServerOptions,\n): Router {\n const router = express.Router()\n\n router.use(createAuthMiddleware({ authToken: options.authToken }))\n\n router.all('/mcp', createStreamableHttpHandler(mcpServer, options))\n\n return router\n}\n\nexport type StartServerOptions = {\n host?: string | null\n port?: number | null\n logFilePath: string\n}\n\nexport function startServer(\n app: Express,\n options: StartServerOptions,\n): Promise<Server> {\n app.use(createErrorMiddleware({ logFilePath: options.logFilePath }))\n\n return new Promise<Server>((resolve, reject) => {\n let httpServer: Server\n\n const callback = () => {\n resolve(httpServer)\n }\n\n try {\n httpServer = options.host\n ? app.listen(options.port ?? 0, options.host, callback)\n : app.listen(options.port ?? 0, callback)\n httpServer.addListener('error', (err: Error) => {\n reject(err)\n })\n } catch (error) {\n reject(error)\n }\n })\n}\n\nexport function getMcpServerDescription(\n httpServer: Server,\n options: McpServerOptions,\n): string {\n const family = (httpServer.address() as any).family\n const port = (httpServer.address() as any).port\n let host = (httpServer.address() as any).address\n if (host === '::') {\n host = 'localhost'\n } else if (family === 'IPv6') {\n host = `[${host}]`\n }\n const serverUrl = `http://${family === 'IPv6' ? `[${host}]` : host}:${port}`\n\n return `Project Tools - MCP Server Started\n\nServer Name: ${options.name}\nServer Version: ${options.version}\nServer URL: ${serverUrl}/mcp\nSSE Endpoint: ${serverUrl}/sse\n\nLog File: ${path.resolve(options.logFilePath)}`\n}\n\nexport type StartMcpServerOptions = Omit<\n CreateServerOptions & McpServerOptions & StartServerOptions,\n 'logFilePath'\n> & {\n logDir: string\n tools: {\n processManager?: null | ProcessManagerOptions\n fsManager?: null | FsManagerOptions\n }\n}\n\nexport async function startMcpServer(\n options: StartMcpServerOptions,\n): Promise<Server> {\n const logFilePath = path.join(options.logDir, createLogFileName())\n\n const app = createServer({\n logFilePath,\n })\n\n const { mcpServer, mcpRouter } = createMcpServer({\n ...options,\n logFilePath,\n })\n app.use(mcpRouter)\n\n const mcpRegisterTool = createMcpRegisterToolFunc(mcpServer, {\n logFilePath,\n })\n\n if (options.tools.processManager) {\n mcpRegisterProcessManager(mcpRegisterTool, options.tools?.processManager)\n }\n\n if (options.tools.fsManager) {\n mcpRegisterFsManager(mcpRegisterTool, options.tools.fsManager)\n }\n\n const httpServer = await startServer(app, {\n host: options.host,\n port: options.port,\n logFilePath,\n })\n\n console.log(\n getMcpServerDescription(httpServer, {\n name: options.name,\n version: options.version,\n authToken: options.authToken,\n logFilePath,\n enableJsonResponse: options.enableJsonResponse,\n }),\n )\n\n return httpServer\n}\n"],"names":["process","ListSchema","commandList","path","walkPathHandleErrorDefault","priority","fs","link"],"mappings":";;;;;;;;;;;;;;;;;AASO,SAAS,qBAAqB,SAAsC;AACzE,QAAM,EAAE,cAAc;AACtB,SAAO,SAAS,eACd,KACA,KACA,MACM;AACN,UAAM,QACH,IAAI,MAAM,SACX,IAAI,QAAQ,eAAe,QAAQ,WAAW,EAAE;AAElD,QAAI,UAAU,WAAW;AACvB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gBAAgB;AAC9C;AAAA,IACF;AAEA,SAAA;AAAA,EACF;AACF;AClBA,eAAsB,UAAU,SAAoC;AAClE,QAAM,EAAE,aAAa,SAAS,KAAA,IAAS;AACvC,MAAI;AACF,UAAM,aAAY,oBAAI,QAAO,cAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AACjE,UAAM,UACJ,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAChE,UAAM,UAAU,IAAI,SAAS,KAAK,OAAO;AAAA,EAAK,OAAO;AAAA;AAAA;AACrD,UAAM,GAAG,SAAS,MAAM,KAAK,QAAQ,WAAW,GAAG,EAAE,WAAW,MAAM;AACtE,UAAM,GAAG,SAAS,WAAW,aAAa,OAAO;AAAA,EACnD,SAAS,KAAK;AACZ,YAAQ,MAAM,kBAAkB,OAAO,MAAM,GAAG;AAAA,EAClD;AACF;ACNO,MAAM,yCAAyB,IAAA;AAS/B,SAAS,4BACd,WACA,SACA;AACA,SAAO,eAAe,sBACpB,KACA,KACe;AACf,UAAM,YACH,IAAI,QAAQ,gBAAgB,KAC5B,IAAI,QAAQ,cAAc,KAC1B,IAAI,MAAM;AACb,QAAI;AAEJ,QAAI,IAAI,WAAW,QAAQ;AACzB,YAAM,UAAU;AAAA,QACd,aAAa,QAAQ;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,IAAI;AAAA,MAAA,CACX;AAED,UAAI,aAAa,mBAAmB,IAAI,SAAS,GAAG;AAClD,oBAAY,mBAAmB,IAAI,SAAS;AAAA,MAC9C,OAAO;AACL,oBAAY,IAAI,8BAA8B;AAAA,UAC5C,oBAAoB,MAClB,aAAa,YAAY,EAAE,EAAE,SAAS,KAAK;AAAA,UAC7C,sBAAsB,CAAC,OAAe;AACpC,+BAAmB,IAAI,IAAI,SAAS;AACpC,oBAAQ,IAAI,wBAAwB,EAAE,EAAE;AAAA,UAC1C;AAAA,UACA,oBAAoB,QAAQ,sBAAsB;AAAA,QAAA,CACnD;AAED,kBAAU,UAAU,MAAM;AACxB,cAAI,UAAU,WAAW;AACvB,+BAAmB,OAAO,UAAU,SAAS;AAC7C,oBAAQ,IAAI,mBAAmB,UAAU,SAAS,EAAE;AAAA,UACtD;AAAA,QACF;AAEA,cAAM,UAAU,QAAQ,SAAS;AAGjC,YAAI,WAAW;AACb,6BAAmB,IAAI,WAAW,SAAS;AAAA,QAC7C;AAAA,MACF;AAEiB,YAAM,UAAU,cAAc,KAAK,KAAK,IAAI,IAAI;AAAA,IACnE,WAAW,IAAI,WAAW,OAAO;AAC/B,UAAI,aAAa,mBAAmB,IAAI,SAAS,GAAG;AAClD,oBAAY,mBAAmB,IAAI,SAAS;AAC5C,cAAM,UAAU,cAAc,KAAK,GAAG;AAAA,MACxC,OAAO;AACL,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,oBAAoB;AAAA,MACpD;AAAA,IACF,OAAO;AACL,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sBAAsB;AAAA,IACtD;AAAA,EACF;AACF;AC7EO,SAAS,eAAe,SAAwC;AACrE,QAAM,EAAE,gBAAgB;AAExB,QAAM,QAAQ,YAAY,MAAM,mBAAmB;AACnD,SAAO,QAAQ,MAAM,CAAC,KAAK,MAAM,CAAC,IAAI,YAAY,MAAM,GAAG,EAAE,CAAC;AAChE;ACLO,MAAM,gCAAgB,IAAA;AAMtB,IAAI,gBAAgB;AAMpB,MAAM,gBAAgB;AAMtB,MAAM,uBAAuB,KAAK,KAAK;AAMvC,MAAM,eAAe;AAMrB,MAAM,uBAAuB;AAM7B,MAAM,eAAe;AAWrB,SAAS,iBAAiB,SAA2C;AAC1E,QAAM,EAAE,aAAa,gBAAA,IAAoB;AACzC,QAAM,UAAU,eAAe,EAAE,aAAa;AAC9C,SAAO,gBAAgB;AAAA,IACrB,aACE,YAAY,WAAW,QAAQ,YAAA,MAAkB,QAAQ,YAAA;AAAA,EAAY;AAE3E;AAMO,SAAS,mBAA2B;AACzC,SAAO,EAAE;AACX;AAEA,IAAI,sBAAsB;AAEnB,SAAS,yBAA+B;AAC7C,MAAI,qBAAqB;AACvB;AAAA,EACF;AACA,wBAAsB;AAEtB,QAAM,OAAO,MAAY;AACvB,YAAQ,IAAI,qCAAqC;AAEjD,eAAW,CAAC,IAAIA,QAAO,KAAK,MAAM,KAAK,UAAU,QAAA,CAAS,GAAG;AAC3D,UAAIA,SAAQ,aAAaA,SAAQ,KAAK;AACpC,YAAI;AACF,mBAASA,SAAQ,KAAK,SAAS;AAAA,QACjC,SAAS,KAAK;AACZ,kBAAQ,MAAM,yBAAyB,EAAE,KAAK,GAAG;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,GAAG,UAAU,IAAI;AACzB,UAAQ,GAAG,WAAW,IAAI;AAC5B;AC5FO,SAAS,sBAA4B;AAC1C,QAAM,MAAM,KAAK,IAAA;AACjB,QAAM,WAAqB,CAAA;AAE3B,aAAW,CAAC,IAAIA,QAAO,KAAK,MAAM,KAAK,UAAU,QAAA,CAAS,GAAG;AAC3D,QAAI,CAACA,SAAQ,aAAaA,SAAQ,SAAS;AACzC,YAAM,eAAe,MAAMA,SAAQ,QAAQ,QAAA;AAC3C,UAAI,eAAe,sBAAsB;AACvC,iBAAS,KAAK,EAAE;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,aAAW,MAAM,UAAU;AACzB,cAAU,OAAO,EAAE;AAAA,EACrB;AACF;ACXO,SAAS,oBAAoB,SAA2C;AAC7E,QAAM,EAAE,SAAAA,aAAY;AACpB,QAAM,MAAM,KAAK,IAAA;AACjB,QAAM,sBAAsB,MAAMA,SAAQ,eAAe,QAAA;AAEzD,MAAI,uBAAuB,sBAAsB;AAC/C,IAAAA,SAAQ,UAAUA,SAAQ;AAC1B,IAAAA,SAAQ,cAAc;AACtB,IAAAA,SAAQ,iBAAiB,IAAI,KAAK,GAAG;AAGrC,QAAIA,SAAQ,OAAO,SAAS,cAAc;AACxC,YAAM,UAAUA,SAAQ,OAAO,SAAS;AACxC,YAAM,cAAc;AAAA,OAAU,OAAO;AAAA;AACrC,YAAM,iBAAiB,eAAe,YAAY;AAElD,UAAI,iBAAiB,GAAG;AACtB,cAAM,OAAO,KAAK,MAAM,iBAAiB,CAAC;AAC1C,QAAAA,SAAQ,SACNA,SAAQ,OAAO,UAAU,GAAG,IAAI,IAChC,cACAA,SAAQ,OAAO;AAAA,UACbA,SAAQ,OAAO,UAAU,iBAAiB;AAAA,QAAA;AAAA,MAEhD,OAAO;AACL,QAAAA,SAAQ,SAASA,SAAQ,OAAO,UAAU,GAAG,YAAY;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AACF;ACnCO,SAAS,SAAS,MAAc,SAAkC;AACvE,QAAM,QAAQ,QAAQ,QAAQ;AAC9B,MAAI,KAAK,UAAU,MAAO,QAAO;AAEjC,QAAM,gBAAgB,KAAK,SAAS;AACpC,QAAM,cAAc;AAAA,OAAU,aAAa;AAAA;AAC3C,QAAM,kBAAkB,QAAQ,YAAY;AAE5C,MAAI,mBAAmB,GAAG;AACxB,WAAO,KAAK,UAAU,GAAG,KAAK;AAAA,EAChC;AAEA,QAAM,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAC3C,SACE,KAAK,UAAU,GAAG,IAAI,IACtB,cACA,KAAK,UAAU,KAAK,UAAU,kBAAkB,KAAK;AAEzD;ACZO,MAAM,eAAe,EAAE,OAAO;AAAA,EACnC,IAAI,EACD,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,SACA,IAAI,YAAY,EAChB,QAAQ,YAAY,EACpB;AAAA,IACC,sJAAsJ,YAAY,yBAAyB,YAAY;AAAA,EAAA;AAE7M,CAAC;AASD,eAAsB,cACpB,MACA,SAC8B;AAC9B,sBAAA;AAEA,QAAM,aAAa,aAAa,MAAM,IAAI;AAC1C,QAAM,EAAE,IAAI,YAAA,IAAgB;AAC5B,QAAMA,WAAU,UAAU,IAAI,EAAE;AAEhC,MAAI,CAACA,UAAS;AACZ,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,sBAAoB,EAAE,SAAAA,UAAS;AAE/B,QAAM,aAAaA,SAAQ,SAASA,SAAQ;AAC5C,QAAM,kBAAkB,SAAS,YAAY,EAAE,OAAO,aAAa;AAGnE,EAAAA,SAAQ,SAAS;AACjB,EAAAA,SAAQ,cAAc;AAEtB,SAAO;AAAA,IACL,IAAIA,SAAQ;AAAA,IACZ,KAAK,KAAK,SAAS,QAAQ,cAAc,IAAIA,SAAQ,GAAG;AAAA,IACxD,aAAaA,SAAQ;AAAA,IACrB,KAAKA,SAAQ;AAAA,IACb,WAAWA,SAAQ,UAAU,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,IACjE,SAASA,SAAQ,SAAS,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,IAC9D,UAAUA,SAAQ;AAAA,IAClB,WAAWA,SAAQ;AAAA,IACnB,QAAQ;AAAA,IACR,OAAOA,SAAQ;AAAA,EAAA;AAEnB;AAEO,SAAS,6BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,aAAa;AAAA,IAAA;AAAA,IAE5B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,cAAc,MAAM,OAAO;AAChD,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,0BAA0B,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACrH;AAAA,EAAA;AAEJ;ACvFO,SAAS,gBAAgB,KAAmB;AAEjD,WAAS,KAAK,WAAW,CAAC,QAAgB;AACxC,QAAI,OAAO,CAAC,IAAI,QAAQ,SAAS,WAAW,GAAG;AAC7C,cAAQ,MAAM,oCAAoC,GAAG,KAAK,GAAG;AAAA,IAC/D;AAAA,EACF,CAAC;AAGD,aAAW,MAAM;AACf,aAAS,KAAK,WAAW,CAAC,QAAgB;AACxC,UAAI,OAAO,CAAC,IAAI,QAAQ,SAAS,WAAW,GAAG;AAC7C,gBAAQ,MAAM,oCAAoC,GAAG,KAAK,GAAG;AAAA,MAC/D;AAAA,IACF,CAAC;AAAA,EACH,GAAG,YAAY;AACjB;ACXO,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EACD,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,QAAA,EACA,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,SACA,IAAI,YAAY,EAChB,QAAQ,YAAY,EACpB;AAAA,IACC,qIAAqI,YAAY,yBAAyB,YAAY;AAAA,EAAA;AAE5L,CAAC;AASD,eAAsB,YACpB,MACA,SAC8B;AAC9B,QAAM,aAAa,WAAW,MAAM,IAAI;AACxC,QAAM,EAAE,IAAI,UAAU,UAAU,gBAAgB;AAChD,QAAMA,WAAU,UAAU,IAAI,EAAE;AAEhC,MAAI,CAACA,UAAS;AACZ,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,QAAM,YAAY,KAAK,IAAA;AACvB,MAAI,mBAAmB;AACvB,MAAI,mBAAmB;AAEvB,MAAI,aAAa,QAAW;AAC1B,UAAM,cAAc,IAAI,QAAc,CAAA,YAAW;AAC/C,YAAM,gBAAgB,YAAY,MAAM;AACtC,YAAI,CAACA,SAAQ,WAAW;AACtB,wBAAc,aAAa;AAC3B,kBAAA;AAAA,QACF,WAAW,KAAK,IAAA,IAAQ,aAAa,WAAW,KAAM;AACpD,wBAAc,aAAa;AAC3B,6BAAmB;AAEnB,cAAI,YAAYA,SAAQ,KAAK;AAC3B,4BAAgBA,SAAQ,GAAG;AAC3B,+BAAmB;AAAA,UACrB;AAEA,kBAAA;AAAA,QACF;AAAA,MACF,GAAG,GAAG;AAAA,IACR,CAAC;AAED,UAAM;AAAA,EACR;AAEA,QAAM,gBAAgB,KAAK,IAAA,IAAQ,aAAa;AAChD,QAAM,SAAS,MAAM;AAAA,IACnB,EAAE,IAAI,YAAA;AAAA,IACN,EAAE,YAAY,QAAQ,WAAA;AAAA,EAAW;AAGnC,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;AAEO,SAAS,2BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,WAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,YAAY,MAAM,OAAO;AAC9C,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,wBAAwB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACnH;AAAA,EAAA;AAEJ;AC/FO,MAAM,YAAY,EAAE,OAAO;AAAA,EAChC,KAAK,EACF,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,QAAA,EACA,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,SACA,IAAI,YAAY,EAChB,QAAQ,YAAY,EACpB;AAAA,IACC,qLAAqL,YAAY,yBAAyB,YAAY;AAAA,EAAA;AAE5O,CAAC;AAUD,eAAsB,WACpB,MACA,SAC8B;AAC9B,sBAAA;AAEA,QAAM,aAAa,UAAU,MAAM,IAAI;AACvC,QAAM,EAAE,aAAa,UAAU,UAAU,gBAAgB;AACzD,QAAM,EAAE,oBAAoB;AAE5B,QAAM,MAAM,KAAK,QAAQ,QAAQ,cAAc,IAAI,WAAW,OAAO,EAAE;AAEvE,MAAI,CAAC,iBAAiB,EAAE,aAAa,gBAAA,CAAiB,GAAG;AACvD,WAAO;AAAA,MACL,OAAO,yBAAyB,WAAW,qGAAqG,gBAAgB,KAAK,IAAI,CAAC,kBAAkB,eAAe,EAAE,YAAA,CAAa,CAAC;AAAA,IAAA;AAAA,EAE/N;AAEA,QAAM,kBAAkB,MAAM,KAAK,UAAU,OAAA,CAAQ,EAAE;AAAA,IACrD,OAAK,EAAE;AAAA,EAAA;AAET,MAAI,gBAAgB,UAAU,eAAe;AAC3C,WAAO;AAAA,MACL,OAAO,6CAA6C,aAAa;AAAA,IAAA;AAAA,EAErE;AAEA,QAAM,KAAK,iBAAA;AACX,QAAM,cAA2B;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA,+BAAe,KAAA;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,oCAAoB,KAAA;AAAA,EAAK;AAG3B,YAAU,IAAI,IAAI,WAAW;AAE7B,MAAI;AACF,UAAM,QAAQ,MAAM,aAAa,IAAI;AAAA,MACnC,OAAO;AAAA,MACP;AAAA,MACA,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAAA,CAC/B;AAED,gBAAY,MAAM,MAAM;AAExB,UAAM,eAAe,CAAC,SAAuB;AAC3C,YAAM,OAAO,KAAK,SAAA;AAClB,kBAAY,eAAe;AAC3B,0BAAoB,EAAE,SAAS,aAAa;AAC5C,cAAQ,IAAI,IAAI;AAAA,IAClB;AAEA,UAAM,QAAQ,GAAG,QAAQ,YAAY;AACrC,UAAM,QAAQ,GAAG,QAAQ,YAAY;AAErC,UAAM,GAAG,SAAS,CAAA,SAAQ;AACxB,kBAAY,YAAY;AACxB,kBAAY,8BAAc,KAAA;AAC1B,kBAAY,WAAW,SAAS,OAAO,OAAO;AAG9C,kBAAY,UAAU,YAAY;AAClC,kBAAY,cAAc;AAE1B,UAAI,YAAY,OAAO,SAAS,cAAc;AAC5C,cAAM,UAAU,YAAY,OAAO,SAAS;AAC5C,cAAM,cAAc;AAAA,OAAU,OAAO;AAAA;AACrC,cAAM,iBAAiB,eAAe,YAAY;AAElD,YAAI,iBAAiB,GAAG;AACtB,gBAAM,OAAO,KAAK,MAAM,iBAAiB,CAAC;AAC1C,sBAAY,SACV,YAAY,OAAO,UAAU,GAAG,IAAI,IACpC,cACA,YAAY,OAAO;AAAA,YACjB,YAAY,OAAO,UAAU,iBAAiB;AAAA,UAAA;AAAA,QAEpD,OAAO;AACL,sBAAY,SAAS,YAAY,OAAO,UAAU,GAAG,YAAY;AAAA,QACnE;AAAA,MACF;AAEA,cAAQ,IAAI,WAAW,EAAE,KAAK,WAAW,sBAAsB,IAAI,EAAE;AAAA,IACvE,CAAC;AAED,UAAM,GAAG,SAAS,CAAA,QAAO;AACvB,kBAAY,YAAY;AACxB,kBAAY,8BAAc,KAAA;AAC1B,kBAAY,QAAQ,IAAI;AACxB,cAAQ,MAAM,WAAW,EAAE,WAAW,IAAI,OAAO;AAAA,IACnD,CAAC;AAGD,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,QACL,EAAE,IAAI,UAAU,UAAU,YAAA;AAAA,QAC1B,EAAE,YAAY,QAAQ,WAAA;AAAA,MAAW;AAAA,IAErC;AAEA,WAAO;AAAA,MACL,EAAE,IAAI,YAAA;AAAA,MACN,EAAE,YAAY,QAAQ,WAAA;AAAA,IAAW;AAAA,EAErC,SAAS,KAAK;AACZ,gBAAY,YAAY;AACxB,gBAAY,8BAAc,KAAA;AAC1B,gBAAY,QAAQ,eAAe,QAAQ,IAAI,UAAU;AACzD,WAAO,EAAE,OAAO,YAAY,MAAA;AAAA,EAC9B;AACF;AAEO,SAAS,0BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aAAa,6hBAA6hB,QAAQ,gBAAgB,KAAK,IAAI,CAAC;AAAA,MAC5kB,aAAa,UAAU;AAAA,IAAA;AAAA,IAEzB,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,WAAW,MAAM,OAAO;AAC7C,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,uBAAuB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IAClH;AAAA,EAAA;AAEJ;AC5LO,MAAMC,eAAa,EAAE,OAAO;AAAA,EACjC,iBAAiB,EACd,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,kBAAkB,EACf,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,YAAY,EACT,QAAA,EACA,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,QAAQ,EACL,MAAM,EAAE,QAAQ,EAChB,WACA;AAAA,IACC;AAAA,EAAA;AAEN,CAAC;AASD,eAAsBC,cACpB,MACA,SAC8B;AAC9B,sBAAA;AAEA,QAAM,aAAaD,aAAW,MAAM,IAAI;AACxC,QAAM,EAAE,iBAAiB,kBAAkB,YAAY,WAAW;AAElE,MAAI,cAAc,MAAM,KAAK,UAAU,QAAQ;AAE/C,MAAI,iBAAiB;AACnB,UAAM,UAAU,IAAI,KAAK,gBAAgB,QAAQ,UAAU,GAAG,CAAC;AAC/D,kBAAc,YAAY,OAAO,CAAA,MAAK,EAAE,aAAa,OAAO;AAAA,EAC9D;AAEA,MAAI,kBAAkB;AACpB,UAAM,UAAU,IAAI,KAAK,iBAAiB,QAAQ,UAAU,GAAG,CAAC;AAChE,kBAAc,YAAY,OAAO,CAAA,MAAK,EAAE,WAAW,EAAE,WAAW,OAAO;AAAA,EACzE;AAEA,MAAI,YAAY;AACd,kBAAc,YAAY,OAAO,CAAA,MAAK,EAAE,SAAS;AAAA,EACnD;AAEA,QAAM,SAAS,YAAY,IAAI,CAAAD,aAAW;AACxC,wBAAoB,EAAE,SAAAA,UAAS;AAE/B,QAAI,cAAmC;AAAA,MACrC,IAAIA,SAAQ;AAAA,MACZ,KAAKG,cAAK,SAAS,QAAQ,cAAc,IAAIH,SAAQ,GAAG;AAAA,MACxD,aAAaA,SAAQ;AAAA,MACrB,KAAKA,SAAQ;AAAA,MACb,WAAWA,SAAQ,UAAU,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,MACjE,SAASA,SAAQ,SAAS,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,MAC9D,UAAUA,SAAQ;AAAA,MAClB,WAAWA,SAAQ;AAAA,MACnB,QAAQA,SAAQ,SAASA,SAAQ;AAAA,MACjC,OAAOA,SAAQ;AAAA,IAAA;AAGjB,QAAI,QAAQ;AACV,YAAM,WAAgC,CAAA;AACtC,iBAAW,SAAS,QAAQ;AAC1B,YAAI,SAAS,aAAa;AACxB,mBAAS,KAAK,IAAI,YAAY,KAAK;AAAA,QACrC;AAAA,MACF;AACA,oBAAc;AAAA,IAChB;AAEA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,WAAW,OAAA;AACtB;AAEO,SAAS,2BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAaC,aAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAMC,cAAY,MAAM,OAAO;AAC9C,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,wBAAwB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACnH;AAAA,EAAA;AAEJ;AChHO,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EACD,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAEN,CAAC;AAKM,SAAS,YACd,MACqB;AACrB,QAAM,aAAa,WAAW,MAAM,IAAI;AACxC,QAAM,EAAE,OAAO;AACf,QAAMF,WAAU,UAAU,IAAI,EAAE;AAEhC,MAAI,CAACA,UAAS;AACZ,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI,CAACA,SAAQ,WAAW;AACtB,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI,CAACA,SAAQ,KAAK;AAChB,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI;AACF,oBAAgBA,SAAQ,GAAG;AAC3B,WAAO,EAAE,SAAS,MAAM,SAAS,+BAA+B,EAAE,GAAA;AAAA,EACpE,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,OAAO,+BAA+B,EAAE,KAAK,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,IAAA;AAAA,EAErG;AACF;AAEO,SAAS,2BACd,iBACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,WAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,YAAY,IAAI;AAC/B,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,wBAAwB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACnH;AAAA,EAAA;AAEJ;ACvDO,SAAS,0BACd,iBACA,SACM;AACN,yBAAA;AAEA,4BAA0B,iBAAiB;AAAA,IACzC,YAAY,QAAQ;AAAA,IACpB,GAAG,QAAQ;AAAA,EAAA,CACZ;AACD,+BAA6B,iBAAiB;AAAA,IAC5C,YAAY,QAAQ;AAAA,EAAA,CACrB;AACD,6BAA2B,iBAAiB;AAAA,IAC1C,YAAY,QAAQ;AAAA,EAAA,CACrB;AACD,6BAA2B,iBAAiB;AAAA,IAC1C,YAAY,QAAQ;AAAA,EAAA,CACrB;AACD,6BAA2B,eAAe;AAE1C,UAAQ;AAAA,IACN;AAAA,uBACmB,KAAK,QAAQ,QAAQ,cAAc,EAAE,CAAC;AAAA,sBACvC,QAAQ,IAAI,gBAAgB,KAAK,IAAI,CAAC;AAAA;AAAA,EAAA;AAG5D;ACbO,SAAS,0BACd,QACA,SACqB;AACrB,SAAO,SAAS,gBAGd,MAAM,QAAQ,UAAU;AACxB,UAAM,iBAAkB,UAAU,SAAS;AACzC,YAAM,UAAU;AAAA,QACd,aAAa,QAAQ;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,EAAE,MAAM,KAAA;AAAA,MAAK,CACpB;AAED,YAAM,SAAS,MAAM,SAAS,GAAG,IAAI;AAErC,YAAM,UAAU;AAAA,QACd,aAAa,QAAQ;AAAA,QACrB,SAAS;AAAA,QACT,MAAM;AAAA,MAAA,CACP;AAED,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UAAA;AAAA,QACR;AAAA,MACF;AAAA,IAEJ;AAEA,WAAO,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;ACnEO,SAAS,SAASG,OAAsB;AAC7C,SAAOA,MAAK,MAAM,gBAAgB,EAAG,CAAC;AACxC;AAEO,SAAS,UAAUA,OAAc,MAAwB;AAC9D,SAAO,SAASA,KAAI,IAAI,MAAM,KAAK;AACrC;AAEO,SAAS,YAAY,OAAuB;AACjD,MAAI,MAAM,SAAS,GAAG,GAAG;AAEvB,aAAS;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,KAAK;AAC3B;ACdO,MAAM,SAAgB,IAAI,KAAK,GAAG,KAAA,EAAO,MAAM;ACwEtD,SAAS,SAAS,WAAyB,UAAwB;AACjE,YAAU,aAAa,SAAS;AAChC,YAAU,sBAAsB,KAAK;AAAA,IACnC,UAAU;AAAA,IACV,SAAS;AAAA,EAAA;AAEX,YAAU,cAAc,SAAS;AACjC,YAAU,aAAa,SAAS;AAChC,YAAU,cAAc,SAAS;AACnC;AAEO,MAAM,6BACX,SAASC,4BAA2B,KAAU;AAC5C,MAAI,IAAI,SAAS,UAAU;AACzB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGF,SAAS,WAAW,SAAiD;AACnE,QAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,WAAO,QAAQ,QAAQ;AAAA,MACrB,WAAW;AAAA,MACX,qBAAqB;AAAA,MACrB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,YAAY;AAAA,IAAA,CACb;AAAA,EACH;AACA,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,YAAY,QAAQ,aAAa,oBAAI,IAAA;AAC3C,QAAM,cAAc,QAAQ;AAC5B,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,cAAc,QAAQ;AAC5B,QAAM,WAAW,QAAQ,YAAY,eAAe,CAAC;AACrD,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,aAAa,QAAQ;AAC3B,QAAM,aAAa,QAAQ;AAC3B,QAAM,YAAY,QAAQ;AAE1B,iBAAe,aAAa,KAAU;AACpC,QAAI,aAAa;AACf,UAAI,MAAM,YAAY,GAAG,GAAG;AAC1B,eAAO;AAAA,MACT;AAAA,IACF;AACA,QAAI,2BAA2B,GAAG,GAAG;AACnC,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AAEA,WAAS,OAAO,UAAkB;AAChC,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AACA,QACE,WAAW,uBAAuB,QAClC,WAAW,WAAW,qBACtB;AACA,aAAO;AAAA,IACT;AACA,QACE,WAAW,kBAAkB,QAC7B,QAAQ,WAAW,gBACnB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,SAAO,mBAAmB,OAAM,iBAAgB;AAC9C,UAAM,sBAAsB,oBAAoB,aAAa,YAAY;AAEzE,UAAM,YAA0B;AAAA,MAC9B,WAAW;AAAA,MACX,qBAAqB;AAAA,MACrB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,YAAY;AAAA,IAAA;AAGd,aAAS,QAAQ,UAAkB,UAAwB;AACzD,UAAI,OAAO,SAAS,SAAS,GAAG;AAE9B,cAAM,UAAU,SAAS,UACtB,eAAe,OAAO,EACtB,QAAQ,MAAM,GAAG,EACjB,SAAS,EAAE;AACd,cAAM,UAAU,GAAG,OAAO,KAAK,QAAQ;AACvC,YAAI,YAAY,WAAW;AACzB,qBAAW,UAAU,OAAO;AAAA,QAC9B,OAAO;AACL,kBAAQ,IAAI,OAAO;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,mBAAe,YACb,UACA,MACA,UACAC,WACkB;AAClB,UAAI,CAAC,YAAY;AACf,eAAO;AAAA,MACT;AACA,aAAO,MAAM,YAAY;AAAA,QACvB;AAAA,QACA,MAAM,YAAY;AAChB,cAAI;AACF,mBAAO,MAAM,WAAW;AAAA,cACtB;AAAA,cACA,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA,aAAa;AAAA,YAAA,CACd;AAAA,UACH,SAAS,KAAK;AACZ,kBAAM,aAAa,GAAG;AACtB,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,QACA,OAAO;AAAA,QACP,UAAAA;AAAAA,QACA,aAAa;AAAA,MAAA,CACd;AAAA,IACH;AAEA,mBAAe,YAEb,kBACA,OACA,aAEA,kBAC8B;AAC9B,UAAI,CAAC,kBAAkB;AACrB,2BAAmB;AAAA,MACrB;AAEA,YAAM,OAAO,MAAM,YAAY;AAAA,QAC7B;AAAA,QACA,MAAM,MAAMC,YAAG,SAAS,MAAM,gBAAgB,EAAE,MAAM,YAAY;AAAA,QAClE,OAAO;AAAA,QACP,UAAU,eAAe,OAAO,eAAe,GAAG,QAAQ,CAAC;AAAA,QAC3D,aAAa;AAAA,MAAA,CACd;AAED,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,eAAe,KAAK,UAAU;AACjC,eAAO;AAAA,MACT;AAGA,YAAM,SAAS,UAAU,kBAAkB,IAAI;AAC/C,UAAI,UAAU,IAAI,MAAM,GAAG;AACzB,eAAO;AAAA,MACT;AACA,gBAAU,IAAI,MAAM;AAEpB,UAAI,WAAyB;AAAA,QAC3B,WAAW,KAAK;AAAA,QAChB,qBAAqB,KAAK,YAAA,IAAgB,IAAI,KAAK;AAAA,QACnD,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,YAAY;AAAA,MAAA;AAGd,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,eAAe,KAAK,YAAA,IAAgB,IAAI,GAAG,QAAQ;AAAA,MAAA;AAGrD,UAAI,KAAK,kBAAkB;AACzB,YAAI,WAAW;AACb,gBAAM,OAAgB,MAAM,YAAY;AAAA,YACtC;AAAA,YACA,MAAM,MACJA,YAAG,SACA,SAAS,gBAAgB,EACzB,MAAM,YAAY,EAClB,KAAK,CAAAC,UAAQA,SAAQ,IAAI;AAAA,YAC9B,OAAO;AAAA,YACP,UAAU;AAAA,YACV,aAAa;AAAA,UAAA,CACd;AAED,cAAI,MAAM;AACR,kBAAM,eAAe,KAAK,WAAW,IAAI,IAAI,OAAO,KAAK,QAAQ,KAAK,QAAQ,gBAAgB,GAAG,IAAI;AACrG,kBAAM,iBAAiB,MAAM,YAAY,cAAc,OAAO,aAAa,gBAAgB;AAC3F,gBAAI,gBAAgB;AAClB,yBAAW;AAAA,YACb;AAAA,UACF;AAAA,QACF;AACA,iBAAS,aAAa;AAEtB,YACE,eACA,SAAS,aAAa,SAAS,YAAY,SAAS,aAAa,GACjE;AACA,gBAAM,gBAAgB,MAAM;AAAA,YAC1B;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAEF,cAAI,eAAe;AACjB,qBAAS,WAAW,QAAQ;AAC5B,oBAAQ,kBAAkB,QAAQ;AAAA,UACpC;AAAA,QACF;AAEA,eAAO;AAAA,MACT,WAAW,KAAK,eAAe;AAE7B,cAAM,WAAW,MAAM,YAAY;AAAA,UACjC;AAAA,UACA,MAAM,MAAMD,YAAG,SAAS,QAAQ,gBAAgB,EAAE,MAAM,YAAY;AAAA,UACpE,OAAO;AAAA,UACP;AAAA,UACA,aAAa;AAAA,QAAA,CACd;AAED,YAAI,UAAU;AACZ,mBAAS,IAAI,GAAG,MAAM,SAAS,QAAQ,IAAI,KAAK,KAAK;AACnD,qBAAS,CAAC,IAAI,KAAK,KAAK,kBAAkB,SAAS,CAAC,CAAC;AAAA,UACvD;AACA,qBAAW,MAAM,WAAW;AAAA,YAC1B,GAAG;AAAA,YACH,OAAO;AAAA,YACP,aAAa;AAAA,YACb,UAAU;AAAA,YACV,OAAO,QAAQ;AAAA,YACf;AAAA,UAAA,CACD;AAAA,QACH;AACA,iBAAS,aAAa;AAAA,MACxB,WAAW,KAAK,UAAU;AACxB,iBAAS,cAAc;AAAA,MACzB;AAEA,UACE,eACA,SAAS,aAAa,SAAS,YAAY,SAAS,aAAa,GACjE;AACA,cAAM,gBAAgB,MAAM;AAAA,UAC1B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAEF,YAAI,eAAe;AACjB,mBAAS,WAAW,QAAQ;AAC5B,kBAAQ,kBAAkB,QAAQ;AAAA,QACpC;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,WAA2C,CAAA;AACjD,aAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,YAAM,WAAW,YAAY,MAAM,CAAC,CAAC;AACrC,YAAM,cAAc,YAAY,UAAU,QAAQ,IAAI;AACtD,UAAI,gBAAgB,OAAO;AACzB;AAAA,MACF;AACA,eAAS,KAAK,YAAY,UAAU,GAAG,WAAW,CAAC;AAAA,IACrD;AAEA,UAAM,QAAQ,IAAI,QAAQ;AAE1B,WAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,UAAU,SAAiD;AACzE,SAAO,WAAW,OAAO;AAC3B;AC5VO,SAAS,eAAe,MAAc,cAA8B;AACzE,MAAI,CAAC,gBAAgB,iBAAiB,KAAK;AACzC,WAAO;AAAA,EACT;AACA,QAAM,UAAU,KAAK,WAAW,GAAG;AACnC,MAAI,SAAS;AACX,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AACA,QAAM,WAAW,KAAK,WAAW,GAAG;AACpC,MAAI,UAAU;AACZ,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AAEA,MAAI,KAAK,WAAW,GAAG,GAAG;AACxB,QAAI,aAAa,SAAS,GAAG,GAAG;AAC9B,qBAAe,aAAa,UAAU,GAAG,aAAa,SAAS,CAAC;AAAA,IAClE;AACA,WAAO,eAAe;AAAA,EACxB,OAAO;AACL,QAAI,CAAC,aAAa,SAAS,GAAG,GAAG;AAC/B,sBAAgB;AAAA,IAClB;AACA,QAAI,KAAK,WAAW,IAAI,GAAG;AACzB,aAAO,eAAe,KAAK,UAAU,CAAC;AAAA,IACxC,WAAW,KAAK,WAAW,KAAK,GAAG;AACjC,aAAO,eAAe;AAAA,IACxB,OAAO;AACL,UAAI,aAAa,WAAW,IAAI,GAAG;AACjC,uBAAe;AAAA,MACjB;AACA,UAAI,KAAK,WAAW,IAAI,GAAG;AACzB,eAAO,eAAe;AAAA,MACxB,OAAO;AACL,eAAO,eAAe,QAAQ;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,UAAU,IAAI,EAAE,QAAQ,OAAO,GAAG;AAE9C,MAAI,UAAU;AACZ,WAAO,MAAM;AAAA,EACf;AACA,MAAI,SAAS;AACX,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;AC5DO,SAAS,yBAAyB,MAAsB;AAC7D,QAAM,WAAW,KAAK,WAAW,GAAG;AACpC,MAAI,UAAU;AACZ,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AAGA,MAAI,KAAK,WAAW,GAAG,GAAG;AACxB,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB,WAAW,CAAC,KAAK,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,KAAK,GAAG;AAC5D,WAAO,MAAM,IAAI;AAAA,EACnB;AACA,MAAI,UAAU;AACZ,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;ACWA,SAAS,YAAY,MAAsB;AACzC,SAAO,MAAM;AACf;AAEA,eAAsB,kBAAkB,UAAqC;AAC3E,QAAM,UAAU,MAAM,GAAG,SAAS,SAAS,UAAU,OAAO;AAC5D,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,QAAkB,CAAA;AACxB,QAAM,QAAQ,CAAA,SAAQ;AACpB,WAAO,KAAK,KAAA;AACZ,QAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,GAAG;AACjC;AAAA,IACF;AACA,UAAM,KAAK,IAAI;AAAA,EACjB,CAAC;AACD,SAAO;AACT;AAEA,eAAsB,UAAU,SAA8C;AAC5E,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,SAAmB,CAAA;AACzB,MAAI,CAAC,QAAQ,OAAO,QAAQ;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,qBAA6B,CAAA;AACnC,UAAQ,MAAM,QAAQ,CAAA,SAAQ;AAC5B,QAAI,CAAC,KAAK,OAAO;AACf;AAAA,IACF;AACA,QAAI,KAAK,cAAc,0BAA0B;AAC/C,yBAAmB,KAAK,IAAI;AAAA,IAC9B,WAAW,KAAK,cAAc,WAAW;AACvC,aAAO,KAAK,KAAK,UAAU,YAAY,KAAK,KAAK,IAAI,KAAK,KAAK;AAAA,IACjE;AAAA,EACF,CAAC;AACD,MAAI,mBAAmB,QAAQ;AAC7B,UAAM,QAAQ;AAAA,MACZ,mBAAmB,IAAI,OAAM,SAAQ;AACnC,cAAM,YAAY;AAAA,UAChB,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM,YAAY;AAChB,kBAAM,WAAW,KAAK,QAAQ,SAAS,KAAK,KAAK;AACjD,kBAAM,QAAQ,MAAM,kBAAkB,QAAQ;AAC9C,kBAAM,eAAe,KAAK,SAAS,SAAS,KAAK,QAAQ,QAAQ,CAAC;AAClE,kBAAM,QAAQ,CAAA,cAAa;AACzB,0BAAY,yBAAyB,SAAS;AAC9C,0BAAY,eAAe,WAAW,YAAY;AAClD,qBAAO,KAAK,KAAK,UAAU,YAAY,SAAS,IAAI,SAAS;AAAA,YAC/D,CAAC;AAAA,UACH;AAAA,QAAA,CACD;AAAA,MACH,CAAC;AAAA,IAAA;AAAA,EAEL;AACA,SAAO;AACT;ACpDO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAAsC;AAQpC,QAAM,aAA0B,CAAA;AAChC,QAAM,QAAQ,CAAA,SAAQ;AACpB,WAAO,KAAK,QAAQ,OAAO,GAAG,EAAE,KAAA;AAChC,UAAM,UAAU,KAAK,WAAW,GAAG;AACnC,QAAI,SAAS;AACX,aAAO,KAAK,UAAU,CAAC,EAAE,KAAA;AAAA,IAC3B;AACA,UAAM,WAAW,KAAK,WAAW,GAAG;AACpC,QAAI,UAAU;AACZ,aAAO,KAAK,UAAU,CAAC,EAAE,KAAA;AAAA,IAC3B;AACA,QAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,GAAG;AAChD,YAAM,IAAI;AAAA,QACR,0BAA0B,IAAI,kBAAkB,KAAK,UAAU,GAAG,CAAC,CAAC;AAAA,MAAA;AAAA,IAExE;AACA,QAAI,KAAK,WAAW,GAAG,GAAG;AACxB,aAAO,MAAM;AAAA,IACf;AAEA,UAAM,eAAe,UACjB,KAAK,QAAQ,SAAS,IAAI,EAAE,QAAQ,OAAO,GAAG,IAC9C;AAEJ,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,gBAAU,UAAU,cAAc;AAAA,QAChC,QAAQ,UAAU;AAAA,QAClB,KAAK;AAAA,QACL,gBAAgB;AAAA;AAAA,MAAA,CACjB;AAAA,IACH,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,0BAA0B,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAAA;AAAA,IAEhG;AAEA,eAAW,KAAK;AAAA,MACd;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,OAAO;AAAA,IAAA,CACR;AAAA,EACH,CAAC;AAED,SAAO,SAAS,UAAU,OAAe;AACvC,YAAQ,MAAM,QAAQ,OAAO,GAAG;AAChC,QAAI,UAA0B;AAC9B,QAAI,UAAU;AACd,aAAS,IAAI,GAAG,MAAM,WAAW,QAAQ,IAAI,KAAK,KAAK;AACrD,YAAM,YAAY,WAAW,CAAC;AAC9B,YAAM,kBAAkB,UAAU,MAAM,KAAK;AAC7C,UAAI,iBAAiB;AACnB,YAAI,UAAU,SAAS;AACrB,oBAAU,CAAC,UAAU;AAAA,QACvB,OAAO;AACL,oBAAU,CAAC,UAAU;AACrB,oBAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AACA,WAAO,UAAU,QAAQ;AAAA,EAC3B;AACF;AC/DA,eAAsB,YACpB,SACyB;AACzB,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,QAAwB,CAAA;AAC9B,QAAM,SAAwB,CAAA;AAC9B,MAAI,QAAQ,OAAO,YAAY;AAC7B,WAAO,aAAa;AAAA,EACtB;AACA,MAAI,QAAQ,OAAO,MAAM;AACvB,WAAO,OAAO;AAAA,EAChB;AAGA,QAAM,QAAQ,MAAM,UAAU;AAAA,IAC5B;AAAA,IACA,OAAO,QAAQ;AAAA,EAAA,CAChB;AAED,QAAM,UAAU;AAAA,IACd,OAAO,CAAC,OAAO;AAAA,IACf,WAAW;AAAA,IACX,WAAW,gBAAgB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AAAA,IACD,YAAY,OAAO,EAAE,MAAM,UAAU,MAAM,eAAe;AACxD,YAAM,eAAe,KAAK,SAAS,SAAS,QAAQ;AAEpD,YAAM,QAAQ,KAAK,YAAA;AACnB,YAAM,SAAS,KAAK,OAAA;AACpB,UAAI,CAAC,SAAS,CAAC,QAAQ;AAErB,eAAO;AAAA,MACT;AAEA,YAAM,SAAS,gBAAgB,KAAK,QAAQ,OAAO,GAAG;AACtD,YAAM,OAAO,QAAQ,QAAQ;AAC7B,YAAM,eAAe,QACjB,SAAS,uBAAuB,OAChC,KAAK;AACT,YAAM,OAAO,QAAQ,SAAS,YAAY,KAAK;AAC/C,YAAM,aAAa,QAAQ,SAAS,aAAa;AAEjD,YAAM,OAAqB;AAAA,QACzB,MAAM;AAAA,QACN;AAAA,MAAA;AAEF,UAAI,QAAQ,OAAO,cAAc;AAC/B,aAAK,eAAe;AAAA,MACtB;AACA,UAAI,QAAQ,OAAO,MAAM;AACvB,aAAK,OAAO;AAAA,MACd;AACA,UAAI,QAAQ,OAAO,YAAY;AAC7B,aAAK,aAAa;AAAA,MACpB;AAGA,UAAI,QAAQ,gBAAgB,gBAAgB,MAAM;AAChD,cAAM,CAAC,SAAS,OAAO,IAAI,QAAQ;AACnC,YACG,WAAW,QAAQ,eAAe,WAClC,WAAW,QAAQ,eAAe,SACnC;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,UAAI,QAAQ,aAAa,QAAQ,MAAM;AACrC,cAAM,CAAC,SAAS,OAAO,IAAI,QAAQ;AACnC,YACG,WAAW,QAAQ,OAAO,WAC1B,WAAW,QAAQ,OAAO,SAC3B;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAIA,UAAI,SAAS,QAAQ;AAEnB,eAAO,cAAc,OAAO,cAAc,KAAK;AAAA,MACjD;AAEA,UAAI,SAAS,UAAU,QAAQ,MAAM;AACnC,eAAO,QAAQ,OAAO,QAAQ,KAAK;AAAA,MACrC;AAEA,UACE,gBAAgB,SACf,OAAO,gBAAgB,QAAQ,eAAe,OAAO,eACtD;AACA,eAAO,eAAe;AAAA,MACxB;AAGA,UAAI,SAAS,CAAC,QAAQ,OAAO,MAAM;AACjC,eAAO;AAAA,MACT;AACA,UAAI,UAAU,CAAC,QAAQ,OAAO,OAAO;AACnC,eAAO;AAAA,MACT;AAEA,YAAM,KAAK,IAAI;AACf,aAAO;AAAA,IACT;AAAA,EAAA,CACD;AAED,SAAO,EAAE,OAAO,OAAA;AAClB;ACtIA,MAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,MAAM,IAAI;AAC1C,MAAM,YAAY;AAElB,SAAS,eAAe,OAA0C;AAChE,MAAI,SAAS,KAAM,QAAO;AAE1B,MAAI,QAAQ,SAAS;AACrB,MAAI,YAAY;AAEhB,SAAO,SAAS,aAAa,YAAY,MAAM,SAAS,GAAG;AACzD,aAAS;AACT;AAAA,EACF;AAEA,QAAM,YAAY,cAAc,IAAI,MAAM,aAAa,MAAM,QAAQ,CAAC;AACtE,SAAO,GAAG,SAAS,GAAG,MAAM,SAAS,CAAC;AACxC;AAEA,SAAS,cAAc,WAA2B;AAChD,QAAM,MAAM,KAAK,IAAA;AACjB,QAAM,SAAS,MAAM;AAErB,MAAI,SAAS,EAAG,QAAO;AAEvB,QAAM,cAAc,KAAK,MAAM,SAAS,GAAI;AAC5C,QAAM,cAAc,KAAK,MAAM,cAAc,EAAE;AAC/C,QAAM,YAAY,KAAK,MAAM,cAAc,EAAE;AAC7C,QAAM,WAAW,KAAK,MAAM,YAAY,EAAE;AAC1C,QAAM,YAAY,KAAK,MAAM,WAAW,CAAC;AACzC,QAAM,aAAa,KAAK,MAAM,WAAW,EAAE;AAC3C,QAAM,YAAY,KAAK,MAAM,WAAW,GAAG;AAE3C,MAAI,YAAY,EAAG,QAAO,GAAG,SAAS;AACtC,MAAI,aAAa,EAAG,QAAO,GAAG,UAAU;AACxC,MAAI,YAAY,EAAG,QAAO,GAAG,SAAS;AACtC,MAAI,WAAW,EAAG,QAAO,GAAG,QAAQ;AACpC,MAAI,YAAY,EAAG,QAAO,GAAG,SAAS;AACtC,MAAI,cAAc,EAAG,QAAO,GAAG,WAAW;AAC1C,SAAO,GAAG,WAAW;AACvB;AAEA,SAAS,aACP,UACA,MACgB;AAChB,MAAI,CAAC,MAAM,OAAQ,QAAO;AAE1B,SAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM;AAClC,aAAS,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC/C,YAAM,aAAa,KAAK,CAAC;AACzB,UAAI;AACJ,UAAI;AAEJ,cAAQ,WAAW,OAAA;AAAA,QACjB,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,MAAA;AAGJ,UAAI,UAAU,MAAM;AAClB,YAAI,UAAU,MAAM;AAClB;AAAA,QACF;AACA,eAAO;AAAA,MACT;AACA,UAAI,UAAU,MAAM;AAClB,eAAO;AAAA,MACT;AAEA,YAAM,aAAa,SAAS,SAAS,IAAI,SAAS,SAAS,KAAK;AAChE,UAAI,eAAe,GAAG;AACpB,eAAO,WAAW,OAAO,CAAC,aAAa;AAAA,MACzC;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,iBACd,gBACA,SACQ;AACR,QAAM,aAAa,aAAa,eAAe,OAAO,QAAQ,QAAQ,EAAE;AACxE,QAAM,SACJ,QAAQ,UAAU,QAAQ,OAAO,SAAS,IAAI,QAAQ,SAAS,CAAA;AAEjE,MAAI,SAAS;AAGb,MAAI,WAAW,SAAS,KAAK,OAAO,SAAS,GAAG;AAE9C,aAAS,IAAI,GAAG,MAAM,OAAO,QAAQ,IAAI,KAAK,KAAK;AACjD,YAAM,QAAQ,OAAO,CAAC;AACtB,UAAI,IAAI,EAAG,WAAU;AACrB,cAAQ,OAAA;AAAA,QACN,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,MAAA;AAAA,IAEN;AAGA,aAAS,IAAI,GAAG,MAAM,WAAW,QAAQ,IAAI,KAAK,KAAK;AACrD,YAAM,OAAO,WAAW,CAAC;AACzB,gBAAU;AAEV,eAAS,IAAI,GAAG,YAAY,OAAO,QAAQ,IAAI,WAAW,KAAK;AAC7D,cAAM,QAAQ,OAAO,CAAC;AACtB,YAAI,IAAI,EAAG,WAAU;AAErB,gBAAQ,OAAA;AAAA,UACN,KAAK;AACH,sBAAU,KAAK,eAAe,cAAc,KAAK,YAAY,IAAI;AACjE;AAAA,UACF,KAAK;AACH,sBAAU,eAAe,KAAK,IAAI;AAClC;AAAA,UACF,KAAK;AACH,sBAAU,KAAK;AACf;AAAA,UACF,KAAK;AACH,sBAAU,KAAK,SAAS,QAAQ,GAAG,KAAK,IAAI,MAAM,KAAK;AACvD;AAAA,UACF,KAAK;AACH,gBAAI,KAAK,SAAS,OAAO;AACvB,wBACE,KAAK,cAAc,OAAO,KAAK,WAAW,aAAa;AAAA,YAC3D,OAAO;AACL,wBAAU;AAAA,YACZ;AACA;AAAA,QAAA;AAAA,MAEN;AAAA,IACF;AAAA,EACF;AAGoB;AAClB,QAAI,OAAO,SAAS,GAAG;AACrB,gBAAU;AAAA,IACZ;AAEA,UAAM,qBAAqB,eAAe,eAAe,OAAO,QAAQ,CAAC;AACzE,UAAM,mBAAmB,eAAe,OAAO,eAC3C,mBAAmB,cAAc,eAAe,OAAO,YAAY,CAAC,SACpE;AAEJ,cAAU,WAAW,eAAe,OAAO,cAAc,CAAC,mBAAmB,kBAAkB,GAAG,gBAAgB;AAAA,EACpH;AAEA,SAAO;AACT;AC9MO,MAAM,cAAc;AACpB,MAAM,iBAAiB;AACvB,MAAM,aACX;AAEK,MAAM,oBAAoB;ACYjC,SAAS,aAAa,YAA4B;AAChD,QAAM,QAAQ,WAAW;AAAA,IACvB;AAAA,EAAA;AAEF,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR,6BAA6B,UAAU;AAAA,IAAA;AAAA,EAE3C;AAEA,QAAM,QAAQ,WAAW,MAAM,CAAC,CAAC;AACjC,MAAI,OAAO,MAAM,CAAC;AAClB,MAAI,SAAS,KAAK;AAChB,WAAO,KAAK,YAAA;AACZ,QAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,aAAO;AAAA,IACT,WAAW,KAAK,SAAS,GAAG;AAC1B,aAAO,KAAK,CAAC;AAAA,IACf;AAAA,EACF;AAEA,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ,KAAK;AAAA,IACtB,KAAK;AACH,aAAO,QAAQ,KAAK,KAAK;AAAA,IAC3B,KAAK;AACH,aAAO,QAAQ,KAAK,KAAK,KAAK;AAAA,IAChC,KAAK;AACH,aAAO,QAAQ,IAAI,KAAK,KAAK,KAAK;AAAA,IACpC,KAAK;AACH,aAAO,QAAQ,KAAK,KAAK,KAAK,KAAK;AAAA,IACrC,KAAK;AACH,aAAO,QAAQ,MAAM,KAAK,KAAK,KAAK;AAAA,IACtC;AACE,YAAM,IAAI;AAAA,QACR,uBAAuB,IAAI;AAAA,MAAA;AAAA,EAC7B;AAEN;AAKA,SAAS,UAAU,SAAyB;AAC1C,QAAM,QAAQ,QAAQ,MAAM,4CAA4C;AACxE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR,yBAAyB,OAAO;AAAA,IAAA;AAAA,EAEpC;AAEA,QAAM,QAAQ,WAAW,MAAM,CAAC,CAAC;AACjC,QAAM,OAAO,MAAM,CAAC,EAAE,YAAA;AAEtB,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ,OAAO;AAAA,IACxB,KAAK;AACH,aAAO,QAAQ,OAAO,OAAO;AAAA,IAC/B,KAAK;AACH,aAAO,QAAQ,OAAO,OAAO,OAAO;AAAA,IACtC;AACE,YAAM,IAAI;AAAA,QACR,uBAAuB,IAAI;AAAA,MAAA;AAAA,EAC7B;AAEN;AAMO,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,SAAS,EACN,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,OAAO,EACJ,MAAM,EAAE,QAAQ,EAChB,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,WAAW,EACR,UACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,UACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,QAAQ,EACL;AAAA,IACC,EAAE,OAAO;AAAA,MACP,OAAO,EACJ,KAAK,CAAC,QAAQ,QAAQ,gBAAgB,QAAQ,iBAAiB,CAAC,EAChE;AAAA,QACC;AAAA,MAAA;AAAA,MAEJ,MAAM,EACH,QAAA,EACA,SAAA,EACA,SAAS,kDAAkD;AAAA,IAAA,CAC/D;AAAA,EAAA,EAEF,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,QAAQ,EACL,MAAM,EAAE,KAAK,CAAC,QAAQ,QAAQ,gBAAgB,QAAQ,iBAAiB,CAAC,CAAC,EACzE,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,YAAY,EACT,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,YAAY,EACT,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,cAAc,EACX,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,cAAc,EACX,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAEN,CAAC;AAUD,eAAsB,YACpB,MACA,SAC8B;AAC9B,QAAM,aAAa,WAAW,MAAM,IAAI;AACxC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAGJ,MACE,WAAW,UACX,WAAW,OAAO,SAAS,KAC3B,CAAC,WAAW,OAAO,SAAS,MAAM,GAClC;AACA,WAAO;AAAA,MACL,OACE;AAAA,IAAA;AAAA,EAEN;AAEA,QAAM,SAAS,WAAW,SACtB,WAAW,OAAO,IAAI,CAAA,MAAK;AACzB,QAAI,MAAM,mBAAmB;AAC3B,aAAO;AAAA,IACT;AACA,QAAI,MAAM,gBAAgB;AACxB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC,IACD,CAAA;AAEJ,MAAI,OACF,WAAW,QAAQ,IAAI,CAAA,MAAK;AAC1B,QAAI,QAAQ,EAAE;AACd,QAAI,UAAU,mBAAmB;AAC/B,cAAQ;AAAA,IACV;AACA,QAAI,UAAU,gBAAgB;AAC5B,cAAQ;AAAA,IACV;AACA,WAAO;AAAA,MACL;AAAA,MACA,MAAM,EAAE,QAAQ;AAAA;AAAA,IAAA;AAAA,EAEpB,CAAC,KAAK;AACR,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAE9B,WAAO,CAAC,EAAE,OAAO,QAAQ,MAAM,OAAO;AAAA,EACxC;AAEA,QAAM,aAAa,MAAM,IAAI,OAAK,EAAE,KAAK,KAAK,CAAA;AAE9C,QAAM,UAAU,KAAK;AAAA,IACnB,QAAQ,cAAc;AAAA,IACtB,WAAW,WAAW;AAAA,EAAA;AAGxB,MAAI;AAEF,QAAI;AACF,YAAM,GAAG,SAAS,OAAO,SAAS,GAAG,UAAU,IAAI;AAAA,IACrD,SAAS,KAAU;AACjB,UAAI,IAAI,SAAS,UAAU;AACzB,eAAO;AAAA,UACL,OAAO,8BAA8B,OAAO;AAAA,QAAA;AAAA,MAEhD;AACA,YAAM;AAAA,IACR;AAGA,UAAM,YACJ,SAAS,MAAM,SAAS,IACpB,MAAM,IAAI,CAAA,OAAM;AAAA,MACd,OAAO;AAAA,MACP,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,EACT,IACF,CAAC,EAAE,OAAO,MAAM,WAAW,WAAW,SAAS,OAAO;AAC5D,UAAM,eAAe,QAAQ,gBAAgB,CAAA;AAC7C,UAAM,iBAAyB,CAAC,GAAG,WAAW,GAAG,YAAY;AAG7D,UAAM,SAAgC;AAAA,MACpC,OAAO,aAAa;AAAA,MACpB,MAAM,YAAY;AAAA,MAClB,cACE,OAAO,SAAS,cAAc,KAAK,WAAW,SAAS,cAAc;AAAA,MACvE,MAAM,OAAO,SAAS,MAAM,KAAK,WAAW,SAAS,MAAM;AAAA,MAC3D,YACE,OAAO,SAAS,YAAY,KAAK,WAAW,SAAS,YAAY;AAAA,IAAA;AAIrE,QAAI,oBAAgD;AACpD,QAAI,iBAA6C;AAEjD,QAAI,cAAc,YAAY;AAC5B,UAAI;AACF,cAAM,MAAM,KAAK,IAAA;AACjB,cAAM,UAAU,aAAa,MAAM,aAAa,UAAU,IAAI;AAC9D,cAAM,UAAU,aAAa,MAAM,aAAa,UAAU,IAAI;AAC9D,4BAAoB,CAAC,SAAS,OAAO;AAAA,MACvC,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,OACE,eAAe,QACX,IAAI,UACJ;AAAA,QAAA;AAAA,MAEV;AAAA,IACF;AAEA,QAAI,gBAAgB,cAAc;AAChC,UAAI;AACF,cAAM,oBAAoB,eAAe,UAAU,YAAY,IAAI;AACnE,cAAM,oBAAoB,eAAe,UAAU,YAAY,IAAI;AACnE,yBAAiB,CAAC,mBAAmB,iBAAiB;AAAA,MACxD,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,OACE,eAAe,QACX,IAAI,UACJ;AAAA,QAAA;AAAA,MAEV;AAAA,IACF;AAGA,UAAM,iBAAiB,MAAM,YAAY;AAAA,MACvC,SAAS,WAAW;AAAA,MACpB,OAAO;AAAA,MACP;AAAA,MACA,cAAc;AAAA,MACd,WAAW;AAAA,IAAA,CACZ;AAGD,QAAI,eAAe,MAAM,SAAS,mBAAmB;AACnD,YAAM,IAAI;AAAA,QACR,oBAAoB,eAAe,MAAM,MAAM,8BAA8B,iBAAiB;AAAA,MAAA;AAAA,IAElG;AAGA,UAAM,kBAAkB,iBAAiB,gBAAgB;AAAA,MACvD;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AAED,WAAO;AAAA,MACL,QAAQ;AAAA,IAAA;AAAA,EAEZ,SAAS,KAAK;AACZ,WAAO,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,gBAAA;AAAA,EACvD;AACF;AAEO,SAAS,sBACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa,WAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,YAAY,MAAM,OAAO;AAC9C,UAAI,OAAO,OAAO;AAChB,eAAO,mBAAmB,KAAK,UAAU,IAAI,CAAC;AAAA,SAAa,OAAO,KAAK;AAAA,MACzE;AACA,aAAO,mBAAmB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,OAAO,UAAU,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IACtG;AAAA,EAAA;AAEJ;AClWO,SAAS,qBACd,iBACA,SACM;AACN,wBAAsB,iBAAiB;AAAA,IACrC,YAAY,QAAQ,cAAc;AAAA,IAClC,GAAG,QAAQ;AAAA,EAAA,CACZ;AAED,UAAQ;AAAA,IACN;AAAA,uBACmB,KAAK,QAAQ,QAAQ,cAAc,EAAE,CAAC;AAAA;AAAA,EAAA;AAG7D;ACnBO,SAAS,sBAAsB,SAAiC;AACrE,QAAM,EAAE,gBAAgB;AAExB,SAAO,eAAe,qBACpB,KACA,KACA,KACA,MACA;AACA,UAAM,UAAU;AAAA,MACd;AAAA,MACA,SAAS;AAAA,MACT,MAAM;AAAA,QACJ,SAAS;AAAA,UACP,KAAK,IAAI;AAAA,UACT,QAAQ,IAAI;AAAA,UACZ,SAAS,IAAI;AAAA,UACb,MAAM,IAAI;AAAA,QAAA;AAAA,QAEZ,OAAO,IAAI;AAAA,QACX,OAAO,IAAI;AAAA,MAAA;AAAA,IACb,CACD;AACD,QAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MACnB,OAAO;AAAA,MACP,SAAS,IAAI,SAAS,IAAI,WAAW,IAAI,SAAA;AAAA,IAAS,CACnD;AAAA,EACH;AACF;ACjBA,SAAS,oBAA4B;AACnC,QAAM,aAAY,oBAAI,KAAA,GACnB,YAAA,EACA,UAAU,GAAG,EAAE,EACf,QAAQ,KAAK,GAAG,EAChB,QAAQ,MAAM,GAAG;AACpB,SAAO,OAAO,SAAS;AACzB;AAMO,SAAS,aAAa,SAAuC;AAClE,QAAM,MAAM,QAAA;AACZ,QAAM,aAAa,iBAElB;AACD,MAAI,IAAI,UAAU;AAClB,SAAO;AACT;AAUO,SAAS,gBAAgB,SAG9B;AACA,QAAM,YAAY,IAAI,UAAU;AAAA,IAC9B,MAAM,QAAQ;AAAA,IACd,SAAS,QAAQ;AAAA,IACjB,OAAO;AAAA,EAAA,CACR;AAED,QAAM,YAAY,gBAAgB,WAAW,OAAO;AAEpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EAAA;AAEJ;AAMO,SAAS,iBAAiB,SAA0C;AACzE,QAAM,SAAS,QAAQ,OAAA;AAEvB,SAAO;AAAA,IACL,KAAK,QAAQ;AAAA,MACX,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,gBAAgB;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,gBAAgB,CAAC,gBAAgB;AAAA,IAAA,CAClC;AAAA,EAAA;AAEH,SAAO,IAAI,QAAQ,MAAM;AAGzB,SAAO;AACT;AAEO,SAAS,gBACd,WACA,SACQ;AACR,QAAM,SAAS,QAAQ,OAAA;AAEvB,SAAO,IAAI,qBAAqB,EAAE,WAAW,QAAQ,UAAA,CAAW,CAAC;AAEjE,SAAO,IAAI,QAAQ,4BAA4B,WAAW,OAAO,CAAC;AAElE,SAAO;AACT;AAQO,SAAS,YACd,KACA,SACiB;AACjB,MAAI,IAAI,sBAAsB,EAAE,aAAa,QAAQ,YAAA,CAAa,CAAC;AAEnE,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,QAAI;AAEJ,UAAM,WAAW,MAAM;AACrB,cAAQ,UAAU;AAAA,IACpB;AAEA,QAAI;AACF,mBAAa,QAAQ,OACjB,IAAI,OAAO,QAAQ,QAAQ,GAAG,QAAQ,MAAM,QAAQ,IACpD,IAAI,OAAO,QAAQ,QAAQ,GAAG,QAAQ;AAC1C,iBAAW,YAAY,SAAS,CAAC,QAAe;AAC9C,eAAO,GAAG;AAAA,MACZ,CAAC;AAAA,IACH,SAAS,OAAO;AACd,aAAO,KAAK;AAAA,IACd;AAAA,EACF,CAAC;AACH;AAEO,SAAS,wBACd,YACA,SACQ;AACR,QAAM,SAAU,WAAW,QAAA,EAAkB;AAC7C,QAAM,OAAQ,WAAW,QAAA,EAAkB;AAC3C,MAAI,OAAQ,WAAW,QAAA,EAAkB;AACzC,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT,WAAW,WAAW,QAAQ;AAC5B,WAAO,IAAI,IAAI;AAAA,EACjB;AACA,QAAM,YAAY,UAAU,WAAW,SAAS,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI;AAE1E,SAAO;AAAA;AAAA,eAEM,QAAQ,IAAI;AAAA,kBACT,QAAQ,OAAO;AAAA,cACnB,SAAS;AAAA,gBACP,SAAS;AAAA;AAAA,YAEb,KAAK,QAAQ,QAAQ,WAAW,CAAC;AAC7C;AAaA,eAAsB,eACpB,SACiB;AACjB,QAAM,cAAc,KAAK,KAAK,QAAQ,QAAQ,mBAAmB;AAEjE,QAAM,MAAM,aAEX;AAED,QAAM,EAAE,WAAW,UAAA,IAAc,gBAAgB;AAAA,IAC/C,GAAG;AAAA,IACH;AAAA,EAAA,CACD;AACD,MAAI,IAAI,SAAS;AAEjB,QAAM,kBAAkB,0BAA0B,WAAW;AAAA,IAC3D;AAAA,EAAA,CACD;AAED,MAAI,QAAQ,MAAM,gBAAgB;AAChC,8BAA0B,iBAAiB,QAAQ,OAAO,cAAc;AAAA,EAC1E;AAEA,MAAI,QAAQ,MAAM,WAAW;AAC3B,yBAAqB,iBAAiB,QAAQ,MAAM,SAAS;AAAA,EAC/D;AAEA,QAAM,aAAa,MAAM,YAAY,KAAK;AAAA,IACxC,MAAM,QAAQ;AAAA,IACd,MAAM,QAAQ;AAAA,IACd;AAAA,EAAA,CACD;AAED,UAAQ;AAAA,IACN,wBAAwB,YAAY;AAAA,MAClC,MAAM,QAAQ;AAAA,MACd,SAAS,QAAQ;AAAA,MACjB,WAAW,QAAQ;AAAA,MACnB;AAAA,MACA,oBAAoB,QAAQ;AAAA,IAAA,CAC7B;AAAA,EAAA;AAGH,SAAO;AACT;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flemist/mcp-project-tools",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "MCP project tools",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1 +0,0 @@
1
- {"version":3,"file":"startMcpServer-B-xjEzCx.js","sources":["../src/server/createAuthMiddleware.ts","../src/helpers/logToFile.ts","../src/server/transport/streamable-http/StreamableHttpHandler.ts","../src/tools/process/helpers/extractCommand.ts","../src/tools/process/common.ts","../src/tools/process/helpers/cleanupOldProcesses.ts","../src/tools/process/helpers/updateProcessOutput.ts","../src/helpers/cropText.ts","../src/tools/process/methods/status.ts","../src/helpers/killProcessById.ts","../src/tools/process/methods/wait.ts","../src/tools/process/methods/run.ts","../src/tools/process/methods/list.ts","../src/tools/process/methods/kill.ts","../src/tools/process/index.ts","../src/server/createMcpRegisterToolFunc.ts","../src/tools/fs/walkPaths/helpers.ts","../src/tools/fs/pools.ts","../src/tools/fs/walkPaths/walkPaths.ts","../src/tools/fs/globToRelative.ts","../src/tools/fs/globGitIgnoreToPicomatch.ts","../src/tools/fs/loadGlobs.ts","../src/tools/fs/walkPaths/createMatchPath.ts","../src/tools/fs/getPathList.ts","../src/tools/fs/pathListToString.ts","../src/config/constants.ts","../src/tools/fs/methods/list.ts","../src/tools/fs/index.ts","../src/server/createErrorMiddleware.ts","../src/server/startMcpServer.ts"],"sourcesContent":["import { NextFunction, Request, Response } from 'express'\n\nexport interface CreateAuthMiddlewareOptions {\n authToken: string\n}\n\n/**\n * Token validation middleware\n */\nexport function createAuthMiddleware(options: CreateAuthMiddlewareOptions) {\n const { authToken } = options\n return function authMiddleware(\n req: Request,\n res: Response,\n next: NextFunction,\n ): void {\n const token =\n (req.query.token as string) ||\n req.headers.authorization?.replace('Bearer ', '')\n\n if (token !== authToken) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n next()\n }\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\n\nexport interface LogOptions {\n logFilePath: string\n message: string\n data: any\n}\n\nexport async function logToFile(options: LogOptions): Promise<void> {\n const { logFilePath, message, data } = options\n try {\n const timestamp = new Date().toISOString().replace(/[TZ]/g, ' ').trim()\n const dataStr =\n typeof data === 'string' ? data : JSON.stringify(data, null, 2)\n const logData = `[${timestamp}] ${message}\\n${dataStr}\\n\\n`\n await fs.promises.mkdir(path.dirname(logFilePath), { recursive: true })\n await fs.promises.appendFile(logFilePath, logData)\n } catch (err) {\n console.error(`Failed to log \"${message}\":`, err)\n }\n}\n","import { randomBytes } from 'crypto'\nimport { Request, Response } from 'express'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'\nimport { logToFile } from 'src/helpers/logToFile'\n\nexport type StreamableHttpHandlerOptions = {\n logFilePath: string\n enableJsonResponse?: boolean | null\n}\n\n/**\n * HTTP session storage (old name: streamableTransports)\n * WHY: Stores active HTTP transport sessions for session management and reuse\n */\nexport const sessionsTransports = new Map<\n string,\n StreamableHTTPServerTransport\n>()\n\n/**\n * MCP over HTTP handler\n * WHY: Handles MCP protocol over HTTP transport, creates and manages HTTP sessions\n */\nexport function createStreamableHttpHandler(\n mcpServer: McpServer,\n options: StreamableHttpHandlerOptions,\n) {\n return async function streamableHttpHandler(\n req: Request,\n res: Response,\n ): Promise<void> {\n const sessionId =\n (req.headers['mcp-session-id'] as string) ||\n (req.headers['x-session-id'] as string) ||\n (req.query.token as string) // Use token as fallback session ID\n let transport: StreamableHTTPServerTransport\n\n if (req.method === 'POST') {\n await logToFile({\n logFilePath: options.logFilePath,\n message: 'REQUEST',\n data: req.body,\n })\n\n if (sessionId && sessionsTransports.has(sessionId)) {\n transport = sessionsTransports.get(sessionId)!\n } else {\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () =>\n sessionId || randomBytes(16).toString('hex'),\n onsessioninitialized: (id: string) => {\n sessionsTransports.set(id, transport)\n console.log(`Session initialized: ${id}`)\n },\n enableJsonResponse: options.enableJsonResponse || false,\n })\n\n transport.onclose = () => {\n if (transport.sessionId) {\n sessionsTransports.delete(transport.sessionId)\n console.log(`Session closed: ${transport.sessionId}`)\n }\n }\n\n await mcpServer.connect(transport)\n\n // Store the transport immediately using the session ID\n if (sessionId) {\n sessionsTransports.set(sessionId, transport)\n }\n }\n\n const response = await transport.handleRequest(req, res, req.body)\n } else if (req.method === 'GET') {\n if (sessionId && sessionsTransports.has(sessionId)) {\n transport = sessionsTransports.get(sessionId)!\n await transport.handleRequest(req, res)\n } else {\n res.status(400).json({ error: 'No valid session' })\n }\n } else {\n res.status(405).json({ error: 'Method not allowed' })\n }\n }\n}\n","export interface ExtractCommandOptions {\n commandLine: string\n}\n\n/**\n * Parse command from command line\n * WHY: Extracts base command from command line for security validation\n */\nexport function extractCommand(options: ExtractCommandOptions): string {\n const { commandLine } = options\n // Extract command from command line considering quotes\n const match = commandLine.match(/^\"([^\"]+)\"|^(\\S+)/)\n return match ? match[1] || match[2] : commandLine.split(' ')[0]\n}\n","import type { ProcessInfo } from './types'\nimport { extractCommand } from './helpers/extractCommand'\nimport treeKill from 'tree-kill'\n\n/**\n * All process tracking data\n * WHY: Central storage for all active and completed processes\n */\nexport const processes = new Map<number, ProcessInfo>()\n\n/**\n * Incremental ID generator (old name: processCounter)\n * WHY: Generates unique process IDs for tracking\n */\nexport let nextProcessId = 0\n\n/**\n * Limit concurrent processes constant\n * WHY: Prevents resource exhaustion by limiting concurrent processes\n */\nexport const MAX_PROCESSES = 10\n\n/**\n * 30min cleanup interval constant\n * WHY: Defines when to remove completed processes from memory\n */\nexport const PROCESS_CLEANUP_TIME = 30 * 60 * 1000 // 30 minutes\n\n/**\n * 2000 char limit constant\n * WHY: Prevents memory issues from excessive process output\n */\nexport const OUTPUT_LIMIT = 2000\n\n/**\n * 500ms throttle constant\n * WHY: Reduces CPU usage by throttling output updates\n */\nexport const OUTPUT_THROTTLE_TIME = 500\n\n/**\n * 5s wait between signals constant\n * WHY: Gives processes time to gracefully exit before force kill\n */\nexport const KILL_TIMEOUT = 5000\n\nexport interface IsCommandAllowedOptions {\n commandLine: string\n allowedCommands: string[]\n}\n\n/**\n * Validate against whitelist\n * WHY: Security function to prevent execution of unauthorized commands\n */\nexport function isCommandAllowed(options: IsCommandAllowedOptions): boolean {\n const { commandLine, allowedCommands } = options\n const command = extractCommand({ commandLine })\n return allowedCommands.some(\n allowed =>\n command === allowed || command.toLowerCase() === allowed.toLowerCase(),\n )\n}\n\n/**\n * Increment process ID counter\n * WHY: Provides thread-safe way to get next unique process ID\n */\nexport function getNextProcessId(): number {\n return ++nextProcessId\n}\n\nlet autoKillInitialized = false\n\nexport function autoKillChildProcesses(): void {\n if (autoKillInitialized) {\n return\n }\n autoKillInitialized = true\n\n const kill = (): void => {\n console.log('Auto-killing all child processes...')\n\n for (const [id, process] of Array.from(processes.entries())) {\n if (process.isRunning && process.pid) {\n try {\n treeKill(process.pid, 'SIGKILL')\n } catch (err) {\n console.error(`Error killing process ${id}:`, err)\n }\n }\n }\n\n process.exit(0)\n }\n\n process.on('SIGINT', kill)\n process.on('SIGTERM', kill)\n}\n","import { processes, PROCESS_CLEANUP_TIME } from '../common'\n\n/**\n * Remove old completed processes\n * WHY: Prevents memory leaks by removing old process data\n */\nexport function cleanupOldProcesses(): void {\n const now = Date.now()\n const toRemove: number[] = []\n\n for (const [id, process] of Array.from(processes.entries())) {\n if (!process.isRunning && process.endTime) {\n const timeSinceEnd = now - process.endTime.getTime()\n if (timeSinceEnd > PROCESS_CLEANUP_TIME) {\n toRemove.push(id)\n }\n }\n }\n\n for (const id of toRemove) {\n processes.delete(id)\n }\n}\n","import type { ProcessInfo } from '../types'\nimport { OUTPUT_THROTTLE_TIME, OUTPUT_LIMIT } from '../common'\n\nexport interface UpdateProcessOutputOptions {\n process: ProcessInfo\n}\n\n/**\n * Throttle output updates\n * WHY: Manages process output buffering and throttling to prevent performance issues\n */\nexport function updateProcessOutput(options: UpdateProcessOutputOptions): void {\n const { process } = options\n const now = Date.now()\n const timeSinceLastUpdate = now - process.lastOutputTime.getTime()\n\n if (timeSinceLastUpdate >= OUTPUT_THROTTLE_TIME) {\n process.output += process.localOutput\n process.localOutput = ''\n process.lastOutputTime = new Date(now)\n\n // Trim output if it exceeds limit\n if (process.output.length > OUTPUT_LIMIT) {\n const removed = process.output.length - OUTPUT_LIMIT\n const trimMessage = `\\n... [${removed} characters trimmed] ...\\n`\n const availableSpace = OUTPUT_LIMIT - trimMessage.length\n\n if (availableSpace > 0) {\n const half = Math.floor(availableSpace / 2)\n process.output =\n process.output.substring(0, half) +\n trimMessage +\n process.output.substring(\n process.output.length - (availableSpace - half),\n )\n } else {\n process.output = process.output.substring(0, OUTPUT_LIMIT)\n }\n }\n }\n}\n","export interface CropTextOptions {\n limit: number\n}\n\n/** Crops text to a specified limit by removing extra text from the middle */\nexport function cropText(text: string, options: CropTextOptions): string {\n const limit = options.limit - 35 // 35 - is trim message length\n if (text.length <= limit) return text\n\n const removedLength = text.length - limit\n const trimMessage = `\\n... [${removedLength} characters trimmed] ...\\n`\n const availableLength = limit - trimMessage.length\n\n if (availableLength <= 0) {\n return text.substring(0, limit)\n }\n\n const half = Math.floor(availableLength / 2)\n return (\n text.substring(0, half) +\n trimMessage +\n text.substring(text.length - (availableLength - half))\n )\n}\n","import { z } from 'zod'\nimport { OUTPUT_LIMIT, processes } from '../common'\nimport { cleanupOldProcesses } from '../helpers/cleanupOldProcesses'\nimport { updateProcessOutput } from '../helpers/updateProcessOutput'\nimport { cropText } from 'src/helpers/cropText'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\n/**\n * Get process status and latest output requests\n */\nexport const StatusSchema = z.object({\n id: z\n .number()\n .describe(\n 'Process ID to get detailed status information for. Get process IDs using process-list. Works for both running and completed processes. Examples: 1, 42, 123.',\n ),\n outputLimit: z\n .number()\n .max(OUTPUT_LIMIT)\n .default(OUTPUT_LIMIT)\n .describe(\n `Maximum number of output characters to return from the process. Output exceeding this limit will be cropped with beginning/end preserved. Maximum: ${OUTPUT_LIMIT} characters. Default: ${OUTPUT_LIMIT}.`,\n ),\n})\n\nexport type ProcessManagerStatusOptions = {\n workingDir?: string | null\n}\n\n/**\n * Get process status and latest output\n */\nexport async function commandStatus(\n args: z.infer<typeof StatusSchema>,\n options: ProcessManagerStatusOptions,\n): Promise<Record<string, any>> {\n cleanupOldProcesses()\n\n const parsedArgs = StatusSchema.parse(args)\n const { id, outputLimit } = parsedArgs\n const process = processes.get(id)\n\n if (!process) {\n return {\n error: `Process ${id} not found. The process may have already completed and been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`,\n }\n }\n\n updateProcessOutput({ process })\n\n const fullOutput = process.output + process.localOutput\n const formattedOutput = cropText(fullOutput, { limit: outputLimit })\n\n // Clear output after retrieval to avoid duplication\n process.output = ''\n process.localOutput = ''\n\n return {\n id: process.id,\n cwd: path.relative(options.workingDir || '', process.cwd),\n commandLine: process.commandLine,\n pid: process.pid,\n startTime: process.startTime.toISOString().replace(/[TZ]/g, ' ').trim(),\n endTime: process.endTime?.toISOString().replace(/[TZ]/g, ' ').trim(),\n exitCode: process.exitCode,\n isRunning: process.isRunning,\n output: formattedOutput,\n error: process.error,\n }\n}\n\nexport function mcpRegisterToolProcessStatus(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerStatusOptions,\n): void {\n mcpRegisterTool(\n 'process-status',\n {\n title: 'Get Host Machine Process Status',\n description:\n 'Get detailed status information about a process on the host machine, including execution details, captured output, exit code, and runtime status. Returns comprehensive process information for both running and completed processes. The output is cleared after retrieval to prevent duplication in subsequent calls. Useful for checking command execution results and monitoring process progress.',\n inputSchema: StatusSchema.shape,\n },\n async args => {\n const result = await commandStatus(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-status(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import treeKill from 'tree-kill'\nimport { KILL_TIMEOUT } from 'src/tools/process/common'\n\n/** Safe kill process by ID */\nexport function killProcessById(pid: number): void {\n // First try soft kill\n treeKill(pid, 'SIGTERM', (err?: Error) => {\n if (err && !err.message.includes('not found')) {\n console.error(`Error sending SIGTERM to process ${pid}:`, err)\n }\n })\n\n // Force kill after timeout\n setTimeout(() => {\n treeKill(pid, 'SIGKILL', (err?: Error) => {\n if (err && !err.message.includes('not found')) {\n console.error(`Error sending SIGKILL to process ${pid}:`, err)\n }\n })\n }, KILL_TIMEOUT)\n}\n","import { z } from 'zod'\nimport { OUTPUT_LIMIT, processes } from '../common'\nimport { commandStatus } from './status'\nimport { killProcessById } from 'src/helpers/killProcessById'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\n\n/**\n * Wait for process completion with timeout operation requests\n */\nexport const WaitSchema = z.object({\n id: z\n .number()\n .describe(\n 'Process ID to wait for completion. Get process IDs using process-list. The process can be running or already completed. Examples: 1, 42, 123.',\n ),\n waitTime: z\n .number()\n .optional()\n .describe(\n 'Maximum time to wait in seconds for process completion. If omitted, waits indefinitely until process completes. If process is already completed, returns immediately. Examples: 30 (wait up to 30 seconds), 300 (wait up to 5 minutes).',\n ),\n autoKill: z\n .boolean()\n .default(false)\n .describe(\n 'Automatically terminate the process if waitTime expires and it is still running. Only applies when waitTime is specified. Default: false (let process continue running after timeout). Set to true for processes that should not run indefinitely.',\n ),\n outputLimit: z\n .number()\n .max(OUTPUT_LIMIT)\n .default(OUTPUT_LIMIT)\n .describe(\n `Maximum number of output characters to capture and return from the process. Output exceeding this limit will be trimmed. Maximum: ${OUTPUT_LIMIT} characters. Default: ${OUTPUT_LIMIT}.`,\n ),\n})\n\nexport type ProcessManagerWaitOptions = {\n workingDir?: string | null\n}\n\n/**\n * Wait for process completion with timeout\n */\nexport async function commandWait(\n args: z.infer<typeof WaitSchema>,\n options: ProcessManagerWaitOptions,\n): Promise<Record<string, any>> {\n const parsedArgs = WaitSchema.parse(args)\n const { id, waitTime, autoKill, outputLimit } = parsedArgs\n const process = processes.get(id)\n\n if (!process) {\n return {\n error: `Process ${id} not found. The process may have already completed and been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`,\n }\n }\n\n const startWait = Date.now()\n let waitTimeExceeded = false\n let autoKillExecuted = false\n\n if (waitTime !== undefined) {\n const waitPromise = new Promise<void>(resolve => {\n const checkInterval = setInterval(() => {\n if (!process.isRunning) {\n clearInterval(checkInterval)\n resolve()\n } else if (Date.now() - startWait >= waitTime * 1000) {\n clearInterval(checkInterval)\n waitTimeExceeded = true\n\n if (autoKill && process.pid) {\n killProcessById(process.pid)\n autoKillExecuted = true\n }\n\n resolve()\n }\n }, 100)\n })\n\n await waitPromise\n }\n\n const waitDuration = (Date.now() - startWait) / 1000\n const status = await commandStatus(\n { id, outputLimit },\n { workingDir: options.workingDir },\n )\n\n return {\n ...status,\n waitDuration,\n waitTimeExceeded,\n autoKillExecuted,\n }\n}\n\nexport function mcpRegisterToolProcessWait(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerWaitOptions,\n): void {\n mcpRegisterTool(\n 'process-wait',\n {\n title: 'Wait for Host Machine Process',\n description:\n 'Wait for a host machine process to complete execution, with optional timeout and auto-kill functionality. Useful for long-running commands like builds, installs, or tests where you need to wait for completion. Returns the final process status along with wait duration and timeout information. Can automatically terminate processes that exceed the wait time limit.',\n inputSchema: WaitSchema.shape,\n },\n async args => {\n const result = await commandWait(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-wait(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import { spawn } from 'child_process'\nimport { z } from 'zod'\nimport type { ProcessInfo } from '../types'\nimport {\n getNextProcessId,\n isCommandAllowed,\n MAX_PROCESSES,\n OUTPUT_LIMIT,\n processes,\n} from '../common'\nimport { cleanupOldProcesses } from '../helpers/cleanupOldProcesses'\nimport { updateProcessOutput } from '../helpers/updateProcessOutput'\nimport { extractCommand } from '../helpers/extractCommand'\nimport { commandWait } from './wait'\nimport { commandStatus } from './status'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\n/**\n * Validates command execution requests\n * WHY: Ensures command execution requests have valid parameters\n */\nexport const RunSchema = z.object({\n cwd: z\n .string()\n .optional()\n .describe(\n 'Working directory for command execution, resolved relative to the current working directory. Leave empty to use current directory. Examples: \"src\" (run in src/ subdirectory), \"../parent\" (run in parent directory), \"build/output\" (run in nested subdirectory). Directory must exist.',\n ),\n commandLine: z\n .string()\n .describe(\n 'Complete command line to execute on the host machine. Include all arguments and options. Examples: \"npm install\", \"pnpm build\", \"node script.js --verbose\", \"git status\". Command must be in the allowed commands list for security.',\n ),\n waitTime: z\n .number()\n .optional()\n .describe(\n 'Time to wait in seconds for process completion before returning results. If specified, will wait this long then return final status. If omitted, returns immediately with initial status. Use process-wait or process-status to check progress later. Examples: 30 (wait 30 seconds), 120 (wait 2 minutes).',\n ),\n autoKill: z\n .boolean()\n .default(false)\n .describe(\n 'Automatically kill the process if waitTime expires and it is still running. Only applies when waitTime is specified. Default: false (let process continue running). Set to true for commands that should not run indefinitely.',\n ),\n outputLimit: z\n .number()\n .max(OUTPUT_LIMIT)\n .default(OUTPUT_LIMIT)\n .describe(\n `Maximum number of output characters to capture and return from the process. Output exceeding this limit will be trimmed with beginning/end preserved and middle removed. Maximum: ${OUTPUT_LIMIT} characters. Default: ${OUTPUT_LIMIT}.`,\n ),\n})\n\nexport type ProcessManagerRunOptions = {\n workingDir?: string | null\n allowedCommands: string[]\n}\n\n/**\n * Execute commands on host\n */\nexport async function commandRun(\n args: z.infer<typeof RunSchema>,\n options: ProcessManagerRunOptions,\n): Promise<Record<string, any>> {\n cleanupOldProcesses()\n\n const parsedArgs = RunSchema.parse(args)\n const { commandLine, waitTime, autoKill, outputLimit } = parsedArgs\n const { allowedCommands } = options\n\n const cwd = path.resolve(options.workingDir || '', parsedArgs.cwd || '')\n\n if (!isCommandAllowed({ commandLine, allowedCommands })) {\n return {\n error: `Command not allowed: \"${commandLine}\". For security, only whitelisted commands can be executed on the host machine. Allowed commands: ${allowedCommands.join(', ')}. The command \"${extractCommand({ commandLine })}\" is not in the allowed list. To use this command, ask the user to add it to the allowedCommands configuration.`,\n }\n }\n\n const activeProcesses = Array.from(processes.values()).filter(\n o => o.isRunning,\n )\n if (activeProcesses.length >= MAX_PROCESSES) {\n return {\n error: `Maximum concurrent process limit reached (${MAX_PROCESSES} processes). Cannot start new process until existing processes complete. Use process-list to see active processes, or process-kill to terminate unnecessary processes.`,\n }\n }\n\n const id = getNextProcessId()\n const processInfo: ProcessInfo = {\n id,\n cwd,\n commandLine,\n startTime: new Date(),\n isRunning: true,\n output: '',\n localOutput: '',\n lastOutputTime: new Date(),\n }\n\n processes.set(id, processInfo)\n\n try {\n const child = spawn(commandLine, [], {\n shell: true,\n cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n processInfo.pid = child.pid\n\n const handleOutput = (data: Buffer): void => {\n const text = data.toString()\n processInfo.localOutput += text\n updateProcessOutput({ process: processInfo })\n console.log(text)\n }\n\n child.stdout?.on('data', handleOutput)\n child.stderr?.on('data', handleOutput)\n\n child.on('close', code => {\n processInfo.isRunning = false\n processInfo.endTime = new Date()\n processInfo.exitCode = code !== null ? code : undefined\n\n // Final output update\n processInfo.output += processInfo.localOutput\n processInfo.localOutput = ''\n\n if (processInfo.output.length > OUTPUT_LIMIT) {\n const removed = processInfo.output.length - OUTPUT_LIMIT\n const trimMessage = `\\n... [${removed} characters trimmed] ...\\n`\n const availableSpace = OUTPUT_LIMIT - trimMessage.length\n\n if (availableSpace > 0) {\n const half = Math.floor(availableSpace / 2)\n processInfo.output =\n processInfo.output.substring(0, half) +\n trimMessage +\n processInfo.output.substring(\n processInfo.output.length - (availableSpace - half),\n )\n } else {\n processInfo.output = processInfo.output.substring(0, OUTPUT_LIMIT)\n }\n }\n\n console.log(`Process ${id} (${commandLine}) exited with code ${code}`)\n })\n\n child.on('error', err => {\n processInfo.isRunning = false\n processInfo.endTime = new Date()\n processInfo.error = err.message\n console.error(`Process ${id} error:`, err.message)\n })\n\n // Wait if requested\n if (waitTime !== undefined) {\n return commandWait(\n { id, waitTime, autoKill, outputLimit },\n { workingDir: options.workingDir },\n )\n }\n\n return commandStatus(\n { id, outputLimit },\n { workingDir: options.workingDir },\n )\n } catch (err) {\n processInfo.isRunning = false\n processInfo.endTime = new Date()\n processInfo.error = err instanceof Error ? err.message : 'Unknown error'\n return { error: processInfo.error }\n }\n}\n\nexport function mcpRegisterToolProcessRun(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerRunOptions,\n): void {\n mcpRegisterTool(\n 'process-run',\n {\n title: 'Execute Command on Host Machine',\n description: `Execute commands on the host machine. This tool allows running system commands that require host environment access, such as package managers (npm, pnpm, yarn), build tools, git operations, and other system utilities. Commands are executed in shell with full argument support. Returns process status and captured output. If waitTime is specified, waits for completion; otherwise returns immediately and you can check progress with process-wait or process-status. Security: Only whitelisted commands are allowed. Current allowed commands: ${options.allowedCommands.join(', ')}.`,\n inputSchema: RunSchema.shape,\n },\n async args => {\n const result = await commandRun(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-run(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import { z } from 'zod'\nimport { processes } from '../common'\nimport { cleanupOldProcesses } from '../helpers/cleanupOldProcesses'\nimport { updateProcessOutput } from '../helpers/updateProcessOutput'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport path from 'path'\n\n/**\n * Load filtered list of processes requests\n */\nexport const ListSchema = z.object({\n minOpenDateTime: z\n .string()\n .optional()\n .describe(\n 'Filter to processes started after this datetime. Accepts ISO format or space-separated format. Examples: \"2024-01-15T10:30:00Z\", \"2024-01-15 10:30:00\". Underscores and spaces are converted to standard ISO format internally.',\n ),\n minCloseDateTime: z\n .string()\n .optional()\n .describe(\n 'Filter to processes that finished after this datetime. Only applies to completed processes. Accepts ISO format or space-separated format. Examples: \"2024-01-15T14:30:00Z\", \"2024-01-15 14:30:00\". Useful for finding recently completed processes.',\n ),\n activeOnly: z\n .boolean()\n .default(false)\n .describe(\n 'Show only currently running processes. Set to true to exclude completed processes, false to show all processes (running and completed). Default: false (show all).',\n ),\n fields: z\n .array(z.string())\n .optional()\n .describe(\n 'Specific process data fields to include in the response. If omitted, returns all available fields. Available fields: id, cwd, commandLine, pid, startTime, endTime, exitCode, isRunning, output, error. Examples: [\"id\", \"commandLine\", \"isRunning\"] for minimal info, [\"id\", \"output\", \"exitCode\"] for execution results.',\n ),\n})\n\nexport type ProcessManagerListOptions = {\n workingDir?: string | null\n}\n\n/**\n * Load filtered list of processes\n */\nexport async function commandList(\n args: z.infer<typeof ListSchema>,\n options: ProcessManagerListOptions,\n): Promise<Record<string, any>> {\n cleanupOldProcesses()\n\n const parsedArgs = ListSchema.parse(args)\n const { minOpenDateTime, minCloseDateTime, activeOnly, fields } = parsedArgs\n\n let processList = Array.from(processes.values())\n\n if (minOpenDateTime) {\n const minDate = new Date(minOpenDateTime.replace(/[_\\s]/g, 'T'))\n processList = processList.filter(p => p.startTime >= minDate)\n }\n\n if (minCloseDateTime) {\n const minDate = new Date(minCloseDateTime.replace(/[_\\s]/g, 'T'))\n processList = processList.filter(p => p.endTime && p.endTime >= minDate)\n }\n\n if (activeOnly) {\n processList = processList.filter(p => p.isRunning)\n }\n\n const result = processList.map(process => {\n updateProcessOutput({ process })\n\n let processData: Record<string, any> = {\n id: process.id,\n cwd: path.relative(options.workingDir || '', process.cwd),\n commandLine: process.commandLine,\n pid: process.pid,\n startTime: process.startTime.toISOString().replace(/[TZ]/g, ' ').trim(),\n endTime: process.endTime?.toISOString().replace(/[TZ]/g, ' ').trim(),\n exitCode: process.exitCode,\n isRunning: process.isRunning,\n output: process.output + process.localOutput,\n error: process.error,\n }\n\n if (fields) {\n const filtered: Record<string, any> = {}\n for (const field of fields) {\n if (field in processData) {\n filtered[field] = processData[field]\n }\n }\n processData = filtered\n }\n\n return processData\n })\n\n return { processes: result }\n}\n\nexport function mcpRegisterToolProcessList(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerListOptions,\n): void {\n mcpRegisterTool(\n 'process-list',\n {\n title: 'List Host Machine Processes',\n description:\n 'List all processes that have been executed on the host machine with filtering and field selection options. Shows both currently running and completed processes with their execution details, output, and status. Useful for monitoring command execution history, checking active processes, and retrieving results from completed commands. Supports datetime filtering to find processes within specific time ranges.',\n inputSchema: ListSchema.shape,\n },\n async args => {\n const result = await commandList(args, options)\n const output = result.output || ''\n delete result.output\n return `Method: process-list(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import { z } from 'zod'\nimport { processes } from '../common'\nimport { killProcessById } from 'src/helpers/killProcessById'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\n\n/**\n * Kill process requests\n */\nexport const KillSchema = z.object({\n id: z\n .number()\n .describe(\n 'Process ID of the process to terminate. Get process IDs using process-list. The process must be currently running. Examples: 1, 42, 123.',\n ),\n})\n\n/**\n * Internal kill process with SIGTERM/SIGKILL\n */\nexport function commandKill(\n args: z.infer<typeof KillSchema>,\n): Record<string, any> {\n const parsedArgs = KillSchema.parse(args)\n const { id } = parsedArgs\n const process = processes.get(id)\n\n if (!process) {\n return {\n error: `Process ${id} not found. The process may have already completed, been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`,\n }\n }\n\n if (!process.isRunning) {\n return {\n error: `Process ${id} is not currently running. The process has already completed or was previously terminated. Use process-list to see the process status and process-status to get final execution details.`,\n }\n }\n\n if (!process.pid) {\n return {\n error: `Process ${id} has no system process ID (PID). This indicates the process failed to start properly or the system was unable to assign a PID. Check process-status for error details.`,\n }\n }\n\n try {\n killProcessById(process.pid)\n return { success: true, message: `Kill signal sent to process ${id}` }\n } catch (err) {\n return {\n error: `Failed to terminate process ${id}: ${err instanceof Error ? err.message : 'Unknown error'}. The process may have already exited, be protected by the system, or there may be insufficient permissions. Use process-status to check current process state.`,\n }\n }\n}\n\nexport function mcpRegisterToolProcessKill(\n mcpRegisterTool: McpRegisterToolFunc,\n): void {\n mcpRegisterTool(\n 'process-kill',\n {\n title: 'Kill Host Machine Process',\n description:\n 'Forcibly terminate a running process on the host machine. Sends SIGTERM signal first for graceful shutdown, then SIGKILL after 5 seconds if the process is still running. Use this to stop runaway processes, hung commands, or long-running tasks that need to be cancelled. The process must be currently running to be terminated.',\n inputSchema: KillSchema.shape,\n },\n async args => {\n const result = commandKill(args)\n const output = result.output || ''\n delete result.output\n return `Method: process-kill(${JSON.stringify(args)})\\n${JSON.stringify(result, null, 2)}\\n\\nOutput:\\n${output}`.trim()\n },\n )\n}\n","import {\n mcpRegisterToolProcessRun,\n type ProcessManagerRunOptions,\n} from 'src/tools/process/methods/run'\nimport { mcpRegisterToolProcessStatus } from 'src/tools/process/methods/status'\nimport { mcpRegisterToolProcessWait } from 'src/tools/process/methods/wait'\nimport { mcpRegisterToolProcessList } from 'src/tools/process/methods/list'\nimport { mcpRegisterToolProcessKill } from 'src/tools/process/methods/kill'\nimport { autoKillChildProcesses } from 'src/tools/process/common'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\nexport type ProcessManagerOptions = {\n workingDir?: string | null\n run: Omit<ProcessManagerRunOptions, 'workingDir'>\n}\n\nexport function mcpRegisterProcessManager(\n mcpRegisterTool: McpRegisterToolFunc,\n options: ProcessManagerOptions,\n): void {\n autoKillChildProcesses()\n\n mcpRegisterToolProcessRun(mcpRegisterTool, {\n workingDir: options.workingDir,\n ...options.run,\n })\n mcpRegisterToolProcessStatus(mcpRegisterTool, {\n workingDir: options.workingDir,\n })\n mcpRegisterToolProcessWait(mcpRegisterTool, {\n workingDir: options.workingDir,\n })\n mcpRegisterToolProcessList(mcpRegisterTool, {\n workingDir: options.workingDir,\n })\n mcpRegisterToolProcessKill(mcpRegisterTool)\n\n console.log(\n `Process manager:\n- Working directory: ${path.resolve(options.workingDir || '')}\n- Allowed commands: ${options.run.allowedCommands.join(', ')}\n`,\n )\n}\n","import { ZodRawShape } from 'zod'\nimport type { PromiseOrValue } from '@flemist/async-utils'\nimport { logToFile } from 'src/helpers/logToFile'\nimport {\n McpServer,\n ToolCallback,\n RegisteredTool,\n} from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\n\nexport type CreateMcpRegisterToolFuncOptions = {\n logFilePath: string\n}\nexport type ToolCallbackExt<InputArgs extends ZodRawShape> = (\n ...args: Parameters<ToolCallback<InputArgs>>\n) => PromiseOrValue<string>\nexport type McpRegisterToolFunc = <\n InputArgs extends ZodRawShape,\n OutputArgs extends ZodRawShape,\n>(\n name: string,\n config: {\n title?: string\n description?: string\n inputSchema?: InputArgs\n outputSchema?: OutputArgs\n annotations?: ToolAnnotations\n },\n cb: ToolCallbackExt<InputArgs>,\n) => RegisteredTool\n\nexport function createMcpRegisterToolFunc(\n server: McpServer,\n options: CreateMcpRegisterToolFuncOptions,\n): McpRegisterToolFunc {\n return function mcpRegisterTool<\n InputArgs extends ZodRawShape,\n OutputArgs extends ZodRawShape,\n >(name, config, callback) {\n const callbackNative = (async (...args) => {\n await logToFile({\n logFilePath: options.logFilePath,\n message: 'REQUEST',\n data: { name, args },\n })\n\n const result = await callback(...args)\n\n await logToFile({\n logFilePath: options.logFilePath,\n message: 'RESPONSE',\n data: result,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: result,\n },\n ],\n }\n }) as ToolCallback<InputArgs>\n\n return server.registerTool<InputArgs, OutputArgs>(\n name,\n config,\n callbackNative,\n )\n }\n}\n","import fs from 'fs'\nimport * as path from 'path'\n\nexport function getDrive(path: string): string {\n return path.match(/^[/\\\\]?[^/\\\\]+/)![0]\n}\n\nexport function getFileId(path: string, stat: fs.Stats): string {\n return getDrive(path) + '|' + stat.ino\n}\n\nexport function pathResolve(_path: string): string {\n if (_path.endsWith(':')) {\n // если этого не сделать path.resolve заменит \"D:\" на \".\", а потом на текущую папку\n _path += '/'\n }\n return path.resolve(_path)\n}\n","import { IPool, Pool } from '@flemist/time-limits'\nimport os from 'node:os'\n\nexport const poolFs: IPool = new Pool(os.cpus().length)\n","import { IPool, poolRunWait } from '@flemist/time-limits'\nimport { Priority, priorityCreate } from '@flemist/priority-queue'\nimport { IAbortSignalFast } from '@flemist/abort-controller-fast'\nimport fs from 'fs'\nimport {\n combineAbortSignals,\n type PromiseOrValue,\n useAbortController,\n} from '@flemist/async-utils'\nimport * as path from 'path'\nimport { getFileId, pathResolve } from './helpers'\nimport { poolFs } from 'src/tools/fs/pools'\nimport type { MatchPath } from 'src/tools/fs/walkPaths/createMatchPath'\n\ntype WalkPathOptionsCommon = {\n paths: string[]\n walkLinks?: null | boolean\n abortSignal?: null | IAbortSignalFast\n pool?: null | IPool\n priority?: null | Priority\n log?: null | WalkPathLogOptions\n handlePath?: null | WalkPathHandlePath\n handleError?: null | WalkPathHandleError\n matchPath?: null | MatchPath\n}\n\n/** @internal */\ntype WalkPathPrivate = WalkPathOptionsCommon & {\n level?: null | number\n walkedIds?: null | Set<string>\n}\n\nexport type WalkPathOptions = WalkPathOptionsCommon\n\n/** @returns true if the error is handled */\nexport type WalkPathHandleError = (\n err: any,\n) => PromiseOrValue<boolean | null | undefined | void>\n\nexport type WalkPathStat = {\n totalSize: number\n countFiles: number\n countDirs: number\n countLinks: number\n maxFileDateModified: number\n}\n\nexport type WalkPathHandlePathArg = {\n level: number\n path: string\n stat: fs.Stats\n itemStat: WalkPathStat\n totalStat: WalkPathStat\n abortSignal: IAbortSignalFast\n}\n\n/**\n * Handler function for processing each discovered path.\n * @param arg - The path processing arguments\n * @returns boolean - true to include this item in totalStat, false to exclude it\n */\nexport type WalkPathHandlePath = (\n arg: WalkPathHandlePathArg,\n) => PromiseOrValue<boolean>\n\nexport type WalkPathLogOptions = {\n /** Don't log paths deeper than this level */\n maxNestedLevel?: null | number\n /** Don't log paths with total size less than this size */\n minTotalContentSize?: null | number\n handleLog?: null | WalkPathLogFunc\n}\n\nexport type WalkPathLogFunc = (message: string) => PromiseOrValue<void>\n\nfunction addStats(totalStat: WalkPathStat, itemStat: WalkPathStat) {\n totalStat.totalSize += itemStat.totalSize\n totalStat.maxFileDateModified = Math.max(\n totalStat.maxFileDateModified,\n itemStat.maxFileDateModified,\n )\n totalStat.countFiles += itemStat.countFiles\n totalStat.countDirs += itemStat.countDirs\n totalStat.countLinks += itemStat.countLinks\n}\n\nexport const walkPathHandleErrorDefault: WalkPathHandleError =\n function walkPathHandleErrorDefault(err: any) {\n if (err.code === 'ENOENT') {\n return true\n }\n return false\n }\n\n/** @internal */\nfunction _walkPaths(options: WalkPathPrivate): Promise<WalkPathStat> {\n const items = options.paths\n if (!items || items.length === 0) {\n return Promise.resolve({\n totalSize: 0,\n maxFileDateModified: 0,\n countFiles: 0,\n countDirs: 0,\n countLinks: 0,\n })\n }\n const level = options.level ?? 0\n const walkedIds = options.walkedIds ?? new Set<string>()\n const abortSignal = options.abortSignal\n const pool = options.pool ?? poolFs\n const handleError = options.handleError\n const priority = options.priority ?? priorityCreate(0)\n const walkLinks = options.walkLinks ?? false\n const logOptions = options.log\n const handlePath = options.handlePath\n const matchPath = options.matchPath\n\n async function _handleError(err: any) {\n if (handleError) {\n if (await handleError(err)) {\n return undefined\n }\n }\n if (walkPathHandleErrorDefault(err)) {\n return undefined\n }\n throw err\n }\n\n function canLog(itemSize: number) {\n if (!logOptions) {\n return false\n }\n if (\n logOptions.minTotalContentSize != null &&\n itemSize < logOptions.minTotalContentSize\n ) {\n return false\n }\n if (\n logOptions.maxNestedLevel != null &&\n level > logOptions.maxNestedLevel\n ) {\n return false\n }\n return true\n }\n\n return useAbortController(async _abortSignal => {\n const abortSignalCombined = combineAbortSignals(abortSignal, _abortSignal)\n\n const totalStat: WalkPathStat = {\n totalSize: 0,\n maxFileDateModified: 0,\n countFiles: 0,\n countDirs: 0,\n countLinks: 0,\n }\n\n function logItem(itemPath: string, itemStat: WalkPathStat) {\n if (canLog(itemStat.totalSize)) {\n // size to string with spaces between thousands\n const sizeStr = itemStat.totalSize\n .toLocaleString('en-US')\n .replace(/,/g, ' ')\n .padStart(19)\n const message = `${sizeStr}: ${itemPath}`\n if (logOptions?.handleLog) {\n logOptions.handleLog(message)\n } else {\n console.log(message)\n }\n }\n }\n\n async function _handlePath(\n itemPath: string,\n stat: fs.Stats,\n itemStat: WalkPathStat,\n priority: Priority,\n ): Promise<boolean> {\n if (!handlePath) {\n return true\n }\n return await poolRunWait({\n pool,\n func: async () => {\n try {\n return await handlePath({\n level,\n path: itemPath,\n stat,\n itemStat,\n totalStat: totalStat,\n abortSignal: abortSignalCombined,\n })\n } catch (err) {\n await _handleError(err)\n return false\n }\n },\n count: 1,\n priority,\n abortSignal: abortSignalCombined,\n })\n }\n\n async function processItem(\n itemPath: string,\n index: number,\n matchResult: boolean | null | undefined,\n ): Promise<WalkPathStat | null> {\n const stat = await poolRunWait({\n pool,\n func: () => fs.promises.lstat(itemPath).catch(_handleError),\n count: 1,\n priority: priorityCreate(index, priorityCreate(1, priority)),\n abortSignal: abortSignalCombined,\n })\n\n if (!stat) {\n return null\n }\n\n if (!matchResult && stat.isFile()) {\n return null\n }\n\n // Check if the file has been walked already\n const itemId = getFileId(itemPath, stat)\n if (walkedIds.has(itemId)) {\n return null\n }\n walkedIds.add(itemId)\n\n let itemStat: WalkPathStat = {\n totalSize: stat.size,\n maxFileDateModified: stat.isDirectory() ? 0 : stat.mtimeMs,\n countFiles: 0,\n countDirs: 0,\n countLinks: 0,\n }\n\n const _priority = priorityCreate(\n index,\n priorityCreate(stat.isDirectory() ? 2 : 3, priority),\n )\n\n if (stat.isSymbolicLink()) {\n if (walkLinks) {\n const link: string = (await poolRunWait({\n pool,\n func: () =>\n fs.promises\n .readlink(itemPath)\n .catch(_handleError)\n .then(link => link ?? null),\n count: 1,\n priority: _priority,\n abortSignal: abortSignalCombined,\n })) as string\n\n if (link) {\n const linkedItemStat = await processItem(link, index, matchResult)\n if (linkedItemStat) {\n itemStat = linkedItemStat\n }\n }\n }\n itemStat.countLinks = 1\n\n if (\n matchResult ||\n itemStat.countFiles + itemStat.countDirs + itemStat.countLinks > 1\n ) {\n const shouldInclude = await _handlePath(\n itemPath,\n stat,\n itemStat,\n _priority,\n )\n if (shouldInclude) {\n addStats(totalStat, itemStat)\n logItem(itemPath, itemStat)\n }\n }\n\n return itemStat\n } else if (stat.isDirectory()) {\n // Get items from the directory\n const dirItems = await poolRunWait({\n pool,\n func: () => fs.promises.readdir(itemPath).catch(_handleError),\n count: 1,\n priority,\n abortSignal: abortSignalCombined,\n })\n\n if (dirItems) {\n for (let i = 0, len = dirItems.length; i < len; i++) {\n dirItems[i] = path.join(itemPath, dirItems[i])\n }\n itemStat = await _walkPaths({\n ...options,\n paths: dirItems,\n abortSignal: abortSignalCombined,\n priority: _priority,\n level: level + 1,\n walkedIds,\n })\n }\n itemStat.countDirs += 1\n } else if (stat.isFile()) {\n itemStat.countFiles += 1\n }\n\n if (\n matchResult ||\n itemStat.countFiles + itemStat.countDirs + itemStat.countLinks > 1\n ) {\n const shouldInclude = await _handlePath(\n itemPath,\n stat,\n itemStat,\n _priority,\n )\n if (shouldInclude) {\n addStats(totalStat, itemStat)\n logItem(itemPath, itemStat)\n }\n }\n\n return itemStat\n }\n\n const promises: Promise<WalkPathStat | null>[] = []\n for (let i = 0, len = items.length; i < len; i++) {\n const itemPath = pathResolve(items[i])\n const matchResult = matchPath ? matchPath(itemPath) : true\n if (matchResult === false) {\n continue\n }\n promises.push(processItem(itemPath, i, matchResult))\n }\n\n await Promise.all(promises)\n\n return totalStat\n })\n}\n\nexport function walkPaths(options: WalkPathOptions): Promise<WalkPathStat> {\n return _walkPaths(options)\n}\n","import * as path from 'path'\n\n// /glob => <relativePath>/glob\n// ./dir/glob => <relativePath>/dir/glob\n// ../glob => <relativePath>/../glob\n// **/glob => <relativePath>/**/glob\n// *.glob => <relativePath>/**/*.glob\n// glob => <relativePath>/**/glob\n/**\n * @param glob - .gitignore glob pattern\n * @param relativePath - relative path from the directory where the glob should be applied\n * @return - glob pattern relative to the given path\n */\nexport function globToRelative(glob: string, relativePath: string): string {\n if (!relativePath || relativePath === '.') {\n return glob\n }\n const exclude = glob.startsWith('^')\n if (exclude) {\n glob = glob.substring(1)\n }\n const negative = glob.startsWith('!')\n if (negative) {\n glob = glob.substring(1)\n }\n\n if (glob.startsWith('/')) {\n if (relativePath.endsWith('/')) {\n relativePath = relativePath.substring(0, relativePath.length - 1)\n }\n glob = relativePath + glob\n } else {\n if (!relativePath.endsWith('/')) {\n relativePath += '/'\n }\n if (glob.startsWith('./')) {\n glob = relativePath + glob.substring(2)\n } else if (glob.startsWith('../')) {\n glob = relativePath + glob\n } else {\n if (relativePath.startsWith('..')) {\n relativePath = ''\n }\n if (glob.startsWith('**')) {\n glob = relativePath + glob\n } else {\n glob = relativePath + '**/' + glob\n }\n }\n }\n\n glob = path.normalize(glob).replace(/\\\\/g, '/')\n\n if (negative) {\n glob = '!' + glob\n }\n if (exclude) {\n glob = '^' + glob\n }\n return glob\n}\n","export function globGitIgnoreToPicomatch(glob: string): string {\n const negative = glob.startsWith('!')\n if (negative) {\n glob = glob.substring(1)\n }\n // Convert glob from .gitignore to picomatch format\n // Because AI agents understands picomatch format better\n if (glob.startsWith('/')) {\n glob = glob.substring(1)\n } else if (!glob.startsWith('**') && !glob.startsWith('../')) {\n glob = `**/${glob}`\n }\n if (negative) {\n glob = '!' + glob\n }\n return glob\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport { globToRelative } from './globToRelative'\nimport { poolRunWait } from '@flemist/time-limits'\nimport { poolFs } from './pools'\nimport { globGitIgnoreToPicomatch } from 'src/tools/fs/globGitIgnoreToPicomatch'\n\n/**\n * @import {CreateMatchPathOptions} from \"./walkPaths/createMatchPath\"\n */\n\n// see CreateMatchPathOptions['globs'] for glob syntax\nexport type Glob = {\n value: string\n valueType: 'file-contains-patterns' | 'pattern'\n /**\n * exclude like .gitignore by adding ^ prefix to glob.\n * @see CreateMatchPathOptions\n */\n exclude: boolean\n}\nexport type LoadGlobsOptions = {\n /** default: cwd */\n rootDir?: string | null\n globs?: Glob[] | null\n}\n\nfunction globExclude(glob: string): string {\n return '^' + glob\n}\n\nexport async function loadGlobsFromFile(filePath: string): Promise<string[]> {\n const content = await fs.promises.readFile(filePath, 'utf-8')\n const lines = content.split('\\n')\n const globs: string[] = []\n lines.forEach(line => {\n line = line.trim()\n if (!line || line.startsWith('#')) {\n return\n }\n globs.push(line)\n })\n return globs\n}\n\nexport async function loadGlobs(options: LoadGlobsOptions): Promise<string[]> {\n const rootDir = options.rootDir ?? '.'\n const result: string[] = []\n if (!options.globs?.length) {\n return result\n }\n const filesContainsGlobs: Glob[] = []\n options.globs.forEach(glob => {\n if (!glob.value) {\n return\n }\n if (glob.valueType === 'file-contains-patterns') {\n filesContainsGlobs.push(glob)\n } else if (glob.valueType === 'pattern') {\n result.push(glob.exclude ? globExclude(glob.value) : glob.value)\n }\n })\n if (filesContainsGlobs.length) {\n await Promise.all(\n filesContainsGlobs.map(async glob => {\n await poolRunWait({\n pool: poolFs,\n count: 1,\n func: async () => {\n const filePath = path.resolve(rootDir, glob.value)\n const globs = await loadGlobsFromFile(filePath)\n const relativePath = path.relative(rootDir, path.dirname(filePath))\n globs.forEach(globValue => {\n globValue = globGitIgnoreToPicomatch(globValue)\n globValue = globToRelative(globValue, relativePath)\n result.push(glob.exclude ? globExclude(globValue) : globValue)\n })\n },\n })\n }),\n )\n }\n return result\n}\n","import picomatch from 'picomatch'\nimport * as path from 'path'\n\n/**\n * true - include the path\n * false - exclude the path\n * null - no match, do default action\n */\nexport type MatchPath = (path: string) => boolean | null\nexport type CreateMatchPathOptions = {\n /**\n * Behavior:\n * let include = false\n * let exclude = false\n *\n * for each glob:\n * if glob matched\n * if pattern is `glob` then include = true; exclude = false\n * if pattern is `!glob` then include = false; exclude = false\n * if pattern is `^glob` then exclude = true\n * if pattern is `^!glob` then exclude = false\n * if pattern is `!^glob` then incorrect should throw error\n *\n * result = include && !exclude\n */\n globs: string[]\n rootDir?: string | null\n noCase?: null | boolean\n}\n\n/** .gitignore-like path matching function */\nexport function createMatchPath({\n globs,\n rootDir,\n noCase,\n}: CreateMatchPathOptions): MatchPath {\n type Condition = {\n exclude: boolean\n negative: boolean\n debugInfo: string\n match: (path: string) => boolean\n }\n\n const conditions: Condition[] = []\n globs.forEach(glob => {\n glob = glob.replace(/\\\\/g, '/').trim()\n const exclude = glob.startsWith('^')\n if (exclude) {\n glob = glob.substring(1).trim()\n }\n const negative = glob.startsWith('!')\n if (negative) {\n glob = glob.substring(1).trim()\n }\n if (glob.startsWith('!') || glob.startsWith('^')) {\n throw new Error(\n `Invalid glob pattern: \"${glob}\". The syntax '${glob.substring(0, 2)}' is not supported. Valid glob patterns use: * (match any characters), ** (match any directories), ? (match single character), [abc] (character class), ! (negate pattern), ^ (exclude if included). Examples of valid patterns: \"*.js\", \"src/**/*.ts\", \"!node_modules\", \"^dist\". Avoid starting with '!' after '^' or multiple special prefixes.`,\n )\n }\n if (glob.startsWith('/')) {\n glob = '.' + glob\n }\n\n const globAbsolute = rootDir\n ? path.resolve(rootDir, glob).replace(/\\\\/g, '/')\n : glob\n\n if (!globAbsolute) {\n return\n }\n\n let matcher: (path: string) => boolean\n try {\n matcher = picomatch(globAbsolute, {\n nocase: noCase ?? false,\n dot: true,\n strictBrackets: true, // Validate bracket balance for patterns like \"[\"\n })\n } catch (error) {\n throw new Error(\n `Invalid glob pattern: \"${glob}\". ${error instanceof Error ? error.message : 'Unknown error'}. Valid glob patterns use: * (match any characters), ** (match any directories), ? (match single character), [abc] (character class with balanced brackets), ! (negate pattern), ^ (exclude if included). Examples: \"*.js\", \"src/**/*.ts\", \"!node_modules\", \"[abc]def.txt\". Ensure all brackets [ ] are properly closed and balanced.`,\n )\n }\n\n conditions.push({\n exclude,\n negative,\n debugInfo: globAbsolute,\n match: matcher,\n })\n })\n\n return function matchPath(_path: string) {\n _path = _path.replace(/\\\\/g, '/')\n let include: boolean | null = null\n let exclude = false\n for (let i = 0, len = conditions.length; i < len; i++) {\n const condition = conditions[i]\n const conditionResult = condition.match(_path)\n if (conditionResult) {\n if (condition.exclude) {\n exclude = !condition.negative\n } else {\n include = !condition.negative\n exclude = false\n }\n }\n }\n return exclude ? false : include\n }\n}\n","import { walkPaths } from 'src/tools/fs/walkPaths/walkPaths'\nimport type { Glob } from 'src/tools/fs/loadGlobs'\nimport { loadGlobs } from 'src/tools/fs/loadGlobs'\nimport * as path from 'path'\nimport { createMatchPath } from 'src/tools/fs/walkPaths/createMatchPath'\nimport { NumberRangeOptional } from 'src/helpers/types'\n\nexport type PathType = 'dir' | 'file'\n\nexport type PathListOptionsResult = {\n dirs?: boolean | null\n files?: boolean | null\n dateModified?: boolean | null\n size?: boolean | null\n countFiles?: boolean | null\n}\n\nexport type PathListOptions = {\n /** default: cwd */\n rootDir?: string | null\n /** prepend all globs from gitIgnore files */\n globs?: Glob[] | null\n result: PathListOptionsResult\n dateModified?: null | NumberRangeOptional\n totalSize?: null | NumberRangeOptional\n}\n\nexport type PathListStats = {\n /** Unix timestamp. Dir path should be calculated as max nested files dateModified */\n dateModified?: number | null\n /** File size in bytes */\n size?: number | null\n /** Total files count for dirs: WalkPathStat.countFiles */\n countFiles?: number | null\n}\n\nexport type PathListItem = PathListStats & {\n /** path relative to rootDir */\n path: string\n type: PathType\n}\n\nexport type PathListResult = {\n items: PathListItem[]\n totals: PathListStats\n}\n\nexport async function getPathList(\n options: PathListOptions,\n): Promise<PathListResult> {\n const rootDir = options.rootDir ?? '.'\n const items: PathListItem[] = []\n const totals: PathListStats = {}\n if (options.result.countFiles) {\n totals.countFiles = 0\n }\n if (options.result.size) {\n totals.size = 0\n }\n\n // Load and process globs with revert logic\n const globs = await loadGlobs({\n rootDir,\n globs: options.globs,\n })\n\n await walkPaths({\n paths: [rootDir],\n walkLinks: true,\n matchPath: createMatchPath({\n globs,\n rootDir,\n noCase: true,\n }),\n handlePath: async ({ path: itemPath, stat, itemStat }) => {\n const relativePath = path.relative(rootDir, itemPath)\n\n const isDir = stat.isDirectory()\n const isFile = stat.isFile()\n if (!isDir && !isFile) {\n // Skip unsupported types but add referenced items to statistics\n return true\n }\n\n const _path = (relativePath || '.').replace(/\\\\/g, '/')\n const type = isDir ? 'dir' : 'file'\n const dateModified = isDir\n ? itemStat.maxFileDateModified || null\n : stat.mtimeMs\n const size = isDir ? itemStat.totalSize : stat.size\n const countFiles = isDir ? itemStat.countFiles : null\n\n const item: PathListItem = {\n path: _path,\n type: type,\n }\n if (options.result.dateModified) {\n item.dateModified = dateModified\n }\n if (options.result.size) {\n item.size = size\n }\n if (options.result.countFiles) {\n item.countFiles = countFiles\n }\n\n // Apply date filters if specified\n if (options.dateModified && dateModified != null) {\n const [minDate, maxDate] = options.dateModified\n if (\n (minDate != null && dateModified < minDate) ||\n (maxDate != null && dateModified > maxDate)\n ) {\n return false // Skip this item due to date filter - exclude from totals and items\n }\n }\n\n // Apply size filters if specified\n if (options.totalSize && size != null) {\n const [minSize, maxSize] = options.totalSize\n if (\n (minSize != null && size < minSize) ||\n (maxSize != null && size > maxSize)\n ) {\n return false // Skip this item due to size filter - exclude from totals and items\n }\n }\n\n // Calculate totals for items that pass date/size filters\n // Note: totals include all files/dirs that pass filters, regardless of show options\n if (type === 'file') {\n // Count files only not the same files from directory statistics\n totals.countFiles = (totals.countFiles ?? 0) + 1\n }\n\n if (type === 'file' && size != null) {\n totals.size = (totals.size ?? 0) + size\n }\n\n if (\n dateModified != null &&\n (totals.dateModified == null || dateModified > totals.dateModified)\n ) {\n totals.dateModified = dateModified\n }\n\n // Filter based on result options for what to show in table\n if (isDir && !options.result.dirs) {\n return true // Include in totals but not in items list\n }\n if (isFile && !options.result.files) {\n return true // Include in totals but not in items list\n }\n\n items.push(item)\n return true // Include in totals and items list\n },\n })\n\n return { items, totals }\n}\n","import type { PathListItem, PathListResult } from 'src/tools/fs/getPathList'\n\nexport type PathListToStringField =\n | 'type'\n | 'path'\n | 'dateModified'\n | 'size'\n | 'countFiles'\nexport type PathListToStringSort = {\n field: PathListToStringField\n desc?: boolean | null\n}\nexport type PathListToStringOptions = {\n sort?: PathListToStringSort[] | null\n fields?: PathListToStringField[] | null\n totals?: boolean | null\n}\n\n/**\n Example of output (with headers):\n Date modified (UTC) | Type | Path \n 2025-12-31 23:59:59 | dir | path/to/dir/ \n 2025-12-31 23:59:59 | file | path/to/dir/file.txt\n 2025-12-31 23:59:59 | dir | path/to/dir/subdir/\n 2025-12-31 23:59:59 | file | path/to/dir/subdir/file.txt\n */\nconst UNITS = ['B', 'KB', 'MB', 'GB', 'TB']\nconst UNIT_SIZE = 1024\n\nfunction fileSizeFormat(bytes: number | null | undefined): string {\n if (bytes == null) return '-'\n\n let value = bytes ?? 0\n let unitIndex = 0\n\n while (value >= UNIT_SIZE && unitIndex < UNITS.length - 1) {\n value /= UNIT_SIZE\n unitIndex++\n }\n\n const formatted = unitIndex === 0 ? value.toString() : value.toFixed(2)\n return `${formatted}${UNITS[unitIndex]}`\n}\n\nfunction timeAgoFormat(timestamp: number): string {\n const now = Date.now()\n const diffMs = now - timestamp\n\n if (diffMs < 0) return '0s' // Future dates\n\n const diffSeconds = Math.floor(diffMs / 1000)\n const diffMinutes = Math.floor(diffSeconds / 60)\n const diffHours = Math.floor(diffMinutes / 60)\n const diffDays = Math.floor(diffHours / 24)\n const diffWeeks = Math.floor(diffDays / 7)\n const diffMonths = Math.floor(diffDays / 30)\n const diffYears = Math.floor(diffDays / 365)\n\n if (diffYears > 0) return `${diffYears}Y`\n if (diffMonths > 0) return `${diffMonths}M`\n if (diffWeeks > 0) return `${diffWeeks}w`\n if (diffDays > 0) return `${diffDays}d`\n if (diffHours > 0) return `${diffHours}h`\n if (diffMinutes > 0) return `${diffMinutes}m`\n return `${diffSeconds}s`\n}\n\nfunction pathListSort(\n pathList: PathListItem[],\n sort: PathListToStringSort[],\n): PathListItem[] {\n if (!sort?.length) return pathList\n\n return [...pathList].sort((a, b) => {\n for (let i = 0, len = sort.length; i < len; i++) {\n const sortConfig = sort[i]\n let aValue: string | number | null | undefined\n let bValue: string | number | null | undefined\n\n switch (sortConfig.field) {\n case 'type':\n aValue = a.type\n bValue = b.type\n break\n case 'path':\n aValue = a.path\n bValue = b.path\n break\n case 'dateModified':\n aValue = a.dateModified\n bValue = b.dateModified\n break\n case 'size':\n aValue = a.size\n bValue = b.size\n break\n case 'countFiles':\n aValue = a.countFiles\n bValue = b.countFiles\n break\n }\n\n if (aValue == null) {\n if (bValue == null) {\n continue\n }\n return 1\n }\n if (bValue == null) {\n return -1\n }\n\n const comparison = aValue > bValue ? 1 : aValue < bValue ? -1 : 0\n if (comparison !== 0) {\n return sortConfig.desc ? -comparison : comparison\n }\n }\n return 0\n })\n}\n\nexport function pathListToString(\n pathListResult: PathListResult,\n options: PathListToStringOptions,\n): string {\n const sortedList = pathListSort(pathListResult.items, options.sort ?? [])\n const fields =\n options.fields && options.fields.length > 0 ? options.fields : []\n\n let result = ''\n\n // Only write table if fields are specified\n if (sortedList.length > 0 && fields.length > 0) {\n // Header row\n for (let i = 0, len = fields.length; i < len; i++) {\n const field = fields[i]\n if (i > 0) result += ' | '\n switch (field) {\n case 'dateModified':\n result += 'Time ago (s/m/h/d/w/M/Y)'\n break\n case 'size':\n result += 'Size (B/KB/MB/TB)'\n break\n case 'type':\n result += 'Type'\n break\n case 'path':\n result += 'Path'\n break\n case 'countFiles':\n result += 'Files Count'\n break\n }\n }\n\n // Data rows\n for (let i = 0, len = sortedList.length; i < len; i++) {\n const item = sortedList[i]\n result += '\\n'\n\n for (let j = 0, fieldsLen = fields.length; j < fieldsLen; j++) {\n const field = fields[j]\n if (j > 0) result += ' | '\n\n switch (field) {\n case 'dateModified':\n result += item.dateModified ? timeAgoFormat(item.dateModified) : '-'\n break\n case 'size':\n result += fileSizeFormat(item.size)\n break\n case 'type':\n result += item.type\n break\n case 'path':\n result += item.type === 'dir' ? `${item.path}/` : item.path\n break\n case 'countFiles':\n if (item.type === 'dir') {\n result +=\n item.countFiles != null ? item.countFiles.toString() : '-'\n } else {\n result += '-'\n }\n break\n }\n }\n }\n }\n\n // Add totals if requested\n if (options.totals) {\n if (result.length > 0) {\n result += '\\n---\\n'\n }\n\n const totalSizeFormatted = fileSizeFormat(pathListResult.totals.size ?? 0)\n const lastModifiedPart = pathListResult.totals.dateModified\n ? `, last modified ${timeAgoFormat(pathListResult.totals.dateModified)} ago`\n : ''\n\n result += `Totals: ${pathListResult.totals.countFiles ?? 0} files in dirs, ${totalSizeFormatted}${lastModifiedPart}`\n }\n\n return result\n}\n","export const SERVER_NAME = 'project-tools'\nexport const SERVER_VERSION = '1.0.0'\nexport const AUTH_TOKEN =\n 'd00f70240703039df14c76176a055bce6b5484d2b552ba2c89820f03b8e5e60d'\n\nexport const MAX_FS_LIST_PATHS = 25000\n","import { z } from 'zod'\nimport { getPathList, type PathListOptionsResult } from '../getPathList'\nimport {\n pathListToString,\n type PathListToStringField,\n type PathListToStringSort,\n} from '../pathListToString'\nimport type { Glob } from '../loadGlobs'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport { MAX_FS_LIST_PATHS } from 'src/config/constants'\nimport * as path from 'path'\nimport * as fs from 'fs'\nimport { NumberRangeOptional } from 'src/helpers/types'\n\n/**\n * Parse time ago format like \"59s\", \"23h\", \"12M\", \"123Y\" to milliseconds\n */\nfunction parseTimeAgo(timeAgoStr: string): number {\n const match = timeAgoStr.match(\n /^\\s*(\\d+(?:\\.\\d+)?)\\s*([smhdwMY]|sec(onds?)?|min(utes?)?|hours?|days?|weeks?|months?|years?)\\s*$/i,\n )\n if (!match) {\n throw new Error(\n `Invalid time ago format: \"${timeAgoStr}\". Must be a number followed by a time unit. Valid units: s/sec/seconds (seconds), m/min/minutes (minutes), h/hours (hours), d/days (days), w/weeks (weeks), M/months (months), Y/years (years). Examples: \"30s\", \"0.5h\", \"1.5d\", \"7d\", \"3w\", \"6M\", \"1Y\". Format is case-insensitive except M (months) must be uppercase to distinguish from m (minutes).`,\n )\n }\n\n const value = parseFloat(match[1])\n let unit = match[2]\n if (unit !== 'M') {\n unit = unit.toLowerCase()\n if (unit.startsWith('month')) {\n unit = 'M'\n } else if (unit.length > 1) {\n unit = unit[0]\n }\n }\n\n switch (unit) {\n case 's':\n return value * 1000\n case 'm':\n return value * 60 * 1000\n case 'h':\n return value * 60 * 60 * 1000\n case 'd':\n return value * 24 * 60 * 60 * 1000\n case 'w':\n return value * 7 * 24 * 60 * 60 * 1000\n case 'M':\n return value * 30 * 24 * 60 * 60 * 1000\n case 'y':\n return value * 365 * 24 * 60 * 60 * 1000\n default:\n throw new Error(\n `Unknown time unit: \"${unit}\". Valid time units are: s (seconds), m (minutes), h (hours), d (days), w (weeks), M (months), Y (years). Use uppercase M for months to distinguish from lowercase m for minutes. Examples: \"30s\", \"5m\", \"2h\", \"7d\", \"3w\", \"6M\", \"1Y\".`,\n )\n }\n}\n\n/**\n * Parse size format like \"1B\", \"2KB\", \"5MB\" to bytes\n */\nfunction parseSize(sizeStr: string): number {\n const match = sizeStr.match(/^\\s*(\\d+(?:\\.\\d+)?)\\s*(B|KB|MB|GB|TB)\\s*$/i)\n if (!match) {\n throw new Error(\n `Invalid size format: \"${sizeStr}\". Must be a number (integer or decimal) followed by a size unit. Valid units: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary units (1024-based). Examples: \"1B\", \"2.5KB\", \"100MB\", \"1.2GB\", \"0.5TB\". Units are case-insensitive.`,\n )\n }\n\n const value = parseFloat(match[1])\n const unit = match[2].toUpperCase()\n\n switch (unit) {\n case 'B':\n return value\n case 'KB':\n return value * 1024\n case 'MB':\n return value * 1024 * 1024\n case 'GB':\n return value * 1024 * 1024 * 1024\n case 'TB':\n return value * 1024 * 1024 * 1024 * 1024\n default:\n throw new Error(\n `Unknown size unit: \"${unit}\". Valid size units are: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary calculation (1KB = 1024 bytes). Examples: \"500B\", \"2KB\", \"100MB\", \"1.5GB\", \"2TB\". Units are case-insensitive.`,\n )\n }\n}\n\n/**\n * Validates filesystem list requests\n * WHY: Ensures filesystem list requests have valid parameters\n */\nexport const ListSchema = z.object({\n rootDir: z\n .string()\n .optional()\n .describe(\n 'Root directory to list files from, resolved relative to the current working directory. Leave empty to use current directory. Examples: \"src\" (list src/ subdirectory), \"../parent\" (list parent directory), \"docs/api\" (list nested subdirectory). Path must exist and be accessible.',\n ),\n globs: z\n .array(z.string())\n .optional()\n .describe(\n 'Glob patterns to filter which files/directories to include. Add leading ** to match files and dirs in subdirectories. Examples: [\"**/*.js\"] (JavaScript files), [\"src/**/*.ts\"] (TypeScript files in src), [\"**/dir/\"] (all directories named \"dir\"), [\"!node_modules\"] (exclude {rootDir}/node_modules). If omitted, includes all files matching other criteria. Supports standard glob syntax: * (any chars), ** (any dirs), ? (single char), [abc] (char class).',\n ),\n showFiles: z\n .boolean()\n .optional()\n .describe(\n 'Whether to show regular files in the report table. Set to true to show files, false to hide them from the table. When both showFiles and showDirs are false, nothing will be shown in the table. It Does not affect totals. Default is false (do not show files in the table).',\n ),\n showDirs: z\n .boolean()\n .optional()\n .describe(\n 'Whether to show directories in the report table. Set to true to show directories, false to hide them from the table. When both showFiles and showDirs are false, nothing will be shown in the table. It Does not affect totals. Default is true (show directories in the table).',\n ),\n sortBy: z\n .array(\n z.object({\n field: z\n .enum(['type', 'path', 'lastModified', 'size', 'totalCountFiles'])\n .describe(\n 'Field to sort results by. \"type\" sorts files before directories. \"path\" sorts alphabetically by file/directory name. \"lastModified\" sorts by modification time (newest first when desc=true). \"size\" sorts by file/directory size (largest first when desc=true). \"totalCountFiles\" sorts by total files count (highest first when desc=true, directories only).',\n ),\n desc: z\n .boolean()\n .optional()\n .describe('Sort in descending order (largest/newest first).'),\n }),\n )\n .optional()\n .describe(\n 'Multi-level sorting configuration. Sorts are applied in array order - first sort is primary, second is secondary, etc. Example: [{field: \"type\", desc: false}, {field: \"size\", desc: true}] sorts by type ascending, then by size descending within each type.',\n ),\n fields: z\n .array(z.enum(['type', 'path', 'lastModified', 'size', 'totalCountFiles']))\n .optional()\n .describe(\n 'Which data fields to include in the formatted table output. \"type\" shows file/directory indicator. \"path\" shows relative file/directory path. \"lastModified\" shows last modification time as time-ago format (5m, 2h, 3d, etc). \"size\" shows file/directory size in human-readable format (KB, MB, GB). \"totalCountFiles\" shows total files count for directories (displays \"-\" for files). Adding lastModified, size, or totalCountFiles fields increases processing time. Do not set fields if you want to show only totals summary.',\n ),\n minTimeAgo: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories modified at least this long ago. Only items older than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: \"1h\" (modified more than 1 hour ago), \"7d\" (modified more than 7 days ago), \"6M\" (modified more than 6 months ago).',\n ),\n maxTimeAgo: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories modified at most this long ago. Only items newer than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: \"1h\" (modified within last hour), \"7d\" (modified within last 7 days), \"1M\" (modified within last month). Combine with minTimeAgo for date ranges.',\n ),\n minTotalSize: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories with total size at least this large. Only items with size >= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: \"1KB\" (at least 1 kilobyte), \"100MB\" (at least 100 megabytes), \"1.5GB\" (at least 1.5 gigabytes).',\n ),\n maxTotalSize: z\n .string()\n .optional()\n .describe(\n 'Filter files/directories with total size at most this large. Only items with size <= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: \"1MB\" (up to 1 megabyte), \"500KB\" (up to 500 kilobytes), \"10GB\" (up to 10 gigabytes). Combine with minTotalSize for size ranges.',\n ),\n})\n\nexport type FsManagerListOptions = {\n workingDir?: string | null\n globsExclude?: Glob[]\n}\n\n/**\n * List filesystem paths\n */\nexport async function commandList(\n args: z.infer<typeof ListSchema>,\n options: FsManagerListOptions,\n): Promise<Record<string, any>> {\n const parsedArgs = ListSchema.parse(args)\n const {\n globs,\n showFiles,\n showDirs,\n sortBy,\n minTimeAgo,\n maxTimeAgo,\n minTotalSize,\n maxTotalSize,\n } = parsedArgs\n\n // Validate fields: if provided, must include 'path'\n if (\n parsedArgs.fields &&\n parsedArgs.fields.length > 0 &&\n !parsedArgs.fields.includes('path')\n ) {\n return {\n error:\n 'Fields array must include \"path\" field when fields are specified. The \"path\" field is required to identify files and directories in the output.',\n }\n }\n\n const fields = parsedArgs.fields\n ? parsedArgs.fields.map(o => {\n if (o === 'totalCountFiles') {\n return 'countFiles' // Convert to internal field name\n }\n if (o === 'lastModified') {\n return 'dateModified' // Convert to internal field name\n }\n return o // Keep other fields as is\n })\n : []\n\n let sort: PathListToStringSort[] | null =\n parsedArgs.sortBy?.map(o => {\n let field = o.field as string\n if (field === 'totalCountFiles') {\n field = 'countFiles' // Convert to internal field name\n }\n if (field === 'lastModified') {\n field = 'dateModified' // Convert to internal field name\n }\n return {\n field: field as PathListToStringField,\n desc: o.desc ?? false, // Default to ascending if not specified\n }\n }) || null\n if (!sort || sort.length === 0) {\n // Default sort by path ascending if no sort specified\n sort = [{ field: 'path', desc: false }]\n }\n\n const sortFields = sort?.map(o => o.field) || []\n\n const rootDir = path.resolve(\n options.workingDir || '',\n parsedArgs.rootDir || '',\n )\n\n try {\n // Check if rootDir exists\n try {\n await fs.promises.access(rootDir, fs.constants.F_OK)\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n return {\n error: `Directory does not exist: \"${rootDir}\". Verify the path is correct and accessible. If using rootDir parameter, ensure it exists relative to the current working directory. Use fs-list without rootDir to list the current directory, or check parent directories first.`,\n }\n }\n throw err\n }\n\n // Convert globs to internal format\n const userGlobs: Glob[] =\n globs && globs.length > 0\n ? globs.map(g => ({\n value: g,\n valueType: 'pattern' as const,\n exclude: false,\n }))\n : [{ value: '**', valueType: 'pattern', exclude: false }]\n const excludeGlobs = options.globsExclude || []\n const globsConverted: Glob[] = [...userGlobs, ...excludeGlobs]\n\n // Build result options based on fields and sorting requirements\n const result: PathListOptionsResult = {\n files: showFiles ?? false,\n dirs: showDirs ?? false,\n dateModified:\n fields.includes('dateModified') || sortFields.includes('dateModified'),\n size: fields.includes('size') || sortFields.includes('size'),\n countFiles:\n fields.includes('countFiles') || sortFields.includes('countFiles'),\n }\n\n // Parse time and size filters\n let dateModifiedRange: NumberRangeOptional | null = null\n let totalSizeRange: NumberRangeOptional | null = null\n\n if (minTimeAgo || maxTimeAgo) {\n try {\n const now = Date.now()\n const minDate = maxTimeAgo ? now - parseTimeAgo(maxTimeAgo) : null\n const maxDate = minTimeAgo ? now - parseTimeAgo(minTimeAgo) : null\n dateModifiedRange = [minDate, maxDate]\n } catch (err) {\n return {\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error parsing time ago filter',\n }\n }\n }\n\n if (minTotalSize || maxTotalSize) {\n try {\n const minTotalSizeBytes = minTotalSize ? parseSize(minTotalSize) : null\n const maxTotalSizeBytes = maxTotalSize ? parseSize(maxTotalSize) : null\n totalSizeRange = [minTotalSizeBytes, maxTotalSizeBytes]\n } catch (err) {\n return {\n error:\n err instanceof Error\n ? err.message\n : 'Unknown error parsing size filter',\n }\n }\n }\n\n // Get path list with filters\n const pathListResult = await getPathList({\n rootDir: rootDir || null,\n globs: globsConverted,\n result,\n dateModified: dateModifiedRange,\n totalSize: totalSizeRange,\n })\n\n // Check if the number of paths exceeds the maximum allowed\n if (pathListResult.items.length > MAX_FS_LIST_PATHS) {\n throw new Error(\n `Number of paths (${pathListResult.items.length}) exceeds maximum allowed (${MAX_FS_LIST_PATHS}). Consider using more specific glob patterns or filters to reduce the result set.`,\n )\n }\n\n // Format as string\n const formattedOutput = pathListToString(pathListResult, {\n sort,\n fields: fields as PathListToStringField[],\n totals: true,\n })\n\n return {\n output: formattedOutput,\n }\n } catch (err) {\n return { error: err instanceof Error ? err.message : 'Unknown error' }\n }\n}\n\nexport function mcpRegisterToolFsList(\n mcpRegisterTool: McpRegisterToolFunc,\n options: FsManagerListOptions,\n): void {\n mcpRegisterTool(\n 'fs-list',\n {\n title: 'List Filesystem Paths',\n description: `List files and directories with advanced filtering, sorting and formatting options. Features include: glob pattern filtering (gitignore-style syntax), date modification filters (modified within/before time ranges), size filters (binary units B/KB/MB/GB/TB), multi-field sorting (type/path/date/size/totalCountFiles), custom field selection, and formatted table output. Returns structured table text with pipe-separated columns. Use showFiles/showDirs to control what types are shown in report table. The totalCountFiles field shows total files count for directories. Supports complex queries like \"all TypeScript files larger than 1KB modified in the last week\".`,\n inputSchema: ListSchema.shape,\n },\n async args => {\n const result = await commandList(args, options)\n if (result.error) {\n return `Method: fs-list(${JSON.stringify(args)})\\nError: ${result.error}`\n }\n return `Method: fs-list(${JSON.stringify(args)})\\n${result.output || JSON.stringify(result, null, 2)}`\n },\n )\n}\n","import {\n type FsManagerListOptions,\n mcpRegisterToolFsList,\n} from 'src/tools/fs/methods/list'\nimport type { McpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport * as path from 'path'\n\nexport type FsManagerOptions = {\n workingDir?: string | null\n list?: Omit<FsManagerListOptions, 'workingDir'> | null\n}\n\nexport function mcpRegisterFsManager(\n mcpRegisterTool: McpRegisterToolFunc,\n options: FsManagerOptions,\n): void {\n mcpRegisterToolFsList(mcpRegisterTool, {\n workingDir: options.workingDir || null,\n ...options.list,\n })\n\n console.log(\n `File manager:\n- Working directory: ${path.resolve(options.workingDir || '')}\n`,\n )\n}\n","import type { Request, Response } from 'express'\nimport { logToFile } from 'src/helpers/logToFile'\n\nexport type ErrorMiddlewareOptions = {\n logFilePath: string\n}\n\nexport function createErrorMiddleware(options: ErrorMiddlewareOptions) {\n const { logFilePath } = options\n\n return async function errorErrorMiddleware(\n err: Error,\n req: Request,\n res: Response,\n next: () => void,\n ) {\n await logToFile({\n logFilePath,\n message: 'ERROR',\n data: {\n request: {\n url: req.url,\n method: req.method,\n headers: req.headers,\n body: req.body,\n },\n error: err.message,\n stack: err.stack,\n },\n })\n res.status(500).send({\n error: 'Internal Server Error',\n message: err.stack || err.message || err.toString(),\n })\n }\n}\n","import express, { type Express, type Router } from 'express'\nimport * as cors from 'cors'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { Server } from 'http'\nimport { createAuthMiddleware } from './createAuthMiddleware'\nimport { createStreamableHttpHandler } from 'src/server/transport/streamable-http/StreamableHttpHandler'\nimport * as path from 'path'\nimport {\n mcpRegisterProcessManager,\n type ProcessManagerOptions,\n} from 'src/tools/process'\nimport { createMcpRegisterToolFunc } from 'src/server/createMcpRegisterToolFunc'\nimport { type FsManagerOptions, mcpRegisterFsManager } from 'src/tools/fs'\nimport { createErrorMiddleware } from 'src/server/createErrorMiddleware'\n\n/**\n * Get timestamped log file name\n */\nfunction createLogFileName(): string {\n const timestamp = new Date()\n .toISOString()\n .substring(0, 19)\n .replace(/T/, '_')\n .replace(/:/g, '-')\n return `mcp_${timestamp}.log`\n}\n\nexport type CreateServerOptions = {\n logFilePath: string\n}\n\nexport function createServer(options: CreateServerOptions): Express {\n const app = express()\n const baseRouter = createBaseRouter({\n logFilePath: options.logFilePath,\n })\n app.use(baseRouter)\n return app\n}\n\nexport type McpServerOptions = {\n name: string\n version: string\n authToken: string\n logFilePath: string\n enableJsonResponse?: boolean | null\n}\n\nexport function createMcpServer(options: McpServerOptions): {\n mcpServer: McpServer\n mcpRouter: Router\n} {\n const mcpServer = new McpServer({\n name: options.name,\n version: options.version,\n title: 'Project Tools',\n })\n\n const mcpRouter = createMcpRouter(mcpServer, options)\n\n return {\n mcpServer,\n mcpRouter,\n }\n}\n\nexport type CreateBaseRouterOptions = {\n logFilePath: string\n}\n\nexport function createBaseRouter(options: CreateBaseRouterOptions): Router {\n const router = express.Router()\n\n router.use(\n cors.default({\n origin: '*',\n credentials: true,\n allowedHeaders: [\n 'Content-Type',\n 'Authorization',\n 'X-Session-Id',\n 'mcp-session-id',\n ],\n exposedHeaders: ['mcp-session-id'],\n }),\n )\n router.use(express.json())\n // router.use(createRequestLoggerMiddleware({ logFilePath: options.logFilePath }))\n\n return router\n}\n\nexport function createMcpRouter(\n mcpServer: McpServer,\n options: McpServerOptions,\n): Router {\n const router = express.Router()\n\n router.use(createAuthMiddleware({ authToken: options.authToken }))\n\n router.all('/mcp', createStreamableHttpHandler(mcpServer, options))\n\n return router\n}\n\nexport type StartServerOptions = {\n host?: string | null\n port?: number | null\n logFilePath: string\n}\n\nexport function startServer(\n app: Express,\n options: StartServerOptions,\n): Promise<Server> {\n app.use(createErrorMiddleware({ logFilePath: options.logFilePath }))\n\n return new Promise<Server>((resolve, reject) => {\n let httpServer: Server\n\n const callback = () => {\n resolve(httpServer)\n }\n\n try {\n httpServer = options.host\n ? app.listen(options.port ?? 0, options.host, callback)\n : app.listen(options.port ?? 0, callback)\n httpServer.addListener('error', (err: Error) => {\n reject(err)\n })\n } catch (error) {\n reject(error)\n }\n })\n}\n\nexport function getMcpServerDescription(\n httpServer: Server,\n options: McpServerOptions,\n): string {\n const family = (httpServer.address() as any).family\n const port = (httpServer.address() as any).port\n let host = (httpServer.address() as any).address\n if (host === '::') {\n host = 'localhost'\n } else if (family === 'IPv6') {\n host = `[${host}]`\n }\n const serverUrl = `http://${family === 'IPv6' ? `[${host}]` : host}:${port}`\n\n return `Project Tools - MCP Server Started\n\nServer Name: ${options.name}\nServer Version: ${options.version}\nServer URL: ${serverUrl}/mcp\nSSE Endpoint: ${serverUrl}/sse\n\nLog File: ${path.resolve(options.logFilePath)}`\n}\n\nexport type StartMcpServerOptions = Omit<\n CreateServerOptions & McpServerOptions & StartServerOptions,\n 'logFilePath'\n> & {\n logDir: string\n tools: {\n processManager?: null | ProcessManagerOptions\n fsManager?: null | FsManagerOptions\n }\n}\n\nexport async function startMcpServer(\n options: StartMcpServerOptions,\n): Promise<Server> {\n const logFilePath = path.join(options.logDir, createLogFileName())\n\n const app = createServer({\n logFilePath,\n })\n\n const { mcpServer, mcpRouter } = createMcpServer({\n ...options,\n logFilePath,\n })\n app.use(mcpRouter)\n\n const mcpRegisterTool = createMcpRegisterToolFunc(mcpServer, {\n logFilePath,\n })\n\n if (options.tools.processManager) {\n mcpRegisterProcessManager(mcpRegisterTool, options.tools?.processManager)\n }\n\n if (options.tools.fsManager) {\n mcpRegisterFsManager(mcpRegisterTool, options.tools.fsManager)\n }\n\n const httpServer = await startServer(app, {\n host: options.host,\n port: options.port,\n logFilePath,\n })\n\n console.log(\n getMcpServerDescription(httpServer, {\n name: options.name,\n version: options.version,\n authToken: options.authToken,\n logFilePath,\n enableJsonResponse: options.enableJsonResponse,\n }),\n )\n\n return httpServer\n}\n"],"names":["process","ListSchema","commandList","path","walkPathHandleErrorDefault","priority","fs","link"],"mappings":";;;;;;;;;;;;;;;;;AASO,SAAS,qBAAqB,SAAsC;AACzE,QAAM,EAAE,cAAc;AACtB,SAAO,SAAS,eACd,KACA,KACA,MACM;AACN,UAAM,QACH,IAAI,MAAM,SACX,IAAI,QAAQ,eAAe,QAAQ,WAAW,EAAE;AAElD,QAAI,UAAU,WAAW;AACvB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gBAAgB;AAC9C;AAAA,IACF;AAEA,SAAA;AAAA,EACF;AACF;AClBA,eAAsB,UAAU,SAAoC;AAClE,QAAM,EAAE,aAAa,SAAS,KAAA,IAAS;AACvC,MAAI;AACF,UAAM,aAAY,oBAAI,QAAO,cAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AACjE,UAAM,UACJ,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAChE,UAAM,UAAU,IAAI,SAAS,KAAK,OAAO;AAAA,EAAK,OAAO;AAAA;AAAA;AACrD,UAAM,GAAG,SAAS,MAAM,KAAK,QAAQ,WAAW,GAAG,EAAE,WAAW,MAAM;AACtE,UAAM,GAAG,SAAS,WAAW,aAAa,OAAO;AAAA,EACnD,SAAS,KAAK;AACZ,YAAQ,MAAM,kBAAkB,OAAO,MAAM,GAAG;AAAA,EAClD;AACF;ACNO,MAAM,yCAAyB,IAAA;AAS/B,SAAS,4BACd,WACA,SACA;AACA,SAAO,eAAe,sBACpB,KACA,KACe;AACf,UAAM,YACH,IAAI,QAAQ,gBAAgB,KAC5B,IAAI,QAAQ,cAAc,KAC1B,IAAI,MAAM;AACb,QAAI;AAEJ,QAAI,IAAI,WAAW,QAAQ;AACzB,YAAM,UAAU;AAAA,QACd,aAAa,QAAQ;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,IAAI;AAAA,MAAA,CACX;AAED,UAAI,aAAa,mBAAmB,IAAI,SAAS,GAAG;AAClD,oBAAY,mBAAmB,IAAI,SAAS;AAAA,MAC9C,OAAO;AACL,oBAAY,IAAI,8BAA8B;AAAA,UAC5C,oBAAoB,MAClB,aAAa,YAAY,EAAE,EAAE,SAAS,KAAK;AAAA,UAC7C,sBAAsB,CAAC,OAAe;AACpC,+BAAmB,IAAI,IAAI,SAAS;AACpC,oBAAQ,IAAI,wBAAwB,EAAE,EAAE;AAAA,UAC1C;AAAA,UACA,oBAAoB,QAAQ,sBAAsB;AAAA,QAAA,CACnD;AAED,kBAAU,UAAU,MAAM;AACxB,cAAI,UAAU,WAAW;AACvB,+BAAmB,OAAO,UAAU,SAAS;AAC7C,oBAAQ,IAAI,mBAAmB,UAAU,SAAS,EAAE;AAAA,UACtD;AAAA,QACF;AAEA,cAAM,UAAU,QAAQ,SAAS;AAGjC,YAAI,WAAW;AACb,6BAAmB,IAAI,WAAW,SAAS;AAAA,QAC7C;AAAA,MACF;AAEiB,YAAM,UAAU,cAAc,KAAK,KAAK,IAAI,IAAI;AAAA,IACnE,WAAW,IAAI,WAAW,OAAO;AAC/B,UAAI,aAAa,mBAAmB,IAAI,SAAS,GAAG;AAClD,oBAAY,mBAAmB,IAAI,SAAS;AAC5C,cAAM,UAAU,cAAc,KAAK,GAAG;AAAA,MACxC,OAAO;AACL,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,oBAAoB;AAAA,MACpD;AAAA,IACF,OAAO;AACL,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sBAAsB;AAAA,IACtD;AAAA,EACF;AACF;AC7EO,SAAS,eAAe,SAAwC;AACrE,QAAM,EAAE,gBAAgB;AAExB,QAAM,QAAQ,YAAY,MAAM,mBAAmB;AACnD,SAAO,QAAQ,MAAM,CAAC,KAAK,MAAM,CAAC,IAAI,YAAY,MAAM,GAAG,EAAE,CAAC;AAChE;ACLO,MAAM,gCAAgB,IAAA;AAMtB,IAAI,gBAAgB;AAMpB,MAAM,gBAAgB;AAMtB,MAAM,uBAAuB,KAAK,KAAK;AAMvC,MAAM,eAAe;AAMrB,MAAM,uBAAuB;AAM7B,MAAM,eAAe;AAWrB,SAAS,iBAAiB,SAA2C;AAC1E,QAAM,EAAE,aAAa,gBAAA,IAAoB;AACzC,QAAM,UAAU,eAAe,EAAE,aAAa;AAC9C,SAAO,gBAAgB;AAAA,IACrB,aACE,YAAY,WAAW,QAAQ,YAAA,MAAkB,QAAQ,YAAA;AAAA,EAAY;AAE3E;AAMO,SAAS,mBAA2B;AACzC,SAAO,EAAE;AACX;AAEA,IAAI,sBAAsB;AAEnB,SAAS,yBAA+B;AAC7C,MAAI,qBAAqB;AACvB;AAAA,EACF;AACA,wBAAsB;AAEtB,QAAM,OAAO,MAAY;AACvB,YAAQ,IAAI,qCAAqC;AAEjD,eAAW,CAAC,IAAIA,QAAO,KAAK,MAAM,KAAK,UAAU,QAAA,CAAS,GAAG;AAC3D,UAAIA,SAAQ,aAAaA,SAAQ,KAAK;AACpC,YAAI;AACF,mBAASA,SAAQ,KAAK,SAAS;AAAA,QACjC,SAAS,KAAK;AACZ,kBAAQ,MAAM,yBAAyB,EAAE,KAAK,GAAG;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,GAAG,UAAU,IAAI;AACzB,UAAQ,GAAG,WAAW,IAAI;AAC5B;AC5FO,SAAS,sBAA4B;AAC1C,QAAM,MAAM,KAAK,IAAA;AACjB,QAAM,WAAqB,CAAA;AAE3B,aAAW,CAAC,IAAIA,QAAO,KAAK,MAAM,KAAK,UAAU,QAAA,CAAS,GAAG;AAC3D,QAAI,CAACA,SAAQ,aAAaA,SAAQ,SAAS;AACzC,YAAM,eAAe,MAAMA,SAAQ,QAAQ,QAAA;AAC3C,UAAI,eAAe,sBAAsB;AACvC,iBAAS,KAAK,EAAE;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,aAAW,MAAM,UAAU;AACzB,cAAU,OAAO,EAAE;AAAA,EACrB;AACF;ACXO,SAAS,oBAAoB,SAA2C;AAC7E,QAAM,EAAE,SAAAA,aAAY;AACpB,QAAM,MAAM,KAAK,IAAA;AACjB,QAAM,sBAAsB,MAAMA,SAAQ,eAAe,QAAA;AAEzD,MAAI,uBAAuB,sBAAsB;AAC/C,IAAAA,SAAQ,UAAUA,SAAQ;AAC1B,IAAAA,SAAQ,cAAc;AACtB,IAAAA,SAAQ,iBAAiB,IAAI,KAAK,GAAG;AAGrC,QAAIA,SAAQ,OAAO,SAAS,cAAc;AACxC,YAAM,UAAUA,SAAQ,OAAO,SAAS;AACxC,YAAM,cAAc;AAAA,OAAU,OAAO;AAAA;AACrC,YAAM,iBAAiB,eAAe,YAAY;AAElD,UAAI,iBAAiB,GAAG;AACtB,cAAM,OAAO,KAAK,MAAM,iBAAiB,CAAC;AAC1C,QAAAA,SAAQ,SACNA,SAAQ,OAAO,UAAU,GAAG,IAAI,IAChC,cACAA,SAAQ,OAAO;AAAA,UACbA,SAAQ,OAAO,UAAU,iBAAiB;AAAA,QAAA;AAAA,MAEhD,OAAO;AACL,QAAAA,SAAQ,SAASA,SAAQ,OAAO,UAAU,GAAG,YAAY;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AACF;ACnCO,SAAS,SAAS,MAAc,SAAkC;AACvE,QAAM,QAAQ,QAAQ,QAAQ;AAC9B,MAAI,KAAK,UAAU,MAAO,QAAO;AAEjC,QAAM,gBAAgB,KAAK,SAAS;AACpC,QAAM,cAAc;AAAA,OAAU,aAAa;AAAA;AAC3C,QAAM,kBAAkB,QAAQ,YAAY;AAE5C,MAAI,mBAAmB,GAAG;AACxB,WAAO,KAAK,UAAU,GAAG,KAAK;AAAA,EAChC;AAEA,QAAM,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAC3C,SACE,KAAK,UAAU,GAAG,IAAI,IACtB,cACA,KAAK,UAAU,KAAK,UAAU,kBAAkB,KAAK;AAEzD;ACZO,MAAM,eAAe,EAAE,OAAO;AAAA,EACnC,IAAI,EACD,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,SACA,IAAI,YAAY,EAChB,QAAQ,YAAY,EACpB;AAAA,IACC,sJAAsJ,YAAY,yBAAyB,YAAY;AAAA,EAAA;AAE7M,CAAC;AASD,eAAsB,cACpB,MACA,SAC8B;AAC9B,sBAAA;AAEA,QAAM,aAAa,aAAa,MAAM,IAAI;AAC1C,QAAM,EAAE,IAAI,YAAA,IAAgB;AAC5B,QAAMA,WAAU,UAAU,IAAI,EAAE;AAEhC,MAAI,CAACA,UAAS;AACZ,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,sBAAoB,EAAE,SAAAA,UAAS;AAE/B,QAAM,aAAaA,SAAQ,SAASA,SAAQ;AAC5C,QAAM,kBAAkB,SAAS,YAAY,EAAE,OAAO,aAAa;AAGnE,EAAAA,SAAQ,SAAS;AACjB,EAAAA,SAAQ,cAAc;AAEtB,SAAO;AAAA,IACL,IAAIA,SAAQ;AAAA,IACZ,KAAK,KAAK,SAAS,QAAQ,cAAc,IAAIA,SAAQ,GAAG;AAAA,IACxD,aAAaA,SAAQ;AAAA,IACrB,KAAKA,SAAQ;AAAA,IACb,WAAWA,SAAQ,UAAU,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,IACjE,SAASA,SAAQ,SAAS,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,IAC9D,UAAUA,SAAQ;AAAA,IAClB,WAAWA,SAAQ;AAAA,IACnB,QAAQ;AAAA,IACR,OAAOA,SAAQ;AAAA,EAAA;AAEnB;AAEO,SAAS,6BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,aAAa;AAAA,IAAA;AAAA,IAE5B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,cAAc,MAAM,OAAO;AAChD,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,0BAA0B,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACrH;AAAA,EAAA;AAEJ;ACvFO,SAAS,gBAAgB,KAAmB;AAEjD,WAAS,KAAK,WAAW,CAAC,QAAgB;AACxC,QAAI,OAAO,CAAC,IAAI,QAAQ,SAAS,WAAW,GAAG;AAC7C,cAAQ,MAAM,oCAAoC,GAAG,KAAK,GAAG;AAAA,IAC/D;AAAA,EACF,CAAC;AAGD,aAAW,MAAM;AACf,aAAS,KAAK,WAAW,CAAC,QAAgB;AACxC,UAAI,OAAO,CAAC,IAAI,QAAQ,SAAS,WAAW,GAAG;AAC7C,gBAAQ,MAAM,oCAAoC,GAAG,KAAK,GAAG;AAAA,MAC/D;AAAA,IACF,CAAC;AAAA,EACH,GAAG,YAAY;AACjB;ACXO,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EACD,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,QAAA,EACA,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,SACA,IAAI,YAAY,EAChB,QAAQ,YAAY,EACpB;AAAA,IACC,qIAAqI,YAAY,yBAAyB,YAAY;AAAA,EAAA;AAE5L,CAAC;AASD,eAAsB,YACpB,MACA,SAC8B;AAC9B,QAAM,aAAa,WAAW,MAAM,IAAI;AACxC,QAAM,EAAE,IAAI,UAAU,UAAU,gBAAgB;AAChD,QAAMA,WAAU,UAAU,IAAI,EAAE;AAEhC,MAAI,CAACA,UAAS;AACZ,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,QAAM,YAAY,KAAK,IAAA;AACvB,MAAI,mBAAmB;AACvB,MAAI,mBAAmB;AAEvB,MAAI,aAAa,QAAW;AAC1B,UAAM,cAAc,IAAI,QAAc,CAAA,YAAW;AAC/C,YAAM,gBAAgB,YAAY,MAAM;AACtC,YAAI,CAACA,SAAQ,WAAW;AACtB,wBAAc,aAAa;AAC3B,kBAAA;AAAA,QACF,WAAW,KAAK,IAAA,IAAQ,aAAa,WAAW,KAAM;AACpD,wBAAc,aAAa;AAC3B,6BAAmB;AAEnB,cAAI,YAAYA,SAAQ,KAAK;AAC3B,4BAAgBA,SAAQ,GAAG;AAC3B,+BAAmB;AAAA,UACrB;AAEA,kBAAA;AAAA,QACF;AAAA,MACF,GAAG,GAAG;AAAA,IACR,CAAC;AAED,UAAM;AAAA,EACR;AAEA,QAAM,gBAAgB,KAAK,IAAA,IAAQ,aAAa;AAChD,QAAM,SAAS,MAAM;AAAA,IACnB,EAAE,IAAI,YAAA;AAAA,IACN,EAAE,YAAY,QAAQ,WAAA;AAAA,EAAW;AAGnC,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;AAEO,SAAS,2BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,WAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,YAAY,MAAM,OAAO;AAC9C,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,wBAAwB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACnH;AAAA,EAAA;AAEJ;AC/FO,MAAM,YAAY,EAAE,OAAO;AAAA,EAChC,KAAK,EACF,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,QAAA,EACA,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,aAAa,EACV,SACA,IAAI,YAAY,EAChB,QAAQ,YAAY,EACpB;AAAA,IACC,qLAAqL,YAAY,yBAAyB,YAAY;AAAA,EAAA;AAE5O,CAAC;AAUD,eAAsB,WACpB,MACA,SAC8B;AAC9B,sBAAA;AAEA,QAAM,aAAa,UAAU,MAAM,IAAI;AACvC,QAAM,EAAE,aAAa,UAAU,UAAU,gBAAgB;AACzD,QAAM,EAAE,oBAAoB;AAE5B,QAAM,MAAM,KAAK,QAAQ,QAAQ,cAAc,IAAI,WAAW,OAAO,EAAE;AAEvE,MAAI,CAAC,iBAAiB,EAAE,aAAa,gBAAA,CAAiB,GAAG;AACvD,WAAO;AAAA,MACL,OAAO,yBAAyB,WAAW,qGAAqG,gBAAgB,KAAK,IAAI,CAAC,kBAAkB,eAAe,EAAE,YAAA,CAAa,CAAC;AAAA,IAAA;AAAA,EAE/N;AAEA,QAAM,kBAAkB,MAAM,KAAK,UAAU,OAAA,CAAQ,EAAE;AAAA,IACrD,OAAK,EAAE;AAAA,EAAA;AAET,MAAI,gBAAgB,UAAU,eAAe;AAC3C,WAAO;AAAA,MACL,OAAO,6CAA6C,aAAa;AAAA,IAAA;AAAA,EAErE;AAEA,QAAM,KAAK,iBAAA;AACX,QAAM,cAA2B;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA,+BAAe,KAAA;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,oCAAoB,KAAA;AAAA,EAAK;AAG3B,YAAU,IAAI,IAAI,WAAW;AAE7B,MAAI;AACF,UAAM,QAAQ,MAAM,aAAa,IAAI;AAAA,MACnC,OAAO;AAAA,MACP;AAAA,MACA,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAAA,CAC/B;AAED,gBAAY,MAAM,MAAM;AAExB,UAAM,eAAe,CAAC,SAAuB;AAC3C,YAAM,OAAO,KAAK,SAAA;AAClB,kBAAY,eAAe;AAC3B,0BAAoB,EAAE,SAAS,aAAa;AAC5C,cAAQ,IAAI,IAAI;AAAA,IAClB;AAEA,UAAM,QAAQ,GAAG,QAAQ,YAAY;AACrC,UAAM,QAAQ,GAAG,QAAQ,YAAY;AAErC,UAAM,GAAG,SAAS,CAAA,SAAQ;AACxB,kBAAY,YAAY;AACxB,kBAAY,8BAAc,KAAA;AAC1B,kBAAY,WAAW,SAAS,OAAO,OAAO;AAG9C,kBAAY,UAAU,YAAY;AAClC,kBAAY,cAAc;AAE1B,UAAI,YAAY,OAAO,SAAS,cAAc;AAC5C,cAAM,UAAU,YAAY,OAAO,SAAS;AAC5C,cAAM,cAAc;AAAA,OAAU,OAAO;AAAA;AACrC,cAAM,iBAAiB,eAAe,YAAY;AAElD,YAAI,iBAAiB,GAAG;AACtB,gBAAM,OAAO,KAAK,MAAM,iBAAiB,CAAC;AAC1C,sBAAY,SACV,YAAY,OAAO,UAAU,GAAG,IAAI,IACpC,cACA,YAAY,OAAO;AAAA,YACjB,YAAY,OAAO,UAAU,iBAAiB;AAAA,UAAA;AAAA,QAEpD,OAAO;AACL,sBAAY,SAAS,YAAY,OAAO,UAAU,GAAG,YAAY;AAAA,QACnE;AAAA,MACF;AAEA,cAAQ,IAAI,WAAW,EAAE,KAAK,WAAW,sBAAsB,IAAI,EAAE;AAAA,IACvE,CAAC;AAED,UAAM,GAAG,SAAS,CAAA,QAAO;AACvB,kBAAY,YAAY;AACxB,kBAAY,8BAAc,KAAA;AAC1B,kBAAY,QAAQ,IAAI;AACxB,cAAQ,MAAM,WAAW,EAAE,WAAW,IAAI,OAAO;AAAA,IACnD,CAAC;AAGD,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,QACL,EAAE,IAAI,UAAU,UAAU,YAAA;AAAA,QAC1B,EAAE,YAAY,QAAQ,WAAA;AAAA,MAAW;AAAA,IAErC;AAEA,WAAO;AAAA,MACL,EAAE,IAAI,YAAA;AAAA,MACN,EAAE,YAAY,QAAQ,WAAA;AAAA,IAAW;AAAA,EAErC,SAAS,KAAK;AACZ,gBAAY,YAAY;AACxB,gBAAY,8BAAc,KAAA;AAC1B,gBAAY,QAAQ,eAAe,QAAQ,IAAI,UAAU;AACzD,WAAO,EAAE,OAAO,YAAY,MAAA;AAAA,EAC9B;AACF;AAEO,SAAS,0BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aAAa,6hBAA6hB,QAAQ,gBAAgB,KAAK,IAAI,CAAC;AAAA,MAC5kB,aAAa,UAAU;AAAA,IAAA;AAAA,IAEzB,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,WAAW,MAAM,OAAO;AAC7C,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,uBAAuB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IAClH;AAAA,EAAA;AAEJ;AC5LO,MAAMC,eAAa,EAAE,OAAO;AAAA,EACjC,iBAAiB,EACd,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,kBAAkB,EACf,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,YAAY,EACT,QAAA,EACA,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,QAAQ,EACL,MAAM,EAAE,QAAQ,EAChB,WACA;AAAA,IACC;AAAA,EAAA;AAEN,CAAC;AASD,eAAsBC,cACpB,MACA,SAC8B;AAC9B,sBAAA;AAEA,QAAM,aAAaD,aAAW,MAAM,IAAI;AACxC,QAAM,EAAE,iBAAiB,kBAAkB,YAAY,WAAW;AAElE,MAAI,cAAc,MAAM,KAAK,UAAU,QAAQ;AAE/C,MAAI,iBAAiB;AACnB,UAAM,UAAU,IAAI,KAAK,gBAAgB,QAAQ,UAAU,GAAG,CAAC;AAC/D,kBAAc,YAAY,OAAO,CAAA,MAAK,EAAE,aAAa,OAAO;AAAA,EAC9D;AAEA,MAAI,kBAAkB;AACpB,UAAM,UAAU,IAAI,KAAK,iBAAiB,QAAQ,UAAU,GAAG,CAAC;AAChE,kBAAc,YAAY,OAAO,CAAA,MAAK,EAAE,WAAW,EAAE,WAAW,OAAO;AAAA,EACzE;AAEA,MAAI,YAAY;AACd,kBAAc,YAAY,OAAO,CAAA,MAAK,EAAE,SAAS;AAAA,EACnD;AAEA,QAAM,SAAS,YAAY,IAAI,CAAAD,aAAW;AACxC,wBAAoB,EAAE,SAAAA,UAAS;AAE/B,QAAI,cAAmC;AAAA,MACrC,IAAIA,SAAQ;AAAA,MACZ,KAAKG,cAAK,SAAS,QAAQ,cAAc,IAAIH,SAAQ,GAAG;AAAA,MACxD,aAAaA,SAAQ;AAAA,MACrB,KAAKA,SAAQ;AAAA,MACb,WAAWA,SAAQ,UAAU,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,MACjE,SAASA,SAAQ,SAAS,YAAA,EAAc,QAAQ,SAAS,GAAG,EAAE,KAAA;AAAA,MAC9D,UAAUA,SAAQ;AAAA,MAClB,WAAWA,SAAQ;AAAA,MACnB,QAAQA,SAAQ,SAASA,SAAQ;AAAA,MACjC,OAAOA,SAAQ;AAAA,IAAA;AAGjB,QAAI,QAAQ;AACV,YAAM,WAAgC,CAAA;AACtC,iBAAW,SAAS,QAAQ;AAC1B,YAAI,SAAS,aAAa;AACxB,mBAAS,KAAK,IAAI,YAAY,KAAK;AAAA,QACrC;AAAA,MACF;AACA,oBAAc;AAAA,IAChB;AAEA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,WAAW,OAAA;AACtB;AAEO,SAAS,2BACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAaC,aAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAMC,cAAY,MAAM,OAAO;AAC9C,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,wBAAwB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACnH;AAAA,EAAA;AAEJ;AChHO,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EACD,OAAA,EACA;AAAA,IACC;AAAA,EAAA;AAEN,CAAC;AAKM,SAAS,YACd,MACqB;AACrB,QAAM,aAAa,WAAW,MAAM,IAAI;AACxC,QAAM,EAAE,OAAO;AACf,QAAMF,WAAU,UAAU,IAAI,EAAE;AAEhC,MAAI,CAACA,UAAS;AACZ,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI,CAACA,SAAQ,WAAW;AACtB,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI,CAACA,SAAQ,KAAK;AAChB,WAAO;AAAA,MACL,OAAO,WAAW,EAAE;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI;AACF,oBAAgBA,SAAQ,GAAG;AAC3B,WAAO,EAAE,SAAS,MAAM,SAAS,+BAA+B,EAAE,GAAA;AAAA,EACpE,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,OAAO,+BAA+B,EAAE,KAAK,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,IAAA;AAAA,EAErG;AACF;AAEO,SAAS,2BACd,iBACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa,WAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,YAAY,IAAI;AAC/B,YAAM,SAAS,OAAO,UAAU;AAChC,aAAO,OAAO;AACd,aAAO,wBAAwB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,MAAM,GAAG,KAAA;AAAA,IACnH;AAAA,EAAA;AAEJ;ACvDO,SAAS,0BACd,iBACA,SACM;AACN,yBAAA;AAEA,4BAA0B,iBAAiB;AAAA,IACzC,YAAY,QAAQ;AAAA,IACpB,GAAG,QAAQ;AAAA,EAAA,CACZ;AACD,+BAA6B,iBAAiB;AAAA,IAC5C,YAAY,QAAQ;AAAA,EAAA,CACrB;AACD,6BAA2B,iBAAiB;AAAA,IAC1C,YAAY,QAAQ;AAAA,EAAA,CACrB;AACD,6BAA2B,iBAAiB;AAAA,IAC1C,YAAY,QAAQ;AAAA,EAAA,CACrB;AACD,6BAA2B,eAAe;AAE1C,UAAQ;AAAA,IACN;AAAA,uBACmB,KAAK,QAAQ,QAAQ,cAAc,EAAE,CAAC;AAAA,sBACvC,QAAQ,IAAI,gBAAgB,KAAK,IAAI,CAAC;AAAA;AAAA,EAAA;AAG5D;ACbO,SAAS,0BACd,QACA,SACqB;AACrB,SAAO,SAAS,gBAGd,MAAM,QAAQ,UAAU;AACxB,UAAM,iBAAkB,UAAU,SAAS;AACzC,YAAM,UAAU;AAAA,QACd,aAAa,QAAQ;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,EAAE,MAAM,KAAA;AAAA,MAAK,CACpB;AAED,YAAM,SAAS,MAAM,SAAS,GAAG,IAAI;AAErC,YAAM,UAAU;AAAA,QACd,aAAa,QAAQ;AAAA,QACrB,SAAS;AAAA,QACT,MAAM;AAAA,MAAA,CACP;AAED,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UAAA;AAAA,QACR;AAAA,MACF;AAAA,IAEJ;AAEA,WAAO,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;ACnEO,SAAS,SAASG,OAAsB;AAC7C,SAAOA,MAAK,MAAM,gBAAgB,EAAG,CAAC;AACxC;AAEO,SAAS,UAAUA,OAAc,MAAwB;AAC9D,SAAO,SAASA,KAAI,IAAI,MAAM,KAAK;AACrC;AAEO,SAAS,YAAY,OAAuB;AACjD,MAAI,MAAM,SAAS,GAAG,GAAG;AAEvB,aAAS;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,KAAK;AAC3B;ACdO,MAAM,SAAgB,IAAI,KAAK,GAAG,KAAA,EAAO,MAAM;ACwEtD,SAAS,SAAS,WAAyB,UAAwB;AACjE,YAAU,aAAa,SAAS;AAChC,YAAU,sBAAsB,KAAK;AAAA,IACnC,UAAU;AAAA,IACV,SAAS;AAAA,EAAA;AAEX,YAAU,cAAc,SAAS;AACjC,YAAU,aAAa,SAAS;AAChC,YAAU,cAAc,SAAS;AACnC;AAEO,MAAM,6BACX,SAASC,4BAA2B,KAAU;AAC5C,MAAI,IAAI,SAAS,UAAU;AACzB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGF,SAAS,WAAW,SAAiD;AACnE,QAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,WAAO,QAAQ,QAAQ;AAAA,MACrB,WAAW;AAAA,MACX,qBAAqB;AAAA,MACrB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,YAAY;AAAA,IAAA,CACb;AAAA,EACH;AACA,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,YAAY,QAAQ,aAAa,oBAAI,IAAA;AAC3C,QAAM,cAAc,QAAQ;AAC5B,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,cAAc,QAAQ;AAC5B,QAAM,WAAW,QAAQ,YAAY,eAAe,CAAC;AACrD,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,aAAa,QAAQ;AAC3B,QAAM,aAAa,QAAQ;AAC3B,QAAM,YAAY,QAAQ;AAE1B,iBAAe,aAAa,KAAU;AACpC,QAAI,aAAa;AACf,UAAI,MAAM,YAAY,GAAG,GAAG;AAC1B,eAAO;AAAA,MACT;AAAA,IACF;AACA,QAAI,2BAA2B,GAAG,GAAG;AACnC,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AAEA,WAAS,OAAO,UAAkB;AAChC,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AACA,QACE,WAAW,uBAAuB,QAClC,WAAW,WAAW,qBACtB;AACA,aAAO;AAAA,IACT;AACA,QACE,WAAW,kBAAkB,QAC7B,QAAQ,WAAW,gBACnB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,SAAO,mBAAmB,OAAM,iBAAgB;AAC9C,UAAM,sBAAsB,oBAAoB,aAAa,YAAY;AAEzE,UAAM,YAA0B;AAAA,MAC9B,WAAW;AAAA,MACX,qBAAqB;AAAA,MACrB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,YAAY;AAAA,IAAA;AAGd,aAAS,QAAQ,UAAkB,UAAwB;AACzD,UAAI,OAAO,SAAS,SAAS,GAAG;AAE9B,cAAM,UAAU,SAAS,UACtB,eAAe,OAAO,EACtB,QAAQ,MAAM,GAAG,EACjB,SAAS,EAAE;AACd,cAAM,UAAU,GAAG,OAAO,KAAK,QAAQ;AACvC,YAAI,YAAY,WAAW;AACzB,qBAAW,UAAU,OAAO;AAAA,QAC9B,OAAO;AACL,kBAAQ,IAAI,OAAO;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,mBAAe,YACb,UACA,MACA,UACAC,WACkB;AAClB,UAAI,CAAC,YAAY;AACf,eAAO;AAAA,MACT;AACA,aAAO,MAAM,YAAY;AAAA,QACvB;AAAA,QACA,MAAM,YAAY;AAChB,cAAI;AACF,mBAAO,MAAM,WAAW;AAAA,cACtB;AAAA,cACA,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA,aAAa;AAAA,YAAA,CACd;AAAA,UACH,SAAS,KAAK;AACZ,kBAAM,aAAa,GAAG;AACtB,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,QACA,OAAO;AAAA,QACP,UAAAA;AAAAA,QACA,aAAa;AAAA,MAAA,CACd;AAAA,IACH;AAEA,mBAAe,YACb,UACA,OACA,aAC8B;AAC9B,YAAM,OAAO,MAAM,YAAY;AAAA,QAC7B;AAAA,QACA,MAAM,MAAMC,YAAG,SAAS,MAAM,QAAQ,EAAE,MAAM,YAAY;AAAA,QAC1D,OAAO;AAAA,QACP,UAAU,eAAe,OAAO,eAAe,GAAG,QAAQ,CAAC;AAAA,QAC3D,aAAa;AAAA,MAAA,CACd;AAED,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,eAAe,KAAK,UAAU;AACjC,eAAO;AAAA,MACT;AAGA,YAAM,SAAS,UAAU,UAAU,IAAI;AACvC,UAAI,UAAU,IAAI,MAAM,GAAG;AACzB,eAAO;AAAA,MACT;AACA,gBAAU,IAAI,MAAM;AAEpB,UAAI,WAAyB;AAAA,QAC3B,WAAW,KAAK;AAAA,QAChB,qBAAqB,KAAK,YAAA,IAAgB,IAAI,KAAK;AAAA,QACnD,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,YAAY;AAAA,MAAA;AAGd,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,eAAe,KAAK,YAAA,IAAgB,IAAI,GAAG,QAAQ;AAAA,MAAA;AAGrD,UAAI,KAAK,kBAAkB;AACzB,YAAI,WAAW;AACb,gBAAM,OAAgB,MAAM,YAAY;AAAA,YACtC;AAAA,YACA,MAAM,MACJA,YAAG,SACA,SAAS,QAAQ,EACjB,MAAM,YAAY,EAClB,KAAK,CAAAC,UAAQA,SAAQ,IAAI;AAAA,YAC9B,OAAO;AAAA,YACP,UAAU;AAAA,YACV,aAAa;AAAA,UAAA,CACd;AAED,cAAI,MAAM;AACR,kBAAM,iBAAiB,MAAM,YAAY,MAAM,OAAO,WAAW;AACjE,gBAAI,gBAAgB;AAClB,yBAAW;AAAA,YACb;AAAA,UACF;AAAA,QACF;AACA,iBAAS,aAAa;AAEtB,YACE,eACA,SAAS,aAAa,SAAS,YAAY,SAAS,aAAa,GACjE;AACA,gBAAM,gBAAgB,MAAM;AAAA,YAC1B;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAEF,cAAI,eAAe;AACjB,qBAAS,WAAW,QAAQ;AAC5B,oBAAQ,UAAU,QAAQ;AAAA,UAC5B;AAAA,QACF;AAEA,eAAO;AAAA,MACT,WAAW,KAAK,eAAe;AAE7B,cAAM,WAAW,MAAM,YAAY;AAAA,UACjC;AAAA,UACA,MAAM,MAAMD,YAAG,SAAS,QAAQ,QAAQ,EAAE,MAAM,YAAY;AAAA,UAC5D,OAAO;AAAA,UACP;AAAA,UACA,aAAa;AAAA,QAAA,CACd;AAED,YAAI,UAAU;AACZ,mBAAS,IAAI,GAAG,MAAM,SAAS,QAAQ,IAAI,KAAK,KAAK;AACnD,qBAAS,CAAC,IAAI,KAAK,KAAK,UAAU,SAAS,CAAC,CAAC;AAAA,UAC/C;AACA,qBAAW,MAAM,WAAW;AAAA,YAC1B,GAAG;AAAA,YACH,OAAO;AAAA,YACP,aAAa;AAAA,YACb,UAAU;AAAA,YACV,OAAO,QAAQ;AAAA,YACf;AAAA,UAAA,CACD;AAAA,QACH;AACA,iBAAS,aAAa;AAAA,MACxB,WAAW,KAAK,UAAU;AACxB,iBAAS,cAAc;AAAA,MACzB;AAEA,UACE,eACA,SAAS,aAAa,SAAS,YAAY,SAAS,aAAa,GACjE;AACA,cAAM,gBAAgB,MAAM;AAAA,UAC1B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAEF,YAAI,eAAe;AACjB,mBAAS,WAAW,QAAQ;AAC5B,kBAAQ,UAAU,QAAQ;AAAA,QAC5B;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,WAA2C,CAAA;AACjD,aAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,YAAM,WAAW,YAAY,MAAM,CAAC,CAAC;AACrC,YAAM,cAAc,YAAY,UAAU,QAAQ,IAAI;AACtD,UAAI,gBAAgB,OAAO;AACzB;AAAA,MACF;AACA,eAAS,KAAK,YAAY,UAAU,GAAG,WAAW,CAAC;AAAA,IACrD;AAEA,UAAM,QAAQ,IAAI,QAAQ;AAE1B,WAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,UAAU,SAAiD;AACzE,SAAO,WAAW,OAAO;AAC3B;ACpVO,SAAS,eAAe,MAAc,cAA8B;AACzE,MAAI,CAAC,gBAAgB,iBAAiB,KAAK;AACzC,WAAO;AAAA,EACT;AACA,QAAM,UAAU,KAAK,WAAW,GAAG;AACnC,MAAI,SAAS;AACX,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AACA,QAAM,WAAW,KAAK,WAAW,GAAG;AACpC,MAAI,UAAU;AACZ,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AAEA,MAAI,KAAK,WAAW,GAAG,GAAG;AACxB,QAAI,aAAa,SAAS,GAAG,GAAG;AAC9B,qBAAe,aAAa,UAAU,GAAG,aAAa,SAAS,CAAC;AAAA,IAClE;AACA,WAAO,eAAe;AAAA,EACxB,OAAO;AACL,QAAI,CAAC,aAAa,SAAS,GAAG,GAAG;AAC/B,sBAAgB;AAAA,IAClB;AACA,QAAI,KAAK,WAAW,IAAI,GAAG;AACzB,aAAO,eAAe,KAAK,UAAU,CAAC;AAAA,IACxC,WAAW,KAAK,WAAW,KAAK,GAAG;AACjC,aAAO,eAAe;AAAA,IACxB,OAAO;AACL,UAAI,aAAa,WAAW,IAAI,GAAG;AACjC,uBAAe;AAAA,MACjB;AACA,UAAI,KAAK,WAAW,IAAI,GAAG;AACzB,eAAO,eAAe;AAAA,MACxB,OAAO;AACL,eAAO,eAAe,QAAQ;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,UAAU,IAAI,EAAE,QAAQ,OAAO,GAAG;AAE9C,MAAI,UAAU;AACZ,WAAO,MAAM;AAAA,EACf;AACA,MAAI,SAAS;AACX,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;AC5DO,SAAS,yBAAyB,MAAsB;AAC7D,QAAM,WAAW,KAAK,WAAW,GAAG;AACpC,MAAI,UAAU;AACZ,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AAGA,MAAI,KAAK,WAAW,GAAG,GAAG;AACxB,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB,WAAW,CAAC,KAAK,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,KAAK,GAAG;AAC5D,WAAO,MAAM,IAAI;AAAA,EACnB;AACA,MAAI,UAAU;AACZ,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;ACWA,SAAS,YAAY,MAAsB;AACzC,SAAO,MAAM;AACf;AAEA,eAAsB,kBAAkB,UAAqC;AAC3E,QAAM,UAAU,MAAM,GAAG,SAAS,SAAS,UAAU,OAAO;AAC5D,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,QAAkB,CAAA;AACxB,QAAM,QAAQ,CAAA,SAAQ;AACpB,WAAO,KAAK,KAAA;AACZ,QAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,GAAG;AACjC;AAAA,IACF;AACA,UAAM,KAAK,IAAI;AAAA,EACjB,CAAC;AACD,SAAO;AACT;AAEA,eAAsB,UAAU,SAA8C;AAC5E,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,SAAmB,CAAA;AACzB,MAAI,CAAC,QAAQ,OAAO,QAAQ;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,qBAA6B,CAAA;AACnC,UAAQ,MAAM,QAAQ,CAAA,SAAQ;AAC5B,QAAI,CAAC,KAAK,OAAO;AACf;AAAA,IACF;AACA,QAAI,KAAK,cAAc,0BAA0B;AAC/C,yBAAmB,KAAK,IAAI;AAAA,IAC9B,WAAW,KAAK,cAAc,WAAW;AACvC,aAAO,KAAK,KAAK,UAAU,YAAY,KAAK,KAAK,IAAI,KAAK,KAAK;AAAA,IACjE;AAAA,EACF,CAAC;AACD,MAAI,mBAAmB,QAAQ;AAC7B,UAAM,QAAQ;AAAA,MACZ,mBAAmB,IAAI,OAAM,SAAQ;AACnC,cAAM,YAAY;AAAA,UAChB,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM,YAAY;AAChB,kBAAM,WAAW,KAAK,QAAQ,SAAS,KAAK,KAAK;AACjD,kBAAM,QAAQ,MAAM,kBAAkB,QAAQ;AAC9C,kBAAM,eAAe,KAAK,SAAS,SAAS,KAAK,QAAQ,QAAQ,CAAC;AAClE,kBAAM,QAAQ,CAAA,cAAa;AACzB,0BAAY,yBAAyB,SAAS;AAC9C,0BAAY,eAAe,WAAW,YAAY;AAClD,qBAAO,KAAK,KAAK,UAAU,YAAY,SAAS,IAAI,SAAS;AAAA,YAC/D,CAAC;AAAA,UACH;AAAA,QAAA,CACD;AAAA,MACH,CAAC;AAAA,IAAA;AAAA,EAEL;AACA,SAAO;AACT;ACpDO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAAsC;AAQpC,QAAM,aAA0B,CAAA;AAChC,QAAM,QAAQ,CAAA,SAAQ;AACpB,WAAO,KAAK,QAAQ,OAAO,GAAG,EAAE,KAAA;AAChC,UAAM,UAAU,KAAK,WAAW,GAAG;AACnC,QAAI,SAAS;AACX,aAAO,KAAK,UAAU,CAAC,EAAE,KAAA;AAAA,IAC3B;AACA,UAAM,WAAW,KAAK,WAAW,GAAG;AACpC,QAAI,UAAU;AACZ,aAAO,KAAK,UAAU,CAAC,EAAE,KAAA;AAAA,IAC3B;AACA,QAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,GAAG;AAChD,YAAM,IAAI;AAAA,QACR,0BAA0B,IAAI,kBAAkB,KAAK,UAAU,GAAG,CAAC,CAAC;AAAA,MAAA;AAAA,IAExE;AACA,QAAI,KAAK,WAAW,GAAG,GAAG;AACxB,aAAO,MAAM;AAAA,IACf;AAEA,UAAM,eAAe,UACjB,KAAK,QAAQ,SAAS,IAAI,EAAE,QAAQ,OAAO,GAAG,IAC9C;AAEJ,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,gBAAU,UAAU,cAAc;AAAA,QAChC,QAAQ,UAAU;AAAA,QAClB,KAAK;AAAA,QACL,gBAAgB;AAAA;AAAA,MAAA,CACjB;AAAA,IACH,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,0BAA0B,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAAA;AAAA,IAEhG;AAEA,eAAW,KAAK;AAAA,MACd;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,OAAO;AAAA,IAAA,CACR;AAAA,EACH,CAAC;AAED,SAAO,SAAS,UAAU,OAAe;AACvC,YAAQ,MAAM,QAAQ,OAAO,GAAG;AAChC,QAAI,UAA0B;AAC9B,QAAI,UAAU;AACd,aAAS,IAAI,GAAG,MAAM,WAAW,QAAQ,IAAI,KAAK,KAAK;AACrD,YAAM,YAAY,WAAW,CAAC;AAC9B,YAAM,kBAAkB,UAAU,MAAM,KAAK;AAC7C,UAAI,iBAAiB;AACnB,YAAI,UAAU,SAAS;AACrB,oBAAU,CAAC,UAAU;AAAA,QACvB,OAAO;AACL,oBAAU,CAAC,UAAU;AACrB,oBAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AACA,WAAO,UAAU,QAAQ;AAAA,EAC3B;AACF;AC/DA,eAAsB,YACpB,SACyB;AACzB,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,QAAwB,CAAA;AAC9B,QAAM,SAAwB,CAAA;AAC9B,MAAI,QAAQ,OAAO,YAAY;AAC7B,WAAO,aAAa;AAAA,EACtB;AACA,MAAI,QAAQ,OAAO,MAAM;AACvB,WAAO,OAAO;AAAA,EAChB;AAGA,QAAM,QAAQ,MAAM,UAAU;AAAA,IAC5B;AAAA,IACA,OAAO,QAAQ;AAAA,EAAA,CAChB;AAED,QAAM,UAAU;AAAA,IACd,OAAO,CAAC,OAAO;AAAA,IACf,WAAW;AAAA,IACX,WAAW,gBAAgB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AAAA,IACD,YAAY,OAAO,EAAE,MAAM,UAAU,MAAM,eAAe;AACxD,YAAM,eAAe,KAAK,SAAS,SAAS,QAAQ;AAEpD,YAAM,QAAQ,KAAK,YAAA;AACnB,YAAM,SAAS,KAAK,OAAA;AACpB,UAAI,CAAC,SAAS,CAAC,QAAQ;AAErB,eAAO;AAAA,MACT;AAEA,YAAM,SAAS,gBAAgB,KAAK,QAAQ,OAAO,GAAG;AACtD,YAAM,OAAO,QAAQ,QAAQ;AAC7B,YAAM,eAAe,QACjB,SAAS,uBAAuB,OAChC,KAAK;AACT,YAAM,OAAO,QAAQ,SAAS,YAAY,KAAK;AAC/C,YAAM,aAAa,QAAQ,SAAS,aAAa;AAEjD,YAAM,OAAqB;AAAA,QACzB,MAAM;AAAA,QACN;AAAA,MAAA;AAEF,UAAI,QAAQ,OAAO,cAAc;AAC/B,aAAK,eAAe;AAAA,MACtB;AACA,UAAI,QAAQ,OAAO,MAAM;AACvB,aAAK,OAAO;AAAA,MACd;AACA,UAAI,QAAQ,OAAO,YAAY;AAC7B,aAAK,aAAa;AAAA,MACpB;AAGA,UAAI,QAAQ,gBAAgB,gBAAgB,MAAM;AAChD,cAAM,CAAC,SAAS,OAAO,IAAI,QAAQ;AACnC,YACG,WAAW,QAAQ,eAAe,WAClC,WAAW,QAAQ,eAAe,SACnC;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,UAAI,QAAQ,aAAa,QAAQ,MAAM;AACrC,cAAM,CAAC,SAAS,OAAO,IAAI,QAAQ;AACnC,YACG,WAAW,QAAQ,OAAO,WAC1B,WAAW,QAAQ,OAAO,SAC3B;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAIA,UAAI,SAAS,QAAQ;AAEnB,eAAO,cAAc,OAAO,cAAc,KAAK;AAAA,MACjD;AAEA,UAAI,SAAS,UAAU,QAAQ,MAAM;AACnC,eAAO,QAAQ,OAAO,QAAQ,KAAK;AAAA,MACrC;AAEA,UACE,gBAAgB,SACf,OAAO,gBAAgB,QAAQ,eAAe,OAAO,eACtD;AACA,eAAO,eAAe;AAAA,MACxB;AAGA,UAAI,SAAS,CAAC,QAAQ,OAAO,MAAM;AACjC,eAAO;AAAA,MACT;AACA,UAAI,UAAU,CAAC,QAAQ,OAAO,OAAO;AACnC,eAAO;AAAA,MACT;AAEA,YAAM,KAAK,IAAI;AACf,aAAO;AAAA,IACT;AAAA,EAAA,CACD;AAED,SAAO,EAAE,OAAO,OAAA;AAClB;ACtIA,MAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,MAAM,IAAI;AAC1C,MAAM,YAAY;AAElB,SAAS,eAAe,OAA0C;AAChE,MAAI,SAAS,KAAM,QAAO;AAE1B,MAAI,QAAQ,SAAS;AACrB,MAAI,YAAY;AAEhB,SAAO,SAAS,aAAa,YAAY,MAAM,SAAS,GAAG;AACzD,aAAS;AACT;AAAA,EACF;AAEA,QAAM,YAAY,cAAc,IAAI,MAAM,aAAa,MAAM,QAAQ,CAAC;AACtE,SAAO,GAAG,SAAS,GAAG,MAAM,SAAS,CAAC;AACxC;AAEA,SAAS,cAAc,WAA2B;AAChD,QAAM,MAAM,KAAK,IAAA;AACjB,QAAM,SAAS,MAAM;AAErB,MAAI,SAAS,EAAG,QAAO;AAEvB,QAAM,cAAc,KAAK,MAAM,SAAS,GAAI;AAC5C,QAAM,cAAc,KAAK,MAAM,cAAc,EAAE;AAC/C,QAAM,YAAY,KAAK,MAAM,cAAc,EAAE;AAC7C,QAAM,WAAW,KAAK,MAAM,YAAY,EAAE;AAC1C,QAAM,YAAY,KAAK,MAAM,WAAW,CAAC;AACzC,QAAM,aAAa,KAAK,MAAM,WAAW,EAAE;AAC3C,QAAM,YAAY,KAAK,MAAM,WAAW,GAAG;AAE3C,MAAI,YAAY,EAAG,QAAO,GAAG,SAAS;AACtC,MAAI,aAAa,EAAG,QAAO,GAAG,UAAU;AACxC,MAAI,YAAY,EAAG,QAAO,GAAG,SAAS;AACtC,MAAI,WAAW,EAAG,QAAO,GAAG,QAAQ;AACpC,MAAI,YAAY,EAAG,QAAO,GAAG,SAAS;AACtC,MAAI,cAAc,EAAG,QAAO,GAAG,WAAW;AAC1C,SAAO,GAAG,WAAW;AACvB;AAEA,SAAS,aACP,UACA,MACgB;AAChB,MAAI,CAAC,MAAM,OAAQ,QAAO;AAE1B,SAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM;AAClC,aAAS,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC/C,YAAM,aAAa,KAAK,CAAC;AACzB,UAAI;AACJ,UAAI;AAEJ,cAAQ,WAAW,OAAA;AAAA,QACjB,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,MAAA;AAGJ,UAAI,UAAU,MAAM;AAClB,YAAI,UAAU,MAAM;AAClB;AAAA,QACF;AACA,eAAO;AAAA,MACT;AACA,UAAI,UAAU,MAAM;AAClB,eAAO;AAAA,MACT;AAEA,YAAM,aAAa,SAAS,SAAS,IAAI,SAAS,SAAS,KAAK;AAChE,UAAI,eAAe,GAAG;AACpB,eAAO,WAAW,OAAO,CAAC,aAAa;AAAA,MACzC;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,iBACd,gBACA,SACQ;AACR,QAAM,aAAa,aAAa,eAAe,OAAO,QAAQ,QAAQ,EAAE;AACxE,QAAM,SACJ,QAAQ,UAAU,QAAQ,OAAO,SAAS,IAAI,QAAQ,SAAS,CAAA;AAEjE,MAAI,SAAS;AAGb,MAAI,WAAW,SAAS,KAAK,OAAO,SAAS,GAAG;AAE9C,aAAS,IAAI,GAAG,MAAM,OAAO,QAAQ,IAAI,KAAK,KAAK;AACjD,YAAM,QAAQ,OAAO,CAAC;AACtB,UAAI,IAAI,EAAG,WAAU;AACrB,cAAQ,OAAA;AAAA,QACN,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,MAAA;AAAA,IAEN;AAGA,aAAS,IAAI,GAAG,MAAM,WAAW,QAAQ,IAAI,KAAK,KAAK;AACrD,YAAM,OAAO,WAAW,CAAC;AACzB,gBAAU;AAEV,eAAS,IAAI,GAAG,YAAY,OAAO,QAAQ,IAAI,WAAW,KAAK;AAC7D,cAAM,QAAQ,OAAO,CAAC;AACtB,YAAI,IAAI,EAAG,WAAU;AAErB,gBAAQ,OAAA;AAAA,UACN,KAAK;AACH,sBAAU,KAAK,eAAe,cAAc,KAAK,YAAY,IAAI;AACjE;AAAA,UACF,KAAK;AACH,sBAAU,eAAe,KAAK,IAAI;AAClC;AAAA,UACF,KAAK;AACH,sBAAU,KAAK;AACf;AAAA,UACF,KAAK;AACH,sBAAU,KAAK,SAAS,QAAQ,GAAG,KAAK,IAAI,MAAM,KAAK;AACvD;AAAA,UACF,KAAK;AACH,gBAAI,KAAK,SAAS,OAAO;AACvB,wBACE,KAAK,cAAc,OAAO,KAAK,WAAW,aAAa;AAAA,YAC3D,OAAO;AACL,wBAAU;AAAA,YACZ;AACA;AAAA,QAAA;AAAA,MAEN;AAAA,IACF;AAAA,EACF;AAGoB;AAClB,QAAI,OAAO,SAAS,GAAG;AACrB,gBAAU;AAAA,IACZ;AAEA,UAAM,qBAAqB,eAAe,eAAe,OAAO,QAAQ,CAAC;AACzE,UAAM,mBAAmB,eAAe,OAAO,eAC3C,mBAAmB,cAAc,eAAe,OAAO,YAAY,CAAC,SACpE;AAEJ,cAAU,WAAW,eAAe,OAAO,cAAc,CAAC,mBAAmB,kBAAkB,GAAG,gBAAgB;AAAA,EACpH;AAEA,SAAO;AACT;AC9MO,MAAM,cAAc;AACpB,MAAM,iBAAiB;AACvB,MAAM,aACX;AAEK,MAAM,oBAAoB;ACYjC,SAAS,aAAa,YAA4B;AAChD,QAAM,QAAQ,WAAW;AAAA,IACvB;AAAA,EAAA;AAEF,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR,6BAA6B,UAAU;AAAA,IAAA;AAAA,EAE3C;AAEA,QAAM,QAAQ,WAAW,MAAM,CAAC,CAAC;AACjC,MAAI,OAAO,MAAM,CAAC;AAClB,MAAI,SAAS,KAAK;AAChB,WAAO,KAAK,YAAA;AACZ,QAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,aAAO;AAAA,IACT,WAAW,KAAK,SAAS,GAAG;AAC1B,aAAO,KAAK,CAAC;AAAA,IACf;AAAA,EACF;AAEA,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ,KAAK;AAAA,IACtB,KAAK;AACH,aAAO,QAAQ,KAAK,KAAK;AAAA,IAC3B,KAAK;AACH,aAAO,QAAQ,KAAK,KAAK,KAAK;AAAA,IAChC,KAAK;AACH,aAAO,QAAQ,IAAI,KAAK,KAAK,KAAK;AAAA,IACpC,KAAK;AACH,aAAO,QAAQ,KAAK,KAAK,KAAK,KAAK;AAAA,IACrC,KAAK;AACH,aAAO,QAAQ,MAAM,KAAK,KAAK,KAAK;AAAA,IACtC;AACE,YAAM,IAAI;AAAA,QACR,uBAAuB,IAAI;AAAA,MAAA;AAAA,EAC7B;AAEN;AAKA,SAAS,UAAU,SAAyB;AAC1C,QAAM,QAAQ,QAAQ,MAAM,4CAA4C;AACxE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR,yBAAyB,OAAO;AAAA,IAAA;AAAA,EAEpC;AAEA,QAAM,QAAQ,WAAW,MAAM,CAAC,CAAC;AACjC,QAAM,OAAO,MAAM,CAAC,EAAE,YAAA;AAEtB,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ,OAAO;AAAA,IACxB,KAAK;AACH,aAAO,QAAQ,OAAO,OAAO;AAAA,IAC/B,KAAK;AACH,aAAO,QAAQ,OAAO,OAAO,OAAO;AAAA,IACtC;AACE,YAAM,IAAI;AAAA,QACR,uBAAuB,IAAI;AAAA,MAAA;AAAA,EAC7B;AAEN;AAMO,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,SAAS,EACN,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,OAAO,EACJ,MAAM,EAAE,QAAQ,EAChB,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,WAAW,EACR,UACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,UACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,QAAQ,EACL;AAAA,IACC,EAAE,OAAO;AAAA,MACP,OAAO,EACJ,KAAK,CAAC,QAAQ,QAAQ,gBAAgB,QAAQ,iBAAiB,CAAC,EAChE;AAAA,QACC;AAAA,MAAA;AAAA,MAEJ,MAAM,EACH,QAAA,EACA,SAAA,EACA,SAAS,kDAAkD;AAAA,IAAA,CAC/D;AAAA,EAAA,EAEF,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,QAAQ,EACL,MAAM,EAAE,KAAK,CAAC,QAAQ,QAAQ,gBAAgB,QAAQ,iBAAiB,CAAC,CAAC,EACzE,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,YAAY,EACT,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,YAAY,EACT,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,cAAc,EACX,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,cAAc,EACX,SACA,WACA;AAAA,IACC;AAAA,EAAA;AAEN,CAAC;AAUD,eAAsB,YACpB,MACA,SAC8B;AAC9B,QAAM,aAAa,WAAW,MAAM,IAAI;AACxC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAGJ,MACE,WAAW,UACX,WAAW,OAAO,SAAS,KAC3B,CAAC,WAAW,OAAO,SAAS,MAAM,GAClC;AACA,WAAO;AAAA,MACL,OACE;AAAA,IAAA;AAAA,EAEN;AAEA,QAAM,SAAS,WAAW,SACtB,WAAW,OAAO,IAAI,CAAA,MAAK;AACzB,QAAI,MAAM,mBAAmB;AAC3B,aAAO;AAAA,IACT;AACA,QAAI,MAAM,gBAAgB;AACxB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC,IACD,CAAA;AAEJ,MAAI,OACF,WAAW,QAAQ,IAAI,CAAA,MAAK;AAC1B,QAAI,QAAQ,EAAE;AACd,QAAI,UAAU,mBAAmB;AAC/B,cAAQ;AAAA,IACV;AACA,QAAI,UAAU,gBAAgB;AAC5B,cAAQ;AAAA,IACV;AACA,WAAO;AAAA,MACL;AAAA,MACA,MAAM,EAAE,QAAQ;AAAA;AAAA,IAAA;AAAA,EAEpB,CAAC,KAAK;AACR,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAE9B,WAAO,CAAC,EAAE,OAAO,QAAQ,MAAM,OAAO;AAAA,EACxC;AAEA,QAAM,aAAa,MAAM,IAAI,OAAK,EAAE,KAAK,KAAK,CAAA;AAE9C,QAAM,UAAU,KAAK;AAAA,IACnB,QAAQ,cAAc;AAAA,IACtB,WAAW,WAAW;AAAA,EAAA;AAGxB,MAAI;AAEF,QAAI;AACF,YAAM,GAAG,SAAS,OAAO,SAAS,GAAG,UAAU,IAAI;AAAA,IACrD,SAAS,KAAU;AACjB,UAAI,IAAI,SAAS,UAAU;AACzB,eAAO;AAAA,UACL,OAAO,8BAA8B,OAAO;AAAA,QAAA;AAAA,MAEhD;AACA,YAAM;AAAA,IACR;AAGA,UAAM,YACJ,SAAS,MAAM,SAAS,IACpB,MAAM,IAAI,CAAA,OAAM;AAAA,MACd,OAAO;AAAA,MACP,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,EACT,IACF,CAAC,EAAE,OAAO,MAAM,WAAW,WAAW,SAAS,OAAO;AAC5D,UAAM,eAAe,QAAQ,gBAAgB,CAAA;AAC7C,UAAM,iBAAyB,CAAC,GAAG,WAAW,GAAG,YAAY;AAG7D,UAAM,SAAgC;AAAA,MACpC,OAAO,aAAa;AAAA,MACpB,MAAM,YAAY;AAAA,MAClB,cACE,OAAO,SAAS,cAAc,KAAK,WAAW,SAAS,cAAc;AAAA,MACvE,MAAM,OAAO,SAAS,MAAM,KAAK,WAAW,SAAS,MAAM;AAAA,MAC3D,YACE,OAAO,SAAS,YAAY,KAAK,WAAW,SAAS,YAAY;AAAA,IAAA;AAIrE,QAAI,oBAAgD;AACpD,QAAI,iBAA6C;AAEjD,QAAI,cAAc,YAAY;AAC5B,UAAI;AACF,cAAM,MAAM,KAAK,IAAA;AACjB,cAAM,UAAU,aAAa,MAAM,aAAa,UAAU,IAAI;AAC9D,cAAM,UAAU,aAAa,MAAM,aAAa,UAAU,IAAI;AAC9D,4BAAoB,CAAC,SAAS,OAAO;AAAA,MACvC,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,OACE,eAAe,QACX,IAAI,UACJ;AAAA,QAAA;AAAA,MAEV;AAAA,IACF;AAEA,QAAI,gBAAgB,cAAc;AAChC,UAAI;AACF,cAAM,oBAAoB,eAAe,UAAU,YAAY,IAAI;AACnE,cAAM,oBAAoB,eAAe,UAAU,YAAY,IAAI;AACnE,yBAAiB,CAAC,mBAAmB,iBAAiB;AAAA,MACxD,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,OACE,eAAe,QACX,IAAI,UACJ;AAAA,QAAA;AAAA,MAEV;AAAA,IACF;AAGA,UAAM,iBAAiB,MAAM,YAAY;AAAA,MACvC,SAAS,WAAW;AAAA,MACpB,OAAO;AAAA,MACP;AAAA,MACA,cAAc;AAAA,MACd,WAAW;AAAA,IAAA,CACZ;AAGD,QAAI,eAAe,MAAM,SAAS,mBAAmB;AACnD,YAAM,IAAI;AAAA,QACR,oBAAoB,eAAe,MAAM,MAAM,8BAA8B,iBAAiB;AAAA,MAAA;AAAA,IAElG;AAGA,UAAM,kBAAkB,iBAAiB,gBAAgB;AAAA,MACvD;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AAED,WAAO;AAAA,MACL,QAAQ;AAAA,IAAA;AAAA,EAEZ,SAAS,KAAK;AACZ,WAAO,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,gBAAA;AAAA,EACvD;AACF;AAEO,SAAS,sBACd,iBACA,SACM;AACN;AAAA,IACE;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa,WAAW;AAAA,IAAA;AAAA,IAE1B,OAAM,SAAQ;AACZ,YAAM,SAAS,MAAM,YAAY,MAAM,OAAO;AAC9C,UAAI,OAAO,OAAO;AAChB,eAAO,mBAAmB,KAAK,UAAU,IAAI,CAAC;AAAA,SAAa,OAAO,KAAK;AAAA,MACzE;AACA,aAAO,mBAAmB,KAAK,UAAU,IAAI,CAAC;AAAA,EAAM,OAAO,UAAU,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IACtG;AAAA,EAAA;AAEJ;AClWO,SAAS,qBACd,iBACA,SACM;AACN,wBAAsB,iBAAiB;AAAA,IACrC,YAAY,QAAQ,cAAc;AAAA,IAClC,GAAG,QAAQ;AAAA,EAAA,CACZ;AAED,UAAQ;AAAA,IACN;AAAA,uBACmB,KAAK,QAAQ,QAAQ,cAAc,EAAE,CAAC;AAAA;AAAA,EAAA;AAG7D;ACnBO,SAAS,sBAAsB,SAAiC;AACrE,QAAM,EAAE,gBAAgB;AAExB,SAAO,eAAe,qBACpB,KACA,KACA,KACA,MACA;AACA,UAAM,UAAU;AAAA,MACd;AAAA,MACA,SAAS;AAAA,MACT,MAAM;AAAA,QACJ,SAAS;AAAA,UACP,KAAK,IAAI;AAAA,UACT,QAAQ,IAAI;AAAA,UACZ,SAAS,IAAI;AAAA,UACb,MAAM,IAAI;AAAA,QAAA;AAAA,QAEZ,OAAO,IAAI;AAAA,QACX,OAAO,IAAI;AAAA,MAAA;AAAA,IACb,CACD;AACD,QAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MACnB,OAAO;AAAA,MACP,SAAS,IAAI,SAAS,IAAI,WAAW,IAAI,SAAA;AAAA,IAAS,CACnD;AAAA,EACH;AACF;ACjBA,SAAS,oBAA4B;AACnC,QAAM,aAAY,oBAAI,KAAA,GACnB,YAAA,EACA,UAAU,GAAG,EAAE,EACf,QAAQ,KAAK,GAAG,EAChB,QAAQ,MAAM,GAAG;AACpB,SAAO,OAAO,SAAS;AACzB;AAMO,SAAS,aAAa,SAAuC;AAClE,QAAM,MAAM,QAAA;AACZ,QAAM,aAAa,iBAElB;AACD,MAAI,IAAI,UAAU;AAClB,SAAO;AACT;AAUO,SAAS,gBAAgB,SAG9B;AACA,QAAM,YAAY,IAAI,UAAU;AAAA,IAC9B,MAAM,QAAQ;AAAA,IACd,SAAS,QAAQ;AAAA,IACjB,OAAO;AAAA,EAAA,CACR;AAED,QAAM,YAAY,gBAAgB,WAAW,OAAO;AAEpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EAAA;AAEJ;AAMO,SAAS,iBAAiB,SAA0C;AACzE,QAAM,SAAS,QAAQ,OAAA;AAEvB,SAAO;AAAA,IACL,KAAK,QAAQ;AAAA,MACX,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,gBAAgB;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,gBAAgB,CAAC,gBAAgB;AAAA,IAAA,CAClC;AAAA,EAAA;AAEH,SAAO,IAAI,QAAQ,MAAM;AAGzB,SAAO;AACT;AAEO,SAAS,gBACd,WACA,SACQ;AACR,QAAM,SAAS,QAAQ,OAAA;AAEvB,SAAO,IAAI,qBAAqB,EAAE,WAAW,QAAQ,UAAA,CAAW,CAAC;AAEjE,SAAO,IAAI,QAAQ,4BAA4B,WAAW,OAAO,CAAC;AAElE,SAAO;AACT;AAQO,SAAS,YACd,KACA,SACiB;AACjB,MAAI,IAAI,sBAAsB,EAAE,aAAa,QAAQ,YAAA,CAAa,CAAC;AAEnE,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,QAAI;AAEJ,UAAM,WAAW,MAAM;AACrB,cAAQ,UAAU;AAAA,IACpB;AAEA,QAAI;AACF,mBAAa,QAAQ,OACjB,IAAI,OAAO,QAAQ,QAAQ,GAAG,QAAQ,MAAM,QAAQ,IACpD,IAAI,OAAO,QAAQ,QAAQ,GAAG,QAAQ;AAC1C,iBAAW,YAAY,SAAS,CAAC,QAAe;AAC9C,eAAO,GAAG;AAAA,MACZ,CAAC;AAAA,IACH,SAAS,OAAO;AACd,aAAO,KAAK;AAAA,IACd;AAAA,EACF,CAAC;AACH;AAEO,SAAS,wBACd,YACA,SACQ;AACR,QAAM,SAAU,WAAW,QAAA,EAAkB;AAC7C,QAAM,OAAQ,WAAW,QAAA,EAAkB;AAC3C,MAAI,OAAQ,WAAW,QAAA,EAAkB;AACzC,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT,WAAW,WAAW,QAAQ;AAC5B,WAAO,IAAI,IAAI;AAAA,EACjB;AACA,QAAM,YAAY,UAAU,WAAW,SAAS,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI;AAE1E,SAAO;AAAA;AAAA,eAEM,QAAQ,IAAI;AAAA,kBACT,QAAQ,OAAO;AAAA,cACnB,SAAS;AAAA,gBACP,SAAS;AAAA;AAAA,YAEb,KAAK,QAAQ,QAAQ,WAAW,CAAC;AAC7C;AAaA,eAAsB,eACpB,SACiB;AACjB,QAAM,cAAc,KAAK,KAAK,QAAQ,QAAQ,mBAAmB;AAEjE,QAAM,MAAM,aAEX;AAED,QAAM,EAAE,WAAW,UAAA,IAAc,gBAAgB;AAAA,IAC/C,GAAG;AAAA,IACH;AAAA,EAAA,CACD;AACD,MAAI,IAAI,SAAS;AAEjB,QAAM,kBAAkB,0BAA0B,WAAW;AAAA,IAC3D;AAAA,EAAA,CACD;AAED,MAAI,QAAQ,MAAM,gBAAgB;AAChC,8BAA0B,iBAAiB,QAAQ,OAAO,cAAc;AAAA,EAC1E;AAEA,MAAI,QAAQ,MAAM,WAAW;AAC3B,yBAAqB,iBAAiB,QAAQ,MAAM,SAAS;AAAA,EAC/D;AAEA,QAAM,aAAa,MAAM,YAAY,KAAK;AAAA,IACxC,MAAM,QAAQ;AAAA,IACd,MAAM,QAAQ;AAAA,IACd;AAAA,EAAA,CACD;AAED,UAAQ;AAAA,IACN,wBAAwB,YAAY;AAAA,MAClC,MAAM,QAAQ;AAAA,MACd,SAAS,QAAQ;AAAA,MACjB,WAAW,QAAQ;AAAA,MACnB;AAAA,MACA,oBAAoB,QAAQ;AAAA,IAAA,CAC7B;AAAA,EAAA;AAGH,SAAO;AACT;"}