n8n-nodes-github-copilot 3.18.0 → 3.20.0

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.
@@ -102,6 +102,18 @@ class GitHubCopilot {
102
102
  description: 'Get shell command suggestions from GitHub Copilot',
103
103
  action: 'Get shell command suggestions',
104
104
  },
105
+ {
106
+ name: 'Revise',
107
+ value: 'revise',
108
+ description: 'Revise and improve existing code or commands',
109
+ action: 'Revise code or commands',
110
+ },
111
+ {
112
+ name: 'Rate Response',
113
+ value: 'rating',
114
+ description: 'Rate a previous GitHub Copilot response',
115
+ action: 'Rate response',
116
+ },
105
117
  ],
106
118
  default: 'suggest',
107
119
  },
@@ -181,6 +193,59 @@ class GitHubCopilot {
181
193
  placeholder: 'Any additional context or constraints...',
182
194
  description: 'Optional additional context to provide better suggestions',
183
195
  },
196
+ {
197
+ displayName: 'Original Code/Command',
198
+ name: 'originalCode',
199
+ type: 'string',
200
+ typeOptions: {
201
+ rows: 4,
202
+ },
203
+ required: true,
204
+ default: '',
205
+ placeholder: 'Enter the original code or command to revise...',
206
+ description: 'The original code or command that you want to improve',
207
+ displayOptions: {
208
+ show: {
209
+ operation: ['revise'],
210
+ },
211
+ },
212
+ },
213
+ {
214
+ displayName: 'Rating',
215
+ name: 'rating',
216
+ type: 'options',
217
+ options: [
218
+ { name: 'Very Good', value: 'very-good' },
219
+ { name: 'Good', value: 'good' },
220
+ { name: 'Fair', value: 'fair' },
221
+ { name: 'Poor', value: 'poor' },
222
+ ],
223
+ required: true,
224
+ default: 'good',
225
+ description: 'Rate the GitHub Copilot response',
226
+ displayOptions: {
227
+ show: {
228
+ operation: ['rating'],
229
+ },
230
+ },
231
+ },
232
+ {
233
+ displayName: 'Response to Rate',
234
+ name: 'responseToRate',
235
+ type: 'string',
236
+ typeOptions: {
237
+ rows: 3,
238
+ },
239
+ required: true,
240
+ default: '',
241
+ placeholder: 'Enter the GitHub Copilot response you want to rate...',
242
+ description: 'The GitHub Copilot response that you want to rate',
243
+ displayOptions: {
244
+ show: {
245
+ operation: ['rating'],
246
+ },
247
+ },
248
+ },
184
249
  ],
185
250
  };
186
251
  }
@@ -220,11 +285,11 @@ class GitHubCopilot {
220
285
  fullPrompt = `[${language}] ${fullPrompt}`;
221
286
  }
222
287
  const escapedSuggestPrompt = fullPrompt.replace(/'/g, `'"'"'`);
223
- command = `/usr/bin/gh copilot suggest '${escapedSuggestPrompt}'`;
288
+ command = `gh copilot suggest '${escapedSuggestPrompt}'`;
224
289
  break;
225
290
  case 'explain':
226
291
  const escapedExplainPrompt = fullPrompt.replace(/'/g, `'"'"'`);
227
- command = `/usr/bin/gh copilot explain '${escapedExplainPrompt}'`;
292
+ command = `gh copilot explain '${escapedExplainPrompt}'`;
228
293
  break;
229
294
  case 'shell':
230
295
  const commandType = this.getNodeParameter('commandType', i);
@@ -246,7 +311,19 @@ class GitHubCopilot {
246
311
  shellPrompt = fullPrompt;
247
312
  }
248
313
  const escapedShellPrompt = shellPrompt.replace(/'/g, `'"'"'`);
249
- command = `/usr/bin/gh copilot suggest '${escapedShellPrompt}' --type shell`;
314
+ command = `gh copilot suggest '${escapedShellPrompt}' --type shell`;
315
+ break;
316
+ case 'revise':
317
+ const originalCode = this.getNodeParameter('originalCode', i);
318
+ const revisePrompt = `${fullPrompt}\n\nOriginal code/command:\n${originalCode}`;
319
+ const escapedRevisePrompt = revisePrompt.replace(/'/g, `'"'"'`);
320
+ command = `gh copilot revise '${escapedRevisePrompt}'`;
321
+ break;
322
+ case 'rating':
323
+ const rating = this.getNodeParameter('rating', i);
324
+ const responseToRate = this.getNodeParameter('responseToRate', i);
325
+ const escapedResponseToRate = responseToRate.replace(/'/g, `'"'"'`);
326
+ command = `gh copilot rate '${escapedResponseToRate}' --rating ${rating}`;
250
327
  break;
251
328
  default:
252
329
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`);
@@ -259,7 +336,6 @@ class GitHubCopilot {
259
336
  try {
260
337
  const envVars = {
261
338
  ...process.env,
262
- HOME: '/opt/n8n-source/packages/cli/bin',
263
339
  };
264
340
  if (useToken) {
265
341
  envVars.GH_TOKEN = githubToken;
@@ -316,6 +392,9 @@ class GitHubCopilot {
316
392
  tokenPrefix: useToken ? githubToken.substring(0, 4) + '...' : 'none',
317
393
  language: operation === 'suggest' ? this.getNodeParameter('language', i) : undefined,
318
394
  commandType: operation === 'shell' ? this.getNodeParameter('commandType', i) : undefined,
395
+ originalCode: operation === 'revise' ? this.getNodeParameter('originalCode', i) : undefined,
396
+ rating: operation === 'rating' ? this.getNodeParameter('rating', i) : undefined,
397
+ responseToRate: operation === 'rating' ? this.getNodeParameter('responseToRate', i) : undefined,
319
398
  output: processedOutput,
320
399
  cliRawOutput: stdout,
321
400
  cliStderr: stderr || undefined,
@@ -10,7 +10,7 @@ class GitHubCopilotChatAPI {
10
10
  this.description = {
11
11
  displayName: 'GitHub Copilot Chat API',
12
12
  name: 'gitHubCopilotChatAPI',
13
- icon: 'file:copilot.svg',
13
+ icon: 'file:../../shared/icons/copilot.svg',
14
14
  group: ['AI'],
15
15
  version: 1,
16
16
  subtitle: '={{$parameter["operation"] + ": " + $parameter["model"]}}',
@@ -8,7 +8,7 @@ class GitHubCopilotChatModel {
8
8
  this.description = {
9
9
  displayName: 'GitHub Copilot Chat Model',
10
10
  name: 'gitHubCopilotChatModel',
11
- icon: 'file:copilot.svg',
11
+ icon: 'file:../../shared/icons/copilot.svg',
12
12
  group: ['transform'],
13
13
  version: 1,
14
14
  description: 'GitHub Copilot chat model for AI workflows - access GPT-5, Claude, Gemini and more using your Copilot subscription',
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class GitHubCopilotTest implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubCopilotTest = void 0;
4
+ async function listAvailableModels(token) {
5
+ var _a, _b;
6
+ try {
7
+ const response = await fetch('https://api.githubcopilot.com/models', {
8
+ method: 'GET',
9
+ headers: {
10
+ 'Authorization': `Bearer ${token}`,
11
+ 'Accept': 'application/json',
12
+ 'Content-Type': 'application/json',
13
+ },
14
+ });
15
+ if (!response.ok) {
16
+ const errorText = await response.text();
17
+ throw new Error(`API Error ${response.status}: ${errorText}`);
18
+ }
19
+ const data = await response.json();
20
+ const enabledModels = ((_a = data.data) === null || _a === void 0 ? void 0 : _a.filter((model) => model.model_picker_enabled !== false)) || [];
21
+ const modelsByProvider = {};
22
+ enabledModels.forEach((model) => {
23
+ const provider = model.name.split('/')[0] || 'unknown';
24
+ if (!modelsByProvider[provider]) {
25
+ modelsByProvider[provider] = [];
26
+ }
27
+ modelsByProvider[provider].push({
28
+ id: model.id,
29
+ name: model.name,
30
+ displayName: model.display_name,
31
+ capabilities: model.capabilities || [],
32
+ });
33
+ });
34
+ const summary = {
35
+ success: true,
36
+ timestamp: new Date().toISOString(),
37
+ totalModels: ((_b = data.data) === null || _b === void 0 ? void 0 : _b.length) || 0,
38
+ enabledModels: enabledModels.length,
39
+ modelsByProvider,
40
+ models: enabledModels.map((model) => ({
41
+ id: model.id,
42
+ name: model.name,
43
+ displayName: model.display_name,
44
+ capabilities: model.capabilities || [],
45
+ })),
46
+ };
47
+ return summary;
48
+ }
49
+ catch (error) {
50
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
51
+ return {
52
+ success: false,
53
+ timestamp: new Date().toISOString(),
54
+ error: errorMessage,
55
+ details: 'Failed to fetch models from GitHub Copilot API',
56
+ };
57
+ }
58
+ }
59
+ class GitHubCopilotTest {
60
+ constructor() {
61
+ this.description = {
62
+ displayName: 'GitHub Copilot Test',
63
+ name: 'gitHubCopilotTest',
64
+ icon: 'file:../../shared/icons/copilot.svg',
65
+ group: ['AI'],
66
+ version: 1,
67
+ subtitle: '={{$parameter["testFunction"]}}',
68
+ description: 'Test GitHub Copilot API credentials with predefined functions',
69
+ defaults: {
70
+ name: 'GitHub Copilot Test',
71
+ },
72
+ inputs: ["main"],
73
+ outputs: ["main"],
74
+ credentials: [
75
+ {
76
+ name: 'githubCopilotApi',
77
+ required: true,
78
+ },
79
+ ],
80
+ properties: [
81
+ {
82
+ displayName: 'Test Function',
83
+ name: 'testFunction',
84
+ type: 'options',
85
+ noDataExpression: true,
86
+ options: [
87
+ {
88
+ name: 'List Available Models',
89
+ value: 'listModels',
90
+ description: 'Get all models available for your GitHub Copilot subscription',
91
+ },
92
+ ],
93
+ default: 'listModels',
94
+ description: 'Select the test function to execute',
95
+ },
96
+ ],
97
+ };
98
+ }
99
+ async execute() {
100
+ const items = this.getInputData();
101
+ const returnData = [];
102
+ for (let i = 0; i < items.length; i++) {
103
+ try {
104
+ const testFunction = this.getNodeParameter('testFunction', i);
105
+ const credentials = await this.getCredentials('githubCopilotApi', i);
106
+ if (!(credentials === null || credentials === void 0 ? void 0 : credentials.token)) {
107
+ throw new Error('GitHub Copilot API credentials are required');
108
+ }
109
+ const token = credentials.token;
110
+ if (!token.startsWith('gho_')) {
111
+ throw new Error('Invalid token format. GitHub Copilot API requires tokens starting with "gho_"');
112
+ }
113
+ let result = {};
114
+ switch (testFunction) {
115
+ case 'listModels':
116
+ result = await listAvailableModels(token);
117
+ break;
118
+ default:
119
+ throw new Error(`Unknown test function: ${testFunction}`);
120
+ }
121
+ returnData.push({
122
+ json: result,
123
+ pairedItem: { item: i },
124
+ });
125
+ }
126
+ catch (error) {
127
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
128
+ if (this.continueOnFail()) {
129
+ returnData.push({
130
+ json: {
131
+ error: errorMessage,
132
+ testFunction: this.getNodeParameter('testFunction', i),
133
+ },
134
+ pairedItem: { item: i },
135
+ });
136
+ }
137
+ else {
138
+ throw error;
139
+ }
140
+ }
141
+ }
142
+ return [returnData];
143
+ }
144
+ }
145
+ exports.GitHubCopilotTest = GitHubCopilotTest;
@@ -0,0 +1,34 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
2
+ <defs>
3
+ <linearGradient id="copilotGradient" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" style="stop-color:#1f6feb;stop-opacity:1" />
5
+ <stop offset="100%" style="stop-color:#0969da;stop-opacity:1" />
6
+ </linearGradient>
7
+ </defs>
8
+
9
+ <!-- GitHub Copilot inspired icon -->
10
+ <circle cx="12" cy="12" r="11" fill="url(#copilotGradient)" stroke="#ffffff" stroke-width="1"/>
11
+
12
+ <!-- Copilot face -->
13
+ <ellipse cx="12" cy="10" rx="8" ry="6" fill="#ffffff" opacity="0.9"/>
14
+
15
+ <!-- Eyes -->
16
+ <circle cx="9" cy="9" r="1.5" fill="#1f6feb"/>
17
+ <circle cx="15" cy="9" r="1.5" fill="#1f6feb"/>
18
+
19
+ <!-- Light reflection in eyes -->
20
+ <circle cx="9.5" cy="8.5" r="0.5" fill="#ffffff"/>
21
+ <circle cx="15.5" cy="8.5" r="0.5" fill="#ffffff"/>
22
+
23
+ <!-- Mouth/Interface line -->
24
+ <path d="M8 12 L16 12" stroke="#1f6feb" stroke-width="1.5" stroke-linecap="round"/>
25
+
26
+ <!-- Code brackets -->
27
+ <path d="M6 15 L8 17 L6 19" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
28
+ <path d="M18 15 L16 17 L18 19" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
29
+
30
+ <!-- AI indicator dots -->
31
+ <circle cx="10" cy="17" r="0.5" fill="#ffffff" opacity="0.8"/>
32
+ <circle cx="12" cy="17" r="0.5" fill="#ffffff" opacity="0.6"/>
33
+ <circle cx="14" cy="17" r="0.5" fill="#ffffff" opacity="0.4"/>
34
+ </svg>
@@ -45,7 +45,9 @@ async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = fals
45
45
  const response = await fetch(`https://api.githubcopilot.com${endpoint}`, options);
46
46
  if (!response.ok) {
47
47
  const errorText = await response.text();
48
- const tokenInfo = token;
48
+ const tokenPrefix = token.substring(0, 4);
49
+ const tokenSuffix = token.substring(token.length - 5);
50
+ const tokenInfo = `${tokenPrefix}...${tokenSuffix}`;
49
51
  console.error(`❌ GitHub Copilot API Error: ${response.status} ${response.statusText}`);
50
52
  console.error(`❌ Error details: ${errorText}`);
51
53
  console.error(`❌ Used credential type: githubCopilotApi`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.18.0",
3
+ "version": "3.20.0",
4
4
  "description": "n8n community node for GitHub Copilot with CLI integration, Chat API access, and AI Chat Model for workflows - access GPT-5, Claude, Gemini and more using your Copilot subscription",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",
@@ -32,7 +32,8 @@
32
32
  "nodes": [
33
33
  "dist/nodes/GitHubCopilot/GitHubCopilot.node.js",
34
34
  "dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js",
35
- "dist/nodes/GitHubCopilotChatModel/GitHubCopilotChatModel.node.js"
35
+ "dist/nodes/GitHubCopilotChatModel/GitHubCopilotChatModel.node.js",
36
+ "dist/nodes/GitHubCopilotTest/GitHubCopilotTest.node.js"
36
37
  ]
37
38
  },
38
39
  "keywords": [