n8n-nodes-github-copilot 1.2.2 → 3.0.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.
package/README.md
CHANGED
|
@@ -4,15 +4,27 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
Este é um **community node** para [n8n](https://n8n.io/) que integra o **GitHub Copilot CLI**
|
|
7
|
+
Este é um **community node** para [n8n](https://n8n.io/) que integra o **GitHub Copilot** de duas formas: através do CLI tradicional e da nova **API oficial do GitHub Copilot**, permitindo acesso direto aos modelos avançados de IA como GPT-5, Claude Opus 4.1, Gemini 2.5 Pro e muito mais usando seus créditos existentes do Copilot.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 🚀 Nodes Disponíveis
|
|
10
10
|
|
|
11
|
+
### 1. GitHub Copilot (CLI)
|
|
11
12
|
- **Sugestões de Código**: Gere código em múltiplas linguagens de programação
|
|
12
13
|
- **Explicação de Código**: Obtenha explicações detalhadas sobre funcionalidades de código
|
|
13
14
|
- **Comandos Shell**: Receba sugestões de comandos para Git, Docker, NPM e muito mais
|
|
14
15
|
- **Múltiplas Linguagens**: Suporte para JavaScript, TypeScript, Python, Ruby, Java, C#, Go, PHP, C++, Rust, SQL, HTML, CSS
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
### 2. GitHub Copilot Chat API (Novo! ⭐)
|
|
18
|
+
- **Chat Completion**: Conversas diretas com modelos avançados de IA
|
|
19
|
+
- **Análise de Imagens**: Processamento de imagens com modelos de visão
|
|
20
|
+
- **Transcrição de Áudio**: Conversão de áudio para texto (planejado)
|
|
21
|
+
- **Modelos Disponíveis**: GPT-5, GPT-5 Mini, Claude Opus 4.1, Gemini 2.5 Pro, Grok Code Fast 1, GPT-4.1 Copilot
|
|
22
|
+
- **Sem Custos Extras**: Usa seus créditos existentes do GitHub Copilot
|
|
23
|
+
|
|
24
|
+
## 🎯 Funcionalidades
|
|
25
|
+
|
|
26
|
+
- **Integração Dual**: CLI tradicional + API oficial do GitHub Copilot
|
|
27
|
+
- **Modelos Premium**: Acesso a GPT-5, Claude, Gemini através de sua assinatura Copilot
|
|
16
28
|
|
|
17
29
|
## 📋 Pré-requisitos
|
|
18
30
|
|
|
@@ -93,18 +105,49 @@ npm install n8n-nodes-github-copilot
|
|
|
93
105
|
|
|
94
106
|
## ⚙️ Configuração
|
|
95
107
|
|
|
96
|
-
###
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
108
|
+
### 🔐 IMPORTANTE: Autenticação
|
|
109
|
+
|
|
110
|
+
**GitHub Copilot CLI tem requisitos específicos de autenticação:**
|
|
111
|
+
|
|
112
|
+
#### ✅ **O que FUNCIONA:**
|
|
113
|
+
- **Autenticação Local**: `gh auth login` (recomendado para servidores)
|
|
114
|
+
- **Tokens do GitHub CLI**: Gerados por `gh auth token` após fazer login
|
|
115
|
+
|
|
116
|
+
#### ❌ **O que NÃO FUNCIONA:**
|
|
117
|
+
- **Personal Access Tokens** criados no site do GitHub
|
|
118
|
+
- **OAuth App Tokens** de aplicações externas
|
|
119
|
+
- **GitHub App Tokens** de aplicações personalizadas
|
|
120
|
+
|
|
121
|
+
### 🛠️ **Configuração Recomendada:**
|
|
122
|
+
|
|
123
|
+
#### **Opção 1: Autenticação Local (Servidores)**
|
|
124
|
+
```bash
|
|
125
|
+
# No servidor onde roda o n8n
|
|
126
|
+
gh auth login
|
|
127
|
+
gh extension install github/gh-copilot
|
|
128
|
+
|
|
129
|
+
# Testar se funciona
|
|
130
|
+
gh copilot explain "ls -la"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### **Opção 2: Token Manual (Para workflows específicos)**
|
|
134
|
+
```bash
|
|
135
|
+
# Primeiro faça login local
|
|
136
|
+
gh auth login
|
|
137
|
+
|
|
138
|
+
# Depois obtenha o token
|
|
139
|
+
gh auth token
|
|
140
|
+
# Resultado: gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
141
|
+
|
|
142
|
+
# Use este token no campo "GitHub Token (Optional)" do node
|
|
143
|
+
```
|
|
102
144
|
|
|
103
|
-
###
|
|
145
|
+
### 1. Adicionar o Node
|
|
104
146
|
1. Crie um novo workflow
|
|
105
147
|
2. Procure por **GitHub Copilot** na lista de nodes
|
|
106
148
|
3. Arraste para o canvas
|
|
107
|
-
4.
|
|
149
|
+
4. **Deixe o campo token vazio** (se o servidor tem `gh auth login`)
|
|
150
|
+
5. **OU** insira um token gerado por `gh auth token`
|
|
108
151
|
|
|
109
152
|
## 🎮 Como Usar
|
|
110
153
|
|
|
@@ -59,53 +59,7 @@ class GitHubCopilot {
|
|
|
59
59
|
},
|
|
60
60
|
inputs: ["main"],
|
|
61
61
|
outputs: ["main"],
|
|
62
|
-
credentials: [
|
|
63
|
-
{
|
|
64
|
-
name: 'gitHubApi',
|
|
65
|
-
displayName: 'GitHub API (OAuth2)',
|
|
66
|
-
required: false,
|
|
67
|
-
displayOptions: {
|
|
68
|
-
show: {
|
|
69
|
-
authType: ['oauth2'],
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: 'gitHubApiManual',
|
|
75
|
-
displayName: 'GitHub API (Manual Token)',
|
|
76
|
-
required: false,
|
|
77
|
-
displayOptions: {
|
|
78
|
-
show: {
|
|
79
|
-
authType: ['manual'],
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
62
|
properties: [
|
|
85
|
-
{
|
|
86
|
-
displayName: 'Authentication Type',
|
|
87
|
-
name: 'authType',
|
|
88
|
-
type: 'options',
|
|
89
|
-
options: [
|
|
90
|
-
{
|
|
91
|
-
name: 'Local CLI Authentication',
|
|
92
|
-
value: 'local',
|
|
93
|
-
description: 'Use GitHub CLI local authentication (recommended)',
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
name: 'OAuth2 (Automatic)',
|
|
97
|
-
value: 'oauth2',
|
|
98
|
-
description: 'Use OAuth2 authentication configured in n8n',
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
name: 'Manual Token',
|
|
102
|
-
value: 'manual',
|
|
103
|
-
description: 'Use manually entered GitHub token',
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
default: 'local',
|
|
107
|
-
description: 'Choose how to authenticate with GitHub',
|
|
108
|
-
},
|
|
109
63
|
{
|
|
110
64
|
displayName: 'Operation',
|
|
111
65
|
name: 'operation',
|
|
@@ -145,6 +99,15 @@ class GitHubCopilot {
|
|
|
145
99
|
placeholder: 'Enter your request...',
|
|
146
100
|
description: 'What you want GitHub Copilot to help with',
|
|
147
101
|
},
|
|
102
|
+
{
|
|
103
|
+
displayName: 'GitHub Token (Optional)',
|
|
104
|
+
name: 'githubToken',
|
|
105
|
+
type: 'string',
|
|
106
|
+
typeOptions: { password: true },
|
|
107
|
+
default: '',
|
|
108
|
+
placeholder: 'gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
|
109
|
+
description: '⚠️ IMPORTANT: Only tokens generated by GitHub CLI itself work with Copilot. Personal Access Tokens from GitHub website DO NOT work. If not provided, will use local "gh auth login" authentication. To get a working token, use: gh auth token',
|
|
110
|
+
},
|
|
148
111
|
{
|
|
149
112
|
displayName: 'Filter Output',
|
|
150
113
|
name: 'filterOutput',
|
|
@@ -220,39 +183,9 @@ class GitHubCopilot {
|
|
|
220
183
|
const operation = this.getNodeParameter('operation', i);
|
|
221
184
|
const prompt = this.getNodeParameter('prompt', i);
|
|
222
185
|
const context = this.getNodeParameter('context', i, '');
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (authType === 'local') {
|
|
227
|
-
credentialType = 'Local CLI';
|
|
228
|
-
accessToken = undefined;
|
|
229
|
-
}
|
|
230
|
-
else if (authType === 'oauth2') {
|
|
231
|
-
const oauthCredentials = await this.getCredentials('gitHubApi');
|
|
232
|
-
console.log('OAuth2 credentials object:', JSON.stringify(oauthCredentials, null, 2));
|
|
233
|
-
const creds = oauthCredentials;
|
|
234
|
-
const oauthTokenData = creds === null || creds === void 0 ? void 0 : creds.oauthTokenData;
|
|
235
|
-
if ((oauthTokenData === null || oauthTokenData === void 0 ? void 0 : oauthTokenData.access_token) && typeof oauthTokenData.access_token === 'string') {
|
|
236
|
-
accessToken = oauthTokenData.access_token;
|
|
237
|
-
credentialType = 'OAuth2';
|
|
238
|
-
console.log('Using OAuth2 token from oauthTokenData.access_token:', accessToken.substring(0, 8) + '...');
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `OAuth2 token not found in oauthTokenData.access_token. Available fields: ${Object.keys(oauthCredentials || {}).join(', ')}. Please switch to Manual Token.`);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
const manualCredentials = await this.getCredentials('gitHubApiManual');
|
|
246
|
-
if ((manualCredentials === null || manualCredentials === void 0 ? void 0 : manualCredentials.accessToken) && typeof manualCredentials.accessToken === 'string') {
|
|
247
|
-
accessToken = manualCredentials.accessToken;
|
|
248
|
-
credentialType = 'Manual Token';
|
|
249
|
-
const tokenPrefix = accessToken.substring(0, 4);
|
|
250
|
-
console.log('Using manual token with prefix:', tokenPrefix + '...');
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Manual token credentials not found or invalid. Please configure Manual Token authentication or switch to OAuth2.');
|
|
254
|
-
}
|
|
255
|
-
}
|
|
186
|
+
const githubToken = this.getNodeParameter('githubToken', i, '');
|
|
187
|
+
const useToken = githubToken && githubToken.trim() !== '';
|
|
188
|
+
const authMethod = useToken ? 'Manual Token' : 'Local CLI';
|
|
256
189
|
let command;
|
|
257
190
|
let fullPrompt = prompt;
|
|
258
191
|
if (context) {
|
|
@@ -297,9 +230,8 @@ class GitHubCopilot {
|
|
|
297
230
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`);
|
|
298
231
|
}
|
|
299
232
|
console.log('Executing command:', command);
|
|
300
|
-
console.log('Auth
|
|
301
|
-
console.log('
|
|
302
|
-
console.log('Token type:', accessToken ? (accessToken.startsWith('gho_') ? 'OAuth' : accessToken.startsWith('ghp_') ? 'Classic' : 'Unknown') : 'Local CLI');
|
|
233
|
+
console.log('Auth method:', authMethod);
|
|
234
|
+
console.log('Using token:', useToken ? 'Yes (Manual)' : 'No (Local CLI)');
|
|
303
235
|
let stdout = '';
|
|
304
236
|
let stderr = '';
|
|
305
237
|
try {
|
|
@@ -307,9 +239,9 @@ class GitHubCopilot {
|
|
|
307
239
|
...process.env,
|
|
308
240
|
HOME: '/opt/n8n-source/packages/cli/bin',
|
|
309
241
|
};
|
|
310
|
-
if (
|
|
311
|
-
envVars.GH_TOKEN =
|
|
312
|
-
envVars.GITHUB_TOKEN =
|
|
242
|
+
if (useToken) {
|
|
243
|
+
envVars.GH_TOKEN = githubToken;
|
|
244
|
+
envVars.GITHUB_TOKEN = githubToken;
|
|
313
245
|
}
|
|
314
246
|
const result = await execAsync(command, {
|
|
315
247
|
env: envVars,
|
|
@@ -324,74 +256,27 @@ class GitHubCopilot {
|
|
|
324
256
|
stderr = err.stderr || err.message || String(execError);
|
|
325
257
|
stdout = err.stdout || '';
|
|
326
258
|
}
|
|
327
|
-
async function checkTokenPermissions(token) {
|
|
328
|
-
try {
|
|
329
|
-
const authCheckCommand = `/usr/bin/gh auth status`;
|
|
330
|
-
const apiCheckCommand = `/usr/bin/gh api user`;
|
|
331
|
-
const envVarsCheck = {
|
|
332
|
-
...process.env,
|
|
333
|
-
HOME: '/opt/n8n-source/packages/cli/bin',
|
|
334
|
-
GH_TOKEN: token,
|
|
335
|
-
GITHUB_TOKEN: token,
|
|
336
|
-
};
|
|
337
|
-
let permissionInfo = '';
|
|
338
|
-
try {
|
|
339
|
-
const authResult = await execAsync(authCheckCommand, { env: envVarsCheck, timeout: 10000 });
|
|
340
|
-
permissionInfo += `Auth Status: ${authResult.stdout.trim()}\n`;
|
|
341
|
-
}
|
|
342
|
-
catch (authError) {
|
|
343
|
-
const err = authError;
|
|
344
|
-
permissionInfo += `Auth Status Error: ${err.stderr || err.message}\n`;
|
|
345
|
-
}
|
|
346
|
-
try {
|
|
347
|
-
const apiResult = await execAsync(apiCheckCommand, { env: envVarsCheck, timeout: 10000 });
|
|
348
|
-
const userInfo = JSON.parse(apiResult.stdout);
|
|
349
|
-
permissionInfo += `User: ${userInfo.login} (${userInfo.name || 'no name'})\n`;
|
|
350
|
-
}
|
|
351
|
-
catch (apiError) {
|
|
352
|
-
const err = apiError;
|
|
353
|
-
permissionInfo += `API Access Error: ${err.stderr || err.message}\n`;
|
|
354
|
-
}
|
|
355
|
-
try {
|
|
356
|
-
await execAsync(`/usr/bin/gh api -H "Accept: application/vnd.github+json" /user`, { env: envVarsCheck, timeout: 10000 });
|
|
357
|
-
permissionInfo += `API Test: Success\n`;
|
|
358
|
-
}
|
|
359
|
-
catch (scopesError) {
|
|
360
|
-
const err = scopesError;
|
|
361
|
-
permissionInfo += `API Test Error: ${err.stderr || err.message}\n`;
|
|
362
|
-
}
|
|
363
|
-
return permissionInfo;
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
return `Permission check failed: ${error}`;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
259
|
if (stderr) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
debugTokenInfo = authType === 'local'
|
|
374
|
-
? ' [Local CLI - no token passed]'
|
|
375
|
-
: ` [Token used: ${accessToken || 'none'}]`;
|
|
376
|
-
if (authType === 'oauth2' && accessToken) {
|
|
377
|
-
permissionInfo = await checkTokenPermissions(accessToken);
|
|
378
|
-
debugTokenInfo += `\n\nToken Permissions Check:\n${permissionInfo}`;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
260
|
+
const debugInfo = useToken
|
|
261
|
+
? ` [Using manual token: ${githubToken.substring(0, 4)}...]`
|
|
262
|
+
: ' [Using local CLI authentication]';
|
|
381
263
|
if (stderr.includes('internal server error') || stderr.includes('code: 500')) {
|
|
382
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot service is temporarily unavailable (HTTP 500). This is a GitHub server issue. Please try again in a few moments.${
|
|
264
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot service is temporarily unavailable (HTTP 500). This is a GitHub server issue. Please try again in a few moments.${debugInfo} Error: ${stderr}`);
|
|
383
265
|
}
|
|
384
266
|
else if (stderr.includes('code: 400') || stderr.includes('Bad Request')) {
|
|
385
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot request failed (HTTP 400). The request is malformed or invalid.${
|
|
267
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot request failed (HTTP 400). The request is malformed or invalid.${debugInfo} Full error response: ${stderr}`);
|
|
386
268
|
}
|
|
387
269
|
else if (stderr.includes('401') || stderr.includes('Unauthorized') || stderr.includes('Bad credentials')) {
|
|
388
|
-
|
|
270
|
+
const tokenHelp = useToken
|
|
271
|
+
? ' IMPORTANT: Only tokens generated by "gh auth token" command work with Copilot. Personal Access Tokens from GitHub website DO NOT work. Try: run "gh auth login" first, then use "gh auth token" to get a working token.'
|
|
272
|
+
: ' Please run "gh auth login" on the server first, or provide a token generated by "gh auth token" command.';
|
|
273
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub authentication failed (HTTP 401).${tokenHelp}${debugInfo} Full error response: ${stderr}`);
|
|
389
274
|
}
|
|
390
275
|
else if (stderr.includes('403') || stderr.includes('Forbidden')) {
|
|
391
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot access denied (HTTP 403). Please ensure your account has Copilot subscription.${
|
|
276
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot access denied (HTTP 403). Please ensure your account has Copilot subscription.${debugInfo} Full error response: ${stderr}`);
|
|
392
277
|
}
|
|
393
278
|
else if (!stdout) {
|
|
394
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot CLI error:${
|
|
279
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `GitHub Copilot CLI error:${debugInfo} Full error response: ${stderr}`);
|
|
395
280
|
}
|
|
396
281
|
}
|
|
397
282
|
const filterOutput = this.getNodeParameter('filterOutput', i, true);
|
|
@@ -404,9 +289,9 @@ class GitHubCopilot {
|
|
|
404
289
|
operation,
|
|
405
290
|
prompt: prompt,
|
|
406
291
|
context: context || undefined,
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
tokenPrefix:
|
|
292
|
+
authMethod: authMethod,
|
|
293
|
+
tokenUsed: useToken,
|
|
294
|
+
tokenPrefix: useToken ? githubToken.substring(0, 4) + '...' : 'none',
|
|
410
295
|
language: operation === 'suggest' ? this.getNodeParameter('language', i) : undefined,
|
|
411
296
|
commandType: operation === 'shell' ? this.getNodeParameter('commandType', i) : undefined,
|
|
412
297
|
output: processedOutput,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class GitHubCopilotChatAPI implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.GitHubCopilotChatAPI = void 0;
|
|
27
|
+
async function makeApiRequest(context, endpoint, body) {
|
|
28
|
+
const credentials = await context.getCredentials('githubApi');
|
|
29
|
+
const options = {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: {
|
|
32
|
+
'Authorization': `Bearer ${credentials.accessToken}`,
|
|
33
|
+
'Content-Type': 'application/json',
|
|
34
|
+
'User-Agent': 'n8n-github-copilot-chat/2.0.0',
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify(body),
|
|
37
|
+
};
|
|
38
|
+
const response = await fetch(`https://api.githubcopilot.com${endpoint}`, options);
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const errorText = await response.text();
|
|
41
|
+
throw new Error(`GitHub Copilot API error: ${response.status} ${response.statusText}. ${errorText}`);
|
|
42
|
+
}
|
|
43
|
+
return await response.json();
|
|
44
|
+
}
|
|
45
|
+
function getMimeType(filename) {
|
|
46
|
+
const ext = filename.toLowerCase().split('.').pop();
|
|
47
|
+
switch (ext) {
|
|
48
|
+
case 'jpg':
|
|
49
|
+
case 'jpeg':
|
|
50
|
+
return 'image/jpeg';
|
|
51
|
+
case 'png':
|
|
52
|
+
return 'image/png';
|
|
53
|
+
case 'webp':
|
|
54
|
+
return 'image/webp';
|
|
55
|
+
case 'gif':
|
|
56
|
+
return 'image/gif';
|
|
57
|
+
default:
|
|
58
|
+
return 'image/jpeg';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
class GitHubCopilotChatAPI {
|
|
62
|
+
constructor() {
|
|
63
|
+
this.description = {
|
|
64
|
+
displayName: 'GitHub Copilot Chat API',
|
|
65
|
+
name: 'gitHubCopilotChatAPI',
|
|
66
|
+
icon: 'file:copilot.svg',
|
|
67
|
+
group: ['AI'],
|
|
68
|
+
version: 1,
|
|
69
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["model"]}}',
|
|
70
|
+
description: 'Use official GitHub Copilot Chat API with your subscription - access GPT-5, Claude, Gemini and more',
|
|
71
|
+
defaults: {
|
|
72
|
+
name: 'GitHub Copilot Chat API',
|
|
73
|
+
},
|
|
74
|
+
inputs: ["main"],
|
|
75
|
+
outputs: ["main"],
|
|
76
|
+
credentials: [
|
|
77
|
+
{
|
|
78
|
+
name: 'githubApi',
|
|
79
|
+
required: true,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
properties: [
|
|
83
|
+
{
|
|
84
|
+
displayName: 'Operation',
|
|
85
|
+
name: 'operation',
|
|
86
|
+
type: 'options',
|
|
87
|
+
options: [
|
|
88
|
+
{
|
|
89
|
+
name: 'Chat Completion',
|
|
90
|
+
value: 'chatCompletion',
|
|
91
|
+
description: 'Send a message and get AI response using Copilot models',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'Audio Transcription',
|
|
95
|
+
value: 'audioTranscription',
|
|
96
|
+
description: 'Transcribe audio file to text using Copilot',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Image Analysis',
|
|
100
|
+
value: 'imageAnalysis',
|
|
101
|
+
description: 'Analyze image with AI (vision models)',
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
default: 'chatCompletion',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
displayName: 'Model',
|
|
108
|
+
name: 'model',
|
|
109
|
+
type: 'options',
|
|
110
|
+
options: [
|
|
111
|
+
{
|
|
112
|
+
name: 'GPT-5 (Latest)',
|
|
113
|
+
value: 'gpt-5',
|
|
114
|
+
description: 'OpenAI GPT-5 - Latest and most advanced model',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'GPT-5 Mini',
|
|
118
|
+
value: 'gpt-5-mini',
|
|
119
|
+
description: 'OpenAI GPT-5 Mini - Faster and more efficient',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'Claude Opus 4.1',
|
|
123
|
+
value: 'claude-opus-4.1',
|
|
124
|
+
description: 'Anthropic Claude Opus 4.1 - Advanced reasoning',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'Gemini 2.5 Pro',
|
|
128
|
+
value: 'gemini-2.5-pro',
|
|
129
|
+
description: 'Google Gemini 2.5 Pro - Multimodal capabilities',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'Grok Code Fast 1',
|
|
133
|
+
value: 'grok-code-fast-1',
|
|
134
|
+
description: 'xAI Grok - Optimized for coding tasks',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'GPT-4.1 Copilot',
|
|
138
|
+
value: 'gpt-4.1-copilot',
|
|
139
|
+
description: 'GitHub Copilot optimized GPT-4.1 model',
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
default: 'gpt-5',
|
|
143
|
+
description: 'Choose the AI model from your Copilot subscription',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
displayName: 'Message',
|
|
147
|
+
name: 'message',
|
|
148
|
+
type: 'string',
|
|
149
|
+
typeOptions: {
|
|
150
|
+
rows: 4,
|
|
151
|
+
},
|
|
152
|
+
default: '',
|
|
153
|
+
placeholder: 'Enter your message here...',
|
|
154
|
+
description: 'The message to send to the AI',
|
|
155
|
+
displayOptions: {
|
|
156
|
+
show: {
|
|
157
|
+
operation: ['chatCompletion', 'imageAnalysis'],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
displayName: 'Audio File',
|
|
163
|
+
name: 'audioFile',
|
|
164
|
+
type: 'string',
|
|
165
|
+
default: '',
|
|
166
|
+
placeholder: 'Path to audio file or base64 data',
|
|
167
|
+
description: 'Audio file to transcribe (supports MP3, WAV, M4A, FLAC, OGG)',
|
|
168
|
+
displayOptions: {
|
|
169
|
+
show: {
|
|
170
|
+
operation: ['audioTranscription'],
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
displayName: 'Audio Language',
|
|
176
|
+
name: 'audioLanguage',
|
|
177
|
+
type: 'options',
|
|
178
|
+
options: [
|
|
179
|
+
{ name: 'Auto-detect', value: 'auto' },
|
|
180
|
+
{ name: 'Portuguese (Brazil)', value: 'pt' },
|
|
181
|
+
{ name: 'English', value: 'en' },
|
|
182
|
+
{ name: 'Spanish', value: 'es' },
|
|
183
|
+
{ name: 'French', value: 'fr' },
|
|
184
|
+
{ name: 'German', value: 'de' },
|
|
185
|
+
{ name: 'Italian', value: 'it' },
|
|
186
|
+
{ name: 'Japanese', value: 'ja' },
|
|
187
|
+
{ name: 'Chinese', value: 'zh' },
|
|
188
|
+
],
|
|
189
|
+
default: 'auto',
|
|
190
|
+
description: 'Language of the audio (helps with accuracy)',
|
|
191
|
+
displayOptions: {
|
|
192
|
+
show: {
|
|
193
|
+
operation: ['audioTranscription'],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
displayName: 'Image File',
|
|
199
|
+
name: 'imageFile',
|
|
200
|
+
type: 'string',
|
|
201
|
+
default: '',
|
|
202
|
+
placeholder: 'Path to image file or base64 data',
|
|
203
|
+
description: 'Image file to analyze (supports JPG, PNG, WebP, GIF)',
|
|
204
|
+
displayOptions: {
|
|
205
|
+
show: {
|
|
206
|
+
operation: ['imageAnalysis'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
displayName: 'System Prompt',
|
|
212
|
+
name: 'systemPrompt',
|
|
213
|
+
type: 'string',
|
|
214
|
+
typeOptions: {
|
|
215
|
+
rows: 2,
|
|
216
|
+
},
|
|
217
|
+
default: '',
|
|
218
|
+
placeholder: 'You are a helpful assistant...',
|
|
219
|
+
description: 'Optional system prompt to set AI behavior',
|
|
220
|
+
displayOptions: {
|
|
221
|
+
show: {
|
|
222
|
+
operation: ['chatCompletion', 'imageAnalysis'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
displayName: 'Temperature',
|
|
228
|
+
name: 'temperature',
|
|
229
|
+
type: 'number',
|
|
230
|
+
typeOptions: {
|
|
231
|
+
minValue: 0,
|
|
232
|
+
maxValue: 2,
|
|
233
|
+
numberStepSize: 0.1,
|
|
234
|
+
},
|
|
235
|
+
default: 1,
|
|
236
|
+
description: 'Controls randomness: 0 = focused, 2 = creative',
|
|
237
|
+
displayOptions: {
|
|
238
|
+
show: {
|
|
239
|
+
operation: ['chatCompletion', 'imageAnalysis'],
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
displayName: 'Max Tokens',
|
|
245
|
+
name: 'maxTokens',
|
|
246
|
+
type: 'number',
|
|
247
|
+
typeOptions: {
|
|
248
|
+
minValue: 1,
|
|
249
|
+
maxValue: 8192,
|
|
250
|
+
},
|
|
251
|
+
default: 2000,
|
|
252
|
+
description: 'Maximum tokens in response',
|
|
253
|
+
displayOptions: {
|
|
254
|
+
show: {
|
|
255
|
+
operation: ['chatCompletion', 'imageAnalysis'],
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async execute() {
|
|
263
|
+
const items = this.getInputData();
|
|
264
|
+
const returnData = [];
|
|
265
|
+
for (let i = 0; i < items.length; i++) {
|
|
266
|
+
try {
|
|
267
|
+
const operation = this.getNodeParameter('operation', i);
|
|
268
|
+
const model = this.getNodeParameter('model', i);
|
|
269
|
+
let result;
|
|
270
|
+
if (operation === 'chatCompletion') {
|
|
271
|
+
const message = this.getNodeParameter('message', i);
|
|
272
|
+
const systemPrompt = this.getNodeParameter('systemPrompt', i);
|
|
273
|
+
const temperature = this.getNodeParameter('temperature', i);
|
|
274
|
+
const maxTokens = this.getNodeParameter('maxTokens', i);
|
|
275
|
+
const messages = [];
|
|
276
|
+
if (systemPrompt) {
|
|
277
|
+
messages.push({ role: 'system', content: systemPrompt });
|
|
278
|
+
}
|
|
279
|
+
messages.push({ role: 'user', content: message });
|
|
280
|
+
const requestBody = {
|
|
281
|
+
model: model,
|
|
282
|
+
messages: messages,
|
|
283
|
+
temperature: temperature,
|
|
284
|
+
max_tokens: maxTokens,
|
|
285
|
+
stream: false,
|
|
286
|
+
};
|
|
287
|
+
const response = await makeApiRequest(this, '/chat/completions', requestBody);
|
|
288
|
+
result = {
|
|
289
|
+
response: response.choices[0].message.content,
|
|
290
|
+
model: model,
|
|
291
|
+
usage: response.usage,
|
|
292
|
+
finish_reason: response.choices[0].finish_reason,
|
|
293
|
+
timestamp: new Date().toISOString(),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
else if (operation === 'audioTranscription') {
|
|
297
|
+
const audioFile = this.getNodeParameter('audioFile', i);
|
|
298
|
+
const language = this.getNodeParameter('audioLanguage', i);
|
|
299
|
+
const transcriptionPrompt = language === 'auto'
|
|
300
|
+
? `Please transcribe this audio file to text. Detect the language automatically and provide the transcription.`
|
|
301
|
+
: `Please transcribe this audio file to text. The audio is in ${language} language.`;
|
|
302
|
+
const messages = [
|
|
303
|
+
{
|
|
304
|
+
role: 'system',
|
|
305
|
+
content: 'You are an expert at audio transcription. When given an audio file, provide an accurate transcription of the spoken content.'
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
role: 'user',
|
|
309
|
+
content: `${transcriptionPrompt}\n\nAudio file: ${audioFile}`
|
|
310
|
+
}
|
|
311
|
+
];
|
|
312
|
+
const requestBody = {
|
|
313
|
+
model: model,
|
|
314
|
+
messages: messages,
|
|
315
|
+
temperature: 0.1,
|
|
316
|
+
max_tokens: 4000,
|
|
317
|
+
stream: false,
|
|
318
|
+
};
|
|
319
|
+
const response = await makeApiRequest(this, '/chat/completions', requestBody);
|
|
320
|
+
result = {
|
|
321
|
+
transcription: response.choices[0].message.content,
|
|
322
|
+
language: language,
|
|
323
|
+
model: model,
|
|
324
|
+
usage: response.usage,
|
|
325
|
+
timestamp: new Date().toISOString(),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
else if (operation === 'imageAnalysis') {
|
|
329
|
+
const message = this.getNodeParameter('message', i);
|
|
330
|
+
const imageFile = this.getNodeParameter('imageFile', i);
|
|
331
|
+
const systemPrompt = this.getNodeParameter('systemPrompt', i);
|
|
332
|
+
const temperature = this.getNodeParameter('temperature', i);
|
|
333
|
+
const maxTokens = this.getNodeParameter('maxTokens', i);
|
|
334
|
+
let imageBase64;
|
|
335
|
+
if (imageFile.startsWith('data:image/')) {
|
|
336
|
+
imageBase64 = imageFile;
|
|
337
|
+
}
|
|
338
|
+
else if (imageFile.match(/^[A-Za-z0-9+/=]+$/)) {
|
|
339
|
+
imageBase64 = `data:image/jpeg;base64,${imageFile}`;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
343
|
+
const imageBuffer = fs.readFileSync(imageFile);
|
|
344
|
+
const mimeType = getMimeType(imageFile);
|
|
345
|
+
imageBase64 = `data:${mimeType};base64,${imageBuffer.toString('base64')}`;
|
|
346
|
+
}
|
|
347
|
+
const messages = [];
|
|
348
|
+
if (systemPrompt) {
|
|
349
|
+
messages.push({ role: 'system', content: systemPrompt });
|
|
350
|
+
}
|
|
351
|
+
messages.push({
|
|
352
|
+
role: 'user',
|
|
353
|
+
content: [
|
|
354
|
+
{ type: 'text', text: message },
|
|
355
|
+
{ type: 'image_url', image_url: { url: imageBase64 } }
|
|
356
|
+
]
|
|
357
|
+
});
|
|
358
|
+
const requestBody = {
|
|
359
|
+
model: model,
|
|
360
|
+
messages: messages,
|
|
361
|
+
temperature: temperature,
|
|
362
|
+
max_tokens: maxTokens,
|
|
363
|
+
stream: false,
|
|
364
|
+
};
|
|
365
|
+
const response = await makeApiRequest(this, '/chat/completions', requestBody);
|
|
366
|
+
result = {
|
|
367
|
+
response: response.choices[0].message.content,
|
|
368
|
+
model: model,
|
|
369
|
+
usage: response.usage,
|
|
370
|
+
finish_reason: response.choices[0].finish_reason,
|
|
371
|
+
timestamp: new Date().toISOString(),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
376
|
+
}
|
|
377
|
+
returnData.push({
|
|
378
|
+
json: result,
|
|
379
|
+
pairedItem: { item: i },
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
if (this.continueOnFail()) {
|
|
384
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
385
|
+
returnData.push({
|
|
386
|
+
json: {
|
|
387
|
+
error: errorMessage,
|
|
388
|
+
operation: this.getNodeParameter('operation', i),
|
|
389
|
+
model: this.getNodeParameter('model', i),
|
|
390
|
+
},
|
|
391
|
+
pairedItem: { item: i },
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return [returnData];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
exports.GitHubCopilotChatAPI = GitHubCopilotChatAPI;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "n8n community node for GitHub Copilot CLI integration",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "n8n community node for GitHub Copilot with CLI integration and official Chat API access to GPT-5, Claude, Gemini and more using your existing Copilot credits",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",
|
|
7
7
|
"author": {
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"dist/credentials/GitHubApiManual.credentials.js"
|
|
32
32
|
],
|
|
33
33
|
"nodes": [
|
|
34
|
-
"dist/nodes/GitHubCopilot/GitHubCopilot.node.js"
|
|
34
|
+
"dist/nodes/GitHubCopilot/GitHubCopilot.node.js",
|
|
35
|
+
"dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js"
|
|
35
36
|
]
|
|
36
37
|
},
|
|
37
38
|
"keywords": [
|
|
@@ -39,6 +40,12 @@
|
|
|
39
40
|
"github",
|
|
40
41
|
"copilot",
|
|
41
42
|
"ai",
|
|
43
|
+
"gpt-5",
|
|
44
|
+
"claude",
|
|
45
|
+
"gemini",
|
|
46
|
+
"chat-completion",
|
|
47
|
+
"image-analysis",
|
|
48
|
+
"audio-transcription",
|
|
42
49
|
"code-generation",
|
|
43
50
|
"automation"
|
|
44
51
|
],
|