diff --git a/apps/rush-mcp-server/package.json b/apps/rush-mcp-server/package.json index ebbbd691ce4..e8b14e82371 100644 --- a/apps/rush-mcp-server/package.json +++ b/apps/rush-mcp-server/package.json @@ -23,11 +23,15 @@ "dependencies": { "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", - "@rushstack/ts-command-line": "workspace:*" + "@rushstack/rush-sdk": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "@modelcontextprotocol/sdk": "~1.10.2", + "zod": "~3.24.3" }, "devDependencies": { "@rushstack/heft": "workspace:*", "local-node-rig": "workspace:*", - "typescript": "~5.8.2" + "typescript": "~5.8.2", + "@types/node": "20.17.19" } } diff --git a/apps/rush-mcp-server/src/index.ts b/apps/rush-mcp-server/src/index.ts new file mode 100644 index 00000000000..7dca0d0f5e9 --- /dev/null +++ b/apps/rush-mcp-server/src/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { log } from './utilities/log'; +export * from './tools'; diff --git a/apps/rush-mcp-server/src/server.ts b/apps/rush-mcp-server/src/server.ts new file mode 100644 index 00000000000..9e4b7e0ced3 --- /dev/null +++ b/apps/rush-mcp-server/src/server.ts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { + type BaseTool, + RushConflictResolverTool, + RushMigrateProjectTool, + RushCommandValidatorTool, + RushWorkspaceDetailsTool, + RushProjectDetailsTool, + RushDocsTool +} from './tools'; + +export class RushMCPServer extends McpServer { + private _rushWorkspacePath: string; + private _tools: BaseTool[] = []; + + public constructor(rushWorkspacePath: string) { + super({ + name: 'rush', + version: '1.0.0' + }); + + this._rushWorkspacePath = rushWorkspacePath; + + this._initializeTools(); + this._registerTools(); + } + + private _initializeTools(): void { + this._tools.push(new RushConflictResolverTool()); + this._tools.push(new RushMigrateProjectTool(this._rushWorkspacePath)); + this._tools.push(new RushCommandValidatorTool()); + this._tools.push(new RushWorkspaceDetailsTool()); + this._tools.push(new RushProjectDetailsTool()); + this._tools.push(new RushDocsTool()); + } + + private _registerTools(): void { + process.chdir(this._rushWorkspacePath); + + for (const tool of this._tools) { + tool.register(this); + } + } +} diff --git a/apps/rush-mcp-server/src/start.ts b/apps/rush-mcp-server/src/start.ts index b2d2e4d1b84..93ab38d285f 100644 --- a/apps/rush-mcp-server/src/start.ts +++ b/apps/rush-mcp-server/src/start.ts @@ -1,2 +1,25 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. + +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; + +import { log } from './utilities/log'; +import { RushMCPServer } from './server'; + +const main = async (): Promise => { + const rushWorkspacePath: string | undefined = process.argv[2]; + if (!rushWorkspacePath) { + throw new Error('Please provide workspace root path as the first argument'); + } + + const server: RushMCPServer = new RushMCPServer(rushWorkspacePath); + const transport: StdioServerTransport = new StdioServerTransport(); + await server.connect(transport); + + log('Rush MCP Server running on stdio'); +}; + +main().catch((error) => { + log('Fatal error running server:', error); + process.exit(1); +}); diff --git a/apps/rush-mcp-server/src/tools/base.tool.ts b/apps/rush-mcp-server/src/tools/base.tool.ts new file mode 100644 index 00000000000..dc9b4d67bdb --- /dev/null +++ b/apps/rush-mcp-server/src/tools/base.tool.ts @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; +import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol'; +import type { + CallToolResultSchema, + ServerNotification, + ServerRequest +} from '@modelcontextprotocol/sdk/types'; +import type { z, ZodRawShape, ZodTypeAny } from 'zod'; + +export type CallToolResult = z.infer; + +type ToolCallback = Args extends ZodRawShape + ? ( + args: z.objectOutputType, + extra: RequestHandlerExtra + ) => CallToolResult | Promise + : ( + extra: RequestHandlerExtra + ) => CallToolResult | Promise; + +export interface IBaseToolOptions { + name: string; + description: string; + schema: Args; +} + +export abstract class BaseTool { + private _options: IBaseToolOptions; + + protected constructor(options: IBaseToolOptions) { + this._options = options; + } + + protected abstract executeAsync(...args: Parameters>): ReturnType>; + + public register(server: McpServer): void { + // TODO: remove ts-ignore + // @ts-ignore + server.tool(this._options.name, this._options.description, this._options.schema, async (...args) => { + try { + const result: CallToolResult = await this.executeAsync(...(args as Parameters>)); + return result; + } catch (error: unknown) { + return { + isError: true, + content: [ + { + type: 'text', + text: error instanceof Error ? error.message : error + } + ] + }; + } + }); + } +} diff --git a/apps/rush-mcp-server/src/tools/conflict-resolver.tool.ts b/apps/rush-mcp-server/src/tools/conflict-resolver.tool.ts new file mode 100644 index 00000000000..20fc16261e8 --- /dev/null +++ b/apps/rush-mcp-server/src/tools/conflict-resolver.tool.ts @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { z } from 'zod'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; +import type { IExecutableSpawnSyncOptions } from '@rushstack/node-core-library'; + +import { CommandRunner } from '../utilities/command-runner'; +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export class RushConflictResolverTool extends BaseTool { + public constructor() { + super({ + name: 'rush_pnpm_lock_file_conflict_resolver', + description: + 'If a user requests to resolve a pnpm-lock.yaml file conflict, use this tool to automatically fix the conflict directly.', + schema: { + lockfilePath: z.string().describe('The path to the pnpm-lock.yaml file, should pass absolute path') + } + }); + } + + private _tryGetSubspaceNameFromLockfilePath( + lockfilePath: string, + rushConfiguration: RushConfiguration + ): string | null { + for (const subspace of rushConfiguration.subspaces) { + const folderPath: string = subspace.getSubspaceConfigFolderPath(); + if (lockfilePath.startsWith(folderPath)) { + return subspace.subspaceName; + } + } + return null; + } + + public async executeAsync({ lockfilePath }: { lockfilePath: string }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const subspaceName: string | null = this._tryGetSubspaceNameFromLockfilePath( + lockfilePath, + rushConfiguration + ); + if (!subspaceName) { + throw new Error('subspace name not found'); + } + + const options: IExecutableSpawnSyncOptions = { + stdio: 'inherit', + currentWorkingDirectory: rushConfiguration.rushJsonFolder + }; + await CommandRunner.runGitCommandAsync(['checkout', '--theirs', lockfilePath], options); + await CommandRunner.runRushCommandAsync(['update', '--subspace', subspaceName], options); + + return { + content: [ + { + type: 'text', + text: 'Conflict resolved successfully' + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/docs.tool.ts b/apps/rush-mcp-server/src/tools/docs.tool.ts new file mode 100644 index 00000000000..ed616dd623f --- /dev/null +++ b/apps/rush-mcp-server/src/tools/docs.tool.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { z } from 'zod'; + +import { BaseTool, type CallToolResult } from './base.tool'; + +interface IDocsResult { + query: string; + results: { + score: number; + text: string; + }[]; + count: number; + searchTimeMs: number; +} + +export class RushDocsTool extends BaseTool { + public constructor() { + super({ + name: 'rush_docs', + description: + 'Search and retrieve relevant sections from Rush official documentation based on user queries.', + schema: { + userQuery: z.string().describe('The user query to search for relevant documentation sections.') + } + }); + } + + public async executeAsync({ userQuery }: { userQuery: string }): Promise { + // An example of a knowledge base that can run, but needs to be replaced with Microsoft’s service. + const response: Response = await fetch('http://47.120.46.115/search', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ query: userQuery, topK: 10 }) + }); + + const result: IDocsResult = (await response.json()) as IDocsResult; + + return { + content: [ + { + type: 'text', + text: result.results.map((item) => item.text).join('\n') + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/index.ts b/apps/rush-mcp-server/src/tools/index.ts new file mode 100644 index 00000000000..025e6d5452c --- /dev/null +++ b/apps/rush-mcp-server/src/tools/index.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export * from './base.tool'; +export * from './migrate-project.tool'; +export * from './project-details.tool'; +export * from './rush-command-validator.tool'; +export * from './workspace-details'; +export * from './conflict-resolver.tool'; +export * from './docs.tool'; diff --git a/apps/rush-mcp-server/src/tools/migrate-project.tool.ts b/apps/rush-mcp-server/src/tools/migrate-project.tool.ts new file mode 100644 index 00000000000..1bdc38d741e --- /dev/null +++ b/apps/rush-mcp-server/src/tools/migrate-project.tool.ts @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { z } from 'zod'; +import { FileSystem, JsonFile } from '@rushstack/node-core-library'; + +import { BaseTool, type CallToolResult } from './base.tool'; +import { getRushConfiguration } from '../utilities/common'; +import path from 'path'; +import type { ISubspacesConfigurationJson } from '@rushstack/rush-sdk/lib/api/SubspacesConfiguration'; +import type { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; +import type { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; +import type { IRushConfigurationJson } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; + +export class RushMigrateProjectTool extends BaseTool { + private _rushWorkspacePath: string; + + public constructor(rushWorkspacePath: string) { + super({ + name: 'rush_migrate_project', + description: 'Migrate a project to a different location or subspace within the Rush monorepo.', + schema: { + projectName: z.string().describe('The name of the project to be migrated'), + targetProjectPath: z.string().optional().describe('The target path to migrate the project to'), + targetSubspaceName: z.string().optional().describe('The target subspace to migrate the project to') + } + }); + + this._rushWorkspacePath = rushWorkspacePath; + } + + private async _modifyAndSaveSubspaceJsonFileAsync( + rushConfiguration: RushConfiguration, + cb: (subspaceNames: string[]) => Promise | string[] + ): Promise { + const subspacesFolderPath: string = path.resolve( + rushConfiguration.commonRushConfigFolder, + 'subspaces.json' + ); + const subspacesConfiguration: ISubspacesConfigurationJson = await JsonFile.loadAsync(subspacesFolderPath); + const newSubspaceNames: string[] = await cb(subspacesConfiguration.subspaceNames); + subspacesConfiguration.subspaceNames = newSubspaceNames; + await JsonFile.saveAsync(subspacesConfiguration, subspacesFolderPath, { + updateExistingFile: true + }); + } + + private async _modifyAndSaveRushConfigurationAsync( + rushConfiguration: RushConfiguration, + cb: ( + projects: IRushConfigurationProjectJson[] + ) => Promise | IRushConfigurationProjectJson[] + ): Promise { + const rushConfigurationJson: IRushConfigurationJson = rushConfiguration.rushConfigurationJson; + const rushConfigurationFile: string = rushConfiguration.rushJsonFile; + const newRushConfigurationProjectJson: IRushConfigurationProjectJson[] = await cb( + rushConfigurationJson.projects + ); + rushConfigurationJson.projects = newRushConfigurationProjectJson; + await JsonFile.saveAsync(rushConfigurationJson, rushConfigurationFile, { updateExistingFile: true }); + } + + public async executeAsync({ + projectName, + targetSubspaceName, + targetProjectPath + }: { + projectName: string; + targetProjectPath: string; + targetSubspaceName: string; + }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const project: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(projectName); + + if (!project) { + return { + isError: true, + content: [{ type: 'text', text: `Project "${projectName}" not found` }] + }; + } + + const rootPath: string = this._rushWorkspacePath; + const sourceProjectSubspaceName: string = project.subspace.subspaceName; + const sourceProjectPath: string = project.projectFolder; + const destinationPath: string = path.resolve(rootPath, targetProjectPath); + const subspacehasOnlyOneProject: boolean = project.subspace.getProjects().length === 1; + + // 1. Remove source subspace folder + if (subspacehasOnlyOneProject) { + const subspaceConfigFolderPath: string = project.subspace.getSubspaceConfigFolderPath(); + await FileSystem.deleteFolderAsync(subspaceConfigFolderPath); + } + + // 2. Move project to target subspace + await FileSystem.moveAsync({ + sourcePath: sourceProjectPath, + destinationPath + }); + + // 3. Update rush configuration + await this._modifyAndSaveRushConfigurationAsync(rushConfiguration, (projects) => { + const projectIndex: number = projects.findIndex(({ packageName }) => packageName === projectName); + projects[projectIndex] = { + ...projects[projectIndex], + subspaceName: targetSubspaceName, + projectFolder: path.relative(rootPath, destinationPath) + }; + return projects; + }); + + // 4. Update `subspaces.json` + await this._modifyAndSaveSubspaceJsonFileAsync(rushConfiguration, (subspaceNames) => { + if (subspacehasOnlyOneProject) { + subspaceNames.splice(subspaceNames.indexOf(sourceProjectSubspaceName), 1); + } + if (!subspaceNames.includes(targetSubspaceName)) { + subspaceNames.push(targetSubspaceName); + } + return subspaceNames; + }); + + return { + content: [ + { + type: 'text', + text: + `Project "${projectName}" migrated to subspace "${targetSubspaceName}" successfully. ` + + `You can ask whether user wants to run "rush update --subspace ${targetSubspaceName}" to update the project. ` + + `If user says "yes" you can run "rush update --subspace ${targetSubspaceName}" directly for them.` + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/project-details.tool.ts b/apps/rush-mcp-server/src/tools/project-details.tool.ts new file mode 100644 index 00000000000..21644eef1f1 --- /dev/null +++ b/apps/rush-mcp-server/src/tools/project-details.tool.ts @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { z } from 'zod'; +import type { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; + +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export class RushProjectDetailsTool extends BaseTool { + public constructor() { + super({ + name: 'rush_project_details', + description: 'Returns the complete project details in JSON format for a given rush project.', + schema: { + projectName: z.string().describe('The name of the project to get details for') + } + }); + } + + public async executeAsync({ projectName }: { projectName: string }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const project: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(projectName); + + if (!project) { + throw new Error(`Project ${projectName} not found`); + } + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + packageJson: project.packageJson, + /** + * Example: `C:\MyRepo\libraries\my-project` + */ + projectFolder: project.projectFolder, + /** + * Example: `libraries/my-project` + */ + projectRelativeFolder: project.projectRelativeFolder, + /** + * Example: `C:\MyRepo\libraries\my-project\config\rush` + */ + projectRushConfigFolder: project.projectRushConfigFolder, + /** + * Example: `my-subspace` + */ + projectSubspaceName: project.subspace.subspaceName + }, + null, + 2 + ) + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/rush-command-validator.tool.ts b/apps/rush-mcp-server/src/tools/rush-command-validator.tool.ts new file mode 100644 index 00000000000..10d2ebee9e4 --- /dev/null +++ b/apps/rush-mcp-server/src/tools/rush-command-validator.tool.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { z } from 'zod'; +import { JsonFile } from '@rushstack/node-core-library'; +import path from 'path'; +import type { ICommandLineJson } from '@rushstack/rush-sdk/lib/api/CommandLineJson'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; + +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export const selectionParamsSet: ReadonlySet = new Set([ + '-t', + '--to', + '--to-except', + '-T', + '--from', + '-f', + '--only', + '-o', + '--impacted-by', + '-i', + '--impacted-by-except', + '-I' +]); + +export class RushCommandValidatorTool extends BaseTool { + public constructor() { + super({ + name: 'rush_command_validator', + description: + 'Validates Rush commands before execution by checking command format and ensuring compliance with Rush command standards. This tool helps prevent invalid command usage and provides guidance on proper parameter selection.', + schema: { + commandName: z.enum(['rush', 'rushx']).describe('The main command to execute (rush or rushx)'), + subCommandName: z + .string() + .describe( + 'The Rush subcommand to validate (install, update, add, remove, purge, list, build, etc.)' + ), + args: z.array(z.string()).describe('The arguments to validate for the subcommand') + } + }); + } + + public async executeAsync({ + commandName, + subCommandName, + args + }: { + commandName: string; + subCommandName: string; + args: string[]; + }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const commandLineJson: ICommandLineJson = await JsonFile.loadAsync( + path.resolve(rushConfiguration.commonFolder, 'config', 'rush', 'command-line.json') + ); + const conditionSubCommandNames: Set = new Set( + commandLineJson.commands + ?.filter((command) => command.commandKind !== 'global') + .map((command) => command.name) + ); + + if (conditionSubCommandNames.has(subCommandName) && !args.some((arg) => selectionParamsSet.has(arg))) { + return { + isError: true, + content: [ + { + type: 'text', + text: `Please add selection parameters like ${Array.from(selectionParamsSet).join( + ', ' + )} to the command and re-validate. The package name should be retrieved from the package.json file in your project folder.` + } + ] + }; + } + + for (const [index, arg] of args.entries()) { + if (selectionParamsSet.has(arg)) { + const packageName: string = args[index + 1]; + const isValidPackage: boolean = + packageName === '.' || rushConfiguration.projects.some((p) => p.packageName === packageName); + + if (!isValidPackage) { + return { + isError: true, + content: [ + { + type: 'text', + text: `The package "${packageName}" does not exist in the Rush workspace. You can retrive package name from 'package.json' file in the project folder.` + } + ] + }; + } + } + } + + const commandStr: string = `${commandName} ${subCommandName} ${args.join(' ')}`; + const text: string = `Command "${commandStr}" validated successfully, you can ${ + commandName === 'rushx' || subCommandName === 'add' ? 'enter the project folder and ' : '' + }execute it now.`; + + return { + content: [ + { + type: 'text', + text + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/workspace-details.ts b/apps/rush-mcp-server/src/tools/workspace-details.ts new file mode 100644 index 00000000000..da93f38abb7 --- /dev/null +++ b/apps/rush-mcp-server/src/tools/workspace-details.ts @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; +import type { IRushConfigurationJson } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; + +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export class RushWorkspaceDetailsTool extends BaseTool { + public constructor() { + super({ + name: 'rush_workspace_details', + description: + 'Retrieves a comprehensive overview of the Rush monorepo project graph in an LLM-friendly format. Use it to answer questions about the current Rush workspace and architecture.', + schema: {} + }); + } + + public async executeAsync(): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const projects: RushConfigurationProject[] = rushConfiguration.projects; + + return { + content: [ + { + type: 'text', + text: this._getWorkspaceDetailsPrompt(rushConfiguration, projects) + } + ] + }; + } + + private _getWorkspaceDetailsPrompt( + rushConfiguration: RushConfiguration, + projects: RushConfigurationProject[] + ): string { + return ` +The following is a comprehensive representation of the Rush monorepo workspace. The information is organized into two sections: + +1. WORKSPACE LEVEL: Contains global configuration information about the Rush workspace itself. +2. PROJECT LEVEL: Lists all projects in the monorepo with their detailed information. + +WORKSPACE LEVEL information includes Rush version, pnpm version, and overall project count. + +PROJECT LEVEL information is separated by tags. Each project contains: +- its direct workspace dependencies package names, marked by "deps: [...]" +- its package name, marked by "packageName: [...]" +- its project type/category, marked by "projectType: [...]" +- its source file location, marked by "projectFolder: [...]" +- its scripts/commands, marked by "scripts: [...]" +- its version, marked by "version: [...]" +- additional metadata if available + +This data is very important. Use it to analyze the workspace and understand the project graph. The user cannot see this data, so don't reference it directly. It is read-only information to help you understand the workspace. + +${this._getRobotReadableWorkspaceDetails(rushConfiguration.rushConfigurationJson, projects)} +`.trim(); + } + + private _getRobotReadableWorkspaceDetails( + rushConfiguration: IRushConfigurationJson, + projects: RushConfigurationProject[] + ): string { + let serializedWorkspace: string = ''; + + // Add workspace-level information with clearer section marking + serializedWorkspace += `======== WORKSPACE LEVEL INFORMATION ========\n`; + serializedWorkspace += `\n`; + serializedWorkspace += ` rushVersion: [${rushConfiguration.rushVersion}]\n`; + serializedWorkspace += ` pnpmVersion: [${rushConfiguration.pnpmVersion}]\n`; + serializedWorkspace += ` projectCount: [${projects.length}]\n`; + serializedWorkspace += `\n\n`; + serializedWorkspace += `======== PROJECT LEVEL INFORMATION ========\n`; + + projects.forEach((project) => { + serializedWorkspace += `<${project.packageName}>\n`; + + serializedWorkspace += ` packageName: [${project.packageName}]\n`; + serializedWorkspace += ` version: [${project.packageJson.version}]\n`; + serializedWorkspace += ` projectFolder: [${project.projectFolder}]\n`; + serializedWorkspace += ` subspaceName: [${project.subspace.subspaceName}]\n`; + + const projectType: string = project.shouldPublish ? 'publishable' : 'local'; + serializedWorkspace += ` projectType: [${projectType}]\n`; + + const dependencies: ReadonlySet = project.dependencyProjects; + const depNames: string[] = Array.from(dependencies, (dep) => dep.packageName); + + if (depNames.length === 0) { + serializedWorkspace += ` deps: []\n`; + } else if (depNames.length <= 5) { + serializedWorkspace += ` deps: [${depNames.join(', ')}]\n`; + } else { + serializedWorkspace += ` deps: [\n ${depNames.join(',\n ')}\n ]\n`; + } + + if (project.packageJson.scripts) { + const scripts: string[] = Object.keys(project.packageJson.scripts); + if (scripts.length === 0) { + serializedWorkspace += ` scripts: []\n`; + } else if (scripts.length <= 5) { + serializedWorkspace += ` scripts: [${scripts.join(', ')}]\n`; + } else { + serializedWorkspace += ` scripts: [\n ${scripts.join(',\n ')}\n ]\n`; + } + } else { + serializedWorkspace += ` scripts: []\n`; + } + + if (project.versionPolicyName) { + serializedWorkspace += ` versionPolicy: [${project.versionPolicyName}]\n`; + } + + if (project.reviewCategory) { + serializedWorkspace += ` reviewCategory: [${project.reviewCategory}]\n`; + } + + serializedWorkspace += `\n\n`; + }); + + return serializedWorkspace; + } +} diff --git a/apps/rush-mcp-server/src/utilities/command-runner.ts b/apps/rush-mcp-server/src/utilities/command-runner.ts new file mode 100644 index 00000000000..f67e00b190c --- /dev/null +++ b/apps/rush-mcp-server/src/utilities/command-runner.ts @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as child_process from 'child_process'; +import { Executable, type IExecutableSpawnSyncOptions } from '@rushstack/node-core-library'; + +interface ICommandResult { + status: number; + stdout: string; + stderr: string; + command: string; + args: string[]; +} + +export class CommandExecutionError extends Error { + public constructor(command: string, args: string[], stderr: string, status: number) { + super(`Command "${command} ${args.join(' ')}" failed with status ${status}:\n${stderr}`); + this.name = 'CommandExecutionError'; + } +} + +export class CommandRunner { + private static readonly _commandCache: Map = new Map(); + + private static _resolveCommand(command: string): string { + const cachedPath: string | null | undefined = this._commandCache.get(command); + if (cachedPath === null) { + throw new Error(`Command "${command}" not found in system PATH`); + } + + if (cachedPath) { + return cachedPath; + } + + const resolvedPath: string | null = Executable.tryResolve(command) ?? null; + this._commandCache.set(command, resolvedPath); + + if (!resolvedPath) { + throw new Error(`Command "${command}" not found in system PATH`); + } + + return resolvedPath; + } + + private static async _executeCommandAsync( + command: string, + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + const commandPath: string = this._resolveCommand(command); + + const result: child_process.SpawnSyncReturns = Executable.spawnSync(commandPath, args, options); + + const status: number = result.status ?? 1; + + if (status !== 0) { + throw new CommandExecutionError(command, args, result.stderr, status); + } + + return { + status, + stdout: result.stdout, + stderr: result.stderr, + command, + args + }; + } + + public static async runRushCommandAsync( + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + return this._executeCommandAsync('rush', args, options); + } + + public static async runRushXCommandAsync( + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + return this._executeCommandAsync('rushx', args, options); + } + + public static async runGitCommandAsync( + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + return this._executeCommandAsync('git', args, options); + } +} diff --git a/apps/rush-mcp-server/src/utilities/common.ts b/apps/rush-mcp-server/src/utilities/common.ts new file mode 100644 index 00000000000..7709416d1c9 --- /dev/null +++ b/apps/rush-mcp-server/src/utilities/common.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as RushLib from '@rushstack/rush-sdk'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; + +export const getRushConfiguration = async (): Promise => { + // Since the MCP server is not always started from the directory of the Rush monorepo, + // it’s necessary to use dynamic import to load the Rush SDK. + const Rush: typeof RushLib = await import('@rushstack/rush-sdk'); + const rushConfiguration: RushConfiguration = Rush.RushConfiguration.loadFromDefaultLocation(); + return rushConfiguration; +}; diff --git a/apps/rush-mcp-server/src/utilities/log.ts b/apps/rush-mcp-server/src/utilities/log.ts new file mode 100644 index 00000000000..26bfa27b80d --- /dev/null +++ b/apps/rush-mcp-server/src/utilities/log.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Terminal, ConsoleTerminalProvider } from '@rushstack/terminal'; + +export const terminal: Terminal = new Terminal(new ConsoleTerminalProvider({ verboseEnabled: true })); + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function log(message?: any, ...optionalParams: any[]): void { + terminal.writeErrorLine(message, ...optionalParams); +} diff --git a/common/changes/@rushstack/mcp-server/origin-main_2025-05-01-15-48.json b/common/changes/@rushstack/mcp-server/origin-main_2025-05-01-15-48.json new file mode 100644 index 00000000000..735c0d6629a --- /dev/null +++ b/common/changes/@rushstack/mcp-server/origin-main_2025-05-01-15-48.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/mcp-server", + "comment": "Add more tools to mcp server", + "type": "patch" + } + ], + "packageName": "@rushstack/mcp-server" +} \ No newline at end of file diff --git a/common/config/rush/browser-approved-packages.json b/common/config/rush/browser-approved-packages.json index 186073a04bf..01b44fa2e61 100644 --- a/common/config/rush/browser-approved-packages.json +++ b/common/config/rush/browser-approved-packages.json @@ -97,6 +97,10 @@ { "name": "tslib", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "zod", + "allowedCategories": [ "libraries" ] } ] } diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json index 231e28659cf..bdcbd6cf572 100644 --- a/common/config/rush/nonbrowser-approved-packages.json +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -78,6 +78,10 @@ "name": "@microsoft/tsdoc-config", "allowedCategories": [ "libraries" ] }, + { + "name": "@modelcontextprotocol/sdk", + "allowedCategories": [ "libraries" ] + }, { "name": "@nodelib/fs.scandir", "allowedCategories": [ "libraries" ] diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index ae605174941..104c481a2f4 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -347,19 +347,31 @@ importers: ../../../apps/rush-mcp-server: dependencies: + '@modelcontextprotocol/sdk': + specifier: ~1.10.2 + version: 1.10.2 '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk '@rushstack/terminal': specifier: workspace:* version: link:../../libraries/terminal '@rushstack/ts-command-line': specifier: workspace:* version: link:../../libraries/ts-command-line + zod: + specifier: ~3.24.3 + version: 3.24.3 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -9601,6 +9613,24 @@ packages: /@microsoft/tsdoc@0.15.1: resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + /@modelcontextprotocol/sdk@1.10.2: + resolution: {integrity: sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==} + engines: {node: '>=18'} + dependencies: + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.3 + eventsource: 3.0.6 + express: 5.1.0 + express-rate-limit: 7.5.0(express@5.1.0) + pkce-challenge: 5.0.0 + raw-body: 3.0.0 + zod: 3.24.3 + zod-to-json-schema: 3.24.5(zod@3.24.3) + transitivePeerDependencies: + - supports-color + dev: false + /@mrmlnc/readdir-enhanced@2.2.1: resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} engines: {node: '>=4'} @@ -11966,7 +11996,7 @@ packages: '@storybook/core-events': 6.4.22 core-js: 3.36.0 global: 4.4.0 - qs: 6.12.0 + qs: 6.13.0 telejson: 5.3.3 dev: true @@ -12054,7 +12084,7 @@ packages: global: 4.4.0 lodash: 4.17.21 memoizerific: 1.11.3 - qs: 6.12.0 + qs: 6.13.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 @@ -12156,7 +12186,7 @@ packages: core-js: 3.36.0 global: 4.4.0 lodash: 4.17.21 - qs: 6.12.0 + qs: 6.13.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 @@ -12472,7 +12502,7 @@ packages: core-js: 3.36.0 global: 4.4.0 lodash: 4.17.21 - qs: 6.12.0 + qs: 6.13.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 @@ -12584,7 +12614,7 @@ packages: history: 5.0.0 lodash: 4.17.21 memoizerific: 1.11.3 - qs: 6.12.0 + qs: 6.13.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) react-router: 6.22.3(@types/react@17.0.74)(react@17.0.2) @@ -12703,7 +12733,7 @@ packages: markdown-to-jsx: 7.4.3(react@17.0.2) memoizerific: 1.11.3 polished: 4.3.1 - qs: 6.12.0 + qs: 6.13.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) react-draggable: 4.4.6(react-dom@17.0.2)(react@17.0.2) @@ -14449,6 +14479,14 @@ packages: mime-types: 2.1.35 negotiator: 0.6.3 + /accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + dev: false + /acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} dependencies: @@ -15501,6 +15539,23 @@ packages: type-is: 1.6.18 unpipe: 1.0.0 + /body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.0 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /bole@4.0.1: resolution: {integrity: sha512-42r0aSOJFJti2l6LasBHq2BuWJzohGs349olQnH/ETlJo87XnoWw7UT8pGE6UstjxzOKkwz7tjoFcmSr6L16vg==} dependencies: @@ -15833,6 +15888,14 @@ packages: normalize-url: 6.1.0 responselike: 2.0.1 + /call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + dev: false + /call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -15843,6 +15906,14 @@ packages: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + /call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + dev: false + /call-me-maybe@1.0.2: resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} dev: true @@ -16460,6 +16531,13 @@ packages: dependencies: safe-buffer: 5.2.1 + /content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: false + /content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -16473,6 +16551,11 @@ packages: /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + /cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + dev: false + /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} @@ -16482,6 +16565,11 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} + /cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + dev: false + /copy-concurrently@1.0.5: resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==} dependencies: @@ -16955,6 +17043,18 @@ packages: ms: 2.1.2 supports-color: 8.1.1 + /debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: false + /debuglog@1.0.1: resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. @@ -17414,6 +17514,15 @@ packages: tslib: 2.3.1 dev: true + /dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + dev: false + /duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} dependencies: @@ -17663,6 +17772,11 @@ packages: dependencies: get-intrinsic: 1.2.4 + /es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + dev: false + /es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} @@ -17709,6 +17823,13 @@ packages: dependencies: es-errors: 1.3.0 + /es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: false + /es-set-tostringtag@2.0.3: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} @@ -18693,6 +18814,18 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + /eventsource-parser@3.0.1: + resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} + engines: {node: '>=18.0.0'} + dev: false + + /eventsource@3.0.6: + resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} + engines: {node: '>=18.0.0'} + dependencies: + eventsource-parser: 3.0.1 + dev: false + /evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} dependencies: @@ -18768,6 +18901,15 @@ packages: jest-message-util: 29.7.0 jest-util: 29.7.0 + /express-rate-limit@7.5.0(express@5.1.0): + resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} + engines: {node: '>= 16'} + peerDependencies: + express: ^4.11 || 5 || ^5.0.0-beta.1 + dependencies: + express: 5.1.0 + dev: false + /express@4.20.0: resolution: {integrity: sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==} engines: {node: '>= 0.10.0'} @@ -18804,6 +18946,41 @@ packages: utils-merge: 1.0.1 vary: 1.1.2 + /express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false + /extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -19071,6 +19248,20 @@ packages: statuses: 2.0.1 unpipe: 1.0.0 + /finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + dependencies: + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /find-cache-dir@2.1.0: resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} engines: {node: '>=6'} @@ -19293,6 +19484,11 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + /fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + dev: false + /from2@2.3.0: resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} dependencies: @@ -19493,6 +19689,22 @@ packages: has-symbols: 1.0.3 hasown: 2.0.2 + /get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + dev: false + /get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -19502,6 +19714,14 @@ packages: engines: {node: '>=8'} dev: true + /get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + dev: false + /get-stream@4.1.0: resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} engines: {node: '>=6'} @@ -19727,6 +19947,11 @@ packages: dependencies: get-intrinsic: 1.2.4 + /gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + dev: false + /got@11.8.6: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} engines: {node: '>=10.19.0'} @@ -19823,6 +20048,11 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + /has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + dev: false + /has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -20794,6 +21024,10 @@ packages: /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: false + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -22449,6 +22683,11 @@ packages: react: 17.0.2 dev: true + /math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + dev: false + /md5.js@1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: @@ -22497,6 +22736,11 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + /media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + dev: false + /mem@8.1.1: resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==} engines: {node: '>=10'} @@ -22560,6 +22804,11 @@ packages: /merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + /merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + dev: false + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -22611,12 +22860,24 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + /mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + dev: false + /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: mime-db: 1.52.0 + /mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.54.0 + dev: false + /mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -22956,6 +23217,11 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} + /negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + dev: false + /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -23247,6 +23513,11 @@ packages: /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + /object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + dev: false + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -23691,6 +23962,11 @@ packages: /path-to-regexp@0.1.10: resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + /path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + dev: false + /path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} engines: {node: '>=4'} @@ -23776,6 +24052,11 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + /pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + engines: {node: '>=16.20.0'} + dev: false + /pkg-dir@3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} @@ -24548,6 +24829,7 @@ packages: engines: {node: '>=0.6'} dependencies: side-channel: 1.0.6 + dev: true /qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} @@ -24555,6 +24837,13 @@ packages: dependencies: side-channel: 1.0.6 + /qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.1.0 + dev: false + /querystring-es3@0.2.1: resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} engines: {node: '>=0.4.x'} @@ -24616,6 +24905,16 @@ packages: iconv-lite: 0.4.24 unpipe: 1.0.0 + /raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + dev: false + /raw-loader@4.0.2(webpack@4.47.0): resolution: {integrity: sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==} engines: {node: '>= 10.13.0'} @@ -25424,6 +25723,19 @@ packages: hash-base: 3.1.0 inherits: 2.0.4 + /router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + dependencies: + debug: 4.4.0 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + dev: false + /rsvp@4.8.5: resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} engines: {node: 6.* || >= 7.*} @@ -25957,6 +26269,25 @@ packages: range-parser: 1.2.1 statuses: 2.0.1 + /send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + dependencies: + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /serialize-javascript@4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} dependencies: @@ -26012,6 +26343,18 @@ packages: parseurl: 1.3.3 send: 0.18.0 + /serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + dev: false + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true @@ -26117,6 +26460,35 @@ packages: rechoir: 0.6.2 dev: true + /side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + dev: false + + /side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + dev: false + + /side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + dev: false + /side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -26126,6 +26498,17 @@ packages: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + /side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + dev: false + /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -27473,6 +27856,15 @@ packages: media-typer: 0.3.0 mime-types: 2.1.35 + /type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + dev: false + /typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -27516,7 +27908,7 @@ packages: /typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} dependencies: - qs: 6.12.0 + qs: 6.13.0 tunnel: 0.0.6 underscore: 1.13.6 dev: true @@ -27848,7 +28240,7 @@ packages: resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} dependencies: punycode: 1.4.1 - qs: 6.12.0 + qs: 6.13.0 /use-composed-ref@1.3.0(react@17.0.2): resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==} @@ -28895,6 +29287,18 @@ packages: readable-stream: 3.6.2 dev: true + /zod-to-json-schema@3.24.5(zod@3.24.3): + resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} + peerDependencies: + zod: ^3.24.1 + dependencies: + zod: 3.24.3 + dev: false + + /zod@3.24.3: + resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} + dev: false + /zwitch@1.0.5: resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} dev: true diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json index 36c19f333d7..e5e157b00f0 100644 --- a/common/config/subspaces/default/repo-state.json +++ b/common/config/subspaces/default/repo-state.json @@ -1,5 +1,5 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "13c465e1adea1d0d99a3d876c393df88da7371e1", + "pnpmShrinkwrapHash": "543a92cc45070b162c2c911f153d08e9577c2c5e", "preferredVersionsHash": "54149ea3f01558a859c96dee2052b797d4defe68" }