snow-flow 1.1.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.
Files changed (240) hide show
  1. package/.env.example +49 -0
  2. package/.mcp.json +106 -0
  3. package/.mcp.json.template +106 -0
  4. package/LICENSE +21 -0
  5. package/README.md +236 -0
  6. package/bin/snow-flow +4 -0
  7. package/bin/snow-flow.js +3 -0
  8. package/claude-flow +79 -0
  9. package/claude-flow.bat +18 -0
  10. package/claude-flow.config.json +20 -0
  11. package/claude-flow.ps1 +24 -0
  12. package/dist/agents/app-creator.agent.d.ts +55 -0
  13. package/dist/agents/app-creator.agent.d.ts.map +1 -0
  14. package/dist/agents/app-creator.agent.js +1292 -0
  15. package/dist/agents/app-creator.agent.js.map +1 -0
  16. package/dist/agents/base-snow-agent.d.ts +63 -0
  17. package/dist/agents/base-snow-agent.d.ts.map +1 -0
  18. package/dist/agents/base-snow-agent.js +296 -0
  19. package/dist/agents/base-snow-agent.js.map +1 -0
  20. package/dist/agents/script-generator.agent.d.ts +32 -0
  21. package/dist/agents/script-generator.agent.d.ts.map +1 -0
  22. package/dist/agents/script-generator.agent.js +772 -0
  23. package/dist/agents/script-generator.agent.js.map +1 -0
  24. package/dist/agents/ui-builder.agent.d.ts +50 -0
  25. package/dist/agents/ui-builder.agent.d.ts.map +1 -0
  26. package/dist/agents/ui-builder.agent.js +1539 -0
  27. package/dist/agents/ui-builder.agent.js.map +1 -0
  28. package/dist/agents/widget-builder.agent.d.ts +32 -0
  29. package/dist/agents/widget-builder.agent.d.ts.map +1 -0
  30. package/dist/agents/widget-builder.agent.js +439 -0
  31. package/dist/agents/widget-builder.agent.js.map +1 -0
  32. package/dist/agents/workflow-designer.agent.d.ts +31 -0
  33. package/dist/agents/workflow-designer.agent.d.ts.map +1 -0
  34. package/dist/agents/workflow-designer.agent.js +583 -0
  35. package/dist/agents/workflow-designer.agent.js.map +1 -0
  36. package/dist/api/error-handling.d.ts +214 -0
  37. package/dist/api/error-handling.d.ts.map +1 -0
  38. package/dist/api/error-handling.js +594 -0
  39. package/dist/api/error-handling.js.map +1 -0
  40. package/dist/api/flow-designer-api.d.ts +167 -0
  41. package/dist/api/flow-designer-api.d.ts.map +1 -0
  42. package/dist/api/flow-designer-api.js +555 -0
  43. package/dist/api/flow-designer-api.js.map +1 -0
  44. package/dist/api/natural-language-mapper.d.ts +126 -0
  45. package/dist/api/natural-language-mapper.d.ts.map +1 -0
  46. package/dist/api/natural-language-mapper.js +498 -0
  47. package/dist/api/natural-language-mapper.js.map +1 -0
  48. package/dist/api/performance-optimizer.d.ts +240 -0
  49. package/dist/api/performance-optimizer.d.ts.map +1 -0
  50. package/dist/api/performance-optimizer.js +701 -0
  51. package/dist/api/performance-optimizer.js.map +1 -0
  52. package/dist/api/transaction-manager.d.ts +189 -0
  53. package/dist/api/transaction-manager.d.ts.map +1 -0
  54. package/dist/api/transaction-manager.js +576 -0
  55. package/dist/api/transaction-manager.js.map +1 -0
  56. package/dist/cli/deploy-artifact.d.ts +7 -0
  57. package/dist/cli/deploy-artifact.d.ts.map +1 -0
  58. package/dist/cli/deploy-artifact.js +279 -0
  59. package/dist/cli/deploy-artifact.js.map +1 -0
  60. package/dist/cli.d.ts +6 -0
  61. package/dist/cli.d.ts.map +1 -0
  62. package/dist/cli.js +2057 -0
  63. package/dist/cli.js.map +1 -0
  64. package/dist/index.d.ts +10 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +35 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/managers/scope-manager.d.ts +75 -0
  69. package/dist/managers/scope-manager.d.ts.map +1 -0
  70. package/dist/managers/scope-manager.js +448 -0
  71. package/dist/managers/scope-manager.js.map +1 -0
  72. package/dist/mcp/mcp-wrapper.d.ts +8 -0
  73. package/dist/mcp/mcp-wrapper.d.ts.map +1 -0
  74. package/dist/mcp/mcp-wrapper.js +77 -0
  75. package/dist/mcp/mcp-wrapper.js.map +1 -0
  76. package/dist/mcp/servicenow-automation-mcp.d.ts +8 -0
  77. package/dist/mcp/servicenow-automation-mcp.d.ts.map +1 -0
  78. package/dist/mcp/servicenow-automation-mcp.js +683 -0
  79. package/dist/mcp/servicenow-automation-mcp.js.map +1 -0
  80. package/dist/mcp/servicenow-deployment-mcp.d.ts +7 -0
  81. package/dist/mcp/servicenow-deployment-mcp.d.ts.map +1 -0
  82. package/dist/mcp/servicenow-deployment-mcp.js +972 -0
  83. package/dist/mcp/servicenow-deployment-mcp.js.map +1 -0
  84. package/dist/mcp/servicenow-flow-composer-mcp.d.ts +7 -0
  85. package/dist/mcp/servicenow-flow-composer-mcp.d.ts.map +1 -0
  86. package/dist/mcp/servicenow-flow-composer-mcp.js +1121 -0
  87. package/dist/mcp/servicenow-flow-composer-mcp.js.map +1 -0
  88. package/dist/mcp/servicenow-graph-memory-mcp.d.ts +7 -0
  89. package/dist/mcp/servicenow-graph-memory-mcp.d.ts.map +1 -0
  90. package/dist/mcp/servicenow-graph-memory-mcp.js +703 -0
  91. package/dist/mcp/servicenow-graph-memory-mcp.js.map +1 -0
  92. package/dist/mcp/servicenow-integration-mcp.d.ts +8 -0
  93. package/dist/mcp/servicenow-integration-mcp.d.ts.map +1 -0
  94. package/dist/mcp/servicenow-integration-mcp.js +689 -0
  95. package/dist/mcp/servicenow-integration-mcp.js.map +1 -0
  96. package/dist/mcp/servicenow-intelligent-mcp.d.ts +7 -0
  97. package/dist/mcp/servicenow-intelligent-mcp.d.ts.map +1 -0
  98. package/dist/mcp/servicenow-intelligent-mcp.js +1138 -0
  99. package/dist/mcp/servicenow-intelligent-mcp.js.map +1 -0
  100. package/dist/mcp/servicenow-mcp-server.d.ts +37 -0
  101. package/dist/mcp/servicenow-mcp-server.d.ts.map +1 -0
  102. package/dist/mcp/servicenow-mcp-server.js +648 -0
  103. package/dist/mcp/servicenow-mcp-server.js.map +1 -0
  104. package/dist/mcp/servicenow-operations-mcp.d.ts +15 -0
  105. package/dist/mcp/servicenow-operations-mcp.d.ts.map +1 -0
  106. package/dist/mcp/servicenow-operations-mcp.js +1287 -0
  107. package/dist/mcp/servicenow-operations-mcp.js.map +1 -0
  108. package/dist/mcp/servicenow-platform-development-mcp.d.ts +8 -0
  109. package/dist/mcp/servicenow-platform-development-mcp.d.ts.map +1 -0
  110. package/dist/mcp/servicenow-platform-development-mcp.js +557 -0
  111. package/dist/mcp/servicenow-platform-development-mcp.js.map +1 -0
  112. package/dist/mcp/servicenow-progressive-indexer.d.ts +79 -0
  113. package/dist/mcp/servicenow-progressive-indexer.d.ts.map +1 -0
  114. package/dist/mcp/servicenow-progressive-indexer.js +320 -0
  115. package/dist/mcp/servicenow-progressive-indexer.js.map +1 -0
  116. package/dist/mcp/servicenow-reporting-analytics-mcp.d.ts +8 -0
  117. package/dist/mcp/servicenow-reporting-analytics-mcp.d.ts.map +1 -0
  118. package/dist/mcp/servicenow-reporting-analytics-mcp.js +888 -0
  119. package/dist/mcp/servicenow-reporting-analytics-mcp.js.map +1 -0
  120. package/dist/mcp/servicenow-security-compliance-mcp.d.ts +8 -0
  121. package/dist/mcp/servicenow-security-compliance-mcp.d.ts.map +1 -0
  122. package/dist/mcp/servicenow-security-compliance-mcp.js +812 -0
  123. package/dist/mcp/servicenow-security-compliance-mcp.js.map +1 -0
  124. package/dist/mcp/servicenow-update-set-mcp.d.ts +7 -0
  125. package/dist/mcp/servicenow-update-set-mcp.d.ts.map +1 -0
  126. package/dist/mcp/servicenow-update-set-mcp.js +599 -0
  127. package/dist/mcp/servicenow-update-set-mcp.js.map +1 -0
  128. package/dist/mcp/start-all-mcp-servers.d.ts +6 -0
  129. package/dist/mcp/start-all-mcp-servers.d.ts.map +1 -0
  130. package/dist/mcp/start-all-mcp-servers.js +65 -0
  131. package/dist/mcp/start-all-mcp-servers.js.map +1 -0
  132. package/dist/mcp/start-servicenow-mcp.d.ts +7 -0
  133. package/dist/mcp/start-servicenow-mcp.d.ts.map +1 -0
  134. package/dist/mcp/start-servicenow-mcp.js +64 -0
  135. package/dist/mcp/start-servicenow-mcp.js.map +1 -0
  136. package/dist/mcp/test-simple-mcp.d.ts +6 -0
  137. package/dist/mcp/test-simple-mcp.d.ts.map +1 -0
  138. package/dist/mcp/test-simple-mcp.js +64 -0
  139. package/dist/mcp/test-simple-mcp.js.map +1 -0
  140. package/dist/orchestrator/flow-composer.d.ts +269 -0
  141. package/dist/orchestrator/flow-composer.d.ts.map +1 -0
  142. package/dist/orchestrator/flow-composer.js +2221 -0
  143. package/dist/orchestrator/flow-composer.js.map +1 -0
  144. package/dist/orchestrator/flow-pattern-templates.d.ts +260 -0
  145. package/dist/orchestrator/flow-pattern-templates.d.ts.map +1 -0
  146. package/dist/orchestrator/flow-pattern-templates.js +906 -0
  147. package/dist/orchestrator/flow-pattern-templates.js.map +1 -0
  148. package/dist/orchestrator/flow-subflow-decision-engine.d.ts +202 -0
  149. package/dist/orchestrator/flow-subflow-decision-engine.d.ts.map +1 -0
  150. package/dist/orchestrator/flow-subflow-decision-engine.js +769 -0
  151. package/dist/orchestrator/flow-subflow-decision-engine.js.map +1 -0
  152. package/dist/orchestrator/flow-validation-engine.d.ts +145 -0
  153. package/dist/orchestrator/flow-validation-engine.d.ts.map +1 -0
  154. package/dist/orchestrator/flow-validation-engine.js +663 -0
  155. package/dist/orchestrator/flow-validation-engine.js.map +1 -0
  156. package/dist/orchestrator/snow-orchestrator.d.ts +49 -0
  157. package/dist/orchestrator/snow-orchestrator.d.ts.map +1 -0
  158. package/dist/orchestrator/snow-orchestrator.js +235 -0
  159. package/dist/orchestrator/snow-orchestrator.js.map +1 -0
  160. package/dist/orchestrator/subflow-creation-handler.d.ts +230 -0
  161. package/dist/orchestrator/subflow-creation-handler.d.ts.map +1 -0
  162. package/dist/orchestrator/subflow-creation-handler.js +791 -0
  163. package/dist/orchestrator/subflow-creation-handler.js.map +1 -0
  164. package/dist/strategies/global-scope-strategy.d.ts +123 -0
  165. package/dist/strategies/global-scope-strategy.d.ts.map +1 -0
  166. package/dist/strategies/global-scope-strategy.js +585 -0
  167. package/dist/strategies/global-scope-strategy.js.map +1 -0
  168. package/dist/types/index.d.ts +138 -0
  169. package/dist/types/index.d.ts.map +1 -0
  170. package/dist/types/index.js +4 -0
  171. package/dist/types/index.js.map +1 -0
  172. package/dist/types/servicenow.types.d.ts +260 -0
  173. package/dist/types/servicenow.types.d.ts.map +1 -0
  174. package/dist/types/servicenow.types.js +3 -0
  175. package/dist/types/servicenow.types.js.map +1 -0
  176. package/dist/types/snow-flow.types.d.ts +114 -0
  177. package/dist/types/snow-flow.types.d.ts.map +1 -0
  178. package/dist/types/snow-flow.types.js +3 -0
  179. package/dist/types/snow-flow.types.js.map +1 -0
  180. package/dist/utils/action-type-cache.d.ts +66 -0
  181. package/dist/utils/action-type-cache.d.ts.map +1 -0
  182. package/dist/utils/action-type-cache.js +237 -0
  183. package/dist/utils/action-type-cache.js.map +1 -0
  184. package/dist/utils/agent-detector.d.ts +35 -0
  185. package/dist/utils/agent-detector.d.ts.map +1 -0
  186. package/dist/utils/agent-detector.js +353 -0
  187. package/dist/utils/agent-detector.js.map +1 -0
  188. package/dist/utils/flow-api-discovery.d.ts +151 -0
  189. package/dist/utils/flow-api-discovery.d.ts.map +1 -0
  190. package/dist/utils/flow-api-discovery.js +440 -0
  191. package/dist/utils/flow-api-discovery.js.map +1 -0
  192. package/dist/utils/flow-xml-generator.d.ts +41 -0
  193. package/dist/utils/flow-xml-generator.d.ts.map +1 -0
  194. package/dist/utils/flow-xml-generator.js +258 -0
  195. package/dist/utils/flow-xml-generator.js.map +1 -0
  196. package/dist/utils/logger.d.ts +13 -0
  197. package/dist/utils/logger.d.ts.map +1 -0
  198. package/dist/utils/logger.js +51 -0
  199. package/dist/utils/logger.js.map +1 -0
  200. package/dist/utils/mcp-auth-middleware.d.ts +58 -0
  201. package/dist/utils/mcp-auth-middleware.d.ts.map +1 -0
  202. package/dist/utils/mcp-auth-middleware.js +227 -0
  203. package/dist/utils/mcp-auth-middleware.js.map +1 -0
  204. package/dist/utils/mcp-config-manager.d.ts +126 -0
  205. package/dist/utils/mcp-config-manager.d.ts.map +1 -0
  206. package/dist/utils/mcp-config-manager.js +209 -0
  207. package/dist/utils/mcp-config-manager.js.map +1 -0
  208. package/dist/utils/mcp-server-manager.d.ts +91 -0
  209. package/dist/utils/mcp-server-manager.d.ts.map +1 -0
  210. package/dist/utils/mcp-server-manager.js +338 -0
  211. package/dist/utils/mcp-server-manager.js.map +1 -0
  212. package/dist/utils/scope-utils.d.ts +72 -0
  213. package/dist/utils/scope-utils.d.ts.map +1 -0
  214. package/dist/utils/scope-utils.js +386 -0
  215. package/dist/utils/scope-utils.js.map +1 -0
  216. package/dist/utils/servicenow-client.d.ts +233 -0
  217. package/dist/utils/servicenow-client.d.ts.map +1 -0
  218. package/dist/utils/servicenow-client.js +1465 -0
  219. package/dist/utils/servicenow-client.js.map +1 -0
  220. package/dist/utils/snow-oauth-old.d.ts +65 -0
  221. package/dist/utils/snow-oauth-old.d.ts.map +1 -0
  222. package/dist/utils/snow-oauth-old.js +345 -0
  223. package/dist/utils/snow-oauth-old.js.map +1 -0
  224. package/dist/utils/snow-oauth.d.ts +85 -0
  225. package/dist/utils/snow-oauth.d.ts.map +1 -0
  226. package/dist/utils/snow-oauth.js +512 -0
  227. package/dist/utils/snow-oauth.js.map +1 -0
  228. package/dist/utils/template-engine.d.ts +76 -0
  229. package/dist/utils/template-engine.d.ts.map +1 -0
  230. package/dist/utils/template-engine.js +391 -0
  231. package/dist/utils/template-engine.js.map +1 -0
  232. package/dist/version.d.ts +35 -0
  233. package/dist/version.d.ts.map +1 -0
  234. package/dist/version.js +72 -0
  235. package/dist/version.js.map +1 -0
  236. package/mcp-wrapper.sh +12 -0
  237. package/package.json +77 -0
  238. package/reports/swarm-auto-centralized-1752649029776.json +13 -0
  239. package/scripts/postinstall.js +30 -0
  240. package/scripts/setup-mcp.js +89 -0
@@ -0,0 +1,1465 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * ServiceNow API Client
5
+ * Handles all ServiceNow API operations with OAuth authentication
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.ServiceNowClient = void 0;
12
+ const axios_1 = __importDefault(require("axios"));
13
+ const snow_oauth_1 = require("./snow-oauth");
14
+ const action_type_cache_1 = require("./action-type-cache");
15
+ class ServiceNowClient {
16
+ constructor() {
17
+ this.credentials = null;
18
+ this.oauth = new snow_oauth_1.ServiceNowOAuth();
19
+ this.client = axios_1.default.create({
20
+ timeout: 30000,
21
+ headers: {
22
+ 'Content-Type': 'application/json',
23
+ 'Accept': 'application/json'
24
+ }
25
+ });
26
+ this.actionTypeCache = new action_type_cache_1.ActionTypeCache(this);
27
+ // Add request interceptor for authentication
28
+ this.client.interceptors.request.use(async (config) => {
29
+ await this.ensureAuthenticated();
30
+ if (this.credentials?.accessToken) {
31
+ config.headers['Authorization'] = `Bearer ${this.credentials.accessToken}`;
32
+ }
33
+ return config;
34
+ });
35
+ // Add response interceptor for error handling
36
+ this.client.interceptors.response.use((response) => response, async (error) => {
37
+ if (error.response?.status === 401) {
38
+ console.log('🔄 Access token expired, refreshing...');
39
+ const refreshResult = await this.oauth.refreshAccessToken();
40
+ if (refreshResult.success && refreshResult.accessToken) {
41
+ // Update the authorization header with new token
42
+ error.config.headers['Authorization'] = `Bearer ${refreshResult.accessToken}`;
43
+ // Retry the original request
44
+ return this.client.request(error.config);
45
+ }
46
+ }
47
+ return Promise.reject(error);
48
+ });
49
+ }
50
+ /**
51
+ * Ensure we have valid authentication
52
+ */
53
+ async ensureAuthenticated() {
54
+ console.log('🔐 Checking authentication...');
55
+ if (!this.credentials) {
56
+ console.log('🔍 Loading credentials...');
57
+ this.credentials = await this.oauth.loadCredentials();
58
+ }
59
+ if (!this.credentials) {
60
+ console.error('❌ No credentials found');
61
+ throw new Error('No ServiceNow credentials found. Please run "snow-flow auth login" first.');
62
+ }
63
+ console.log('✅ Credentials loaded, checking if authenticated...');
64
+ const isAuth = await this.oauth.isAuthenticated();
65
+ if (!isAuth) {
66
+ console.error('❌ Authentication expired');
67
+ throw new Error('ServiceNow authentication expired. Please run "snow-flow auth login" again.');
68
+ }
69
+ console.log('✅ Authentication successful');
70
+ }
71
+ /**
72
+ * Get base URL for ServiceNow instance
73
+ */
74
+ getBaseUrl() {
75
+ if (!this.credentials) {
76
+ throw new Error('No credentials available');
77
+ }
78
+ return `https://${this.credentials.instance}`;
79
+ }
80
+ /**
81
+ * Sanitize a flow name for use as internal_name
82
+ */
83
+ sanitizeInternalName(name) {
84
+ return name
85
+ .toLowerCase()
86
+ .replace(/[^a-z0-9_\s]/g, '') // Remove special characters except underscores and spaces
87
+ .replace(/\s+/g, '_') // Replace spaces with underscores
88
+ .replace(/_+/g, '_') // Replace multiple underscores with single
89
+ .replace(/^_|_$/g, '') // Remove leading/trailing underscores
90
+ .substring(0, 80); // Limit length to 80 characters
91
+ }
92
+ /**
93
+ * Test connection to ServiceNow
94
+ */
95
+ async testConnection() {
96
+ try {
97
+ // Ensure we have credentials first
98
+ await this.ensureAuthenticated();
99
+ // Use the /api/now/v2/table/sys_user?sysparm_limit=1 endpoint to test
100
+ // This is a more reliable endpoint that should work on all instances
101
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/v2/table/sys_user?sysparm_limit=1&sysparm_query=user_name=admin`);
102
+ // If we can query users, we're connected
103
+ return {
104
+ success: true,
105
+ data: {
106
+ name: 'ServiceNow Instance',
107
+ user_name: 'Connected',
108
+ email: `${this.credentials?.instance}`,
109
+ message: 'Connection successful'
110
+ }
111
+ };
112
+ }
113
+ catch (error) {
114
+ // Try a simpler endpoint if the first one fails
115
+ try {
116
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_properties?sysparm_limit=1`);
117
+ return {
118
+ success: true,
119
+ data: {
120
+ name: 'ServiceNow Instance',
121
+ user_name: 'Connected',
122
+ email: `${this.credentials?.instance}`,
123
+ message: 'Connection successful (limited access)'
124
+ }
125
+ };
126
+ }
127
+ catch (secondError) {
128
+ return {
129
+ success: false,
130
+ error: error instanceof Error ? error.message : String(error)
131
+ };
132
+ }
133
+ }
134
+ }
135
+ /**
136
+ * Create a new ServiceNow widget
137
+ */
138
+ async createWidget(widget) {
139
+ try {
140
+ console.log('🎨 Creating ServiceNow widget...');
141
+ console.log(`📋 Widget Name: ${widget.name}`);
142
+ // Ensure we have credentials before making the API call
143
+ await this.ensureAuthenticated();
144
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sp_widget`, {
145
+ name: widget.name,
146
+ id: widget.id,
147
+ title: widget.title,
148
+ description: widget.description,
149
+ template: widget.template,
150
+ css: widget.css,
151
+ client_script: widget.client_script,
152
+ server_script: widget.server_script,
153
+ option_schema: widget.option_schema || '[]',
154
+ demo_data: widget.demo_data || '{}',
155
+ has_preview: widget.has_preview || false,
156
+ category: widget.category || 'custom'
157
+ });
158
+ console.log('✅ Widget created successfully!');
159
+ console.log(`🆔 Widget ID: ${response.data.result.sys_id}`);
160
+ return {
161
+ success: true,
162
+ data: response.data.result
163
+ };
164
+ }
165
+ catch (error) {
166
+ console.error('❌ Failed to create widget:', error);
167
+ return {
168
+ success: false,
169
+ error: error instanceof Error ? error.message : String(error)
170
+ };
171
+ }
172
+ }
173
+ /**
174
+ * Update an existing ServiceNow widget
175
+ */
176
+ async updateWidget(sysId, widget) {
177
+ try {
178
+ console.log(`🔄 Updating widget ${sysId}...`);
179
+ // Ensure we have credentials before making the API call
180
+ await this.ensureAuthenticated();
181
+ const response = await this.client.patch(`${this.getBaseUrl()}/api/now/table/sp_widget/${sysId}`, widget);
182
+ console.log('✅ Widget updated successfully!');
183
+ return {
184
+ success: true,
185
+ data: response.data.result
186
+ };
187
+ }
188
+ catch (error) {
189
+ console.error('❌ Failed to update widget:', error);
190
+ return {
191
+ success: false,
192
+ error: error instanceof Error ? error.message : String(error)
193
+ };
194
+ }
195
+ }
196
+ /**
197
+ * Get widget by ID
198
+ */
199
+ async getWidget(widgetId) {
200
+ try {
201
+ // Ensure we have credentials before making the API call
202
+ await this.ensureAuthenticated();
203
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sp_widget?sysparm_query=id=${widgetId}`);
204
+ if (response.data.result.length === 0) {
205
+ return {
206
+ success: false,
207
+ error: 'Widget not found'
208
+ };
209
+ }
210
+ return {
211
+ success: true,
212
+ data: response.data.result[0]
213
+ };
214
+ }
215
+ catch (error) {
216
+ return {
217
+ success: false,
218
+ error: error instanceof Error ? error.message : String(error)
219
+ };
220
+ }
221
+ }
222
+ /**
223
+ * Create a new ServiceNow workflow
224
+ */
225
+ async createWorkflow(workflow) {
226
+ try {
227
+ console.log('🔄 Creating ServiceNow workflow...');
228
+ console.log(`📋 Workflow Name: ${workflow.name}`);
229
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/wf_workflow`, {
230
+ name: workflow.name,
231
+ description: workflow.description,
232
+ active: workflow.active,
233
+ workflow_version: workflow.workflow_version,
234
+ table: workflow.table || '',
235
+ condition: workflow.condition || ''
236
+ });
237
+ console.log('✅ Workflow created successfully!');
238
+ console.log(`🆔 Workflow ID: ${response.data.result.sys_id}`);
239
+ return {
240
+ success: true,
241
+ data: response.data.result
242
+ };
243
+ }
244
+ catch (error) {
245
+ console.error('❌ Failed to create workflow:', error);
246
+ return {
247
+ success: false,
248
+ error: error instanceof Error ? error.message : String(error)
249
+ };
250
+ }
251
+ }
252
+ /**
253
+ * Create a new ServiceNow application
254
+ */
255
+ async createApplication(application) {
256
+ try {
257
+ console.log('🏗️ Creating ServiceNow application...');
258
+ console.log(`📋 Application Name: ${application.name}`);
259
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_app`, {
260
+ name: application.name,
261
+ scope: application.scope,
262
+ version: application.version,
263
+ short_description: application.short_description,
264
+ description: application.description,
265
+ vendor: application.vendor,
266
+ vendor_prefix: application.vendor_prefix,
267
+ template: application.template || '',
268
+ logo: application.logo || '',
269
+ active: application.active
270
+ });
271
+ console.log('✅ Application created successfully!');
272
+ console.log(`🆔 Application ID: ${response.data.result.sys_id}`);
273
+ return {
274
+ success: true,
275
+ data: response.data.result
276
+ };
277
+ }
278
+ catch (error) {
279
+ console.error('❌ Failed to create application:', error);
280
+ return {
281
+ success: false,
282
+ error: error instanceof Error ? error.message : String(error)
283
+ };
284
+ }
285
+ }
286
+ /**
287
+ * Execute a ServiceNow script
288
+ */
289
+ async executeScript(script) {
290
+ try {
291
+ console.log('⚡ Executing ServiceNow script...');
292
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_script_execution`, {
293
+ script: script,
294
+ type: 'server'
295
+ });
296
+ console.log('✅ Script executed successfully!');
297
+ return {
298
+ success: true,
299
+ data: response.data.result
300
+ };
301
+ }
302
+ catch (error) {
303
+ console.error('❌ Failed to execute script:', error);
304
+ return {
305
+ success: false,
306
+ error: error instanceof Error ? error.message : String(error)
307
+ };
308
+ }
309
+ }
310
+ /**
311
+ * Get all widgets
312
+ */
313
+ async getWidgets() {
314
+ try {
315
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sp_widget?sysparm_limit=100`);
316
+ return {
317
+ success: true,
318
+ result: response.data.result
319
+ };
320
+ }
321
+ catch (error) {
322
+ return {
323
+ success: false,
324
+ error: error instanceof Error ? error.message : String(error)
325
+ };
326
+ }
327
+ }
328
+ /**
329
+ * Get all workflows
330
+ */
331
+ async getWorkflows() {
332
+ try {
333
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/wf_workflow?sysparm_limit=100`);
334
+ return {
335
+ success: true,
336
+ result: response.data.result
337
+ };
338
+ }
339
+ catch (error) {
340
+ return {
341
+ success: false,
342
+ error: error instanceof Error ? error.message : String(error)
343
+ };
344
+ }
345
+ }
346
+ /**
347
+ * Get all applications
348
+ */
349
+ async getApplications() {
350
+ try {
351
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_app?sysparm_limit=100`);
352
+ return {
353
+ success: true,
354
+ result: response.data.result
355
+ };
356
+ }
357
+ catch (error) {
358
+ return {
359
+ success: false,
360
+ error: error instanceof Error ? error.message : String(error)
361
+ };
362
+ }
363
+ }
364
+ /**
365
+ * Get default flow structure from ServiceNow
366
+ */
367
+ async getFlowDefaults() {
368
+ try {
369
+ // Try to get an existing flow to see the structure
370
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_hub_flow?sysparm_limit=1&sysparm_fields=sys_class_name,type,status,access,source_ui,sys_domain,sys_domain_path`);
371
+ if (response.data.result && response.data.result.length > 0) {
372
+ const sample = response.data.result[0];
373
+ return {
374
+ sys_class_name: sample.sys_class_name || 'sys_hub_flow',
375
+ type: sample.type || 'flow',
376
+ status: sample.status || 'published',
377
+ access: sample.access || 'public',
378
+ source_ui: sample.source_ui || 'flow_designer',
379
+ sys_domain: sample.sys_domain || 'global',
380
+ sys_domain_path: sample.sys_domain_path || '/'
381
+ };
382
+ }
383
+ }
384
+ catch (error) {
385
+ console.log('Could not fetch flow defaults, using minimal defaults');
386
+ }
387
+ // Return minimal defaults if we can't get from ServiceNow
388
+ return {
389
+ sys_class_name: 'sys_hub_flow',
390
+ type: 'flow',
391
+ status: 'published',
392
+ access: 'public'
393
+ };
394
+ }
395
+ /**
396
+ * Get instance info
397
+ */
398
+ async getInstanceInfo() {
399
+ try {
400
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_properties?sysparm_query=name=instance.name`);
401
+ return {
402
+ success: true,
403
+ data: response.data.result[0]
404
+ };
405
+ }
406
+ catch (error) {
407
+ return {
408
+ success: false,
409
+ error: error instanceof Error ? error.message : String(error)
410
+ };
411
+ }
412
+ }
413
+ /**
414
+ * Get a specific record by sys_id
415
+ */
416
+ async getRecord(table, sys_id) {
417
+ try {
418
+ // Ensure we have credentials before making the API call
419
+ await this.ensureAuthenticated();
420
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/${table}/${sys_id}`);
421
+ return response.data.result;
422
+ }
423
+ catch (error) {
424
+ console.error(`Failed to get record from ${table}:`, error);
425
+ throw error;
426
+ }
427
+ }
428
+ /**
429
+ * Get multiple records from a table
430
+ */
431
+ async getRecords(table, params) {
432
+ try {
433
+ // Ensure we have credentials before making the API call
434
+ await this.ensureAuthenticated();
435
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/${table}`, { params });
436
+ return {
437
+ success: true,
438
+ data: response.data.result
439
+ };
440
+ }
441
+ catch (error) {
442
+ console.error(`Failed to get records from ${table}:`, error);
443
+ return {
444
+ success: false,
445
+ error: error instanceof Error ? error.message : String(error)
446
+ };
447
+ }
448
+ }
449
+ /**
450
+ * Search records in a table using encoded query
451
+ */
452
+ async searchRecords(table, query, limit = 10) {
453
+ try {
454
+ await this.ensureAuthenticated();
455
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/${table}`, {
456
+ params: {
457
+ sysparm_query: query,
458
+ sysparm_limit: limit
459
+ }
460
+ });
461
+ return {
462
+ success: true,
463
+ data: {
464
+ result: response.data.result || []
465
+ }
466
+ };
467
+ }
468
+ catch (error) {
469
+ console.error(`Failed to search records in ${table}:`, error);
470
+ return {
471
+ success: false,
472
+ error: error instanceof Error ? error.message : String(error)
473
+ };
474
+ }
475
+ }
476
+ /**
477
+ * Create a record in any ServiceNow table
478
+ */
479
+ async createRecord(table, data) {
480
+ try {
481
+ await this.ensureAuthenticated();
482
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/${table}`, data);
483
+ return {
484
+ success: true,
485
+ data: response.data.result
486
+ };
487
+ }
488
+ catch (error) {
489
+ console.error(`Failed to create record in ${table}:`, error);
490
+ return {
491
+ success: false,
492
+ error: error instanceof Error ? error.message : String(error)
493
+ };
494
+ }
495
+ }
496
+ /**
497
+ * Search for available flow actions in ServiceNow
498
+ */
499
+ async searchFlowActions(searchTerm) {
500
+ try {
501
+ console.log(`🔍 Searching for flow actions: ${searchTerm}`);
502
+ // Search in sys_hub_action_type_base for available action types
503
+ const results = await this.searchRecords('sys_hub_action_type_base', `nameLIKE${searchTerm}^ORlabelLIKE${searchTerm}^ORdescriptionLIKE${searchTerm}`, 20);
504
+ // Also search in sys_hub_action_instance for existing actions
505
+ const instanceResults = await this.searchRecords('sys_hub_action_instance', `action_nameLIKE${searchTerm}^ORdescriptionLIKE${searchTerm}`, 10);
506
+ const actionTypes = results.success ? results.data.result : [];
507
+ const actionInstances = instanceResults.success ? instanceResults.data.result : [];
508
+ console.log(`✅ Found ${actionTypes.length} action types and ${actionInstances.length} action instances`);
509
+ return {
510
+ actionTypes,
511
+ actionInstances
512
+ };
513
+ }
514
+ catch (error) {
515
+ console.error('Failed to search flow actions:', error);
516
+ return { actionTypes: [], actionInstances: [] };
517
+ }
518
+ }
519
+ /**
520
+ * Get flow action details
521
+ */
522
+ async getFlowActionDetails(actionTypeId) {
523
+ try {
524
+ const actionType = await this.getRecord('sys_hub_action_type_base', actionTypeId);
525
+ // Get input/output variables for this action type
526
+ const inputs = await this.searchRecords('sys_hub_action_input', `action_type=${actionTypeId}`, 50);
527
+ const outputs = await this.searchRecords('sys_hub_action_output', `action_type=${actionTypeId}`, 50);
528
+ return {
529
+ actionType,
530
+ inputs: inputs.success ? inputs.data.result : [],
531
+ outputs: outputs.success ? outputs.data.result : []
532
+ };
533
+ }
534
+ catch (error) {
535
+ console.error('Failed to get flow action details:', error);
536
+ return null;
537
+ }
538
+ }
539
+ /**
540
+ * Create a simple Flow Designer flow
541
+ * Focusing on basic flow creation with simple actions
542
+ */
543
+ async createFlow(flow) {
544
+ try {
545
+ console.log('🔄 Creating Flow Designer flow...');
546
+ console.log(`📋 Flow: ${flow.name}`);
547
+ // First, ensure we have an Update Set
548
+ const updateSetResult = await this.ensureUpdateSet();
549
+ // Get dynamic defaults from ServiceNow
550
+ const flowDefaults = await this.getFlowDefaults();
551
+ // Build flow structure with dynamic defaults
552
+ const flowData = {
553
+ name: flow.name,
554
+ description: flow.description || flow.name,
555
+ active: flow.active !== false,
556
+ internal_name: this.sanitizeInternalName(flow.name),
557
+ category: flow.category || 'custom',
558
+ run_as: 'user_who_triggers',
559
+ // Merge with dynamic defaults from ServiceNow
560
+ ...flowDefaults,
561
+ // Override with any specific values from the flow parameter
562
+ ...flow.overrides
563
+ };
564
+ // Create the main flow record
565
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_hub_flow`, flowData);
566
+ if (!response.data || !response.data.result) {
567
+ throw new Error('No response data from flow creation');
568
+ }
569
+ const flowId = response.data.result.sys_id;
570
+ console.log('✅ Flow created successfully!');
571
+ console.log(`🆔 Flow sys_id: ${flowId}`);
572
+ // Create trigger first
573
+ let triggerInstanceId = null;
574
+ let triggerLogicId = null;
575
+ if (flow.trigger_type) {
576
+ console.log('📋 Creating flow trigger...');
577
+ try {
578
+ const triggerResult = await this.createFlowTrigger(flowId, {
579
+ type: flow.trigger_type,
580
+ table: flow.table || 'incident',
581
+ condition: flow.trigger_condition || flow.condition || ''
582
+ });
583
+ triggerInstanceId = triggerResult.sys_id;
584
+ // Create trigger logic entry
585
+ console.log('📋 Creating trigger logic...');
586
+ const triggerLogic = await this.createFlowLogic(flowId, {
587
+ name: 'Trigger',
588
+ type: 'trigger',
589
+ order: 0,
590
+ instance: triggerInstanceId
591
+ });
592
+ triggerLogicId = triggerLogic.sys_id;
593
+ }
594
+ catch (triggerError) {
595
+ console.error('Failed to create trigger:', triggerError);
596
+ }
597
+ }
598
+ // Create flow actions with logic entries
599
+ const actionLogicIds = [];
600
+ if (flow.actions && Array.isArray(flow.actions)) {
601
+ console.log(`📋 Creating ${flow.actions.length} flow actions...`);
602
+ for (let i = 0; i < flow.actions.length; i++) {
603
+ const action = flow.actions[i];
604
+ try {
605
+ const actionResult = await this.createFlowActionInstance(flowId, action, (i + 1) * 100);
606
+ // Create action logic entry
607
+ const actionLogic = await this.createFlowLogic(flowId, {
608
+ name: action.name,
609
+ type: 'action',
610
+ order: (i + 1) * 100,
611
+ instance: actionResult.sys_id
612
+ });
613
+ actionLogicIds.push(actionLogic.sys_id);
614
+ }
615
+ catch (actionError) {
616
+ console.error(`Failed to create action ${action.name}:`, actionError);
617
+ }
618
+ }
619
+ }
620
+ // Create connections between trigger and actions
621
+ if (triggerLogicId && actionLogicIds.length > 0) {
622
+ console.log('📋 Creating flow connections...');
623
+ try {
624
+ // Connect trigger to first action
625
+ await this.createFlowConnection(flowId, triggerLogicId, actionLogicIds[0]);
626
+ // Connect actions in sequence
627
+ for (let i = 0; i < actionLogicIds.length - 1; i++) {
628
+ await this.createFlowConnection(flowId, actionLogicIds[i], actionLogicIds[i + 1]);
629
+ }
630
+ }
631
+ catch (connError) {
632
+ console.error('Failed to create connections:', connError);
633
+ }
634
+ }
635
+ return {
636
+ success: true,
637
+ data: response.data.result
638
+ };
639
+ }
640
+ catch (error) {
641
+ console.error('❌ Failed to create flow:', error);
642
+ return {
643
+ success: false,
644
+ error: error instanceof Error ? error.message : String(error)
645
+ };
646
+ }
647
+ }
648
+ /**
649
+ * Create a flow action using discovered ServiceNow action types
650
+ */
651
+ async createFlowAction(flowId, action, order) {
652
+ try {
653
+ console.log(`Creating flow action: ${action.type} - ${action.name}`);
654
+ // If we have a discovered action type, use it
655
+ let actionTypeId = action.action_type_id;
656
+ // If no specific action type provided, search for one
657
+ if (!actionTypeId) {
658
+ const searchResults = await this.searchFlowActions(action.type);
659
+ if (searchResults.actionTypes && searchResults.actionTypes.length > 0) {
660
+ actionTypeId = searchResults.actionTypes[0].sys_id;
661
+ console.log(`📋 Using discovered action type: ${searchResults.actionTypes[0].name}`);
662
+ }
663
+ else {
664
+ // Fallback to common action types
665
+ const fallbackMap = {
666
+ 'notification': 'com.glideapp.servicenow_common.send_email',
667
+ 'field_update': 'com.glideapp.servicenow_common.update_record',
668
+ 'create_task': 'com.glideapp.servicenow_common.create_record',
669
+ 'log': 'com.glideapp.servicenow_common.log_message',
670
+ 'wait': 'com.glideapp.servicenow_common.timer',
671
+ 'approval': 'com.glideapp.servicenow_common.approval'
672
+ };
673
+ actionTypeId = fallbackMap[action.type] || 'com.glideapp.servicenow_common.script';
674
+ console.log(`📋 Using fallback action type: ${actionTypeId}`);
675
+ }
676
+ }
677
+ // Get action details to understand inputs/outputs
678
+ const actionDetails = await this.getFlowActionDetails(actionTypeId);
679
+ // Build inputs based on action details
680
+ const inputs = this.buildActionInputs(action, actionDetails);
681
+ const actionData = {
682
+ flow: flowId,
683
+ action_name: action.name,
684
+ action_type: actionTypeId,
685
+ order: order * 100,
686
+ active: true,
687
+ // Use proper ServiceNow action configuration
688
+ inputs: JSON.stringify(inputs),
689
+ configuration: this.buildActionConfiguration(action)
690
+ };
691
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_hub_action_instance`, actionData);
692
+ console.log(`✅ Flow action created: ${action.name}`);
693
+ return response.data.result;
694
+ }
695
+ catch (error) {
696
+ console.error('Failed to create flow action:', error);
697
+ throw error;
698
+ }
699
+ }
700
+ /**
701
+ * Build action inputs based on action details
702
+ */
703
+ buildActionInputs(action, actionDetails) {
704
+ const inputs = {};
705
+ if (!actionDetails || !actionDetails.inputs) {
706
+ return inputs;
707
+ }
708
+ // Map action properties to ServiceNow input variables
709
+ for (const input of actionDetails.inputs) {
710
+ const inputName = input.name;
711
+ switch (action.type) {
712
+ case 'notification':
713
+ if (inputName === 'to' || inputName === 'recipient') {
714
+ inputs[inputName] = action.to || '${trigger.record.assigned_to}';
715
+ }
716
+ else if (inputName === 'subject') {
717
+ inputs[inputName] = action.subject || 'Flow Notification';
718
+ }
719
+ else if (inputName === 'message' || inputName === 'body') {
720
+ inputs[inputName] = action.message || 'Flow action executed';
721
+ }
722
+ break;
723
+ case 'field_update':
724
+ if (inputName === 'record' || inputName === 'table') {
725
+ inputs[inputName] = '${trigger.record}';
726
+ }
727
+ else if (inputName === 'field') {
728
+ inputs[inputName] = action.field;
729
+ }
730
+ else if (inputName === 'value') {
731
+ inputs[inputName] = action.value;
732
+ }
733
+ break;
734
+ case 'create_task':
735
+ if (inputName === 'table') {
736
+ inputs[inputName] = action.target_table || 'task';
737
+ }
738
+ else if (inputName === 'fields') {
739
+ inputs[inputName] = action.fields || {};
740
+ }
741
+ break;
742
+ case 'log':
743
+ if (inputName === 'message') {
744
+ inputs[inputName] = action.message || 'Flow action executed';
745
+ }
746
+ else if (inputName === 'level') {
747
+ inputs[inputName] = action.level || 'info';
748
+ }
749
+ break;
750
+ case 'wait':
751
+ if (inputName === 'duration') {
752
+ inputs[inputName] = action.duration || 300;
753
+ }
754
+ break;
755
+ case 'approval':
756
+ if (inputName === 'approvers') {
757
+ inputs[inputName] = action.approvers || '${trigger.record.assigned_to.manager}';
758
+ }
759
+ break;
760
+ }
761
+ }
762
+ return inputs;
763
+ }
764
+ /**
765
+ * Build simple action configuration
766
+ */
767
+ buildActionConfiguration(action) {
768
+ const config = {
769
+ name: action.name,
770
+ type: action.type
771
+ };
772
+ switch (action.type) {
773
+ case 'notification':
774
+ config.to = action.to || 'assigned_to';
775
+ config.subject = action.subject || 'Flow Notification';
776
+ config.body = action.message || 'A flow action has been triggered.';
777
+ break;
778
+ case 'field_update':
779
+ config.field = action.field;
780
+ config.value = action.value;
781
+ break;
782
+ case 'create_task':
783
+ config.table = action.target_table || 'task';
784
+ config.fields = action.fields || {};
785
+ break;
786
+ case 'log':
787
+ config.message = action.message || 'Flow action executed';
788
+ config.level = action.level || 'info';
789
+ break;
790
+ case 'wait':
791
+ config.duration = action.duration || 300; // 5 minutes default
792
+ break;
793
+ case 'approval':
794
+ config.approvers = action.approvers || 'assigned_to.manager';
795
+ break;
796
+ default:
797
+ config.script = action.script || '// Custom action';
798
+ }
799
+ return JSON.stringify(config);
800
+ }
801
+ /**
802
+ * Create a flow trigger instance
803
+ */
804
+ async createFlowTrigger(flowId, trigger) {
805
+ try {
806
+ // Get trigger type from cache
807
+ let triggerType = await this.actionTypeCache.getTriggerType(trigger.type);
808
+ if (!triggerType) {
809
+ console.warn(`Trigger type '${trigger.type}' not found in cache, using default`);
810
+ // Fallback to 'Created' trigger if not found
811
+ triggerType = await this.actionTypeCache.getTriggerType('Created');
812
+ if (!triggerType) {
813
+ throw new Error('Could not find any trigger types');
814
+ }
815
+ }
816
+ const triggerTypeId = triggerType.sys_id;
817
+ const triggerData = {
818
+ flow: flowId,
819
+ trigger_type: triggerTypeId,
820
+ table_name: trigger.table || 'incident',
821
+ condition: trigger.condition || '',
822
+ order: 0,
823
+ active: true
824
+ };
825
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_hub_trigger_instance`, triggerData);
826
+ console.log('✅ Trigger created successfully');
827
+ return response.data.result;
828
+ }
829
+ catch (error) {
830
+ console.error('Failed to create flow trigger:', error);
831
+ throw error;
832
+ }
833
+ }
834
+ /**
835
+ * Create a flow action instance using simplified approach
836
+ */
837
+ async createFlowActionInstance(flowId, action, order) {
838
+ try {
839
+ console.log(`Creating action instance: ${action.name}`);
840
+ // Map action types to search terms
841
+ const actionSearchMap = {
842
+ 'notification': 'Send Email',
843
+ 'email': 'Send Email',
844
+ 'field_update': 'Update Record',
845
+ 'create_task': 'Create Record',
846
+ 'create_record': 'Create Record',
847
+ 'wait': 'Wait',
848
+ 'approval': 'Approval',
849
+ 'log': 'Log'
850
+ };
851
+ const searchTerm = actionSearchMap[action.type] || action.type;
852
+ let actionType = await this.actionTypeCache.getActionType(searchTerm);
853
+ if (!actionType) {
854
+ console.warn(`Action type '${searchTerm}' not found in cache, using Script action`);
855
+ // Fallback to Script action if not found
856
+ actionType = await this.actionTypeCache.getActionType('Script');
857
+ if (!actionType) {
858
+ throw new Error('Could not find any action types');
859
+ }
860
+ }
861
+ const actionTypeId = actionType.sys_id;
862
+ // Build inputs based on action type
863
+ let inputs = {};
864
+ switch (action.type) {
865
+ case 'notification':
866
+ case 'email':
867
+ inputs = {
868
+ email_to: action.to || '${trigger.assigned_to.email}',
869
+ email_subject: action.subject || 'Notification',
870
+ email_body: action.message || 'Notification from flow'
871
+ };
872
+ break;
873
+ case 'field_update':
874
+ inputs = {
875
+ table: action.table || 'current',
876
+ field: action.field || 'state',
877
+ value: action.value || ''
878
+ };
879
+ break;
880
+ case 'create_task':
881
+ case 'create_record':
882
+ inputs = {
883
+ table: action.target_table || 'task',
884
+ field_values: JSON.stringify({
885
+ short_description: action.short_description || 'Task from flow',
886
+ assigned_to: action.assigned_to || '${trigger.assigned_to}'
887
+ })
888
+ };
889
+ break;
890
+ case 'wait':
891
+ inputs = {
892
+ duration: action.duration || 300,
893
+ unit: 'seconds'
894
+ };
895
+ break;
896
+ case 'approval':
897
+ inputs = {
898
+ approvers: action.approvers || '${trigger.assigned_to.manager}',
899
+ approval_field: 'approval'
900
+ };
901
+ break;
902
+ default:
903
+ inputs = action.inputs || {};
904
+ }
905
+ const actionData = {
906
+ flow: flowId,
907
+ action_name: action.name,
908
+ action_type: actionTypeId,
909
+ order: order,
910
+ active: true,
911
+ inputs: JSON.stringify(inputs)
912
+ };
913
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_hub_action_instance`, actionData);
914
+ console.log(`✅ Action created: ${action.name}`);
915
+ return response.data.result;
916
+ }
917
+ catch (error) {
918
+ console.error(`Failed to create action instance ${action.name}:`, error);
919
+ throw error;
920
+ }
921
+ }
922
+ /**
923
+ * Create a flow operation (activity) for a Flow Designer flow
924
+ */
925
+ async createFlowOperation(flowId, operation) {
926
+ try {
927
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_hub_flow_operation`, {
928
+ flow: flowId,
929
+ name: operation.name,
930
+ type: operation.type || 'core',
931
+ action_type: operation.action_type || 'script',
932
+ order: operation.order || 100,
933
+ // Operation-specific configuration
934
+ configuration: JSON.stringify({
935
+ script: operation.script,
936
+ inputs: operation.inputs || {},
937
+ outputs: operation.outputs || {},
938
+ artifact_reference: operation.artifact_reference
939
+ })
940
+ });
941
+ return response.data.result;
942
+ }
943
+ catch (error) {
944
+ console.error('Failed to create flow operation:', error);
945
+ throw error;
946
+ }
947
+ }
948
+ /**
949
+ * Create a Script Include
950
+ */
951
+ async createScriptInclude(scriptInclude) {
952
+ try {
953
+ console.log('📝 Creating Script Include...');
954
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_script_include`, {
955
+ name: scriptInclude.name,
956
+ api_name: scriptInclude.api_name,
957
+ description: scriptInclude.description,
958
+ script: scriptInclude.script,
959
+ active: scriptInclude.active,
960
+ access: scriptInclude.access || 'public'
961
+ });
962
+ console.log('✅ Script Include created successfully!');
963
+ return {
964
+ success: true,
965
+ data: response.data.result
966
+ };
967
+ }
968
+ catch (error) {
969
+ console.error('❌ Failed to create script include:', error);
970
+ return {
971
+ success: false,
972
+ error: error instanceof Error ? error.message : String(error)
973
+ };
974
+ }
975
+ }
976
+ /**
977
+ * Create a Business Rule
978
+ */
979
+ async createBusinessRule(businessRule) {
980
+ try {
981
+ console.log('📋 Creating Business Rule...');
982
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_script`, {
983
+ name: businessRule.name,
984
+ collection: businessRule.table,
985
+ when: businessRule.when,
986
+ condition: businessRule.condition,
987
+ script: businessRule.script,
988
+ description: businessRule.description,
989
+ active: businessRule.active,
990
+ order: businessRule.order || 100
991
+ });
992
+ console.log('✅ Business Rule created successfully!');
993
+ return {
994
+ success: true,
995
+ data: response.data.result
996
+ };
997
+ }
998
+ catch (error) {
999
+ console.error('❌ Failed to create business rule:', error);
1000
+ return {
1001
+ success: false,
1002
+ error: error instanceof Error ? error.message : String(error)
1003
+ };
1004
+ }
1005
+ }
1006
+ /**
1007
+ * Create a Table
1008
+ */
1009
+ async createTable(table) {
1010
+ try {
1011
+ console.log('🗄️ Creating Table...');
1012
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_db_object`, {
1013
+ name: table.name,
1014
+ label: table.label,
1015
+ extends_table: table.extends_table || 'sys_metadata',
1016
+ is_extendable: table.is_extendable !== false,
1017
+ access: table.access || 'public',
1018
+ create_access_controls: table.create_access_controls !== false
1019
+ });
1020
+ console.log('✅ Table created successfully!');
1021
+ return {
1022
+ success: true,
1023
+ data: response.data.result
1024
+ };
1025
+ }
1026
+ catch (error) {
1027
+ console.error('❌ Failed to create table:', error);
1028
+ return {
1029
+ success: false,
1030
+ error: error instanceof Error ? error.message : String(error)
1031
+ };
1032
+ }
1033
+ }
1034
+ /**
1035
+ * Create a Table Field
1036
+ */
1037
+ async createTableField(field) {
1038
+ try {
1039
+ console.log('📊 Creating Table Field...');
1040
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_dictionary`, {
1041
+ name: `${field.table}.${field.element}`,
1042
+ element: field.element,
1043
+ column_label: field.column_label,
1044
+ internal_type: field.internal_type || 'string',
1045
+ max_length: field.max_length || 255,
1046
+ active: true
1047
+ });
1048
+ console.log('✅ Table Field created successfully!');
1049
+ return {
1050
+ success: true,
1051
+ data: response.data.result
1052
+ };
1053
+ }
1054
+ catch (error) {
1055
+ console.error('❌ Failed to create table field:', error);
1056
+ return {
1057
+ success: false,
1058
+ error: error instanceof Error ? error.message : String(error)
1059
+ };
1060
+ }
1061
+ }
1062
+ /**
1063
+ * Create a new Update Set
1064
+ */
1065
+ async createUpdateSet(updateSet) {
1066
+ try {
1067
+ console.log('📦 Creating Update Set...');
1068
+ // Ensure we have credentials before making the API call
1069
+ await this.ensureAuthenticated();
1070
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_update_set`, {
1071
+ name: updateSet.name,
1072
+ description: updateSet.description,
1073
+ release_date: updateSet.release_date,
1074
+ state: updateSet.state || 'in_progress',
1075
+ application: updateSet.application || 'global'
1076
+ });
1077
+ console.log('✅ Update Set created successfully!');
1078
+ return {
1079
+ success: true,
1080
+ data: response.data.result
1081
+ };
1082
+ }
1083
+ catch (error) {
1084
+ console.error('❌ Failed to create Update Set:', error);
1085
+ return {
1086
+ success: false,
1087
+ error: error instanceof Error ? error.message : String(error)
1088
+ };
1089
+ }
1090
+ }
1091
+ /**
1092
+ * Set current Update Set for the session
1093
+ */
1094
+ async setCurrentUpdateSet(updateSetId) {
1095
+ try {
1096
+ console.log('🔄 Setting current Update Set...');
1097
+ // Ensure we have credentials before making the API call
1098
+ await this.ensureAuthenticated();
1099
+ // Use the sys_user_preference table to set the current update set
1100
+ // First, check if a preference already exists
1101
+ const existingPref = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_user_preference`, {
1102
+ params: {
1103
+ sysparm_query: 'name=sys_update_set^user=javascript:gs.getUserID()',
1104
+ sysparm_limit: 1
1105
+ }
1106
+ });
1107
+ let response;
1108
+ if (existingPref.data.result && existingPref.data.result.length > 0) {
1109
+ // Update existing preference
1110
+ response = await this.client.patch(`${this.getBaseUrl()}/api/now/table/sys_user_preference/${existingPref.data.result[0].sys_id}`, {
1111
+ value: updateSetId
1112
+ });
1113
+ }
1114
+ else {
1115
+ // Create new preference
1116
+ response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_user_preference`, {
1117
+ name: 'sys_update_set',
1118
+ value: updateSetId,
1119
+ user: 'javascript:gs.getUserID()'
1120
+ });
1121
+ }
1122
+ console.log('✅ Current Update Set changed successfully!');
1123
+ return {
1124
+ success: true,
1125
+ data: response.data.result
1126
+ };
1127
+ }
1128
+ catch (error) {
1129
+ console.error('❌ Failed to set current Update Set:', error);
1130
+ return {
1131
+ success: false,
1132
+ error: error instanceof Error ? error.message : String(error)
1133
+ };
1134
+ }
1135
+ }
1136
+ /**
1137
+ * Get current Update Set
1138
+ */
1139
+ async getCurrentUpdateSet() {
1140
+ try {
1141
+ console.log('📋 Getting current Update Set...');
1142
+ // Ensure we have credentials before making the API call
1143
+ await this.ensureAuthenticated();
1144
+ // Try to get the current update set using sys_user_preference table
1145
+ // This is more reliable than the UI API
1146
+ try {
1147
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_user_preference`, {
1148
+ params: {
1149
+ sysparm_query: 'name=sys_update_set^user=javascript:gs.getUserID()',
1150
+ sysparm_limit: 1
1151
+ }
1152
+ });
1153
+ if (response.data.result && response.data.result.length > 0) {
1154
+ const updateSetId = response.data.result[0].value;
1155
+ // Get Update Set details
1156
+ const updateSetResponse = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_update_set/${updateSetId}`);
1157
+ return {
1158
+ success: true,
1159
+ data: updateSetResponse.data.result
1160
+ };
1161
+ }
1162
+ }
1163
+ catch (prefError) {
1164
+ console.log('⚠️ User preference lookup failed, trying fallback...');
1165
+ }
1166
+ // Fallback: Get the most recent in-progress update set for the current user
1167
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_update_set`, {
1168
+ params: {
1169
+ sysparm_query: 'state=in_progress^sys_created_by=javascript:gs.getUserName()',
1170
+ sysparm_orderby: 'sys_created_on',
1171
+ sysparm_limit: 1
1172
+ }
1173
+ });
1174
+ if (response.data.result && response.data.result.length > 0) {
1175
+ return {
1176
+ success: true,
1177
+ data: response.data.result[0]
1178
+ };
1179
+ }
1180
+ return {
1181
+ success: false,
1182
+ error: 'No current Update Set found'
1183
+ };
1184
+ }
1185
+ catch (error) {
1186
+ console.error('❌ Failed to get current Update Set:', error);
1187
+ return {
1188
+ success: false,
1189
+ error: error instanceof Error ? error.message : String(error)
1190
+ };
1191
+ }
1192
+ }
1193
+ /**
1194
+ * Get Update Set by ID
1195
+ */
1196
+ async getUpdateSet(updateSetId) {
1197
+ try {
1198
+ console.log(`📋 Getting Update Set ${updateSetId}...`);
1199
+ // Ensure we have credentials before making the API call
1200
+ await this.ensureAuthenticated();
1201
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_update_set/${updateSetId}`);
1202
+ return {
1203
+ success: true,
1204
+ data: response.data.result
1205
+ };
1206
+ }
1207
+ catch (error) {
1208
+ console.error('❌ Failed to get Update Set:', error);
1209
+ return {
1210
+ success: false,
1211
+ error: error instanceof Error ? error.message : String(error)
1212
+ };
1213
+ }
1214
+ }
1215
+ /**
1216
+ * List Update Sets
1217
+ */
1218
+ async listUpdateSets(options) {
1219
+ try {
1220
+ console.log('📋 Listing Update Sets...');
1221
+ // Ensure we have credentials before making the API call
1222
+ await this.ensureAuthenticated();
1223
+ let query = 'sys_created_by=javascript:gs.getUserName()';
1224
+ if (options.state) {
1225
+ query += `^state=${options.state}`;
1226
+ }
1227
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_update_set`, {
1228
+ params: {
1229
+ sysparm_query: query,
1230
+ sysparm_limit: options.limit || 10,
1231
+ sysparm_orderby: 'sys_created_on^DESC'
1232
+ }
1233
+ });
1234
+ return {
1235
+ success: true,
1236
+ data: response.data.result
1237
+ };
1238
+ }
1239
+ catch (error) {
1240
+ console.error('❌ Failed to list Update Sets:', error);
1241
+ return {
1242
+ success: false,
1243
+ error: error instanceof Error ? error.message : String(error)
1244
+ };
1245
+ }
1246
+ }
1247
+ /**
1248
+ * Complete an Update Set
1249
+ */
1250
+ async completeUpdateSet(updateSetId, notes) {
1251
+ try {
1252
+ console.log('✅ Completing Update Set...');
1253
+ // Ensure we have credentials before making the API call
1254
+ await this.ensureAuthenticated();
1255
+ const response = await this.client.patch(`${this.getBaseUrl()}/api/now/table/sys_update_set/${updateSetId}`, {
1256
+ state: 'complete',
1257
+ description: notes ? `${notes}\n\nCompleted: ${new Date().toISOString()}` : undefined
1258
+ });
1259
+ console.log('✅ Update Set completed successfully!');
1260
+ return {
1261
+ success: true,
1262
+ data: response.data.result
1263
+ };
1264
+ }
1265
+ catch (error) {
1266
+ console.error('❌ Failed to complete Update Set:', error);
1267
+ return {
1268
+ success: false,
1269
+ error: error instanceof Error ? error.message : String(error)
1270
+ };
1271
+ }
1272
+ }
1273
+ /**
1274
+ * Preview Update Set changes
1275
+ */
1276
+ async previewUpdateSet(updateSetId) {
1277
+ try {
1278
+ console.log('🔍 Previewing Update Set changes...');
1279
+ // Get Update Set details
1280
+ const updateSetResponse = await this.getUpdateSet(updateSetId);
1281
+ if (!updateSetResponse.success) {
1282
+ return updateSetResponse;
1283
+ }
1284
+ // Get Update Set changes
1285
+ const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_update_xml`, {
1286
+ params: {
1287
+ sysparm_query: `update_set=${updateSetId}`,
1288
+ sysparm_limit: 1000
1289
+ }
1290
+ });
1291
+ return {
1292
+ success: true,
1293
+ data: {
1294
+ ...updateSetResponse.data,
1295
+ changes: response.data.result
1296
+ }
1297
+ };
1298
+ }
1299
+ catch (error) {
1300
+ console.error('❌ Failed to preview Update Set:', error);
1301
+ return {
1302
+ success: false,
1303
+ error: error instanceof Error ? error.message : String(error)
1304
+ };
1305
+ }
1306
+ }
1307
+ /**
1308
+ * Export Update Set as XML
1309
+ */
1310
+ /**
1311
+ * Ensure we have an active Update Set for tracking changes
1312
+ */
1313
+ async ensureUpdateSet() {
1314
+ try {
1315
+ // Check if we have a current Update Set
1316
+ const currentUpdateSet = await this.getCurrentUpdateSet();
1317
+ if (currentUpdateSet.success && currentUpdateSet.data) {
1318
+ console.log(`📦 Using existing Update Set: ${currentUpdateSet.data.name}`);
1319
+ return currentUpdateSet;
1320
+ }
1321
+ // Create a new Update Set if none exists
1322
+ const updateSetName = `Snow-Flow Changes ${new Date().toISOString().split('T')[0]}`;
1323
+ console.log(`📦 Creating new Update Set: ${updateSetName}`);
1324
+ const newUpdateSet = await this.createUpdateSet({
1325
+ name: updateSetName,
1326
+ description: 'Automated changes from Snow-Flow MCP',
1327
+ state: 'in_progress'
1328
+ });
1329
+ if (newUpdateSet.success && newUpdateSet.data) {
1330
+ // Set it as current
1331
+ await this.setCurrentUpdateSet(newUpdateSet.data.sys_id);
1332
+ return newUpdateSet;
1333
+ }
1334
+ // If Update Set creation fails, continue without it
1335
+ console.warn('⚠️ Could not create Update Set, changes will not be tracked');
1336
+ return { success: false, error: 'Update Set creation failed' };
1337
+ }
1338
+ catch (error) {
1339
+ console.warn('⚠️ Update Set management failed:', error);
1340
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
1341
+ }
1342
+ }
1343
+ async exportUpdateSet(updateSetId) {
1344
+ try {
1345
+ console.log('📤 Exporting Update Set...');
1346
+ // Get Update Set details first
1347
+ const updateSetResponse = await this.getUpdateSet(updateSetId);
1348
+ if (!updateSetResponse.success) {
1349
+ return updateSetResponse;
1350
+ }
1351
+ // Use the unload processor to export
1352
+ const response = await this.client.get(`${this.getBaseUrl()}/unload.do`, {
1353
+ params: {
1354
+ sysparm_sys_id: updateSetId,
1355
+ sysparm_table: 'sys_update_set',
1356
+ sysparm_unload_format: 'xml'
1357
+ },
1358
+ responseType: 'text'
1359
+ });
1360
+ return {
1361
+ success: true,
1362
+ data: {
1363
+ name: updateSetResponse.data.name,
1364
+ xml: response.data,
1365
+ change_count: updateSetResponse.data.update_count || 0
1366
+ }
1367
+ };
1368
+ }
1369
+ catch (error) {
1370
+ console.error('❌ Failed to export Update Set:', error);
1371
+ return {
1372
+ success: false,
1373
+ error: error instanceof Error ? error.message : String(error)
1374
+ };
1375
+ }
1376
+ }
1377
+ /**
1378
+ * Debug flow structure - check what's missing for Flow Designer
1379
+ */
1380
+ async debugFlow(flowId) {
1381
+ try {
1382
+ console.log('🔍 Debugging flow structure...');
1383
+ // Get the flow record
1384
+ const flowResponse = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_hub_flow/${flowId}`);
1385
+ if (!flowResponse.data.result) {
1386
+ return { success: false, error: 'Flow not found' };
1387
+ }
1388
+ const flow = flowResponse.data.result;
1389
+ // Check for sys_hub_flow_logic entries
1390
+ const logicResponse = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_hub_flow_logic?sysparm_query=flow=${flowId}`);
1391
+ // Check for trigger instances
1392
+ const triggerResponse = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_hub_trigger_instance?sysparm_query=flow=${flowId}`);
1393
+ // Check for action instances
1394
+ const actionResponse = await this.client.get(`${this.getBaseUrl()}/api/now/table/sys_hub_action_instance?sysparm_query=flow=${flowId}`);
1395
+ return {
1396
+ success: true,
1397
+ data: {
1398
+ flow: {
1399
+ sys_id: flow.sys_id,
1400
+ name: flow.name,
1401
+ internal_name: flow.internal_name,
1402
+ status: flow.status,
1403
+ type: flow.type,
1404
+ sys_class_name: flow.sys_class_name,
1405
+ missing_fields: []
1406
+ },
1407
+ logic_count: logicResponse.data.result.length,
1408
+ trigger_count: triggerResponse.data.result.length,
1409
+ action_count: actionResponse.data.result.length,
1410
+ logic_entries: logicResponse.data.result,
1411
+ triggers: triggerResponse.data.result,
1412
+ actions: actionResponse.data.result
1413
+ }
1414
+ };
1415
+ }
1416
+ catch (error) {
1417
+ return {
1418
+ success: false,
1419
+ error: error instanceof Error ? error.message : String(error)
1420
+ };
1421
+ }
1422
+ }
1423
+ /**
1424
+ * Create a flow logic entry (visual representation in Flow Designer)
1425
+ */
1426
+ async createFlowLogic(flowId, logic) {
1427
+ try {
1428
+ const logicData = {
1429
+ flow: flowId,
1430
+ name: logic.name,
1431
+ type: logic.type,
1432
+ order: logic.order,
1433
+ active: true,
1434
+ instance: logic.instance
1435
+ };
1436
+ const response = await this.client.post(`${this.getBaseUrl()}/api/now/table/sys_hub_flow_logic`, logicData);
1437
+ return response.data.result;
1438
+ }
1439
+ catch (error) {
1440
+ console.error('Failed to create flow logic:', error);
1441
+ throw error;
1442
+ }
1443
+ }
1444
+ /**
1445
+ * Create a connection between flow logic elements
1446
+ */
1447
+ async createFlowConnection(flowId, fromId, toId) {
1448
+ try {
1449
+ // In ServiceNow, connections are stored as part of the flow logic
1450
+ // We need to update the 'from' element to point to the 'to' element
1451
+ const connectionData = {
1452
+ next: toId
1453
+ };
1454
+ const response = await this.client.patch(`${this.getBaseUrl()}/api/now/table/sys_hub_flow_logic/${fromId}`, connectionData);
1455
+ return response.data.result;
1456
+ }
1457
+ catch (error) {
1458
+ console.error('Failed to create flow connection:', error);
1459
+ // Don't throw - connections might work differently in some versions
1460
+ return null;
1461
+ }
1462
+ }
1463
+ }
1464
+ exports.ServiceNowClient = ServiceNowClient;
1465
+ //# sourceMappingURL=servicenow-client.js.map