Skip to main content
Glama
nrwl

Nx MCP Server

Official
by nrwl
init-nx-cloud-view.ts6.87 kB
import { getPackageManagerCommand } from '@nx-console/shared-npm'; import { TelemetryEventSource } from '@nx-console/shared-telemetry'; import { CIPEInfo, CIPEInfoError } from '@nx-console/shared-types'; import { throttle } from '@nx-console/shared-utils'; import { onWorkspaceRefreshed, showRefreshLoadingAtLocation, } from '@nx-console/vscode-lsp-client'; import { getCloudOnboardingInfo } from '@nx-console/vscode-nx-workspace'; import { getNxlsOutputChannel, showOutputChannel, vscodeLogger, } from '@nx-console/vscode-output-channels'; import { CliTaskProvider } from '@nx-console/vscode-tasks'; import { getTelemetry } from '@nx-console/vscode-telemetry'; import { getWorkspacePath } from '@nx-console/vscode-utils'; import { commands, ExtensionContext, ExtensionMode, ShellExecution, Task, TaskProcessEndEvent, tasks, TaskScope, Uri, window, } from 'vscode'; import { createActor } from 'xstate'; import { getAiFixStatusBarService } from './ai-fix-status-bar-service'; import { CIPENotificationService } from './cipe-notification-service'; import { CloudOnboardingViewProvider } from './cloud-onboarding-view'; import { CloudRecentCIPEProvider } from './cloud-recent-cipe-view'; import { machine } from './cloud-view-state-machine'; import { closeCloudFixDiffTab, NxCloudFixWebview, } from './nx-cloud-fix-webview'; export function initNxCloudView(context: ExtensionContext) { closeCloudFixDiffTab(); const notificationService = new CIPENotificationService(); const statusBarService = getAiFixStatusBarService(); // set up state machine & listeners const actor = createActor( machine.provide({ actions: { compareCIPEDataAndSendNotification: ( _, params: { oldData: CIPEInfo[] | null; newData: CIPEInfo[]; }, ) => { statusBarService.updateAiFixStatusBar(params.newData); notificationService.compareCIPEDataAndSendNotifications( params.oldData, params.newData, ); }, setViewVisible: (_, params: { viewId: string }) => { setCloudViewContext(params.viewId); }, setErrorContext: ({ context }) => { setCIPEErrorContext(context.cipeError?.type); }, }, }), { inspect: getStateMachineLogger(context), systemId: 'cloud-view', }, ).start(); CloudOnboardingViewProvider.create(context, actor); CloudRecentCIPEProvider.create(context, actor); NxCloudFixWebview.create(context, actor); async function updateOnboarding(force = false) { const onboardingInfo = await getCloudOnboardingInfo(force); actor.send({ type: 'UPDATE_ONBOARDING', value: onboardingInfo, }); } const throttledRefresh = throttle(() => { actor.system.get('polling').send({ type: 'FORCE_POLL' }); const loadingPromise = updateOnboarding(true).catch(() => { // ignore errors to make sure the loading state is cleaned up // errors will be shown in nxls logs already }); window.withProgress( { location: { viewId: 'nxCloudLoading' } }, async () => await loadingPromise, ); window.withProgress( { location: { viewId: 'nxCloudRecentCIPE' } }, async () => await loadingPromise, ); window.withProgress( { location: { viewId: 'nxCloudOnboarding' } }, async () => await loadingPromise, ); }, 1000); updateOnboarding(); context.subscriptions.push( onWorkspaceRefreshed(async () => { updateOnboarding(); }), ); context.subscriptions.push( showRefreshLoadingAtLocation({ viewId: 'nxCloudLoading' }), showRefreshLoadingAtLocation({ viewId: 'nxCloudRecentCIPE' }), showRefreshLoadingAtLocation({ viewId: 'nxCloudOnboarding' }), statusBarService, ); // register commands context.subscriptions.push( commands.registerCommand('nx.connectToCloud', async () => { runNxConnect('command'); }), commands.registerCommand( 'nxConsole.connectToCloud.welcomeView', async () => { runNxConnect('welcome-view'); }, ), commands.registerCommand('nxCloud.refresh', throttledRefresh), commands.registerCommand('nxCloud.login', async () => { const workspacePath = getWorkspacePath(); const pkgManagerCommands = await getPackageManagerCommand(workspacePath); const command = 'nx-cloud login'; const task = new Task( { type: 'nx' }, TaskScope.Workspace, command, 'nx', new ShellExecution(`${pkgManagerCommands.dlx} ${command}`, { cwd: workspacePath, env: { ...process.env, NX_CONSOLE: 'true', }, }), ); task.presentationOptions.focus = true; tasks.executeTask(task); const subscription = tasks.onDidEndTaskProcess( (e: TaskProcessEndEvent) => { if (e.execution.task.name === command) { actor.system.get('polling').send({ type: 'FORCE_POLL' }); subscription.dispose(); } }, ); }), commands.registerCommand('nxCloud.viewRecentError', () => { const error = actor.getSnapshot().context.cipeError?.message; if (error) { vscodeLogger.log(`Nx Cloud Error: ${error}`); showOutputChannel(); } else { getNxlsOutputChannel().show(); } }), ); } export function runNxConnect(source: TelemetryEventSource = 'command') { getTelemetry().logUsage('cloud.connect', { source, }); // we want to make sure to always use `npx nx@latest connect` here CliTaskProvider.instance.executeTask({ command: 'connect', useLatestNxVersion: true, flags: [], }); } const getStateMachineLogger = (context: ExtensionContext) => context.extensionMode === ExtensionMode.Production ? undefined : (event: any) => { const snapshot = event.actorRef.getSnapshot(); if ( event.type === '@xstate.snapshot' && snapshot.value && (event.actorRef as any)['_systemId'] === 'cloud-view' && snapshot.value !== 'recent-cipe' ) { vscodeLogger.log(`Nx Cloud - ${JSON.stringify(snapshot.value)}`); } }; function setCloudViewContext(viewId: string) { const availableViews = ['loading', 'onboarding', 'recent-cipe']; availableViews.forEach((view) => { if (view === viewId) { commands.executeCommand( 'setContext', `nxCloudView.visible.${view}`, true, ); } else { commands.executeCommand( 'setContext', `nxCloudView.visible.${view}`, false, ); } }); } function setCIPEErrorContext(type: CIPEInfoError['type'] | undefined) { commands.executeCommand('setContext', 'nxCloudView.error', type ?? false); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nrwl/nx-console'

If you have feedback or need assistance with the MCP directory API, please join our Discord server