n8n-nodes-github-copilot 3.32.0 → 3.32.1

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.
@@ -10,89 +10,20 @@ class GitHubCopilotApi {
10
10
  this.documentationUrl = "https://docs.github.com/en/copilot/github-copilot-chat/copilot-chat-in-ides/using-github-copilot-chat-in-your-ide";
11
11
  this.properties = [
12
12
  {
13
- displayName: "Authentication Method",
14
- name: "authMethod",
15
- type: "options",
16
- options: [
17
- {
18
- name: "GitHub CLI Token (Auto OAuth) - RECOMMENDED",
19
- value: "githubToken",
20
- description: "Automatically generates and refreshes OAuth tokens every 20 minutes",
21
- },
22
- {
23
- name: "Manual OAuth Token (Advanced)",
24
- value: "oauthToken",
25
- description: "Manually provide OAuth token (expires in 20 minutes)",
26
- },
27
- ],
28
- default: "githubToken",
29
- description: "Choose how to authenticate with GitHub Copilot API",
30
- },
31
- {
32
- displayName: "ℹ️ Auto OAuth Token Generation",
33
- name: "autoOAuthNotice",
34
- type: "notice",
35
- default: "Your GitHub CLI token will be used to automatically generate OAuth tokens. Tokens are cached and refreshed automatically before expiration (every ~20 minutes). No manual intervention needed!",
36
- displayOptions: {
37
- show: {
38
- authMethod: ["githubToken"],
39
- },
40
- },
41
- },
42
- {
43
- displayName: "⚠️ IMPORTANT: GitHub CLI Token Required",
44
- name: "warningNotice",
45
- type: "notice",
46
- default: "",
47
- displayOptions: {
48
- show: {
49
- authMethod: ["githubToken"],
50
- },
51
- },
52
- },
53
- {
54
- displayName: "🚀 Don't have GitHub CLI installed?",
55
- name: "helperNotice1",
56
- type: "notice",
57
- default: "Use the visual 'GitHub Copilot Auth Helper' node to generate your token without touching the terminal!",
58
- displayOptions: {
59
- show: {
60
- authMethod: ["githubToken"],
61
- },
62
- },
63
- },
64
- {
65
- displayName: "📝 Step 1: Create Helper Workflow",
66
- name: "helperNotice2",
67
- type: "notice",
68
- default: "Add a new workflow and insert the 'GitHub Copilot Auth Helper' trigger node.",
69
- displayOptions: {
70
- show: {
71
- authMethod: ["githubToken"],
72
- },
73
- },
74
- },
75
- {
76
- displayName: "▶️ Step 2: Activate & Access",
77
- name: "helperNotice3",
78
- type: "notice",
79
- default: "Activate the workflow, then click 'Test workflow' to open the visual token generator in your browser.",
80
- displayOptions: {
81
- show: {
82
- authMethod: ["githubToken"],
83
- },
84
- },
85
- },
86
- {
87
- displayName: "📋 Step 3: Copy Token",
88
- name: "helperNotice4",
13
+ displayName: "Setup Instructions",
14
+ name: "setupNotice",
89
15
  type: "notice",
90
- default: "Follow the on-screen instructions to authenticate with GitHub and copy the generated 'gho_' token back here.",
91
- displayOptions: {
92
- show: {
93
- authMethod: ["githubToken"],
94
- },
95
- },
16
+ default: "ℹ️ Auto OAuth Token Generation\n" +
17
+ "Your GitHub CLI token will be used to automatically generate OAuth tokens. Tokens are cached and refreshed automatically before expiration (every ~20 minutes). No manual intervention needed!\n\n" +
18
+ "⚠️ IMPORTANT: GitHub CLI Token Required\n\n" +
19
+ "🚀 Don't have GitHub CLI installed?\n" +
20
+ "Use the visual 'GitHub Copilot Auth Helper' node to generate your token without touching the terminal!\n\n" +
21
+ "📝 Step 1: Create Helper Workflow\n" +
22
+ "Add a new workflow and insert the 'GitHub Copilot Auth Helper' trigger node.\n\n" +
23
+ "▶️ Step 2: Activate & Access\n" +
24
+ "Activate the workflow, then click 'Test workflow' to open the visual token generator in your browser.\n\n" +
25
+ "📋 Step 3: Copy Token\n" +
26
+ "Follow the on-screen instructions to authenticate with GitHub and copy the generated 'gho_' token back here.",
96
27
  },
97
28
  {
98
29
  displayName: "GitHub CLI Token",
@@ -105,39 +36,6 @@ class GitHubCopilotApi {
105
36
  required: true,
106
37
  description: "Token generated by GitHub CLI (starts with 'gho_'). OAuth tokens will be auto-generated and refreshed from this token.",
107
38
  placeholder: "gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
108
- displayOptions: {
109
- show: {
110
- authMethod: ["githubToken"],
111
- },
112
- },
113
- },
114
- {
115
- displayName: "⚠️ Manual OAuth Token (Advanced)",
116
- name: "manualOAuthNotice",
117
- type: "notice",
118
- default: "OAuth tokens expire after ~20 minutes. You will need to manually regenerate and update this token frequently. Consider using GitHub CLI Token mode instead for automatic token management.",
119
- displayOptions: {
120
- show: {
121
- authMethod: ["oauthToken"],
122
- },
123
- },
124
- },
125
- {
126
- displayName: "OAuth Token",
127
- name: "oauthToken",
128
- type: "string",
129
- typeOptions: {
130
- password: true,
131
- },
132
- default: "",
133
- required: true,
134
- description: "Manual OAuth token (starts with 'tid='). Expires in ~20 minutes.",
135
- placeholder: "tid=xxxxx;exp=xxxxx;sku=xxxxx;...",
136
- displayOptions: {
137
- show: {
138
- authMethod: ["oauthToken"],
139
- },
140
- },
141
39
  },
142
40
  ];
143
41
  this.test = {
@@ -149,19 +47,19 @@ class GitHubCopilotApi {
149
47
  };
150
48
  }
151
49
  async authenticate(credentials, requestOptions) {
152
- const authMethod = credentials.authMethod;
50
+ const githubToken = credentials.token;
51
+ if (!githubToken) {
52
+ throw new Error("GitHub CLI token is required");
53
+ }
54
+ if (!githubToken.startsWith("gho_")) {
55
+ throw new Error("Invalid token format. GitHub CLI token must start with 'gho_'");
56
+ }
153
57
  let authToken;
154
- if (authMethod === "githubToken") {
155
- const githubToken = credentials.token;
156
- try {
157
- authToken = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
158
- }
159
- catch (error) {
160
- throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
161
- }
58
+ try {
59
+ authToken = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
162
60
  }
163
- else {
164
- authToken = credentials.oauthToken;
61
+ catch (error) {
62
+ throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
165
63
  }
166
64
  if (!requestOptions.headers) {
167
65
  requestOptions.headers = {};
@@ -31,7 +31,7 @@ class GitHubCopilotChatAPI {
31
31
  };
32
32
  }
33
33
  async execute() {
34
- var _a, _b, _c, _d;
34
+ var _a, _b, _c, _d, _e, _f;
35
35
  const items = this.getInputData();
36
36
  const returnData = [];
37
37
  for (let i = 0; i < items.length; i++) {
@@ -109,34 +109,41 @@ class GitHubCopilotChatAPI {
109
109
  const hasMedia = includeMedia;
110
110
  let response = null;
111
111
  let attempt = 1;
112
- while (attempt <= maxRetries + 1) {
112
+ const totalAttempts = maxRetries + 1;
113
+ let retriesUsed = 0;
114
+ while (attempt <= totalAttempts) {
113
115
  try {
114
116
  response = await (0, utils_1.makeApiRequest)(this, GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ENDPOINTS.CHAT_COMPLETIONS, requestBody, hasMedia);
117
+ retriesUsed = ((_a = response._retryMetadata) === null || _a === void 0 ? void 0 : _a.retries) || 0;
118
+ attempt = ((_b = response._retryMetadata) === null || _b === void 0 ? void 0 : _b.attempts) || 1;
115
119
  break;
116
120
  }
117
121
  catch (error) {
118
- const isLastAttempt = attempt >= maxRetries + 1;
122
+ const isLastAttempt = attempt >= totalAttempts;
119
123
  const errorObj = error;
120
- const is403Error = errorObj.status === 403 || ((_a = errorObj.message) === null || _a === void 0 ? void 0 : _a.includes("403"));
124
+ const is403Error = errorObj.status === 403 || ((_c = errorObj.message) === null || _c === void 0 ? void 0 : _c.includes("403"));
121
125
  if (is403Error && enableRetry && !isLastAttempt) {
122
126
  const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);
123
- console.log(`GitHub Copilot API attempt ${attempt} failed with 403, retrying in ${delay}ms...`);
127
+ console.log(`GitHub Copilot API attempt ${attempt}/${totalAttempts} failed with 403, retrying in ${delay}ms...`);
124
128
  await new Promise((resolve) => setTimeout(resolve, delay));
125
129
  attempt++;
126
130
  continue;
127
131
  }
132
+ retriesUsed = attempt - 1;
128
133
  throw error;
129
134
  }
130
135
  }
131
136
  if (!response) {
132
- throw new Error("Failed to get response from GitHub Copilot API after all retry attempts");
137
+ throw new Error(`Failed to get response from GitHub Copilot API after ${totalAttempts} attempts (${retriesUsed} retries)`);
133
138
  }
134
139
  const result = {
135
- message: ((_c = (_b = response.choices[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content) || "",
140
+ message: ((_e = (_d = response.choices[0]) === null || _d === void 0 ? void 0 : _d.message) === null || _e === void 0 ? void 0 : _e.content) || "",
136
141
  model,
137
142
  operation,
138
143
  usage: response.usage || null,
139
- finish_reason: ((_d = response.choices[0]) === null || _d === void 0 ? void 0 : _d.finish_reason) || "unknown",
144
+ finish_reason: ((_f = response.choices[0]) === null || _f === void 0 ? void 0 : _f.finish_reason) || "unknown",
145
+ retries: retriesUsed,
146
+ attempts: attempt,
140
147
  };
141
148
  returnData.push({
142
149
  json: result,
@@ -30,6 +30,7 @@ class GitHubCopilotOpenAI {
30
30
  };
31
31
  }
32
32
  async execute() {
33
+ var _a, _b;
33
34
  const items = this.getInputData();
34
35
  const returnData = [];
35
36
  for (let i = 0; i < items.length; i++) {
@@ -163,6 +164,11 @@ class GitHubCopilotOpenAI {
163
164
  requestBody.seed = seed;
164
165
  }
165
166
  const response = await (0, utils_1.makeApiRequest)(this, GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ENDPOINTS.CHAT_COMPLETIONS, requestBody, false);
167
+ const retriesUsed = ((_a = response._retryMetadata) === null || _a === void 0 ? void 0 : _a.retries) || 0;
168
+ const attemptsUsed = ((_b = response._retryMetadata) === null || _b === void 0 ? void 0 : _b.attempts) || 1;
169
+ if (retriesUsed > 0) {
170
+ console.log(`ℹ️ Request completed after ${attemptsUsed} attempts (${retriesUsed} retries)`);
171
+ }
166
172
  const cleanJsonFromMarkdown = (content) => {
167
173
  if (!content || typeof content !== 'string') {
168
174
  return content;
@@ -230,6 +236,12 @@ class GitHubCopilotOpenAI {
230
236
  completion_tokens: 0,
231
237
  total_tokens: 0,
232
238
  },
239
+ ...(retriesUsed > 0 && {
240
+ _retry_info: {
241
+ attempts: attemptsUsed,
242
+ retries: retriesUsed,
243
+ }
244
+ }),
233
245
  };
234
246
  returnData.push({
235
247
  json: openAIResponse,
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.32.0",
3
+ "version": "3.32.1",
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",
@@ -26,6 +26,11 @@ export interface CopilotResponse {
26
26
  completion_tokens: number;
27
27
  total_tokens: number;
28
28
  };
29
+ _retryMetadata?: {
30
+ attempts: number;
31
+ retries: number;
32
+ succeeded: boolean;
33
+ };
29
34
  }
30
35
  export interface RetryConfig {
31
36
  maxRetries?: number;
@@ -12,7 +12,7 @@ exports.truncateToTokenLimit = truncateToTokenLimit;
12
12
  const GitHubCopilotEndpoints_1 = require("./GitHubCopilotEndpoints");
13
13
  const OAuthTokenManager_1 = require("./OAuthTokenManager");
14
14
  async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = false, retryConfig) {
15
- var _a, _b, _c, _d;
15
+ var _a, _b, _c;
16
16
  const MAX_RETRIES = (_a = retryConfig === null || retryConfig === void 0 ? void 0 : retryConfig.maxRetries) !== null && _a !== void 0 ? _a : 3;
17
17
  const BASE_DELAY = (_b = retryConfig === null || retryConfig === void 0 ? void 0 : retryConfig.baseDelay) !== null && _b !== void 0 ? _b : 500;
18
18
  const RETRY_ON_403 = (_c = retryConfig === null || retryConfig === void 0 ? void 0 : retryConfig.retryOn403) !== null && _c !== void 0 ? _c : true;
@@ -25,43 +25,21 @@ async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = fals
25
25
  }
26
26
  const credentials = await context.getCredentials(credentialType);
27
27
  console.log(`🔍 ${credentialType} Credentials Debug:`, Object.keys(credentials));
28
- const authMethod = credentials.authMethod;
29
- let token;
30
- if (authMethod === "githubToken" || credentials.token) {
31
- const githubToken = credentials.token;
32
- if (!githubToken) {
33
- throw new Error("GitHub token (gho_*) not found in credentials");
34
- }
35
- if (!githubToken.startsWith("gho_")) {
36
- throw new Error("Invalid GitHub token format. Must start with gho_");
37
- }
38
- console.log(`🔄 Using GitHub token to generate OAuth token...`);
39
- try {
40
- token = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
41
- console.log(`✅ OAuth token ready (auto-generated from GitHub token)`);
42
- }
43
- catch (error) {
44
- throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
45
- }
28
+ const githubToken = credentials.token;
29
+ if (!githubToken) {
30
+ throw new Error("GitHub CLI token (gho_*) not found in credentials");
46
31
  }
47
- else if (authMethod === "oauthToken" || credentials.oauthToken) {
48
- token = credentials.oauthToken;
49
- if (!token) {
50
- throw new Error("OAuth token not found in credentials");
51
- }
52
- console.log(`✅ Using manual OAuth token`);
32
+ if (!githubToken.startsWith("gho_")) {
33
+ throw new Error("Invalid GitHub token format. Must start with gho_");
53
34
  }
54
- else {
55
- token = (credentials.accessToken ||
56
- credentials.access_token ||
57
- ((_d = credentials.oauthTokenData) === null || _d === void 0 ? void 0 : _d.access_token) ||
58
- credentials.token);
59
- if (!token) {
60
- console.error(`❌ Available ${credentialType} credential properties:`, Object.keys(credentials));
61
- throw new Error(`No access token found in ${credentialType} credentials. Available properties: ` +
62
- Object.keys(credentials).join(", "));
63
- }
64
- console.log(`⚠️ Using legacy token format (consider updating credential configuration)`);
35
+ console.log(`🔄 Using GitHub token to generate OAuth token...`);
36
+ let token;
37
+ try {
38
+ token = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
39
+ console.log(`✅ OAuth token ready (auto-generated from GitHub token)`);
40
+ }
41
+ catch (error) {
42
+ throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
65
43
  }
66
44
  if (!token) {
67
45
  console.error(`❌ Available ${credentialType} credential properties:`, Object.keys(credentials));
@@ -118,7 +96,13 @@ async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = fals
118
96
  if (attempt > 1) {
119
97
  console.log(`✅ GitHub Copilot API succeeded on attempt ${attempt}/${MAX_RETRIES}`);
120
98
  }
121
- return await response.json();
99
+ const responseData = await response.json();
100
+ responseData._retryMetadata = {
101
+ attempts: attempt,
102
+ retries: attempt - 1,
103
+ succeeded: true
104
+ };
105
+ return responseData;
122
106
  }
123
107
  catch (error) {
124
108
  lastError = error instanceof Error ? error : new Error(String(error));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.32.0",
3
+ "version": "3.32.1",
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",