snow-flow 10.0.1-dev.424 → 10.0.1-dev.427

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.
@@ -166,7 +166,7 @@ export * from './mappers/index.js';
166
166
  // Decoders (1 tool)
167
167
  export * from './decoders/index.js';
168
168
 
169
- // Plugins (3 tools)
169
+ // Plugins (1 tool - unified plugin management)
170
170
  export * from './plugins/index.js';
171
171
 
172
172
  // Addons (3 tools)
@@ -1,3 +1 @@
1
- export { toolDefinition as snow_custom_plugin_def, execute as snow_custom_plugin_exec } from './snow_custom_plugin.js';
2
- export { toolDefinition as snow_activate_plugin_def, execute as snow_activate_plugin_exec } from './snow_activate_plugin.js';
3
- export { toolDefinition as snow_list_plugins_def, execute as snow_list_plugins_exec } from './snow_list_plugins.js';
1
+ export { toolDefinition as snow_plugin_manage_def, execute as snow_plugin_manage_exec } from './snow_plugin_manage.js'
@@ -0,0 +1,295 @@
1
+ /**
2
+ * snow_plugin_manage - Unified Plugin Management
3
+ *
4
+ * Single tool for all ServiceNow plugin operations:
5
+ * list, check, activate, deactivate.
6
+ */
7
+
8
+ import { MCPToolDefinition, ServiceNowContext, ToolResult } from '../../shared/types.js'
9
+ import { getAuthenticatedClient } from '../../shared/auth.js'
10
+ import { createSuccessResult, createErrorResult } from '../../shared/error-handler.js'
11
+
12
+ export const toolDefinition: MCPToolDefinition = {
13
+ name: 'snow_plugin_manage',
14
+ description: `Manage ServiceNow plugins: list, check status, activate, or deactivate.
15
+
16
+ Actions:
17
+ • list — Search and list plugins. Filter by name/ID, show only active.
18
+ • check — Get detailed info on a specific plugin (status, version, dependencies).
19
+ • activate — Activate a plugin (admin only). Uses CICD API with table fallback.
20
+ • deactivate — Deactivate a plugin (admin only). Uses CICD API with table fallback.
21
+
22
+ Examples:
23
+ • { action: "list", search: "incident" }
24
+ • { action: "check", plugin_id: "com.snc.incident" }
25
+ • { action: "activate", plugin_id: "com.snc.incident" }`,
26
+ category: 'advanced',
27
+ subcategory: 'administration',
28
+ use_cases: ['plugin-discovery', 'plugin-management', 'plugin-status', 'activation', 'deactivation'],
29
+ complexity: 'intermediate',
30
+ frequency: 'low',
31
+ permission: 'write',
32
+ allowedRoles: ['developer', 'admin'],
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ action: {
37
+ type: 'string',
38
+ description: 'Operation to perform',
39
+ enum: ['list', 'check', 'activate', 'deactivate'],
40
+ },
41
+ plugin_id: {
42
+ type: 'string',
43
+ description: '[check/activate/deactivate] Plugin identifier (e.g. "com.snc.incident") or sys_id',
44
+ },
45
+ search: {
46
+ type: 'string',
47
+ description: '[list] Filter by plugin name or ID (e.g. "incident", "com.snc")',
48
+ },
49
+ active_only: {
50
+ type: 'boolean',
51
+ description: '[list] Only show active plugins',
52
+ default: false,
53
+ },
54
+ limit: {
55
+ type: 'number',
56
+ description: '[list] Max results to return (default 50)',
57
+ default: 50,
58
+ },
59
+ },
60
+ required: ['action'],
61
+ },
62
+ }
63
+
64
+ export async function execute(args: any, context: ServiceNowContext): Promise<ToolResult> {
65
+ const { action } = args
66
+ try {
67
+ switch (action) {
68
+ case 'list':
69
+ return await executeList(args, context)
70
+ case 'check':
71
+ return await executeCheck(args, context)
72
+ case 'activate':
73
+ return await executeActivate(args, context)
74
+ case 'deactivate':
75
+ return await executeDeactivate(args, context)
76
+ default:
77
+ return createErrorResult(
78
+ 'Unknown action: ' + action + '. Valid actions: list, check, activate, deactivate'
79
+ )
80
+ }
81
+ } catch (error: any) {
82
+ return createErrorResult(error.message)
83
+ }
84
+ }
85
+
86
+ // ==================== LIST ====================
87
+ async function executeList(args: any, context: ServiceNowContext): Promise<ToolResult> {
88
+ const { search, active_only = false, limit = 50 } = args
89
+ const client = await getAuthenticatedClient(context)
90
+
91
+ const queryParts: string[] = []
92
+ if (search) {
93
+ queryParts.push('nameLIKE' + search + '^ORidLIKE' + search)
94
+ }
95
+ if (active_only) {
96
+ queryParts.push('active=true')
97
+ }
98
+
99
+ const response = await client.get('/api/now/table/v_plugin', {
100
+ params: {
101
+ sysparm_query: queryParts.join('^'),
102
+ sysparm_fields: 'sys_id,id,name,active,version,description',
103
+ sysparm_limit: limit,
104
+ sysparm_display_value: 'true',
105
+ },
106
+ })
107
+
108
+ const plugins = response.data.result || []
109
+ const activeCount = plugins.filter((p: any) => p.active === 'true' || p.active === true).length
110
+ const inactiveCount = plugins.length - activeCount
111
+
112
+ const summary =
113
+ 'Found ' +
114
+ plugins.length +
115
+ ' plugin(s)' +
116
+ (search ? ' matching "' + search + '"' : '') +
117
+ '. Active: ' +
118
+ activeCount +
119
+ ', Inactive: ' +
120
+ inactiveCount +
121
+ '.'
122
+
123
+ return createSuccessResult(
124
+ { action: 'list', plugins, count: plugins.length },
125
+ { active_count: activeCount, inactive_count: inactiveCount },
126
+ summary
127
+ )
128
+ }
129
+
130
+ // ==================== CHECK ====================
131
+ async function executeCheck(args: any, context: ServiceNowContext): Promise<ToolResult> {
132
+ const { plugin_id } = args
133
+ if (!plugin_id) return createErrorResult('plugin_id is required for check action')
134
+
135
+ const client = await getAuthenticatedClient(context)
136
+
137
+ const response = await client.get('/api/now/table/v_plugin', {
138
+ params: {
139
+ sysparm_query: 'id=' + plugin_id + '^ORsys_id=' + plugin_id,
140
+ sysparm_fields: 'sys_id,id,name,active,version,description,parent,optional,licensable',
141
+ sysparm_limit: 1,
142
+ sysparm_display_value: 'true',
143
+ },
144
+ })
145
+
146
+ const results = response.data.result || []
147
+ if (results.length === 0) {
148
+ return createErrorResult('Plugin not found: ' + plugin_id)
149
+ }
150
+
151
+ const plugin = results[0]
152
+ const active = plugin.active === 'true' || plugin.active === true
153
+ const summary =
154
+ 'Plugin "' +
155
+ plugin.name +
156
+ '" (' +
157
+ plugin.id +
158
+ ') is ' +
159
+ (active ? 'ACTIVE' : 'INACTIVE') +
160
+ '. Version: ' +
161
+ (plugin.version || 'unknown') +
162
+ '.'
163
+
164
+ return createSuccessResult(
165
+ { action: 'check', plugin },
166
+ { status: active ? 'active' : 'inactive' },
167
+ summary
168
+ )
169
+ }
170
+
171
+ // ==================== ACTIVATE ====================
172
+ async function executeActivate(args: any, context: ServiceNowContext): Promise<ToolResult> {
173
+ const { plugin_id } = args
174
+ if (!plugin_id) return createErrorResult('plugin_id is required for activate action')
175
+
176
+ const client = await getAuthenticatedClient(context)
177
+ const plugin = await lookupPlugin(client, plugin_id)
178
+ if (!plugin) return createErrorResult('Plugin not found: ' + plugin_id)
179
+
180
+ if (plugin.active === 'true' || plugin.active === true) {
181
+ return createSuccessResult(
182
+ { action: 'activate', plugin, activated: false, already_active: true },
183
+ {},
184
+ 'Plugin "' + plugin.name + '" (' + plugin.id + ') is already active.'
185
+ )
186
+ }
187
+
188
+ const { success, method, error } = await togglePlugin(client, plugin, 'activate')
189
+ if (!success) return createErrorResult(error!)
190
+
191
+ const verified = await verifyPluginState(client, plugin.sys_id, true)
192
+ const summary = verified
193
+ ? 'Plugin "' + plugin.name + '" (' + plugin.id + ') activated successfully via ' + method + '.'
194
+ : 'Activation request sent for "' + plugin.name + '" via ' + method + '. May take a moment to fully activate.'
195
+
196
+ return createSuccessResult({ action: 'activate', plugin, activated: true, verified, method }, {}, summary)
197
+ }
198
+
199
+ // ==================== DEACTIVATE ====================
200
+ async function executeDeactivate(args: any, context: ServiceNowContext): Promise<ToolResult> {
201
+ const { plugin_id } = args
202
+ if (!plugin_id) return createErrorResult('plugin_id is required for deactivate action')
203
+
204
+ const client = await getAuthenticatedClient(context)
205
+ const plugin = await lookupPlugin(client, plugin_id)
206
+ if (!plugin) return createErrorResult('Plugin not found: ' + plugin_id)
207
+
208
+ if (plugin.active !== 'true' && plugin.active !== true) {
209
+ return createSuccessResult(
210
+ { action: 'deactivate', plugin, deactivated: false, already_inactive: true },
211
+ {},
212
+ 'Plugin "' + plugin.name + '" (' + plugin.id + ') is already inactive.'
213
+ )
214
+ }
215
+
216
+ const { success, method, error } = await togglePlugin(client, plugin, 'deactivate')
217
+ if (!success) return createErrorResult(error!)
218
+
219
+ const verified = await verifyPluginState(client, plugin.sys_id, false)
220
+ const summary = verified
221
+ ? 'Plugin "' + plugin.name + '" (' + plugin.id + ') deactivated successfully via ' + method + '.'
222
+ : 'Deactivation request sent for "' + plugin.name + '" via ' + method + '. May take a moment to fully deactivate.'
223
+
224
+ return createSuccessResult({ action: 'deactivate', plugin, deactivated: true, verified, method }, {}, summary)
225
+ }
226
+
227
+ // ==================== HELPERS ====================
228
+
229
+ async function lookupPlugin(client: any, pluginId: string): Promise<any | null> {
230
+ const response = await client.get('/api/now/table/v_plugin', {
231
+ params: {
232
+ sysparm_query: 'id=' + pluginId + '^ORsys_id=' + pluginId,
233
+ sysparm_fields: 'sys_id,id,name,active',
234
+ sysparm_limit: 1,
235
+ },
236
+ })
237
+ const results = response.data.result || []
238
+ return results.length > 0 ? results[0] : null
239
+ }
240
+
241
+ async function togglePlugin(
242
+ client: any,
243
+ plugin: any,
244
+ operation: 'activate' | 'deactivate'
245
+ ): Promise<{ success: boolean; method: string; error?: string }> {
246
+ // Try CICD Plugin API first
247
+ try {
248
+ await client.post('/api/sn_cicd/plugin/' + encodeURIComponent(plugin.id) + '/' + operation)
249
+ return { success: true, method: 'cicd_api' }
250
+ } catch (cicdError: any) {
251
+ const status = cicdError.response ? cicdError.response.status : 0
252
+ if (status === 404 || status === 400) {
253
+ // Fallback to sys_plugins PATCH
254
+ try {
255
+ const activeValue = operation === 'activate' ? 'true' : 'false'
256
+ await client.patch('/api/now/table/sys_plugins/' + plugin.sys_id, { active: activeValue })
257
+ return { success: true, method: 'table_api' }
258
+ } catch (patchError: any) {
259
+ return {
260
+ success: false,
261
+ method: '',
262
+ error:
263
+ 'Failed to ' +
264
+ operation +
265
+ ' plugin via both CICD API and Table API. CICD: ' +
266
+ (cicdError.message || 'unknown') +
267
+ '. Table API: ' +
268
+ (patchError.message || 'unknown'),
269
+ }
270
+ }
271
+ }
272
+ return { success: false, method: '', error: 'CICD Plugin API error: ' + (cicdError.message || 'unknown') }
273
+ }
274
+ }
275
+
276
+ async function verifyPluginState(client: any, sysId: string, expectActive: boolean): Promise<boolean> {
277
+ try {
278
+ const response = await client.get('/api/now/table/v_plugin', {
279
+ params: {
280
+ sysparm_query: 'sys_id=' + sysId,
281
+ sysparm_fields: 'active',
282
+ sysparm_limit: 1,
283
+ },
284
+ })
285
+ const results = response.data.result || []
286
+ if (results.length === 0) return false
287
+ const isActive = results[0].active === 'true' || results[0].active === true
288
+ return expectActive ? isActive : !isActive
289
+ } catch {
290
+ return false
291
+ }
292
+ }
293
+
294
+ export const version = '1.0.0'
295
+ export const author = 'Snow-Flow'
@@ -1,47 +0,0 @@
1
- /**
2
- * snow_activate_plugin
3
- */
4
-
5
- import { MCPToolDefinition, ServiceNowContext, ToolResult } from '../../shared/types.js';
6
- import { getAuthenticatedClient } from '../../shared/auth.js';
7
- import { createSuccessResult, createErrorResult } from '../../shared/error-handler.js';
8
-
9
- export const toolDefinition: MCPToolDefinition = {
10
- name: 'snow_activate_plugin',
11
- description: 'Activate ServiceNow plugin',
12
- // Metadata for tool discovery (not sent to LLM)
13
- category: 'advanced',
14
- subcategory: 'administration',
15
- use_cases: ['plugin-management', 'activation', 'configuration'],
16
- complexity: 'intermediate',
17
- frequency: 'low',
18
-
19
- // Permission enforcement
20
- // Classification: WRITE - Write operation based on name pattern
21
- permission: 'write',
22
- allowedRoles: ['developer', 'admin'],
23
- inputSchema: {
24
- type: 'object',
25
- properties: {
26
- plugin_id: { type: 'string', description: 'Plugin ID' }
27
- },
28
- required: ['plugin_id']
29
- }
30
- };
31
-
32
- export async function execute(args: any, context: ServiceNowContext): Promise<ToolResult> {
33
- const { plugin_id } = args;
34
- try {
35
- const client = await getAuthenticatedClient(context);
36
- const response = await client.post('/api/now/table/v_plugin', {
37
- id: plugin_id,
38
- active: true
39
- });
40
- return createSuccessResult({ activated: true, plugin: response.data.result });
41
- } catch (error: any) {
42
- return createErrorResult(error.message);
43
- }
44
- }
45
-
46
- export const version = '1.0.0';
47
- export const author = 'Snow-Flow SDK Migration';
@@ -1,46 +0,0 @@
1
- /**
2
- * snow_custom_plugin
3
- */
4
-
5
- import { MCPToolDefinition, ServiceNowContext, ToolResult } from '../../shared/types.js';
6
- import { createSuccessResult, createErrorResult } from '../../shared/error-handler.js';
7
-
8
- export const toolDefinition: MCPToolDefinition = {
9
- name: 'snow_custom_plugin',
10
- description: 'Execute custom plugin logic',
11
- // Metadata for tool discovery (not sent to LLM)
12
- category: 'advanced',
13
- subcategory: 'administration',
14
- use_cases: ['plugin-customization', 'extensions', 'custom-logic'],
15
- complexity: 'advanced',
16
- frequency: 'low',
17
-
18
- // Permission enforcement
19
- // Classification: WRITE - Plugin function - executes custom plugin which can modify data
20
- permission: 'write',
21
- allowedRoles: ['developer', 'admin'],
22
- inputSchema: {
23
- type: 'object',
24
- properties: {
25
- plugin_name: { type: 'string', description: 'Plugin name' },
26
- parameters: { type: 'object', description: 'Plugin parameters' }
27
- },
28
- required: ['plugin_name']
29
- }
30
- };
31
-
32
- export async function execute(args: any, context: ServiceNowContext): Promise<ToolResult> {
33
- const { plugin_name, parameters = {} } = args;
34
- try {
35
- return createSuccessResult({
36
- executed: true,
37
- plugin_name,
38
- parameters
39
- });
40
- } catch (error: any) {
41
- return createErrorResult(error.message);
42
- }
43
- }
44
-
45
- export const version = '1.0.0';
46
- export const author = 'Snow-Flow SDK Migration';
@@ -1,52 +0,0 @@
1
- /**
2
- * snow_list_plugins
3
- */
4
-
5
- import { MCPToolDefinition, ServiceNowContext, ToolResult } from '../../shared/types.js';
6
- import { getAuthenticatedClient } from '../../shared/auth.js';
7
- import { createSuccessResult, createErrorResult } from '../../shared/error-handler.js';
8
-
9
- export const toolDefinition: MCPToolDefinition = {
10
- name: 'snow_list_plugins',
11
- description: 'List installed plugins',
12
- // Metadata for tool discovery (not sent to LLM)
13
- category: 'advanced',
14
- subcategory: 'administration',
15
- use_cases: ['plugin-discovery', 'plugin-management', 'administration'],
16
- complexity: 'beginner',
17
- frequency: 'low',
18
-
19
- // Permission enforcement
20
- // Classification: READ - Read-only operation based on name pattern
21
- permission: 'read',
22
- allowedRoles: ['developer', 'stakeholder', 'admin'],
23
- inputSchema: {
24
- type: 'object',
25
- properties: {
26
- active_only: { type: 'boolean', default: false }
27
- }
28
- }
29
- };
30
-
31
- export async function execute(args: any, context: ServiceNowContext): Promise<ToolResult> {
32
- const { active_only = false } = args;
33
- try {
34
- const client = await getAuthenticatedClient(context);
35
- const query = active_only ? 'active=true' : '';
36
- const response = await client.get('/api/now/table/v_plugin', {
37
- params: {
38
- sysparm_query: query,
39
- sysparm_limit: 100
40
- }
41
- });
42
- return createSuccessResult({
43
- plugins: response.data.result,
44
- count: response.data.result.length
45
- });
46
- } catch (error: any) {
47
- return createErrorResult(error.message);
48
- }
49
- }
50
-
51
- export const version = '1.0.0';
52
- export const author = 'Snow-Flow SDK Migration';