snow-flow 2.9.4 → 2.9.6

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.
@@ -15,6 +15,7 @@ const scope_manager_js_1 = require("../managers/scope-manager.js");
15
15
  const global_scope_strategy_js_1 = require("../strategies/global-scope-strategy.js");
16
16
  const artifact_tracker_js_1 = require("../utils/artifact-tracker.js");
17
17
  const servicenow_id_generator_js_1 = require("../utils/servicenow-id-generator.js");
18
+ const deployment_auth_fix_js_1 = require("../utils/deployment-auth-fix.js");
18
19
  const fs_1 = require("fs");
19
20
  const path_1 = require("path");
20
21
  class ServiceNowDeploymentMCP {
@@ -30,6 +31,7 @@ class ServiceNowDeploymentMCP {
30
31
  this.client = new servicenow_client_js_1.ServiceNowClient();
31
32
  this.oauth = new snow_oauth_js_1.ServiceNowOAuth();
32
33
  this.logger = new logger_js_1.Logger('ServiceNowDeploymentMCP');
34
+ this.deploymentAuthManager = new deployment_auth_fix_js_1.DeploymentAuthManager();
33
35
  // Initialize global scope management
34
36
  this.scopeManager = new scope_manager_js_1.ScopeManager({
35
37
  defaultScope: global_scope_strategy_js_1.ScopeType.GLOBAL,
@@ -472,6 +474,45 @@ class ServiceNowDeploymentMCP {
472
474
  updateSetName: updateSetName
473
475
  };
474
476
  }
477
+ /**
478
+ * Create a record with automatic 403 error recovery
479
+ * Will attempt to refresh token and retry once if 403 error occurs
480
+ */
481
+ async createRecordWithRetry(table, data) {
482
+ try {
483
+ // First attempt
484
+ return await this.client.createRecord(table, data);
485
+ }
486
+ catch (error) {
487
+ // Check if it's a 403 error
488
+ if (error.response?.status === 403 || error.message?.includes('403')) {
489
+ this.logger.warn('Got 403 error, attempting token refresh and retry...');
490
+ // Refresh token
491
+ const refreshResult = await this.deploymentAuthManager.forceTokenRefresh();
492
+ if (refreshResult.success && refreshResult.accessToken) {
493
+ // Client will use the new token automatically from unified auth store
494
+ // No need to call authenticate - the client reads from auth store
495
+ // Retry the operation
496
+ try {
497
+ this.logger.info('Retrying operation with refreshed token...');
498
+ return await this.client.createRecord(table, data);
499
+ }
500
+ catch (retryError) {
501
+ this.logger.error('Retry failed after token refresh:', retryError);
502
+ throw retryError;
503
+ }
504
+ }
505
+ else {
506
+ this.logger.error('Failed to refresh token for retry');
507
+ throw error;
508
+ }
509
+ }
510
+ else {
511
+ // Not a 403 error, just re-throw
512
+ throw error;
513
+ }
514
+ }
515
+ }
475
516
  /**
476
517
  * Ensure artifact is tracked in current Update Set
477
518
  */
@@ -537,17 +578,26 @@ class ServiceNowDeploymentMCP {
537
578
  }
538
579
  async deployWidget(args) {
539
580
  try {
540
- // Check authentication first
541
- const isAuth = await this.oauth.isAuthenticated();
542
- if (!isAuth) {
543
- return {
544
- content: [
545
- {
546
- type: 'text',
547
- text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
548
- },
549
- ],
550
- };
581
+ // Enhanced authentication check with token refresh for deployment
582
+ const authResult = await this.deploymentAuthManager.ensureDeploymentAuth();
583
+ if (!authResult.isValid) {
584
+ this.logger.error('Deployment authentication failed:', authResult.error);
585
+ // If auth failed, try to refresh token
586
+ const refreshResult = await this.deploymentAuthManager.forceTokenRefresh();
587
+ if (!refreshResult.success) {
588
+ return {
589
+ content: [
590
+ {
591
+ type: 'text',
592
+ text: `❌ Deployment authentication failed.\n\nError: ${authResult.error || 'Unable to authenticate'}\n\nRecommendations:\n${(authResult.recommendations || ['Run: snow-flow auth login']).map(r => `• ${r}`).join('\n')}\n\nNote: Deployment requires valid OAuth tokens with write permissions.`,
593
+ },
594
+ ],
595
+ };
596
+ }
597
+ }
598
+ // Warn if token may lack write permissions
599
+ if (!authResult.hasWriteScope) {
600
+ this.logger.warn('⚠️ Token may lack write permissions, deployment might fail with 403');
551
601
  }
552
602
  this.logger.info('Deploying widget to ServiceNow', { name: args.name });
553
603
  // ENHANCED: Mandatory Update Set management with auto-activation
@@ -695,7 +745,7 @@ class ServiceNowDeploymentMCP {
695
745
  // Strategy 2: Direct table record creation (fallback)
696
746
  try {
697
747
  this.logger.info('🔄 Attempting fallback: Direct table record creation');
698
- result = await this.client.createRecord('sp_widget', {
748
+ result = await this.createRecordWithRetry('sp_widget', {
699
749
  name: args.name,
700
750
  id: args.name,
701
751
  title: args.title,
@@ -1069,17 +1119,26 @@ Use \`snow_deployment_debug\` for more information about this session.`,
1069
1119
  */
1070
1120
  async deployPortalPage(args) {
1071
1121
  try {
1072
- // Check authentication first
1073
- const isAuth = await this.oauth.isAuthenticated();
1074
- if (!isAuth) {
1075
- return {
1076
- content: [
1077
- {
1078
- type: 'text',
1079
- text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
1080
- },
1081
- ],
1082
- };
1122
+ // Enhanced authentication check with token refresh for deployment
1123
+ const authResult = await this.deploymentAuthManager.ensureDeploymentAuth();
1124
+ if (!authResult.isValid) {
1125
+ this.logger.error('Deployment authentication failed:', authResult.error);
1126
+ // If auth failed, try to refresh token
1127
+ const refreshResult = await this.deploymentAuthManager.forceTokenRefresh();
1128
+ if (!refreshResult.success) {
1129
+ return {
1130
+ content: [
1131
+ {
1132
+ type: 'text',
1133
+ text: `❌ Deployment authentication failed.\n\nError: ${authResult.error || 'Unable to authenticate'}\n\nRecommendations:\n${(authResult.recommendations || ['Run: snow-flow auth login']).map(r => `• ${r}`).join('\n')}\n\nNote: Deployment requires valid OAuth tokens with write permissions.`,
1134
+ },
1135
+ ],
1136
+ };
1137
+ }
1138
+ }
1139
+ // Warn if token may lack write permissions
1140
+ if (!authResult.hasWriteScope) {
1141
+ this.logger.warn('⚠️ Token may lack write permissions, deployment might fail with 403');
1083
1142
  }
1084
1143
  this.logger.info('Deploying portal page to ServiceNow', { name: args.page_id });
1085
1144
  // Ensure Update Set is active
@@ -1124,7 +1183,7 @@ Use \`snow_deployment_debug\` for more information about this session.`,
1124
1183
  let pageResult;
1125
1184
  try {
1126
1185
  // Create the page record
1127
- pageResult = await this.client.createRecord('sp_page', {
1186
+ pageResult = await this.createRecordWithRetry('sp_page', {
1128
1187
  id: args.page_id,
1129
1188
  title: args.title,
1130
1189
  short_description: args.description || `Portal page created by Snow-Flow`,
@@ -1512,17 +1571,26 @@ ${args.widgets && args.widgets.length > 0 ? args.widgets.map((w, i) => `
1512
1571
  }
1513
1572
  async deployFlow(args) {
1514
1573
  try {
1515
- // Check authentication first
1516
- const isAuth = await this.oauth.isAuthenticated();
1517
- if (!isAuth) {
1518
- return {
1519
- content: [
1520
- {
1521
- type: 'text',
1522
- text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
1523
- },
1524
- ],
1525
- };
1574
+ // Enhanced authentication check with token refresh for deployment
1575
+ const authResult = await this.deploymentAuthManager.ensureDeploymentAuth();
1576
+ if (!authResult.isValid) {
1577
+ this.logger.error('Deployment authentication failed:', authResult.error);
1578
+ // If auth failed, try to refresh token
1579
+ const refreshResult = await this.deploymentAuthManager.forceTokenRefresh();
1580
+ if (!refreshResult.success) {
1581
+ return {
1582
+ content: [
1583
+ {
1584
+ type: 'text',
1585
+ text: `❌ Deployment authentication failed.\n\nError: ${authResult.error || 'Unable to authenticate'}\n\nRecommendations:\n${(authResult.recommendations || ['Run: snow-flow auth login']).map(r => `• ${r}`).join('\n')}\n\nNote: Deployment requires valid OAuth tokens with write permissions.`,
1586
+ },
1587
+ ],
1588
+ };
1589
+ }
1590
+ }
1591
+ // Warn if token may lack write permissions
1592
+ if (!authResult.hasWriteScope) {
1593
+ this.logger.warn('⚠️ Token may lack write permissions, deployment might fail with 403');
1526
1594
  }
1527
1595
  // Ensure we have a flow definition
1528
1596
  if (!args.flow_definition) {
@@ -1964,17 +2032,26 @@ ${isComposedFlow ? `
1964
2032
  }
1965
2033
  async deployApplication(args) {
1966
2034
  try {
1967
- // Check authentication first
1968
- const isAuth = await this.oauth.isAuthenticated();
1969
- if (!isAuth) {
1970
- return {
1971
- content: [
1972
- {
1973
- type: 'text',
1974
- text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
1975
- },
1976
- ],
1977
- };
2035
+ // Enhanced authentication check with token refresh for deployment
2036
+ const authResult = await this.deploymentAuthManager.ensureDeploymentAuth();
2037
+ if (!authResult.isValid) {
2038
+ this.logger.error('Deployment authentication failed:', authResult.error);
2039
+ // If auth failed, try to refresh token
2040
+ const refreshResult = await this.deploymentAuthManager.forceTokenRefresh();
2041
+ if (!refreshResult.success) {
2042
+ return {
2043
+ content: [
2044
+ {
2045
+ type: 'text',
2046
+ text: `❌ Deployment authentication failed.\n\nError: ${authResult.error || 'Unable to authenticate'}\n\nRecommendations:\n${(authResult.recommendations || ['Run: snow-flow auth login']).map(r => `• ${r}`).join('\n')}\n\nNote: Deployment requires valid OAuth tokens with write permissions.`,
2047
+ },
2048
+ ],
2049
+ };
2050
+ }
2051
+ }
2052
+ // Warn if token may lack write permissions
2053
+ if (!authResult.hasWriteScope) {
2054
+ this.logger.warn('⚠️ Token may lack write permissions, deployment might fail with 403');
1978
2055
  }
1979
2056
  this.logger.info('Deploying application with intelligent scope management', { name: args.name });
1980
2057
  // Ensure Update Set is active
@@ -3480,13 +3557,13 @@ Run snow_deployment_debug for basic session info or check the logs for more deta
3480
3557
  async previewWidget(args) {
3481
3558
  try {
3482
3559
  // Check authentication first
3483
- const isAuth = await this.oauth.isAuthenticated();
3484
- if (!isAuth) {
3560
+ const authResult = await this.deploymentAuthManager.ensureDeploymentAuth();
3561
+ if (!authResult.isValid) {
3485
3562
  return {
3486
3563
  content: [
3487
3564
  {
3488
3565
  type: 'text',
3489
- text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
3566
+ text: `❌ Deployment authentication failed.\n\nError: ${authResult.error || 'Unable to authenticate'}\n\nRecommendations:\n${(authResult.recommendations || ['Run: snow-flow auth login']).map(r => `• ${r}`).join('\n')}\n\nNote: Deployment requires valid OAuth tokens with write permissions.`,
3490
3567
  },
3491
3568
  ],
3492
3569
  };
@@ -3653,13 +3730,13 @@ Use \`snow_widget_test\` to run automated tests with different scenarios.`,
3653
3730
  async testWidget(args) {
3654
3731
  try {
3655
3732
  // Check authentication first
3656
- const isAuth = await this.oauth.isAuthenticated();
3657
- if (!isAuth) {
3733
+ const authResult = await this.deploymentAuthManager.ensureDeploymentAuth();
3734
+ if (!authResult.isValid) {
3658
3735
  return {
3659
3736
  content: [
3660
3737
  {
3661
3738
  type: 'text',
3662
- text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
3739
+ text: `❌ Deployment authentication failed.\n\nError: ${authResult.error || 'Unable to authenticate'}\n\nRecommendations:\n${(authResult.recommendations || ['Run: snow-flow auth login']).map(r => `• ${r}`).join('\n')}\n\nNote: Deployment requires valid OAuth tokens with write permissions.`,
3663
3740
  },
3664
3741
  ],
3665
3742
  };
@@ -4689,21 +4766,21 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
4689
4766
  };
4690
4767
  case 'script':
4691
4768
  case 'script_include':
4692
- const scriptResult = await this.client.createRecord('sys_script_include', config);
4769
+ const scriptResult = await this.createRecordWithRetry('sys_script_include', config);
4693
4770
  return {
4694
4771
  success: scriptResult.success,
4695
4772
  sys_id: scriptResult.data?.sys_id,
4696
4773
  message: scriptResult.success ? 'Script deployed' : scriptResult.error
4697
4774
  };
4698
4775
  case 'business_rule':
4699
- const ruleResult = await this.client.createRecord('sys_script', config);
4776
+ const ruleResult = await this.createRecordWithRetry('sys_script', config);
4700
4777
  return {
4701
4778
  success: ruleResult.success,
4702
4779
  sys_id: ruleResult.data?.sys_id,
4703
4780
  message: ruleResult.success ? 'Business rule deployed' : ruleResult.error
4704
4781
  };
4705
4782
  case 'table':
4706
- const tableResult = await this.client.createRecord('sys_db_object', config);
4783
+ const tableResult = await this.createRecordWithRetry('sys_db_object', config);
4707
4784
  return {
4708
4785
  success: tableResult.success,
4709
4786
  sys_id: tableResult.data?.sys_id,
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Deployment Authentication Fix
3
+ * Ensures OAuth tokens are properly refreshed and validated before deployment operations
4
+ */
5
+ export interface AuthValidationResult {
6
+ isValid: boolean;
7
+ hasWriteScope: boolean;
8
+ tokenAge?: number;
9
+ expiresIn?: number;
10
+ error?: string;
11
+ recommendations?: string[];
12
+ }
13
+ export declare class DeploymentAuthManager {
14
+ private oauth;
15
+ private lastTokenRefresh;
16
+ constructor();
17
+ /**
18
+ * Ensure we have valid tokens for deployment operations
19
+ * This is MORE strict than regular authentication
20
+ */
21
+ ensureDeploymentAuth(): Promise<AuthValidationResult>;
22
+ /**
23
+ * Validate token by making a simple API call
24
+ */
25
+ private validateTokenWithAPI;
26
+ /**
27
+ * Check if token has write permissions by attempting to read widget table
28
+ */
29
+ private checkWritePermissions;
30
+ /**
31
+ * Force a fresh token for deployment operations
32
+ */
33
+ forceTokenRefresh(): Promise<{
34
+ success: boolean;
35
+ accessToken?: string;
36
+ error?: string;
37
+ }>;
38
+ /**
39
+ * Get fresh access token for deployment
40
+ */
41
+ getDeploymentToken(): Promise<string | null>;
42
+ }
43
+ //# sourceMappingURL=deployment-auth-fix.d.ts.map
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ /**
3
+ * Deployment Authentication Fix
4
+ * Ensures OAuth tokens are properly refreshed and validated before deployment operations
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.DeploymentAuthManager = void 0;
8
+ const snow_oauth_js_1 = require("./snow-oauth.js");
9
+ const unified_auth_store_js_1 = require("./unified-auth-store.js");
10
+ const logger_js_1 = require("./logger.js");
11
+ const logger = new logger_js_1.Logger('DeploymentAuthFix');
12
+ class DeploymentAuthManager {
13
+ constructor() {
14
+ this.lastTokenRefresh = 0;
15
+ this.oauth = new snow_oauth_js_1.ServiceNowOAuth();
16
+ }
17
+ /**
18
+ * Ensure we have valid tokens for deployment operations
19
+ * This is MORE strict than regular authentication
20
+ */
21
+ async ensureDeploymentAuth() {
22
+ try {
23
+ logger.info('🔐 Validating deployment authentication...');
24
+ // Step 1: Check if we have any auth at all
25
+ const isAuth = await this.oauth.isAuthenticated();
26
+ if (!isAuth) {
27
+ return {
28
+ isValid: false,
29
+ hasWriteScope: false,
30
+ error: 'Not authenticated',
31
+ recommendations: [
32
+ 'Run: snow-flow auth login',
33
+ 'Ensure OAuth app has write/admin scopes'
34
+ ]
35
+ };
36
+ }
37
+ // Step 2: Get current tokens
38
+ let tokens = await this.oauth.loadTokens();
39
+ if (!tokens || !tokens.accessToken) {
40
+ // Try unified auth store as fallback
41
+ tokens = await unified_auth_store_js_1.unifiedAuthStore.getTokens();
42
+ if (!tokens || !tokens.accessToken) {
43
+ return {
44
+ isValid: false,
45
+ hasWriteScope: false,
46
+ error: 'No access token found',
47
+ recommendations: [
48
+ 'Run: snow-flow auth login',
49
+ 'Check .env configuration'
50
+ ]
51
+ };
52
+ }
53
+ }
54
+ // Step 3: Check token age and expiry
55
+ const now = Date.now();
56
+ const tokenAge = tokens.issuedAt ? now - tokens.issuedAt : null;
57
+ const expiresIn = tokens.expiresAt ? tokens.expiresAt - now : null;
58
+ // If token expires in less than 5 minutes, refresh it
59
+ if (expiresIn && expiresIn < 300000) { // 5 minutes
60
+ logger.info('⚠️ Token expires soon, refreshing...');
61
+ try {
62
+ const refreshResult = await this.oauth.refreshAccessToken();
63
+ if (refreshResult.success && refreshResult.accessToken) {
64
+ logger.info('✅ Token refreshed successfully');
65
+ tokens = {
66
+ ...tokens,
67
+ accessToken: refreshResult.accessToken,
68
+ expiresAt: refreshResult.expiresIn ? now + refreshResult.expiresIn * 1000 : undefined,
69
+ issuedAt: now
70
+ };
71
+ // Update unified auth store
72
+ await unified_auth_store_js_1.unifiedAuthStore.saveTokens(tokens);
73
+ }
74
+ else {
75
+ logger.warn('Failed to refresh token:', refreshResult.error);
76
+ }
77
+ }
78
+ catch (error) {
79
+ logger.error('Token refresh error:', error);
80
+ }
81
+ }
82
+ // Step 4: Validate token by making a test API call
83
+ try {
84
+ const testResponse = await this.validateTokenWithAPI(tokens.accessToken);
85
+ if (!testResponse.success) {
86
+ // Token is invalid, try to refresh
87
+ logger.warn('Token validation failed, attempting refresh...');
88
+ const refreshResult = await this.oauth.refreshAccessToken();
89
+ if (refreshResult.success && refreshResult.accessToken) {
90
+ tokens.accessToken = refreshResult.accessToken;
91
+ await unified_auth_store_js_1.unifiedAuthStore.saveTokens(tokens);
92
+ // Validate again
93
+ const retryResponse = await this.validateTokenWithAPI(tokens.accessToken);
94
+ if (!retryResponse.success) {
95
+ return {
96
+ isValid: false,
97
+ hasWriteScope: false,
98
+ error: 'Token validation failed after refresh',
99
+ recommendations: [
100
+ 'Run: snow-flow auth login',
101
+ 'Check ServiceNow OAuth app configuration',
102
+ 'Verify API access is enabled for your user'
103
+ ]
104
+ };
105
+ }
106
+ }
107
+ else {
108
+ return {
109
+ isValid: false,
110
+ hasWriteScope: false,
111
+ error: 'Failed to refresh invalid token',
112
+ recommendations: [
113
+ 'Run: snow-flow auth login',
114
+ 'Your session may have expired'
115
+ ]
116
+ };
117
+ }
118
+ }
119
+ }
120
+ catch (error) {
121
+ logger.error('Token validation error:', error);
122
+ return {
123
+ isValid: false,
124
+ hasWriteScope: false,
125
+ error: `Token validation failed: ${error.message}`,
126
+ recommendations: [
127
+ 'Check network connectivity',
128
+ 'Verify ServiceNow instance is accessible',
129
+ 'Run: snow-flow auth login'
130
+ ]
131
+ };
132
+ }
133
+ // Step 5: Check for write permissions
134
+ const hasWriteScope = await this.checkWritePermissions(tokens.accessToken);
135
+ return {
136
+ isValid: true,
137
+ hasWriteScope,
138
+ tokenAge: tokenAge ? Math.round(tokenAge / 1000) : undefined,
139
+ expiresIn: expiresIn ? Math.round(expiresIn / 1000) : undefined,
140
+ recommendations: hasWriteScope ? [] : [
141
+ 'OAuth token is valid but may lack write permissions',
142
+ 'Check OAuth app scopes in ServiceNow',
143
+ 'Ensure user has sp_admin or admin role'
144
+ ]
145
+ };
146
+ }
147
+ catch (error) {
148
+ logger.error('Deployment auth validation error:', error);
149
+ return {
150
+ isValid: false,
151
+ hasWriteScope: false,
152
+ error: error.message,
153
+ recommendations: [
154
+ 'Unexpected error during authentication',
155
+ 'Run: snow-flow auth login',
156
+ 'Check error logs for details'
157
+ ]
158
+ };
159
+ }
160
+ }
161
+ /**
162
+ * Validate token by making a simple API call
163
+ */
164
+ async validateTokenWithAPI(accessToken) {
165
+ try {
166
+ const axios = require('axios');
167
+ const credentials = await this.oauth.loadCredentials();
168
+ if (!credentials?.instance) {
169
+ return { success: false, error: 'No instance configured' };
170
+ }
171
+ const response = await axios.get(`https://${credentials.instance}/api/now/table/sys_user?sysparm_limit=1`, {
172
+ headers: {
173
+ 'Authorization': `Bearer ${accessToken}`,
174
+ 'Accept': 'application/json'
175
+ },
176
+ timeout: 10000
177
+ });
178
+ return { success: response.status === 200 };
179
+ }
180
+ catch (error) {
181
+ if (error.response?.status === 401) {
182
+ return { success: false, error: 'Token is invalid or expired' };
183
+ }
184
+ return { success: false, error: error.message };
185
+ }
186
+ }
187
+ /**
188
+ * Check if token has write permissions by attempting to read widget table
189
+ */
190
+ async checkWritePermissions(accessToken) {
191
+ try {
192
+ const axios = require('axios');
193
+ const credentials = await this.oauth.loadCredentials();
194
+ if (!credentials?.instance) {
195
+ return false;
196
+ }
197
+ // Try to read from sp_widget table (requires portal access)
198
+ const response = await axios.get(`https://${credentials.instance}/api/now/table/sp_widget?sysparm_limit=1`, {
199
+ headers: {
200
+ 'Authorization': `Bearer ${accessToken}`,
201
+ 'Accept': 'application/json'
202
+ },
203
+ timeout: 10000
204
+ });
205
+ // If we can read widgets, we likely have portal access
206
+ return response.status === 200;
207
+ }
208
+ catch (error) {
209
+ // 403 means we don't have permission
210
+ if (error.response?.status === 403) {
211
+ logger.warn('No write permissions for Service Portal');
212
+ return false;
213
+ }
214
+ // Other errors we'll assume no permission
215
+ return false;
216
+ }
217
+ }
218
+ /**
219
+ * Force a fresh token for deployment operations
220
+ */
221
+ async forceTokenRefresh() {
222
+ try {
223
+ logger.info('🔄 Forcing token refresh for deployment...');
224
+ const refreshResult = await this.oauth.refreshAccessToken();
225
+ if (refreshResult.success && refreshResult.accessToken) {
226
+ // Store in unified auth store
227
+ const tokens = await this.oauth.loadTokens();
228
+ if (tokens) {
229
+ tokens.accessToken = refreshResult.accessToken;
230
+ tokens.expiresAt = refreshResult.expiresIn ? Date.now() + refreshResult.expiresIn * 1000 : undefined;
231
+ tokens.issuedAt = Date.now();
232
+ await unified_auth_store_js_1.unifiedAuthStore.saveTokens(tokens);
233
+ }
234
+ logger.info('✅ Token refreshed successfully');
235
+ return {
236
+ success: true,
237
+ accessToken: refreshResult.accessToken
238
+ };
239
+ }
240
+ return {
241
+ success: false,
242
+ error: refreshResult.error || 'Failed to refresh token'
243
+ };
244
+ }
245
+ catch (error) {
246
+ logger.error('Force refresh error:', error);
247
+ return {
248
+ success: false,
249
+ error: error.message
250
+ };
251
+ }
252
+ }
253
+ /**
254
+ * Get fresh access token for deployment
255
+ */
256
+ async getDeploymentToken() {
257
+ // First ensure we have valid auth
258
+ const authResult = await this.ensureDeploymentAuth();
259
+ if (!authResult.isValid) {
260
+ logger.error('Invalid authentication for deployment:', authResult.error);
261
+ throw new Error(authResult.error || 'Authentication failed');
262
+ }
263
+ if (!authResult.hasWriteScope) {
264
+ logger.warn('⚠️ Token may lack write permissions, deployment might fail');
265
+ }
266
+ // Get the token
267
+ const tokens = await this.oauth.loadTokens();
268
+ return tokens?.accessToken || null;
269
+ }
270
+ }
271
+ exports.DeploymentAuthManager = DeploymentAuthManager;
272
+ //# sourceMappingURL=deployment-auth-fix.js.map
@@ -0,0 +1,70 @@
1
+ /**
2
+ * MCP Process Manager - SAFE VERSION
3
+ * Emergency fix for memory crash issues
4
+ * Implements graceful shutdown and memory-safe cleanup
5
+ */
6
+ export declare class MCPProcessManager {
7
+ private static instance;
8
+ private readonly MAX_MCP_SERVERS;
9
+ private readonly MAX_MEMORY_MB;
10
+ private readonly CLEANUP_ENABLED;
11
+ private readonly CLEANUP_INTERVAL;
12
+ private cleanupTimer?;
13
+ private isCleaningUp;
14
+ private constructor();
15
+ static getInstance(): MCPProcessManager;
16
+ /**
17
+ * Check if we can spawn a new MCP server
18
+ */
19
+ canSpawnServer(): boolean;
20
+ /**
21
+ * Get current MCP system status - SAFER VERSION
22
+ */
23
+ getSystemStatus(): {
24
+ processCount: number;
25
+ memoryUsageMB: number;
26
+ processes: Array<{
27
+ pid: number;
28
+ memory: number;
29
+ name: string;
30
+ }>;
31
+ };
32
+ /**
33
+ * Gracefully shutdown a process with timeout
34
+ */
35
+ private gracefulKill;
36
+ /**
37
+ * Kill duplicate MCP servers - SAFER VERSION
38
+ */
39
+ killDuplicates(): Promise<void>;
40
+ /**
41
+ * Emergency cleanup - only for critical situations
42
+ */
43
+ emergencyCleanup(): Promise<void>;
44
+ /**
45
+ * Safe cleanup - only when absolutely necessary
46
+ */
47
+ cleanup(): Promise<void>;
48
+ /**
49
+ * Start periodic cleanup - MUCH SAFER
50
+ */
51
+ private startPeriodicCleanup;
52
+ /**
53
+ * Stop periodic cleanup
54
+ */
55
+ stopPeriodicCleanup(): void;
56
+ /**
57
+ * Kill all MCP servers - USE WITH CAUTION
58
+ */
59
+ killAll(): Promise<void>;
60
+ /**
61
+ * Get resource usage summary
62
+ */
63
+ getResourceSummary(): string;
64
+ /**
65
+ * Get health status
66
+ */
67
+ getHealthStatus(): 'healthy' | 'warning' | 'critical';
68
+ }
69
+ export declare const mcpProcessManager: MCPProcessManager;
70
+ //# sourceMappingURL=mcp-process-manager-safe.d.ts.map