n8n-nodes-github-copilot 4.1.1 → 4.2.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/dist/nodes/GitHubCopilot/GitHubCopilot.node.js +27 -17
- package/dist/package.json +4 -3
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +15 -0
- package/dist/shared/utils/provider-injection.d.ts +15 -0
- package/dist/shared/utils/provider-injection.js +177 -0
- package/dist/shared/utils/version-detection.d.ts +11 -0
- package/dist/shared/utils/version-detection.js +78 -0
- package/package.json +4 -3
- package/shared/icons/copilot.svg +34 -0
- package/shared/index.ts +27 -0
- package/shared/models/DynamicModelLoader.ts +124 -0
- package/shared/models/GitHubCopilotModels.ts +420 -0
- package/shared/models/ModelVersionRequirements.ts +165 -0
- package/shared/properties/ModelProperties.ts +52 -0
- package/shared/properties/ModelSelectionProperty.ts +68 -0
- package/shared/utils/DynamicModelsManager.ts +355 -0
- package/shared/utils/EmbeddingsApiUtils.ts +135 -0
- package/shared/utils/FileChunkingApiUtils.ts +176 -0
- package/shared/utils/FileOptimizationUtils.ts +210 -0
- package/shared/utils/GitHubCopilotApiUtils.ts +407 -0
- package/shared/utils/GitHubCopilotEndpoints.ts +212 -0
- package/shared/utils/GitHubDeviceFlowHandler.ts +276 -0
- package/shared/utils/OAuthTokenManager.ts +196 -0
- package/shared/utils/provider-injection.ts +277 -0
- package/shared/utils/version-detection.ts +145 -0
|
@@ -66,14 +66,6 @@ class GitHubCopilot {
|
|
|
66
66
|
placeholder: 'Example: Show me this week\'s commits and summarize them',
|
|
67
67
|
description: 'Your query or task for GitHub Copilot CLI. Will be executed with: copilot -p "your prompt"',
|
|
68
68
|
},
|
|
69
|
-
{
|
|
70
|
-
displayName: 'Model',
|
|
71
|
-
name: 'model',
|
|
72
|
-
type: 'string',
|
|
73
|
-
default: '',
|
|
74
|
-
placeholder: 'gpt-4o, o1, claude-3.5-sonnet, etc.',
|
|
75
|
-
description: 'Model to use (optional). Leave empty for default (Claude Sonnet 4.5). Examples: gpt-4o, gpt-4o-mini, o1, o1-mini, o1-preview, claude-3.5-sonnet',
|
|
76
|
-
},
|
|
77
69
|
{
|
|
78
70
|
displayName: 'Tool Approval',
|
|
79
71
|
name: 'toolApproval',
|
|
@@ -88,6 +80,30 @@ class GitHubCopilot {
|
|
|
88
80
|
default: 'manual',
|
|
89
81
|
description: 'Which tools Copilot can use without asking. WARNING: "Allow All" is dangerous - Copilot can execute ANY command!',
|
|
90
82
|
},
|
|
83
|
+
{
|
|
84
|
+
displayName: 'Options',
|
|
85
|
+
name: 'options',
|
|
86
|
+
type: 'collection',
|
|
87
|
+
placeholder: 'Add Option',
|
|
88
|
+
default: {},
|
|
89
|
+
options: [
|
|
90
|
+
{
|
|
91
|
+
displayName: 'Model',
|
|
92
|
+
name: 'model',
|
|
93
|
+
type: 'string',
|
|
94
|
+
default: '',
|
|
95
|
+
placeholder: 'gpt-4o, o1, claude-3.5-sonnet, etc.',
|
|
96
|
+
description: 'Model to use. Leave empty for default (Claude Sonnet 4.5). Examples: gpt-4o, gpt-4o-mini, o1, o1-mini, o1-preview, claude-3.5-sonnet',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
displayName: 'Timeout (seconds)',
|
|
100
|
+
name: 'timeout',
|
|
101
|
+
type: 'number',
|
|
102
|
+
default: 60,
|
|
103
|
+
description: 'Maximum execution time in seconds',
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
91
107
|
{
|
|
92
108
|
displayName: 'Allowed Tools',
|
|
93
109
|
name: 'allowedTools',
|
|
@@ -101,13 +117,6 @@ class GitHubCopilot {
|
|
|
101
117
|
placeholder: '--allow-tool \'shell(git)\' --allow-tool \'write\'',
|
|
102
118
|
description: 'Custom tool approval flags (space-separated). Example: --allow-tool \'shell(git)\' --deny-tool \'shell(rm)\'',
|
|
103
119
|
},
|
|
104
|
-
{
|
|
105
|
-
displayName: 'Timeout (seconds)',
|
|
106
|
-
name: 'timeout',
|
|
107
|
-
type: 'number',
|
|
108
|
-
default: 60,
|
|
109
|
-
description: 'Maximum execution time in seconds',
|
|
110
|
-
},
|
|
111
120
|
],
|
|
112
121
|
};
|
|
113
122
|
}
|
|
@@ -130,10 +139,11 @@ class GitHubCopilot {
|
|
|
130
139
|
try {
|
|
131
140
|
const operation = this.getNodeParameter('operation', i);
|
|
132
141
|
const prompt = this.getNodeParameter('prompt', i);
|
|
133
|
-
const model = this.getNodeParameter('model', i, '');
|
|
134
142
|
const toolApproval = this.getNodeParameter('toolApproval', i);
|
|
135
|
-
const timeout = this.getNodeParameter('timeout', i, 60);
|
|
136
143
|
const useCredential = this.getNodeParameter('useCredential', i, false);
|
|
144
|
+
const options = this.getNodeParameter('options', i, {});
|
|
145
|
+
const model = options.model || '';
|
|
146
|
+
const timeout = options.timeout || 60;
|
|
137
147
|
let githubToken = '';
|
|
138
148
|
let authMethod = 'Local Copilot CLI';
|
|
139
149
|
if (useCredential) {
|
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "n8n community node for GitHub Copilot with
|
|
3
|
+
"version": "4.2.0",
|
|
4
|
+
"description": "n8n community node for GitHub Copilot with CLI, Chat API, AI Chat Model, and n8n v2 Chat Hub integration - access GPT-5, Claude Sonnet 4.5, Gemini and more using your Copilot subscription",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",
|
|
7
7
|
"author": {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"prepublishOnly": "npm run build"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
|
-
"dist"
|
|
24
|
+
"dist",
|
|
25
|
+
"shared"
|
|
25
26
|
],
|
|
26
27
|
"n8n": {
|
|
27
28
|
"n8nNodesApiVersion": 1,
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { detectN8nVersion, isN8nV2OrHigher, isChatHubAvailable, getN8nVersionString, type N8nVersionInfo, } from './utils/version-detection';
|
|
2
|
+
export { injectGitHubCopilotProvider, getInjectionStatus, isProviderInjected, autoInject, type ProviderInjectionStatus, } from './utils/provider-injection';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.autoInject = exports.isProviderInjected = exports.getInjectionStatus = exports.injectGitHubCopilotProvider = exports.getN8nVersionString = exports.isChatHubAvailable = exports.isN8nV2OrHigher = exports.detectN8nVersion = void 0;
|
|
4
|
+
var version_detection_1 = require("./utils/version-detection");
|
|
5
|
+
Object.defineProperty(exports, "detectN8nVersion", { enumerable: true, get: function () { return version_detection_1.detectN8nVersion; } });
|
|
6
|
+
Object.defineProperty(exports, "isN8nV2OrHigher", { enumerable: true, get: function () { return version_detection_1.isN8nV2OrHigher; } });
|
|
7
|
+
Object.defineProperty(exports, "isChatHubAvailable", { enumerable: true, get: function () { return version_detection_1.isChatHubAvailable; } });
|
|
8
|
+
Object.defineProperty(exports, "getN8nVersionString", { enumerable: true, get: function () { return version_detection_1.getN8nVersionString; } });
|
|
9
|
+
var provider_injection_1 = require("./utils/provider-injection");
|
|
10
|
+
Object.defineProperty(exports, "injectGitHubCopilotProvider", { enumerable: true, get: function () { return provider_injection_1.injectGitHubCopilotProvider; } });
|
|
11
|
+
Object.defineProperty(exports, "getInjectionStatus", { enumerable: true, get: function () { return provider_injection_1.getInjectionStatus; } });
|
|
12
|
+
Object.defineProperty(exports, "isProviderInjected", { enumerable: true, get: function () { return provider_injection_1.isProviderInjected; } });
|
|
13
|
+
Object.defineProperty(exports, "autoInject", { enumerable: true, get: function () { return provider_injection_1.autoInject; } });
|
|
14
|
+
const provider_injection_2 = require("./utils/provider-injection");
|
|
15
|
+
(0, provider_injection_2.autoInject)();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ProviderInjectionStatus {
|
|
2
|
+
attempted: boolean;
|
|
3
|
+
success: boolean;
|
|
4
|
+
n8nVersion: string;
|
|
5
|
+
chatHubAvailable: boolean;
|
|
6
|
+
error?: string;
|
|
7
|
+
modifications: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function injectGitHubCopilotProvider(options?: {
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
force?: boolean;
|
|
12
|
+
}): ProviderInjectionStatus;
|
|
13
|
+
export declare function getInjectionStatus(): ProviderInjectionStatus | null;
|
|
14
|
+
export declare function isProviderInjected(): boolean;
|
|
15
|
+
export declare function autoInject(): void;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.injectGitHubCopilotProvider = injectGitHubCopilotProvider;
|
|
4
|
+
exports.getInjectionStatus = getInjectionStatus;
|
|
5
|
+
exports.isProviderInjected = isProviderInjected;
|
|
6
|
+
exports.autoInject = autoInject;
|
|
7
|
+
const version_detection_1 = require("./version-detection");
|
|
8
|
+
let injectionStatus = null;
|
|
9
|
+
function injectGitHubCopilotProvider(options = {}) {
|
|
10
|
+
const { debug = false, force = false } = options;
|
|
11
|
+
if (injectionStatus && !force) {
|
|
12
|
+
if (debug) {
|
|
13
|
+
console.log('[GitHub Copilot] Provider already injected:', injectionStatus);
|
|
14
|
+
}
|
|
15
|
+
return injectionStatus;
|
|
16
|
+
}
|
|
17
|
+
const status = {
|
|
18
|
+
attempted: true,
|
|
19
|
+
success: false,
|
|
20
|
+
n8nVersion: (0, version_detection_1.getN8nVersionString)(),
|
|
21
|
+
chatHubAvailable: false,
|
|
22
|
+
modifications: [],
|
|
23
|
+
};
|
|
24
|
+
try {
|
|
25
|
+
if (!(0, version_detection_1.isN8nV2OrHigher)()) {
|
|
26
|
+
status.error = `n8n v2+ required. Detected: ${status.n8nVersion}`;
|
|
27
|
+
if (debug) {
|
|
28
|
+
console.log('[GitHub Copilot] Skipping injection:', status.error);
|
|
29
|
+
}
|
|
30
|
+
injectionStatus = status;
|
|
31
|
+
return status;
|
|
32
|
+
}
|
|
33
|
+
if (!(0, version_detection_1.isChatHubAvailable)()) {
|
|
34
|
+
status.error = 'Chat Hub APIs not available';
|
|
35
|
+
if (debug) {
|
|
36
|
+
console.log('[GitHub Copilot] Skipping injection:', status.error);
|
|
37
|
+
}
|
|
38
|
+
injectionStatus = status;
|
|
39
|
+
return status;
|
|
40
|
+
}
|
|
41
|
+
status.chatHubAvailable = true;
|
|
42
|
+
injectIntoApiTypes(status, debug);
|
|
43
|
+
injectIntoConstants(status, debug);
|
|
44
|
+
injectIntoFrontend(status, debug);
|
|
45
|
+
status.success = status.modifications.length > 0;
|
|
46
|
+
if (debug) {
|
|
47
|
+
console.log('[GitHub Copilot] Provider injection completed:', status);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
status.error = error instanceof Error ? error.message : String(error);
|
|
52
|
+
if (debug) {
|
|
53
|
+
console.error('[GitHub Copilot] Provider injection failed:', error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
injectionStatus = status;
|
|
57
|
+
return status;
|
|
58
|
+
}
|
|
59
|
+
function injectIntoApiTypes(status, debug) {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
try {
|
|
62
|
+
const apiTypes = require('@n8n/api-types');
|
|
63
|
+
if ((_b = (_a = apiTypes.chatHubLLMProviderSchema) === null || _a === void 0 ? void 0 : _a._def) === null || _b === void 0 ? void 0 : _b.values) {
|
|
64
|
+
const values = apiTypes.chatHubLLMProviderSchema._def.values;
|
|
65
|
+
if (!values.includes('githubCopilot')) {
|
|
66
|
+
values.push('githubCopilot');
|
|
67
|
+
status.modifications.push('Added githubCopilot to chatHubLLMProviderSchema');
|
|
68
|
+
if (debug) {
|
|
69
|
+
console.log('[GitHub Copilot] ✓ Injected into chatHubLLMProviderSchema');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (apiTypes.PROVIDER_CREDENTIAL_TYPE_MAP) {
|
|
74
|
+
if (!apiTypes.PROVIDER_CREDENTIAL_TYPE_MAP.githubCopilot) {
|
|
75
|
+
apiTypes.PROVIDER_CREDENTIAL_TYPE_MAP.githubCopilot = 'gitHubCopilotApi';
|
|
76
|
+
status.modifications.push('Added githubCopilot to PROVIDER_CREDENTIAL_TYPE_MAP');
|
|
77
|
+
if (debug) {
|
|
78
|
+
console.log('[GitHub Copilot] ✓ Injected into PROVIDER_CREDENTIAL_TYPE_MAP');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (apiTypes.emptyChatModelsResponse) {
|
|
83
|
+
if (!apiTypes.emptyChatModelsResponse.githubCopilot) {
|
|
84
|
+
apiTypes.emptyChatModelsResponse.githubCopilot = { models: [] };
|
|
85
|
+
status.modifications.push('Added githubCopilot to emptyChatModelsResponse');
|
|
86
|
+
if (debug) {
|
|
87
|
+
console.log('[GitHub Copilot] ✓ Injected into emptyChatModelsResponse');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (debug) {
|
|
94
|
+
console.warn('[GitHub Copilot] Failed to inject into @n8n/api-types:', error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function injectIntoConstants(status, debug) {
|
|
99
|
+
try {
|
|
100
|
+
const possiblePaths = [
|
|
101
|
+
'@n8n/cli/dist/modules/chat-hub/chat-hub.constants',
|
|
102
|
+
'n8n/dist/modules/chat-hub/chat-hub.constants',
|
|
103
|
+
];
|
|
104
|
+
let constants = null;
|
|
105
|
+
for (const path of possiblePaths) {
|
|
106
|
+
try {
|
|
107
|
+
constants = require(path);
|
|
108
|
+
if (constants.PROVIDER_NODE_TYPE_MAP) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!constants) {
|
|
117
|
+
if (debug) {
|
|
118
|
+
console.warn('[GitHub Copilot] Could not find chat-hub.constants module');
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (constants.PROVIDER_NODE_TYPE_MAP) {
|
|
123
|
+
if (!constants.PROVIDER_NODE_TYPE_MAP.githubCopilot) {
|
|
124
|
+
constants.PROVIDER_NODE_TYPE_MAP.githubCopilot = 'n8n-nodes-copilot.gitHubCopilotChatModel';
|
|
125
|
+
status.modifications.push('Added githubCopilot to PROVIDER_NODE_TYPE_MAP');
|
|
126
|
+
if (debug) {
|
|
127
|
+
console.log('[GitHub Copilot] ✓ Injected into PROVIDER_NODE_TYPE_MAP');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (debug) {
|
|
134
|
+
console.warn('[GitHub Copilot] Failed to inject into constants:', error);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function injectIntoFrontend(status, debug) {
|
|
139
|
+
var _a;
|
|
140
|
+
try {
|
|
141
|
+
if (typeof globalThis !== 'undefined' && globalThis.window) {
|
|
142
|
+
const win = globalThis.window;
|
|
143
|
+
if ((_a = win.__VUE_DEVTOOLS_GLOBAL_HOOK__) === null || _a === void 0 ? void 0 : _a.store) {
|
|
144
|
+
if (debug) {
|
|
145
|
+
console.log('[GitHub Copilot] Browser context detected, but store injection not yet implemented');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
if (debug) {
|
|
151
|
+
console.log('[GitHub Copilot] Not in browser context, skipping frontend injection');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (debug) {
|
|
157
|
+
console.warn('[GitHub Copilot] Failed to inject into frontend:', error);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function getInjectionStatus() {
|
|
162
|
+
return injectionStatus;
|
|
163
|
+
}
|
|
164
|
+
function isProviderInjected() {
|
|
165
|
+
var _a;
|
|
166
|
+
return (_a = injectionStatus === null || injectionStatus === void 0 ? void 0 : injectionStatus.success) !== null && _a !== void 0 ? _a : false;
|
|
167
|
+
}
|
|
168
|
+
function autoInject() {
|
|
169
|
+
const autoInjectEnabled = process.env.GITHUB_COPILOT_AUTO_INJECT === 'true';
|
|
170
|
+
const debugEnabled = process.env.GITHUB_COPILOT_DEBUG === 'true';
|
|
171
|
+
if (autoInjectEnabled) {
|
|
172
|
+
if (debugEnabled) {
|
|
173
|
+
console.log('[GitHub Copilot] Auto-injection enabled');
|
|
174
|
+
}
|
|
175
|
+
injectGitHubCopilotProvider({ debug: debugEnabled });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface N8nVersionInfo {
|
|
2
|
+
version: string;
|
|
3
|
+
major: number;
|
|
4
|
+
minor: number;
|
|
5
|
+
patch: number;
|
|
6
|
+
isV2OrHigher: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function detectN8nVersion(): N8nVersionInfo | null;
|
|
9
|
+
export declare function isN8nV2OrHigher(): boolean;
|
|
10
|
+
export declare function isChatHubAvailable(): boolean;
|
|
11
|
+
export declare function getN8nVersionString(): string;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectN8nVersion = detectN8nVersion;
|
|
4
|
+
exports.isN8nV2OrHigher = isN8nV2OrHigher;
|
|
5
|
+
exports.isChatHubAvailable = isChatHubAvailable;
|
|
6
|
+
exports.getN8nVersionString = getN8nVersionString;
|
|
7
|
+
function detectN8nVersion() {
|
|
8
|
+
try {
|
|
9
|
+
const n8nWorkflow = require('n8n-workflow/package.json');
|
|
10
|
+
if (n8nWorkflow === null || n8nWorkflow === void 0 ? void 0 : n8nWorkflow.version) {
|
|
11
|
+
return parseVersionString(n8nWorkflow.version);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
if (typeof global !== 'undefined' && global.N8N_VERSION) {
|
|
18
|
+
return parseVersionString(global.N8N_VERSION);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
if (process.env.N8N_VERSION) {
|
|
25
|
+
return parseVersionString(process.env.N8N_VERSION);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const apiTypes = require('@n8n/api-types');
|
|
32
|
+
if (apiTypes.chatHubLLMProviderSchema) {
|
|
33
|
+
return {
|
|
34
|
+
version: '2.0.0',
|
|
35
|
+
major: 2,
|
|
36
|
+
minor: 0,
|
|
37
|
+
patch: 0,
|
|
38
|
+
isV2OrHigher: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function parseVersionString(versionString) {
|
|
47
|
+
const cleanVersion = versionString.replace(/^v/, '');
|
|
48
|
+
const parts = cleanVersion.split('.').map(p => parseInt(p, 10));
|
|
49
|
+
const [major = 0, minor = 0, patch = 0] = parts;
|
|
50
|
+
return {
|
|
51
|
+
version: cleanVersion,
|
|
52
|
+
major,
|
|
53
|
+
minor,
|
|
54
|
+
patch,
|
|
55
|
+
isV2OrHigher: major >= 2,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function isN8nV2OrHigher() {
|
|
59
|
+
var _a;
|
|
60
|
+
const versionInfo = detectN8nVersion();
|
|
61
|
+
return (_a = versionInfo === null || versionInfo === void 0 ? void 0 : versionInfo.isV2OrHigher) !== null && _a !== void 0 ? _a : false;
|
|
62
|
+
}
|
|
63
|
+
function isChatHubAvailable() {
|
|
64
|
+
try {
|
|
65
|
+
const apiTypes = require('@n8n/api-types');
|
|
66
|
+
return !!(apiTypes.chatHubLLMProviderSchema && apiTypes.PROVIDER_CREDENTIAL_TYPE_MAP);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function getN8nVersionString() {
|
|
73
|
+
const versionInfo = detectN8nVersion();
|
|
74
|
+
if (!versionInfo) {
|
|
75
|
+
return 'unknown';
|
|
76
|
+
}
|
|
77
|
+
return `${versionInfo.version} (v${versionInfo.major})`;
|
|
78
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "n8n community node for GitHub Copilot with
|
|
3
|
+
"version": "4.2.0",
|
|
4
|
+
"description": "n8n community node for GitHub Copilot with CLI, Chat API, AI Chat Model, and n8n v2 Chat Hub integration - access GPT-5, Claude Sonnet 4.5, Gemini and more using your Copilot subscription",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",
|
|
7
7
|
"author": {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"prepublishOnly": "npm run build"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
|
-
"dist"
|
|
24
|
+
"dist",
|
|
25
|
+
"shared"
|
|
25
26
|
],
|
|
26
27
|
"n8n": {
|
|
27
28
|
"n8nNodesApiVersion": 1,
|
|
@@ -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>
|
package/shared/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities and models for n8n-nodes-copilot
|
|
3
|
+
*
|
|
4
|
+
* @module shared
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Version detection utilities
|
|
8
|
+
export {
|
|
9
|
+
detectN8nVersion,
|
|
10
|
+
isN8nV2OrHigher,
|
|
11
|
+
isChatHubAvailable,
|
|
12
|
+
getN8nVersionString,
|
|
13
|
+
type N8nVersionInfo,
|
|
14
|
+
} from './utils/version-detection';
|
|
15
|
+
|
|
16
|
+
// Provider injection utilities
|
|
17
|
+
export {
|
|
18
|
+
injectGitHubCopilotProvider,
|
|
19
|
+
getInjectionStatus,
|
|
20
|
+
isProviderInjected,
|
|
21
|
+
autoInject,
|
|
22
|
+
type ProviderInjectionStatus,
|
|
23
|
+
} from './utils/provider-injection';
|
|
24
|
+
|
|
25
|
+
// Auto-inject on module load if enabled
|
|
26
|
+
import { autoInject } from './utils/provider-injection';
|
|
27
|
+
autoInject();
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic Model Loader for n8n Nodes
|
|
3
|
+
*
|
|
4
|
+
* Provides dynamic model loading functionality for n8n nodes.
|
|
5
|
+
* Models are loaded based on the authenticated user's available models.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ILoadOptionsFunctions, INodePropertyOptions } from "n8n-workflow";
|
|
9
|
+
import { DynamicModelsManager } from "../utils/DynamicModelsManager";
|
|
10
|
+
import { OAuthTokenManager } from "../utils/OAuthTokenManager";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Load available models dynamically based on user authentication
|
|
14
|
+
* Use this in node properties with `loadOptions` method
|
|
15
|
+
*
|
|
16
|
+
* @param forceRefresh - If true, bypasses cache and fetches fresh data from API
|
|
17
|
+
*/
|
|
18
|
+
export async function loadAvailableModels(
|
|
19
|
+
this: ILoadOptionsFunctions,
|
|
20
|
+
forceRefresh = false
|
|
21
|
+
): Promise<INodePropertyOptions[]> {
|
|
22
|
+
return loadModelsWithFilter.call(this, "chat", forceRefresh);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Load available embedding models dynamically
|
|
27
|
+
* Use this in embedding nodes with `loadOptions` method
|
|
28
|
+
*
|
|
29
|
+
* @param forceRefresh - If true, bypasses cache and fetches fresh data from API
|
|
30
|
+
*/
|
|
31
|
+
export async function loadAvailableEmbeddingModels(
|
|
32
|
+
this: ILoadOptionsFunctions,
|
|
33
|
+
forceRefresh = false
|
|
34
|
+
): Promise<INodePropertyOptions[]> {
|
|
35
|
+
return loadModelsWithFilter.call(this, "embeddings", forceRefresh);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Internal function to load models with type filter
|
|
40
|
+
*/
|
|
41
|
+
async function loadModelsWithFilter(
|
|
42
|
+
this: ILoadOptionsFunctions,
|
|
43
|
+
modelType: "chat" | "embeddings",
|
|
44
|
+
forceRefresh = false
|
|
45
|
+
): Promise<INodePropertyOptions[]> {
|
|
46
|
+
try {
|
|
47
|
+
// Get credentials
|
|
48
|
+
const credentials = await this.getCredentials("githubCopilotApi");
|
|
49
|
+
|
|
50
|
+
if (!credentials || !credentials.token) {
|
|
51
|
+
console.warn("⚠️ No credentials found for dynamic model loading");
|
|
52
|
+
// Return only manual input option (no fallback)
|
|
53
|
+
return [
|
|
54
|
+
{
|
|
55
|
+
name: "✏️ Enter Custom Model Name",
|
|
56
|
+
value: "__manual__",
|
|
57
|
+
description: "Type your own model name (no credentials found)",
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Get GitHub token
|
|
63
|
+
const githubToken = credentials.token as string;
|
|
64
|
+
|
|
65
|
+
// Generate OAuth token
|
|
66
|
+
let oauthToken: string;
|
|
67
|
+
try {
|
|
68
|
+
oauthToken = await OAuthTokenManager.getValidOAuthToken(githubToken);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error("❌ Failed to generate OAuth token for model loading:", error);
|
|
71
|
+
// Return only manual input option (no fallback)
|
|
72
|
+
return [
|
|
73
|
+
{
|
|
74
|
+
name: "✏️ Enter Custom Model Name",
|
|
75
|
+
value: "__manual__",
|
|
76
|
+
description: "Type your own model name (OAuth generation failed)",
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Clear cache if force refresh requested
|
|
82
|
+
if (forceRefresh) {
|
|
83
|
+
DynamicModelsManager.clearCache(oauthToken);
|
|
84
|
+
console.log("🔄 Force refreshing models list...");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Fetch available models
|
|
88
|
+
const allModels = await DynamicModelsManager.getAvailableModels(oauthToken);
|
|
89
|
+
|
|
90
|
+
// Filter by type
|
|
91
|
+
const models = DynamicModelsManager.filterModelsByType(allModels, modelType);
|
|
92
|
+
|
|
93
|
+
console.log(`🔍 Filtered ${models.length} ${modelType} models from ${allModels.length} total models`);
|
|
94
|
+
|
|
95
|
+
// Convert to n8n options format
|
|
96
|
+
const options = DynamicModelsManager.modelsToN8nOptions(models);
|
|
97
|
+
|
|
98
|
+
// Add manual input option at the top (for both chat and embeddings)
|
|
99
|
+
const optionsWithManualInput: INodePropertyOptions[] = [
|
|
100
|
+
{
|
|
101
|
+
name: "✏️ Enter Custom Model Name",
|
|
102
|
+
value: "__manual__",
|
|
103
|
+
description: "Type your own model name (for new/beta models)",
|
|
104
|
+
},
|
|
105
|
+
...options,
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
console.log(`✅ Loaded ${options.length} ${modelType} models dynamically (+ manual input option)`);
|
|
109
|
+
return optionsWithManualInput;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error("❌ Error loading dynamic models:", error);
|
|
112
|
+
// Return empty list with manual input option (no fallback)
|
|
113
|
+
// User must enter model name manually or wait for next successful discovery
|
|
114
|
+
return [
|
|
115
|
+
{
|
|
116
|
+
name: "✏️ Enter Custom Model Name",
|
|
117
|
+
value: "__manual__",
|
|
118
|
+
description: "Type your own model name (discovery failed, using previous cache if available)",
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|