snow-flow 3.3.2 → 3.3.4

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.
@@ -234,15 +234,60 @@ class ServiceNowDeploymentMCP {
234
234
  required: ['name', 'artifacts'],
235
235
  },
236
236
  },
237
+ {
238
+ name: 'snow_update',
239
+ description: 'Updates existing ServiceNow artifacts (widgets, applications, etc.). Finds artifact by name or sys_id and modifies it. Use snow_deploy for creating new artifacts.',
240
+ inputSchema: {
241
+ type: 'object',
242
+ properties: {
243
+ type: {
244
+ type: 'string',
245
+ enum: [
246
+ 'widget', 'application', 'business_rule', 'script_include', 'ui_page',
247
+ 'client_script', 'ui_action', 'ui_policy', 'acl', 'table', 'field',
248
+ 'workflow', 'flow', 'notification', 'scheduled_job'
249
+ ],
250
+ description: 'Type of artifact to update'
251
+ },
252
+ identifier: {
253
+ type: 'string',
254
+ description: 'sys_id or name of existing artifact to update'
255
+ },
256
+ config: {
257
+ type: 'object',
258
+ description: 'New configuration/content for the artifact'
259
+ },
260
+ instruction: {
261
+ type: 'string',
262
+ description: 'Natural language description of changes to make'
263
+ },
264
+ create_if_not_exists: {
265
+ type: 'boolean',
266
+ default: false,
267
+ description: 'Create artifact if it does not exist'
268
+ },
269
+ auto_update_set: {
270
+ type: 'boolean',
271
+ default: true,
272
+ description: 'Automatically manage update set'
273
+ }
274
+ },
275
+ required: ['type', 'identifier']
276
+ }
277
+ },
237
278
  {
238
279
  name: 'snow_deploy',
239
- description: 'Universal deployment tool for all ServiceNow artifacts. Features automatic update set management, permission escalation, retry logic, and comprehensive error recovery. Primary deployment method for v3.0.0+',
280
+ description: 'Universal deployment tool for creating NEW ServiceNow artifacts. For updating existing artifacts, use snow_update. Features automatic update set management, permission escalation, retry logic, and comprehensive error recovery.',
240
281
  inputSchema: {
241
282
  type: 'object',
242
283
  properties: {
243
284
  type: {
244
285
  type: 'string',
245
- enum: ['widget', 'portal_page', 'application', 'script', 'business_rule', 'table'],
286
+ enum: [
287
+ 'widget', 'portal_page', 'application', 'script', 'business_rule', 'table',
288
+ 'script_include', 'ui_page', 'client_script', 'ui_action', 'ui_policy',
289
+ 'acl', 'field', 'workflow', 'flow', 'notification', 'scheduled_job'
290
+ ],
246
291
  description: 'Type of artifact to deploy'
247
292
  },
248
293
  instruction: {
@@ -313,6 +358,8 @@ class ServiceNowDeploymentMCP {
313
358
  return await this.createSolutionPackage(args);
314
359
  case 'snow_deploy':
315
360
  return await this.unifiedDeploy(args);
361
+ case 'snow_update':
362
+ return await this.updateArtifact(args);
316
363
  default:
317
364
  throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
318
365
  }
@@ -8092,6 +8139,713 @@ ${updateSetSession ? `📋 **Update Set**: ${updateSetSession.name}
8092
8139
  throw new Error(`Update Set session required for deployment. Error: ${error.message}`);
8093
8140
  }
8094
8141
  }
8142
+ /**
8143
+ * Update existing ServiceNow artifact
8144
+ */
8145
+ async updateArtifact(args) {
8146
+ try {
8147
+ this.logger.info('Starting artifact update', args);
8148
+ // Check authentication first
8149
+ const isAuthenticated = await this.oauth.isAuthenticated();
8150
+ if (!isAuthenticated) {
8151
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, 'Not authenticated. Run "snow-flow auth login" first.');
8152
+ }
8153
+ const { type, identifier, config, instruction, create_if_not_exists = false, auto_update_set = true } = args;
8154
+ // Step 1: Ensure Update Set if requested
8155
+ let updateSetSession = null;
8156
+ if (auto_update_set) {
8157
+ try {
8158
+ const ensureResponse = await this.ensureActiveUpdateSet(`${type} update: ${identifier}`);
8159
+ updateSetSession = ensureResponse.session;
8160
+ }
8161
+ catch (error) {
8162
+ this.logger.warn('Failed to ensure Update Set, continuing without', error);
8163
+ }
8164
+ }
8165
+ // Step 2: Determine table name
8166
+ let tableName;
8167
+ switch (type) {
8168
+ case 'widget':
8169
+ tableName = 'sp_widget';
8170
+ break;
8171
+ case 'application':
8172
+ tableName = 'sys_app';
8173
+ break;
8174
+ case 'business_rule':
8175
+ tableName = 'sys_script';
8176
+ break;
8177
+ case 'script_include':
8178
+ tableName = 'sys_script_include';
8179
+ break;
8180
+ case 'ui_page':
8181
+ tableName = 'sys_ui_page';
8182
+ break;
8183
+ case 'client_script':
8184
+ tableName = 'sys_script_client';
8185
+ break;
8186
+ case 'ui_action':
8187
+ tableName = 'sys_ui_action';
8188
+ break;
8189
+ case 'ui_policy':
8190
+ tableName = 'sys_ui_policy';
8191
+ break;
8192
+ case 'acl':
8193
+ tableName = 'sys_security_acl';
8194
+ break;
8195
+ case 'table':
8196
+ tableName = 'sys_db_object';
8197
+ break;
8198
+ case 'field':
8199
+ tableName = 'sys_dictionary';
8200
+ break;
8201
+ case 'workflow':
8202
+ tableName = 'wf_workflow';
8203
+ break;
8204
+ case 'flow':
8205
+ tableName = 'sys_hub_flow';
8206
+ break;
8207
+ case 'notification':
8208
+ tableName = 'sysevent_email_action';
8209
+ break;
8210
+ case 'scheduled_job':
8211
+ tableName = 'sysauto_script';
8212
+ break;
8213
+ default:
8214
+ throw new Error(`Unsupported artifact type: ${type}`);
8215
+ }
8216
+ // Step 3: Find existing artifact
8217
+ let existingArtifact = null;
8218
+ let searchQuery = '';
8219
+ // Check if identifier is a sys_id (32 char hex) or a name
8220
+ const isSysId = /^[a-f0-9]{32}$/.test(identifier);
8221
+ if (isSysId) {
8222
+ searchQuery = `sys_id=${identifier}`;
8223
+ }
8224
+ else {
8225
+ searchQuery = `name=${identifier}`;
8226
+ }
8227
+ this.logger.info(`Searching for ${type} with query: ${searchQuery}`);
8228
+ try {
8229
+ const searchResponse = await this.client.searchRecords(tableName, searchQuery, 1);
8230
+ if (searchResponse?.data?.result?.length > 0) {
8231
+ existingArtifact = searchResponse.data.result[0];
8232
+ this.logger.info(`Found existing ${type}: ${existingArtifact.sys_id}`);
8233
+ }
8234
+ }
8235
+ catch (searchError) {
8236
+ this.logger.error(`Failed to search for ${type}:`, searchError);
8237
+ }
8238
+ // Step 4: Handle artifact not found
8239
+ if (!existingArtifact) {
8240
+ if (create_if_not_exists) {
8241
+ this.logger.info(`${type} not found, creating new one as requested`);
8242
+ // Delegate to snow_deploy for creation
8243
+ return await this.unifiedDeploy({
8244
+ type,
8245
+ config,
8246
+ instruction,
8247
+ auto_update_set
8248
+ });
8249
+ }
8250
+ else {
8251
+ return {
8252
+ content: [{
8253
+ type: 'text',
8254
+ text: `❌ ${type} not found: "${identifier}"
8255
+
8256
+ 🔍 **Search Details:**
8257
+ - Table: ${tableName}
8258
+ - Search Query: ${searchQuery}
8259
+ - Results: 0
8260
+
8261
+ 💡 **Suggestions:**
8262
+ 1. Check the ${isSysId ? 'sys_id' : 'name'} is correct
8263
+ 2. Verify you have read permissions for ${tableName}
8264
+ 3. Use exact ${isSysId ? 'sys_id format (32 char hex)' : 'name (case sensitive)'}
8265
+ 4. Add create_if_not_exists: true to create if missing
8266
+
8267
+ 🔧 **Alternative Commands:**
8268
+ - List existing: \`snow_query_table({ table: "${tableName}", limit: 10 })\`
8269
+ - Create new: \`snow_deploy({ type: "${type}", ... })\`
8270
+ - Find by name: \`snow_update({ type: "${type}", identifier: "exact_name" })\``
8271
+ }]
8272
+ };
8273
+ }
8274
+ }
8275
+ // Step 5: Process update configuration
8276
+ let updateData = {};
8277
+ if (instruction) {
8278
+ // Natural language instruction - convert to specific updates
8279
+ updateData = await this.processUpdateInstruction(type, instruction, existingArtifact);
8280
+ }
8281
+ else if (config) {
8282
+ updateData = config;
8283
+ }
8284
+ else {
8285
+ throw new Error('Either instruction or config must be provided for update');
8286
+ }
8287
+ // Step 6: Perform the update
8288
+ this.logger.info(`Updating ${type} ${existingArtifact.sys_id}`, updateData);
8289
+ const updateResponse = await this.client.updateRecord(tableName, existingArtifact.sys_id, updateData);
8290
+ if (!updateResponse?.success) {
8291
+ throw new Error(`Failed to update ${type}: ${updateResponse?.error || 'Unknown error'}`);
8292
+ }
8293
+ // Step 7: Track the update
8294
+ if (updateSetSession) {
8295
+ artifact_tracker_js_1.artifactTracker.trackArtifact(existingArtifact.sys_id, tableName, existingArtifact.name, type, 'update');
8296
+ }
8297
+ // Step 8: Return success response
8298
+ const updatedFields = Object.keys(updateData);
8299
+ return {
8300
+ content: [{
8301
+ type: 'text',
8302
+ text: `✅ ${type} updated successfully!
8303
+
8304
+ 📝 **Updated Artifact:**
8305
+ - Name: ${existingArtifact.name}
8306
+ - sys_id: ${existingArtifact.sys_id}
8307
+ - Table: ${tableName}
8308
+
8309
+ 🔧 **Fields Updated:**
8310
+ ${updatedFields.map(field => `- ${field}`).join('\n')}
8311
+
8312
+ ${updateSetSession ? `📦 **Update Set:**
8313
+ - Name: ${updateSetSession.name}
8314
+ - sys_id: ${updateSetSession.update_set_id}
8315
+ - Ready for promotion to higher environments` : '🔄 Changes made outside Update Set - track manually'}
8316
+
8317
+ 💡 **Next Steps:**
8318
+ 1. Test the updated ${type} in your environment
8319
+ 2. ${updateSetSession ? 'Preview and commit Update Set when ready' : 'Create Update Set to track changes'}
8320
+ 3. Promote to production after validation
8321
+
8322
+ 🔗 **ServiceNow Links:**
8323
+ - View artifact: /nav_to.do?uri=${tableName}.do?sys_id=${existingArtifact.sys_id}
8324
+ ${updateSetSession ? `- View Update Set: /nav_to.do?uri=sys_update_set.do?sys_id=${updateSetSession.update_set_id}` : ''}`
8325
+ }]
8326
+ };
8327
+ }
8328
+ catch (error) {
8329
+ this.logger.error('Artifact update failed:', error);
8330
+ return {
8331
+ content: [{
8332
+ type: 'text',
8333
+ text: `❌ Failed to update ${args.type}: ${error.message}
8334
+
8335
+ 🔍 **Troubleshooting:**
8336
+ 1. Verify the artifact exists: \`snow_query_table({ table: "${this.getTableName(args.type)}", query: "name=${args.identifier}" })\`
8337
+ 2. Check permissions for ${this.getTableName(args.type)} table
8338
+ 3. Ensure Update Set is active (if required)
8339
+ 4. Try with create_if_not_exists: true if artifact might not exist
8340
+
8341
+ 💡 **Alternative:**
8342
+ Use \`snow_deploy\` to create a new ${args.type} instead.`
8343
+ }]
8344
+ };
8345
+ }
8346
+ }
8347
+ /**
8348
+ * Process natural language instruction for updates
8349
+ */
8350
+ /**
8351
+ * Intelligent Natural Language Processing for ServiceNow artifact updates
8352
+ * Converts natural language instructions into valid ServiceNow field updates
8353
+ */
8354
+ async processUpdateInstruction(type, instruction, existingArtifact) {
8355
+ const updateData = {};
8356
+ const lowerInstruction = instruction.toLowerCase().trim();
8357
+ this.logger.info(`Processing update instruction for ${type}`, { instruction });
8358
+ try {
8359
+ // First, extract any code blocks or explicit values
8360
+ const codeBlocks = this.extractCodeBlocks(instruction);
8361
+ const explicitValues = this.extractExplicitValues(instruction);
8362
+ // Apply type-specific intelligent parsing
8363
+ switch (type) {
8364
+ case 'widget':
8365
+ await this.parseWidgetInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8366
+ break;
8367
+ case 'business_rule':
8368
+ case 'client_script':
8369
+ case 'script_include':
8370
+ await this.parseScriptInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8371
+ break;
8372
+ case 'ui_action':
8373
+ await this.parseUIActionInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8374
+ break;
8375
+ case 'ui_policy':
8376
+ await this.parseUIPolicyInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8377
+ break;
8378
+ case 'notification':
8379
+ await this.parseNotificationInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8380
+ break;
8381
+ case 'acl':
8382
+ await this.parseACLInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8383
+ break;
8384
+ case 'table':
8385
+ await this.parseTableInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8386
+ break;
8387
+ case 'field':
8388
+ await this.parseFieldInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8389
+ break;
8390
+ case 'workflow':
8391
+ await this.parseWorkflowInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8392
+ break;
8393
+ case 'flow':
8394
+ await this.parseFlowInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8395
+ break;
8396
+ case 'scheduled_job':
8397
+ await this.parseScheduledJobInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8398
+ break;
8399
+ default:
8400
+ // Generic parsing for unsupported types
8401
+ await this.parseGenericInstruction(updateData, lowerInstruction, codeBlocks, explicitValues, existingArtifact);
8402
+ }
8403
+ // Apply common field updates
8404
+ this.applyCommonUpdates(updateData, lowerInstruction, explicitValues);
8405
+ // Validate that we have valid updates
8406
+ if (Object.keys(updateData).length === 0) {
8407
+ throw new Error(`Unable to parse instruction: "${instruction}". Please use more specific language or provide explicit field values.
8408
+
8409
+ 📝 **Examples that work:**
8410
+ - "Change the title to 'New Widget Title'"
8411
+ - "Update the description to 'Updated description'"
8412
+ - "Add this CSS: .my-class { color: blue; }"
8413
+ - "Change the script to: function() { console.log('updated'); }"
8414
+ - "Set active to false"
8415
+
8416
+ 💡 **Or use the config parameter directly:**
8417
+ snow_update({
8418
+ type: "${type}",
8419
+ identifier: "${existingArtifact?.name || 'artifact_name'}",
8420
+ config: {
8421
+ field_name: "new_value"
8422
+ }
8423
+ })`);
8424
+ }
8425
+ this.logger.info(`Parsed ${Object.keys(updateData).length} field updates`, { updateData });
8426
+ return updateData;
8427
+ }
8428
+ catch (error) {
8429
+ this.logger.error('Failed to process update instruction', { error: error instanceof Error ? error.message : error });
8430
+ throw error;
8431
+ }
8432
+ }
8433
+ /**
8434
+ * Extract code blocks from instruction text
8435
+ */
8436
+ extractCodeBlocks(instruction) {
8437
+ const codeBlocks = {};
8438
+ // Extract different types of code blocks
8439
+ const htmlMatch = instruction.match(/```html\s*\n([\s\S]*?)\n```/i);
8440
+ if (htmlMatch)
8441
+ codeBlocks.html = htmlMatch[1].trim();
8442
+ const cssMatch = instruction.match(/```css\s*\n([\s\S]*?)\n```/i);
8443
+ if (cssMatch)
8444
+ codeBlocks.css = cssMatch[1].trim();
8445
+ const jsMatch = instruction.match(/```javascript\s*\n([\s\S]*?)\n```/i);
8446
+ if (jsMatch)
8447
+ codeBlocks.javascript = jsMatch[1].trim();
8448
+ const jsonMatch = instruction.match(/```json\s*\n([\s\S]*?)\n```/i);
8449
+ if (jsonMatch) {
8450
+ try {
8451
+ codeBlocks.json = JSON.parse(jsonMatch[1].trim());
8452
+ }
8453
+ catch (e) {
8454
+ codeBlocks.json = jsonMatch[1].trim();
8455
+ }
8456
+ }
8457
+ return codeBlocks;
8458
+ }
8459
+ /**
8460
+ * Extract explicit field values from instruction
8461
+ */
8462
+ extractExplicitValues(instruction) {
8463
+ const values = {};
8464
+ // Common patterns for explicit values
8465
+ const patterns = [
8466
+ { regex: /title[:\s]+["']([^"']+)["']/i, field: 'title' },
8467
+ { regex: /name[:\s]+["']([^"']+)["']/i, field: 'name' },
8468
+ { regex: /description[:\s]+["']([^"']+)["']/i, field: 'description' },
8469
+ { regex: /subject[:\s]+["']([^"']+)["']/i, field: 'subject' },
8470
+ { regex: /label[:\s]+["']([^"']+)["']/i, field: 'label' },
8471
+ { regex: /condition[:\s]+["']([^"']+)["']/i, field: 'condition' },
8472
+ { regex: /script[:\s]+["']([^"']+)["']/i, field: 'script' },
8473
+ { regex: /active[:\s]+(\w+)/i, field: 'active', transform: (v) => v.toLowerCase() === 'true' },
8474
+ { regex: /priority[:\s]+(\d+)/i, field: 'priority', transform: (v) => parseInt(v) },
8475
+ { regex: /order[:\s]+(\d+)/i, field: 'order', transform: (v) => parseInt(v) }
8476
+ ];
8477
+ for (const pattern of patterns) {
8478
+ const match = instruction.match(pattern.regex);
8479
+ if (match) {
8480
+ values[pattern.field] = pattern.transform ? pattern.transform(match[1]) : match[1];
8481
+ }
8482
+ }
8483
+ return values;
8484
+ }
8485
+ /**
8486
+ * Parse widget-specific instructions
8487
+ */
8488
+ async parseWidgetInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8489
+ // Handle code blocks
8490
+ if (codeBlocks.html)
8491
+ updateData.template = codeBlocks.html;
8492
+ if (codeBlocks.css)
8493
+ updateData.css = codeBlocks.css;
8494
+ if (codeBlocks.javascript)
8495
+ updateData.script = codeBlocks.javascript;
8496
+ // Handle semantic instructions for widgets
8497
+ if (instruction.includes('add') && instruction.includes('chart')) {
8498
+ // User wants to add a chart - enhance existing template
8499
+ if (existingArtifact?.template) {
8500
+ const currentTemplate = existingArtifact.template || '';
8501
+ if (!currentTemplate.includes('canvas') && !currentTemplate.includes('chart')) {
8502
+ updateData.template = currentTemplate + '\n<div class="chart-container">\n <canvas id="widget-chart"></canvas>\n</div>';
8503
+ }
8504
+ }
8505
+ // Add chart CSS if not present
8506
+ if (existingArtifact?.css && !existingArtifact.css.includes('chart-container')) {
8507
+ updateData.css = (existingArtifact.css || '') + '\n\n.chart-container {\n margin: 20px 0;\n height: 300px;\n}\n\ncanvas {\n width: 100% !important;\n height: 100% !important;\n}';
8508
+ }
8509
+ // Add chart script if not present
8510
+ if (existingArtifact?.script && !existingArtifact.script.includes('Chart')) {
8511
+ const chartScript = `
8512
+ // Chart functionality added
8513
+ c.initChart = function() {
8514
+ if (typeof Chart !== 'undefined' && document.getElementById('widget-chart')) {
8515
+ var ctx = document.getElementById('widget-chart').getContext('2d');
8516
+ c.chart = new Chart(ctx, {
8517
+ type: 'bar',
8518
+ data: c.data.chartData || { labels: [], datasets: [] },
8519
+ options: { responsive: true, maintainAspectRatio: false }
8520
+ });
8521
+ }
8522
+ };
8523
+
8524
+ // Add to existing onInit
8525
+ var originalInit = c.$onInit;
8526
+ c.$onInit = function() {
8527
+ if (originalInit) originalInit();
8528
+ c.initChart();
8529
+ };`;
8530
+ updateData.script = (existingArtifact.script || '') + chartScript;
8531
+ }
8532
+ }
8533
+ // Handle title/name changes
8534
+ if (instruction.includes('change') && instruction.includes('title')) {
8535
+ const titleMatch = instruction.match(/title[:\s]+["']([^"']+)["']/i) ||
8536
+ instruction.match(/to\s+["']([^"']+)["']/i);
8537
+ if (titleMatch)
8538
+ updateData.title = titleMatch[1];
8539
+ }
8540
+ // Handle style updates
8541
+ if (instruction.includes('style') || instruction.includes('css')) {
8542
+ if (!codeBlocks.css) {
8543
+ // Generate basic style updates based on instruction
8544
+ if (instruction.includes('color')) {
8545
+ const colorMatch = instruction.match(/color[:\s]+(\w+|#[a-fA-F0-9]{6}|#[a-fA-F0-9]{3})/i);
8546
+ if (colorMatch) {
8547
+ updateData.css = (existingArtifact?.css || '') + `\n\n.widget-content { color: ${colorMatch[1]}; }`;
8548
+ }
8549
+ }
8550
+ }
8551
+ }
8552
+ // Apply explicit values
8553
+ Object.assign(updateData, explicitValues);
8554
+ }
8555
+ /**
8556
+ * Parse script-based artifact instructions (business_rule, script_include, client_script)
8557
+ */
8558
+ async parseScriptInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8559
+ if (codeBlocks.javascript) {
8560
+ updateData.script = codeBlocks.javascript;
8561
+ }
8562
+ // Handle condition updates
8563
+ if (instruction.includes('condition') && !codeBlocks.javascript) {
8564
+ const conditionMatch = instruction.match(/condition[:\s]+["']([^"']+)["']/i);
8565
+ if (conditionMatch)
8566
+ updateData.condition = conditionMatch[1];
8567
+ }
8568
+ // Handle when/trigger changes for business rules
8569
+ if (instruction.includes('when') || instruction.includes('trigger')) {
8570
+ const whenOptions = ['before', 'after', 'async', 'display'];
8571
+ for (const option of whenOptions) {
8572
+ if (instruction.includes(option)) {
8573
+ updateData.when = option;
8574
+ break;
8575
+ }
8576
+ }
8577
+ }
8578
+ // Handle table changes
8579
+ if (instruction.includes('table')) {
8580
+ const tableMatch = instruction.match(/table[:\s]+["']?([a-z_]+)["']?/i);
8581
+ if (tableMatch)
8582
+ updateData.table = tableMatch[1];
8583
+ }
8584
+ Object.assign(updateData, explicitValues);
8585
+ }
8586
+ /**
8587
+ * Parse UI Action instructions
8588
+ */
8589
+ async parseUIActionInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8590
+ if (codeBlocks.javascript) {
8591
+ updateData.script = codeBlocks.javascript;
8592
+ }
8593
+ // Handle label/action name changes
8594
+ if (instruction.includes('label') || instruction.includes('button') || instruction.includes('action name')) {
8595
+ const labelMatch = instruction.match(/(?:label|button|action name)[:\s]+["']([^"']+)["']/i);
8596
+ if (labelMatch)
8597
+ updateData.action_name = labelMatch[1];
8598
+ }
8599
+ // Handle condition changes
8600
+ if (instruction.includes('condition')) {
8601
+ const conditionMatch = instruction.match(/condition[:\s]+["']([^"']+)["']/i);
8602
+ if (conditionMatch)
8603
+ updateData.condition = conditionMatch[1];
8604
+ }
8605
+ Object.assign(updateData, explicitValues);
8606
+ }
8607
+ /**
8608
+ * Parse UI Policy instructions
8609
+ */
8610
+ async parseUIPolicyInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8611
+ if (codeBlocks.javascript) {
8612
+ updateData.script_true = codeBlocks.javascript;
8613
+ }
8614
+ if (instruction.includes('condition')) {
8615
+ const conditionMatch = instruction.match(/condition[:\s]+["']([^"']+)["']/i);
8616
+ if (conditionMatch)
8617
+ updateData.conditions = conditionMatch[1];
8618
+ }
8619
+ Object.assign(updateData, explicitValues);
8620
+ }
8621
+ /**
8622
+ * Parse notification instructions
8623
+ */
8624
+ async parseNotificationInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8625
+ if (codeBlocks.html) {
8626
+ updateData.message_html = codeBlocks.html;
8627
+ }
8628
+ // Handle subject changes
8629
+ if (instruction.includes('subject')) {
8630
+ const subjectMatch = instruction.match(/subject[:\s]+["']([^"']+)["']/i);
8631
+ if (subjectMatch)
8632
+ updateData.subject = subjectMatch[1];
8633
+ }
8634
+ // Handle body/message changes
8635
+ if (instruction.includes('body') || instruction.includes('message')) {
8636
+ if (!codeBlocks.html) {
8637
+ const messageMatch = instruction.match(/(?:body|message)[:\s]+["']([^"']+)["']/i);
8638
+ if (messageMatch)
8639
+ updateData.message_html = messageMatch[1];
8640
+ }
8641
+ }
8642
+ // Handle recipient changes
8643
+ if (instruction.includes('recipient') || instruction.includes('to')) {
8644
+ const recipientMatch = instruction.match(/(?:recipient|to)[:\s]+["']([^"']+)["']/i);
8645
+ if (recipientMatch)
8646
+ updateData.recipient = recipientMatch[1];
8647
+ }
8648
+ Object.assign(updateData, explicitValues);
8649
+ }
8650
+ /**
8651
+ * Parse ACL instructions
8652
+ */
8653
+ async parseACLInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8654
+ if (codeBlocks.javascript) {
8655
+ updateData.script = codeBlocks.javascript;
8656
+ }
8657
+ // Handle operation changes
8658
+ const operations = ['read', 'write', 'create', 'delete', 'execute'];
8659
+ for (const op of operations) {
8660
+ if (instruction.includes(op)) {
8661
+ updateData.operation = op;
8662
+ break;
8663
+ }
8664
+ }
8665
+ // Handle role changes
8666
+ if (instruction.includes('role')) {
8667
+ const roleMatch = instruction.match(/role[:\s]+["']([^"']+)["']/i);
8668
+ if (roleMatch)
8669
+ updateData.role = roleMatch[1];
8670
+ }
8671
+ Object.assign(updateData, explicitValues);
8672
+ }
8673
+ /**
8674
+ * Parse table instructions
8675
+ */
8676
+ async parseTableInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8677
+ if (instruction.includes('label')) {
8678
+ const labelMatch = instruction.match(/label[:\s]+["']([^"']+)["']/i);
8679
+ if (labelMatch)
8680
+ updateData.label = labelMatch[1];
8681
+ }
8682
+ if (instruction.includes('access')) {
8683
+ const accessMatch = instruction.match(/access[:\s]+["']([^"']+)["']/i);
8684
+ if (accessMatch)
8685
+ updateData.access = accessMatch[1];
8686
+ }
8687
+ Object.assign(updateData, explicitValues);
8688
+ }
8689
+ /**
8690
+ * Parse field instructions
8691
+ */
8692
+ async parseFieldInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8693
+ if (instruction.includes('label')) {
8694
+ const labelMatch = instruction.match(/label[:\s]+["']([^"']+)["']/i);
8695
+ if (labelMatch)
8696
+ updateData.column_label = labelMatch[1];
8697
+ }
8698
+ if (instruction.includes('type')) {
8699
+ const typeMatch = instruction.match(/type[:\s]+["']([^"']+)["']/i);
8700
+ if (typeMatch)
8701
+ updateData.internal_type = typeMatch[1];
8702
+ }
8703
+ // Handle mandatory/required changes
8704
+ if (instruction.includes('mandatory') || instruction.includes('required')) {
8705
+ if (instruction.includes('make mandatory') || instruction.includes('make required')) {
8706
+ updateData.mandatory = true;
8707
+ }
8708
+ else if (instruction.includes('remove mandatory') || instruction.includes('optional')) {
8709
+ updateData.mandatory = false;
8710
+ }
8711
+ }
8712
+ Object.assign(updateData, explicitValues);
8713
+ }
8714
+ /**
8715
+ * Parse workflow instructions
8716
+ */
8717
+ async parseWorkflowInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8718
+ if (instruction.includes('description')) {
8719
+ const descMatch = instruction.match(/description[:\s]+["']([^"']+)["']/i);
8720
+ if (descMatch)
8721
+ updateData.description = descMatch[1];
8722
+ }
8723
+ Object.assign(updateData, explicitValues);
8724
+ }
8725
+ /**
8726
+ * Parse flow instructions
8727
+ */
8728
+ async parseFlowInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8729
+ if (instruction.includes('description')) {
8730
+ const descMatch = instruction.match(/description[:\s]+["']([^"']+)["']/i);
8731
+ if (descMatch)
8732
+ updateData.description = descMatch[1];
8733
+ }
8734
+ if (instruction.includes('trigger')) {
8735
+ const triggerMatch = instruction.match(/trigger[:\s]+["']([^"']+)["']/i);
8736
+ if (triggerMatch)
8737
+ updateData.trigger = triggerMatch[1];
8738
+ }
8739
+ Object.assign(updateData, explicitValues);
8740
+ }
8741
+ /**
8742
+ * Parse scheduled job instructions
8743
+ */
8744
+ async parseScheduledJobInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8745
+ if (codeBlocks.javascript) {
8746
+ updateData.script = codeBlocks.javascript;
8747
+ }
8748
+ if (instruction.includes('schedule') || instruction.includes('cron')) {
8749
+ const scheduleMatch = instruction.match(/(?:schedule|cron)[:\s]+["']([^"']+)["']/i);
8750
+ if (scheduleMatch) {
8751
+ updateData.run_type = 'Periodically';
8752
+ updateData.run_period = scheduleMatch[1];
8753
+ }
8754
+ // Handle time-based schedules
8755
+ if (instruction.includes('hour')) {
8756
+ const hourMatch = instruction.match(/(\d+)\s*hour/i);
8757
+ if (hourMatch) {
8758
+ updateData.run_type = 'Periodically';
8759
+ updateData.run_period = `0 0 */${hourMatch[1]} * * *`;
8760
+ }
8761
+ }
8762
+ if (instruction.includes('daily')) {
8763
+ updateData.run_type = 'Periodically';
8764
+ updateData.run_period = '0 0 0 * * *'; // Daily at midnight
8765
+ }
8766
+ if (instruction.includes('weekly')) {
8767
+ updateData.run_type = 'Periodically';
8768
+ updateData.run_period = '0 0 0 * * 0'; // Weekly on Sunday
8769
+ }
8770
+ }
8771
+ Object.assign(updateData, explicitValues);
8772
+ }
8773
+ /**
8774
+ * Generic parsing for unsupported types
8775
+ */
8776
+ async parseGenericInstruction(updateData, instruction, codeBlocks, explicitValues, existingArtifact) {
8777
+ // Apply only explicit values for unsupported types
8778
+ Object.assign(updateData, explicitValues);
8779
+ // Handle common script field
8780
+ if (codeBlocks.javascript && !updateData.script) {
8781
+ updateData.script = codeBlocks.javascript;
8782
+ }
8783
+ }
8784
+ /**
8785
+ * Apply common field updates across all artifact types
8786
+ */
8787
+ applyCommonUpdates(updateData, instruction, explicitValues) {
8788
+ // Handle active/inactive states
8789
+ if (instruction.includes('activate') || instruction.includes('enable')) {
8790
+ updateData.active = true;
8791
+ }
8792
+ else if (instruction.includes('deactivate') || instruction.includes('disable')) {
8793
+ updateData.active = false;
8794
+ }
8795
+ // Handle description updates (various field names)
8796
+ if (instruction.includes('description') && !updateData.description && !updateData.short_description) {
8797
+ const descMatch = instruction.match(/description[:\s]+["']([^"']+)["']/i);
8798
+ if (descMatch) {
8799
+ // Use appropriate description field based on common patterns
8800
+ updateData.short_description = descMatch[1];
8801
+ }
8802
+ }
8803
+ // Handle name updates
8804
+ if (instruction.includes('name') && instruction.includes('change')) {
8805
+ const nameMatch = instruction.match(/name[:\s]+["']([^"']+)["']/i);
8806
+ if (nameMatch)
8807
+ updateData.name = nameMatch[1];
8808
+ }
8809
+ }
8810
+ /**
8811
+ * Get table name for artifact type
8812
+ */
8813
+ getTableName(type) {
8814
+ switch (type) {
8815
+ case 'widget':
8816
+ return 'sp_widget';
8817
+ case 'application':
8818
+ return 'sys_app';
8819
+ case 'business_rule':
8820
+ return 'sys_script';
8821
+ case 'script_include':
8822
+ return 'sys_script_include';
8823
+ case 'ui_page':
8824
+ return 'sys_ui_page';
8825
+ case 'client_script':
8826
+ return 'sys_script_client';
8827
+ case 'ui_action':
8828
+ return 'sys_ui_action';
8829
+ case 'ui_policy':
8830
+ return 'sys_ui_policy';
8831
+ case 'acl':
8832
+ return 'sys_security_acl';
8833
+ case 'table':
8834
+ return 'sys_db_object';
8835
+ case 'field':
8836
+ return 'sys_dictionary';
8837
+ case 'workflow':
8838
+ return 'wf_workflow';
8839
+ case 'flow':
8840
+ return 'sys_hub_flow';
8841
+ case 'notification':
8842
+ return 'sysevent_email_action';
8843
+ case 'scheduled_job':
8844
+ return 'sysauto_script';
8845
+ default:
8846
+ return 'sys_metadata';
8847
+ }
8848
+ }
8095
8849
  async start() {
8096
8850
  const transport = new stdio_js_1.StdioServerTransport();
8097
8851
  await this.server.connect(transport);