Skip to content

Commit

Permalink
feat(vscode): add copilot chat participant
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKless committed Feb 7, 2025
1 parent aa81ff9 commit e452613
Show file tree
Hide file tree
Showing 22 changed files with 766 additions and 203 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@

/apps/generate-ui-v2/ @MaxKless

/libs/vscode/copilot/ @MaxKless

/libs/vscode/nvm-tip/ @MaxKless

/libs/shared/schema/ @MaxKless
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,5 @@ apps/vscode-e2e/.screenshots
.nx/powerpack
**/cypress/downloads
migrations.json

test-output
25 changes: 24 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch Extension",
"args": [
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}/dist/apps/vscode"
],
"name": "Launch Extension",
"outFiles": [
"${workspaceFolder}/dist/apps/vscode",
"${workspaceFolder}/dist/apps/generate-ui-v2",
Expand All @@ -28,6 +28,29 @@
"!**/node_modules/**"
]
},
{
"name": "Launch Extension (with other extensions)",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}/dist/apps/vscode"
],
"outFiles": [
"${workspaceFolder}/dist/apps/vscode",
"${workspaceFolder}/dist/apps/generate-ui-v2",
"${workspaceFolder}/node_modules"
],
"request": "launch",
"skipFiles": [
"<node_internals>/**",
"/Applications/Visual Studio Code.app/**"
],
"type": "extensionHost",
"enableTurboSourcemaps": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
]
},

{
"type": "node",
"request": "attach",
Expand Down
24 changes: 24 additions & 0 deletions apps/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,30 @@
}
]
},
"chatParticipants": [
{
"id": "nx-console.nx",
"fullName": "Nx",
"name": "nx",
"description": "Get insights into your Nx workspace",
"isSticky": true,
"disambiguation": [
{
"category": "nx",
"description": "The user wants to include context-aware insights using their Nx monorepo.",
"examples": [
"Tell me about my nx workspace",
"What libraries exist in my workspace?",
"Find a core components library and create a new Dialog component.",
"Remove the deprecated properties from the Auth API and update all clients.",
"What is the impact of merging 'ui-common' and 'ui-core'?",
"Compare the retry logic in all data access libraries for the shop app",
"Show me all the core projects"
]
}
]
}
],
"commands": [
{
"command": "nxConsole.refreshWorkspace",
Expand Down
Binary file added apps/vscode/src/assets/nx.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion apps/vscode/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { initNxConversion } from '@nx-console/vscode-nx-conversion';
import { initHelpAndFeedbackView } from '@nx-console/vscode-nx-help-and-feedback-view';
import { initVscodeProjectGraph } from '@nx-console/vscode-project-graph';
import { initTypeScriptServerPlugin } from '@nx-console/vscode-typescript-plugin';
import { initCopilot } from '@nx-console/vscode-copilot';

import {
NxWorkspaceRefreshNotification,
Expand Down Expand Up @@ -253,6 +254,7 @@ async function setWorkspace(workspacePath: string) {
getNxlsClient().start(workspacePath);

tasks.registerTaskProvider('nx', CliTaskProvider.instance);
initOutputChannels(context);
initTasks(context);
registerVscodeAddDependency(context);

Expand All @@ -266,7 +268,7 @@ async function setWorkspace(workspacePath: string) {
initVscodeProjectDetails(context);
initVscodeProjectGraph(context);
initErrorDiagnostics(context);
initOutputChannels(context);
initCopilot(context);

nxProjectsTreeProvider = initNxProjectView(context);

Expand Down
3 changes: 3 additions & 0 deletions apps/vscode/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
{
"path": "../../libs/language-server/types/tsconfig.lib.json"
},
{
"path": "../../libs/vscode/copilot/tsconfig.lib.json"
},
{
"path": "../../libs/vscode/typescript-plugin/tsconfig.lib.json"
},
Expand Down
3 changes: 3 additions & 0 deletions apps/vscode/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
{
"path": "../../libs/language-server/types"
},
{
"path": "../../libs/vscode/copilot"
},
{
"path": "../../libs/vscode/typescript-plugin"
},
Expand Down
18 changes: 18 additions & 0 deletions libs/vscode/copilot/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
22 changes: 22 additions & 0 deletions libs/vscode/copilot/.spec.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": []
}
7 changes: 7 additions & 0 deletions libs/vscode/copilot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# vscode-copilot

This library was generated with [Nx](https://nx.dev).

## Running unit tests

Run `nx test vscode-copilot` to execute the unit tests via [Jest](https://jestjs.io).
21 changes: 21 additions & 0 deletions libs/vscode/copilot/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable */
import { readFileSync } from 'fs';

// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8')
);

// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;

export default {
displayName: 'vscode-copilot',
preset: '../../../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: 'test-output/jest/coverage',
};
15 changes: 15 additions & 0 deletions libs/vscode/copilot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@nx-console/vscode-copilot",
"version": "0.0.1",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"nx": {
"name": "vscode-copilot",
"sourceRoot": "libs/vscode/copilot/src",
"projectType": "library",
"tags": [
"type:vscode"
]
}
}
1 change: 1 addition & 0 deletions libs/vscode/copilot/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/init-copilot.js';
79 changes: 79 additions & 0 deletions libs/vscode/copilot/src/lib/init-copilot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {
CancellationToken,
ChatContext,
ChatRequest,
ChatRequestHandler,
ChatResponseStream,
ExtensionContext,
LanguageModelChatMessage,
Uri,
chat,
} from 'vscode';
import { getNxWorkspace } from '@nx-console/vscode-nx-workspace';
import { BASE_PROMPT } from './prompt.js';

export function initCopilot(context: ExtensionContext) {
const nxParticipant = chat.createChatParticipant('nx-console.nx', handler);
nxParticipant.iconPath = Uri.joinPath(
context.extensionUri,
'assets',
'nx.png'
);
}

const handler: ChatRequestHandler = async (
request: ChatRequest,
context: ChatContext,
stream: ChatResponseStream,
token: CancellationToken
) => {
const prompt = BASE_PROMPT;

stream.progress('Retrieving workspace information...');

const projectGraph = await getPrunedProjectGraph();

const messages = [LanguageModelChatMessage.User(prompt)];

messages.push(LanguageModelChatMessage.User(request.prompt));
messages.push(LanguageModelChatMessage.User(JSON.stringify(projectGraph)));

const chatResponse = await request.model.sendRequest(messages, {}, token);

for await (const fragment of chatResponse.text) {
stream.markdown(fragment);
}

return;
};

async function getPrunedProjectGraph() {
const nxWorkspace = await getNxWorkspace();
const projectGraph = nxWorkspace.projectGraph;
return {
nodes: Object.entries(projectGraph.nodes)
.map(([name, node]) => {
const prunedNode = {
type: node.type,
} as any;
if (node.data.metadata?.technologies) {
prunedNode.technologies = node.data.metadata.technologies;
}
return [name, prunedNode] as const;
})
.reduce((acc, [name, node]) => {
acc[name] = node;
return acc;
}, {}),
dependencies: Object.entries(projectGraph.dependencies)
.filter(([key]) => !key.startsWith('npm:'))
.map(
([key, deps]) =>
[key, deps.filter((dep) => !dep.target.startsWith('npm:'))] as const
)
.reduce((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {}),
};
}
11 changes: 11 additions & 0 deletions libs/vscode/copilot/src/lib/prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const BASE_PROMPT = `
You are an AI assistant specialized in Nx workspaces and monorepo development. You provide precise, technical guidance for developers working with Nx tools, patterns, and best practices.
You have access to the project graph and can use it to provide context-aware suggestions and solutions.
Remember to:
- Provide complete, working examples
- Explain your approach and any assumptions made about the workspace
- Reference official Nx documentation when relevant
- Use code examples when applicable
- Be concise and clear
`;
16 changes: 16 additions & 0 deletions libs/vscode/copilot/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "../../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "../nx-workspace"
},
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
14 changes: 14 additions & 0 deletions libs/vscode/copilot/tsconfig.lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "out-tsc/vscode-copilot",
"types": ["node"]
},
"include": ["src/**/*.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"references": [
{
"path": "../nx-workspace/tsconfig.lib.json"
}
]
}
20 changes: 20 additions & 0 deletions libs/vscode/copilot/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./out-tsc/jest",
"types": ["jest", "node"],
"strict": true,
"noImplicitReturns": true
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}
Loading

0 comments on commit e452613

Please sign in to comment.