n8n-nodes-github-copilot 4.1.2 → 4.2.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.
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "4.1.2",
4
- "description": "n8n community node for GitHub Copilot with NEW CLI programmatic mode, Chat API access, and AI Chat Model for workflows - access GPT-5, Claude Sonnet 4.5, Gemini and more using your Copilot subscription",
3
+ "version": "4.2.1",
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.1.2",
4
- "description": "n8n community node for GitHub Copilot with NEW CLI programmatic mode, Chat API access, and AI Chat Model for workflows - access GPT-5, Claude Sonnet 4.5, Gemini and more using your Copilot subscription",
3
+ "version": "4.2.1",
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>
@@ -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
+