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.
- package/README.md +84 -7
- package/dist/cli-new-prompt.d.ts +2 -0
- package/dist/cli-new-prompt.js +420 -0
- package/dist/cli.js +119 -887
- package/dist/dynamic-version.js +1 -1
- package/dist/mcp/servicenow-deployment-mcp.js +756 -2
- package/dist/queen/servicenow-queen.d.ts +1 -45
- package/dist/queen/servicenow-queen.js +615 -566
- package/package.json +2 -2
- package/src/cli.ts.backup-20250809-125529 +4773 -0
|
@@ -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
|
|
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: [
|
|
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);
|