snow-flow 10.0.1-dev.401 → 10.0.1-dev.403

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.1-dev.401",
3
+ "version": "10.0.1-dev.403",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -4,10 +4,10 @@
4
4
  * Create, list, get, update, activate, deactivate, delete and publish
5
5
  * Flow Designer flows and subflows.
6
6
  *
7
- * For create/create_subflow: uses a bootstrapped Scripted REST API
8
- * ("Flow Factory") that runs GlideRecord server-side, ensuring
9
- * sys_hub_flow_version records are created and all Business Rules fire.
10
- * Falls back to Table API if the factory is unavailable.
7
+ * For create/create_subflow: uses a Scheduled Job (sysauto_script) that
8
+ * runs GlideRecord server-side, ensuring sys_hub_flow_version records are
9
+ * created, flow_definition is set, and sn_fd engine registration is
10
+ * attempted. Falls back to Table API if the scheduled job fails.
11
11
  *
12
12
  * All other actions (list, get, update, activate, etc.) use the Table API.
13
13
  */
@@ -59,6 +59,13 @@ async function createFlowViaScheduledJob(
59
59
  category: string;
60
60
  runAs: string;
61
61
  shouldActivate: boolean;
62
+ triggerType?: string;
63
+ triggerTable?: string;
64
+ triggerCondition?: string;
65
+ activities?: Array<{ name: string; type?: string; inputs?: any }>;
66
+ inputs?: Array<{ name: string; label?: string; type?: string; mandatory?: boolean; default_value?: string }>;
67
+ outputs?: Array<{ name: string; label?: string; type?: string }>;
68
+ flowDefinition?: any;
62
69
  }
63
70
  ): Promise<{
64
71
  success: boolean;
@@ -71,6 +78,7 @@ async function createFlowViaScheduledJob(
71
78
  error?: string;
72
79
  }> {
73
80
  var resultPropName = 'snow_flow.factory_result.' + Date.now();
81
+ var flowDefStr = params.flowDefinition ? JSON.stringify(params.flowDefinition) : '';
74
82
 
75
83
  // Build the server-side ES5 script
76
84
  var script = [
@@ -85,9 +93,20 @@ async function createFlowViaScheduledJob(
85
93
  " var flowCat = '" + escForScript(params.category) + "';",
86
94
  " var runAs = '" + escForScript(params.runAs) + "';",
87
95
  " var activate = " + (params.shouldActivate ? "true" : "false") + ";",
96
+ " var trigType = '" + escForScript(params.triggerType || 'manual') + "';",
97
+ " var trigTable = '" + escForScript(params.triggerTable || '') + "';",
98
+ " var trigCondition = '" + escForScript(params.triggerCondition || '') + "';",
99
+ " var flowDefStr = '" + escForScript(flowDefStr) + "';",
100
+ " var activitiesJson = '" + escForScript(JSON.stringify(params.activities || [])) + "';",
101
+ " var inputsJson = '" + escForScript(JSON.stringify(params.inputs || [])) + "';",
102
+ " var outputsJson = '" + escForScript(JSON.stringify(params.outputs || [])) + "';",
103
+ " var activities = []; try { activities = JSON.parse(activitiesJson); } catch(e) {}",
104
+ " var inputs = []; try { inputs = JSON.parse(inputsJson); } catch(e) {}",
105
+ " var outputs = []; try { outputs = JSON.parse(outputsJson); } catch(e) {}",
88
106
  " var flowSysId = null;",
89
107
  " var verSysId = null;",
90
108
  "",
109
+ // ── TIER 1: sn_fd.FlowDesigner API ──
91
110
  " try {",
92
111
  " if (typeof sn_fd !== 'undefined' && sn_fd.FlowDesigner && typeof sn_fd.FlowDesigner.createFlow === 'function') {",
93
112
  " var fdR = sn_fd.FlowDesigner.createFlow({ name: flowName, description: flowDesc, type: isSubflow ? 'subflow' : 'flow', category: flowCat, run_as: runAs });",
@@ -104,6 +123,7 @@ async function createFlowViaScheduledJob(
104
123
  " }",
105
124
  " } catch(t1e) { r.steps.tier1 = { success: false, error: t1e.getMessage ? t1e.getMessage() : t1e + '' }; }",
106
125
  "",
126
+ // ── TIER 2: GlideRecord with flow_definition ──
107
127
  " if (!flowSysId) {",
108
128
  " try {",
109
129
  " var f = new GlideRecord('sys_hub_flow');",
@@ -113,6 +133,7 @@ async function createFlowViaScheduledJob(
113
133
  " f.setValue('run_as', runAs); f.setValue('active', false);",
114
134
  " f.setValue('status', 'draft'); f.setValue('validated', true);",
115
135
  " f.setValue('type', isSubflow ? 'subflow' : 'flow');",
136
+ " if (flowDefStr) { f.setValue('flow_definition', flowDefStr); f.setValue('latest_snapshot', flowDefStr); }",
116
137
  " flowSysId = f.insert();",
117
138
  " r.steps.flow_insert = { success: !!flowSysId, sys_id: flowSysId + '' };",
118
139
  " if (flowSysId) {",
@@ -122,6 +143,7 @@ async function createFlowViaScheduledJob(
122
143
  " v.setValue('version', '1.0'); v.setValue('state', 'draft');",
123
144
  " v.setValue('active', true); v.setValue('compile_state', 'draft');",
124
145
  " v.setValue('is_current', true);",
146
+ " if (flowDefStr) v.setValue('flow_definition', flowDefStr);",
125
147
  " verSysId = v.insert();",
126
148
  " r.steps.version_insert = { success: !!verSysId, sys_id: verSysId + '' };",
127
149
  " if (verSysId) {",
@@ -141,8 +163,117 @@ async function createFlowViaScheduledJob(
141
163
  " } catch(t2e) { r.steps.tier2 = { success: false, error: t2e.getMessage ? t2e.getMessage() : t2e + '' }; }",
142
164
  " }",
143
165
  "",
166
+ // ── Trigger, action, variable creation (runs for any tier) ──
167
+ " if (flowSysId) {",
168
+ // Trigger
169
+ " if (!isSubflow && trigType !== 'manual') {",
170
+ " try {",
171
+ " var triggerMap = { 'record_created': 'sn_fd.trigger.record_created', 'record_updated': 'sn_fd.trigger.record_updated', 'scheduled': 'sn_fd.trigger.scheduled' };",
172
+ " var trigIntName = triggerMap[trigType] || '';",
173
+ " if (trigIntName) {",
174
+ " var trigDef = new GlideRecord('sys_hub_action_type_definition');",
175
+ " trigDef.addQuery('internal_name', trigIntName); trigDef.query();",
176
+ " if (trigDef.next()) {",
177
+ " var trigInst = new GlideRecord('sys_hub_trigger_instance');",
178
+ " trigInst.initialize();",
179
+ " trigInst.setValue('flow', flowSysId); trigInst.setValue('action_type', trigDef.getUniqueValue());",
180
+ " trigInst.setValue('name', trigType); trigInst.setValue('order', 0); trigInst.setValue('active', true);",
181
+ " if (trigTable) trigInst.setValue('table', trigTable);",
182
+ " if (trigCondition) trigInst.setValue('condition', trigCondition);",
183
+ " var trigId = trigInst.insert();",
184
+ " r.steps.trigger = { success: !!trigId, sys_id: trigId + '' };",
185
+ " } else { r.steps.trigger = { success: false, error: 'Trigger def not found: ' + trigIntName }; }",
186
+ " }",
187
+ " } catch(te) { r.steps.trigger = { success: false, error: te.getMessage ? te.getMessage() : te + '' }; }",
188
+ " }",
189
+ // Actions
190
+ " var actionsCreated = 0;",
191
+ " for (var ai = 0; ai < activities.length; ai++) {",
192
+ " try {",
193
+ " var act = activities[ai];",
194
+ " var actDef = new GlideRecord('sys_hub_action_type_definition');",
195
+ " actDef.addQuery('internal_name', 'CONTAINS', act.type || 'script');",
196
+ " actDef.addOrCondition('name', 'CONTAINS', act.type || 'script'); actDef.query();",
197
+ " var actInst = new GlideRecord('sys_hub_action_instance');",
198
+ " actInst.initialize();",
199
+ " actInst.setValue('flow', flowSysId); actInst.setValue('name', act.name || 'Action ' + (ai + 1));",
200
+ " actInst.setValue('order', (ai + 1) * 100); actInst.setValue('active', true);",
201
+ " if (actDef.next()) actInst.setValue('action_type', actDef.getUniqueValue());",
202
+ " if (actInst.insert()) actionsCreated++;",
203
+ " } catch(ae) {}",
204
+ " }",
205
+ " r.steps.actions = { success: true, created: actionsCreated, requested: activities.length };",
206
+ // Variables (subflows)
207
+ " var varsCreated = 0;",
208
+ " if (isSubflow) {",
209
+ " for (var vi = 0; vi < inputs.length; vi++) {",
210
+ " try { var inp = inputs[vi]; var fv = new GlideRecord('sys_hub_flow_variable'); fv.initialize();",
211
+ " fv.setValue('flow', flowSysId); fv.setValue('name', inp.name); fv.setValue('label', inp.label || inp.name);",
212
+ " fv.setValue('type', inp.type || 'string'); fv.setValue('mandatory', inp.mandatory || false);",
213
+ " fv.setValue('default_value', inp.default_value || ''); fv.setValue('variable_type', 'input');",
214
+ " if (fv.insert()) varsCreated++;",
215
+ " } catch(ve) {}",
216
+ " }",
217
+ " for (var vo = 0; vo < outputs.length; vo++) {",
218
+ " try { var ot = outputs[vo]; var ov = new GlideRecord('sys_hub_flow_variable'); ov.initialize();",
219
+ " ov.setValue('flow', flowSysId); ov.setValue('name', ot.name); ov.setValue('label', ot.label || ot.name);",
220
+ " ov.setValue('type', ot.type || 'string'); ov.setValue('variable_type', 'output');",
221
+ " if (ov.insert()) varsCreated++;",
222
+ " } catch(ve) {}",
223
+ " }",
224
+ " }",
225
+ " r.steps.variables = { success: true, created: varsCreated };",
226
+ "",
227
+ // ── Engine registration (server-side sn_fd APIs) ──
228
+ " r.steps.engine = { apis_found: [] };",
229
+ " try {",
230
+ " if (typeof sn_fd !== 'undefined') {",
231
+ " r.steps.engine.sn_fd = 'available';",
232
+ " if (sn_fd.FlowDesigner) {",
233
+ " r.steps.engine.apis_found.push('FlowDesigner');",
234
+ " if (typeof sn_fd.FlowDesigner.publishFlow === 'function') {",
235
+ " try {",
236
+ " sn_fd.FlowDesigner.publishFlow(flowSysId);",
237
+ " r.steps.engine.publish = 'success';",
238
+ " } catch(pe) { r.steps.engine.publish = pe.getMessage ? pe.getMessage() : pe + ''; }",
239
+ " }",
240
+ " }",
241
+ " if (sn_fd.FlowCompiler) {",
242
+ " r.steps.engine.apis_found.push('FlowCompiler');",
243
+ " if (typeof sn_fd.FlowCompiler.compile === 'function') {",
244
+ " try {",
245
+ " sn_fd.FlowCompiler.compile(flowSysId);",
246
+ " r.steps.engine.compile = 'success';",
247
+ " } catch(ce) { r.steps.engine.compile = ce.getMessage ? ce.getMessage() : ce + ''; }",
248
+ " }",
249
+ " }",
250
+ " var otherApis = ['FlowAPI', 'FlowPublisher'];",
251
+ " for (var oa = 0; oa < otherApis.length; oa++) {",
252
+ " if (sn_fd[otherApis[oa]]) {",
253
+ " r.steps.engine.apis_found.push(otherApis[oa]);",
254
+ " var apiObj = sn_fd[otherApis[oa]];",
255
+ " if (typeof apiObj.publish === 'function') {",
256
+ " try { apiObj.publish(flowSysId); r.steps.engine[otherApis[oa] + '_publish'] = 'success'; }",
257
+ " catch(e) { r.steps.engine[otherApis[oa] + '_publish'] = e + ''; }",
258
+ " }",
259
+ " }",
260
+ " }",
261
+ " } else {",
262
+ " r.steps.engine.sn_fd = 'unavailable';",
263
+ " }",
264
+ " try {",
265
+ " if (typeof GlideFlowDesigner !== 'undefined') {",
266
+ " r.steps.engine.apis_found.push('GlideFlowDesigner');",
267
+ " }",
268
+ " } catch(e) {}",
269
+ " } catch(engineErr) {",
270
+ " r.steps.engine.error = engineErr.getMessage ? engineErr.getMessage() : engineErr + '';",
271
+ " }",
272
+ " }",
273
+ "",
144
274
  " r.flow_sys_id = flowSysId ? flowSysId + '' : null;",
145
275
  " r.version_sys_id = verSysId ? verSysId + '' : null;",
276
+ // ── Post-engine check: re-read latest_version ──
146
277
  " if (flowSysId) {",
147
278
  " var cf = new GlideRecord('sys_hub_flow');",
148
279
  " if (cf.get(flowSysId)) {",
@@ -175,9 +306,10 @@ async function createFlowViaScheduledJob(
175
306
  });
176
307
  var jobSysId = jobResp.data.result?.sys_id;
177
308
 
178
- // 3. Poll for result (15 attempts * 2s = 30s max)
309
+ // 3. Poll for result (adaptive: 5×1s + 2s + 5×3s = 30s max)
179
310
  for (var i = 0; i < 15; i++) {
180
- await new Promise(resolve => setTimeout(resolve, 2000));
311
+ var delay = i < 5 ? 1000 : i < 10 ? 2000 : 3000;
312
+ await new Promise(resolve => setTimeout(resolve, delay));
181
313
  var propResp = await client.get('/api/now/table/sys_properties', {
182
314
  params: {
183
315
  sysparm_query: 'name=' + resultPropName,
@@ -1157,7 +1289,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
1157
1289
  delete flowDefinition.trigger;
1158
1290
  }
1159
1291
 
1160
- // ── Try Scripted REST API (Flow Factory) first ──────────────
1292
+ // ── Pipeline: Scheduled Job (primary) → Table API (fallback) ──
1161
1293
  var flowSysId: string | null = null;
1162
1294
  var usedMethod = 'table_api';
1163
1295
  var versionCreated = false;
@@ -1168,7 +1300,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
1168
1300
 
1169
1301
  // Diagnostics: track every step for debugging "flow cannot be found" issues
1170
1302
  var diagnostics: any = {
1171
- factory_bootstrap: null,
1303
+ factory_bootstrap: 'skipped (direct scheduled job)',
1172
1304
  factory_namespace: null,
1173
1305
  factory_call: null,
1174
1306
  table_api_used: false,
@@ -1179,133 +1311,65 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
1179
1311
  post_verify: null
1180
1312
  };
1181
1313
 
1314
+ // ── Scheduled Job (primary — server-side GlideRecord) ───────
1315
+ // This runs inside ServiceNow as a system job, so it CAN set
1316
+ // computed fields like latest_version that Table API cannot.
1317
+ // Also attempts sn_fd engine registration server-side.
1182
1318
  try {
1183
- var factory = await ensureFlowFactoryAPI(client, context.instanceUrl);
1184
- diagnostics.factory_bootstrap = 'success';
1185
- diagnostics.factory_namespace = factory.namespace;
1186
-
1187
- // Call /discover to learn what sn_fd APIs exist on this instance
1188
- var discovery = await discoverInstanceCapabilities(client, factory.namespace);
1189
- if (discovery) {
1190
- diagnostics.instance_build = discovery.build_tag || discovery.build_name || 'unknown';
1191
- diagnostics.available_apis = discovery.apis || {};
1192
- diagnostics.available_methods = discovery.methods || {};
1193
- }
1194
-
1195
- var factoryPayload = {
1319
+ var scheduledResult = await createFlowViaScheduledJob(client, {
1196
1320
  name: flowName,
1197
1321
  description: flowDescription,
1198
- type: isSubflow ? 'subflow' : 'flow',
1322
+ internalName: sanitizeInternalName(flowName),
1323
+ isSubflow: isSubflow,
1199
1324
  category: flowCategory,
1200
- run_as: flowRunAs,
1201
- activate: shouldActivate,
1202
- trigger_type: triggerType,
1203
- trigger_table: flowTable,
1204
- trigger_condition: triggerCondition,
1325
+ runAs: flowRunAs,
1326
+ shouldActivate: shouldActivate,
1327
+ triggerType: triggerType,
1328
+ triggerTable: flowTable,
1329
+ triggerCondition: triggerCondition,
1205
1330
  activities: activitiesArg.map(function (act: any, idx: number) {
1206
- return { name: act.name, type: act.type || 'script', inputs: act.inputs || {}, order: (idx + 1) * 100 };
1331
+ return { name: act.name, type: act.type || 'script', inputs: act.inputs || {} };
1207
1332
  }),
1208
1333
  inputs: inputsArg,
1209
1334
  outputs: outputsArg,
1210
- flow_definition: flowDefinition
1335
+ flowDefinition: flowDefinition
1336
+ });
1337
+ diagnostics.scheduled_job = {
1338
+ success: scheduledResult.success,
1339
+ tierUsed: scheduledResult.tierUsed,
1340
+ latestVersionSet: scheduledResult.latestVersionSet,
1341
+ latestVersionValue: scheduledResult.latestVersionValue,
1342
+ steps: scheduledResult.steps,
1343
+ error: scheduledResult.error
1211
1344
  };
1212
-
1213
- var factoryEndpoint = '/api/' + factory.namespace + '/' + FLOW_FACTORY_API_ID + '/create';
1214
- var factoryResp: any;
1215
-
1216
- try {
1217
- factoryResp = await client.post(factoryEndpoint, factoryPayload);
1218
- } catch (callError: any) {
1219
- // 404 = API was deleted externally → invalidate cache, retry once
1220
- if (callError.response?.status === 404) {
1221
- invalidateFlowFactoryCache();
1222
- var retryFactory = await ensureFlowFactoryAPI(client, context.instanceUrl);
1223
- diagnostics.factory_namespace = retryFactory.namespace;
1224
- var retryEndpoint = '/api/' + retryFactory.namespace + '/' + FLOW_FACTORY_API_ID + '/create';
1225
- factoryResp = await client.post(retryEndpoint, factoryPayload);
1226
- } else {
1227
- throw callError;
1228
- }
1229
- }
1230
-
1231
- var factoryResult = factoryResp.data?.result || factoryResp.data;
1232
- if (factoryResult && factoryResult.success && factoryResult.flow_sys_id) {
1233
- var tierUsed = factoryResult.tier_used || 'unknown';
1234
- diagnostics.factory_call = 'success';
1235
- diagnostics.factory_tier = tierUsed;
1236
- diagnostics.factory_steps = factoryResult.steps || {};
1237
- flowSysId = factoryResult.flow_sys_id;
1238
- usedMethod = 'scripted_rest_api';
1239
- versionCreated = !!factoryResult.version_created;
1345
+ if (scheduledResult.success && scheduledResult.flowSysId) {
1346
+ flowSysId = scheduledResult.flowSysId;
1347
+ usedMethod = 'scheduled_job (' + (scheduledResult.tierUsed || 'unknown') + ')';
1348
+ versionCreated = !!scheduledResult.versionSysId;
1240
1349
  diagnostics.version_created = versionCreated;
1241
- diagnostics.version_method = 'factory (' + tierUsed + ')';
1242
- diagnostics.version_fields_set = ['flow', 'name', 'version', 'state', 'active', 'compile_state', 'is_current', 'published_flow'];
1243
-
1244
- // Extract step details
1245
- var steps = factoryResult.steps || {};
1246
- if (steps.trigger) {
1247
- triggerCreated = !!steps.trigger.success;
1248
- if (!steps.trigger.success && steps.trigger.error) {
1249
- factoryWarnings.push('Trigger: ' + steps.trigger.error);
1250
- }
1251
- }
1252
- if (steps.actions) {
1253
- actionsCreated = steps.actions.created || 0;
1350
+ diagnostics.version_method = 'scheduled_job';
1351
+ diagnostics.latest_version_auto_set = scheduledResult.latestVersionSet;
1352
+ // Extract engine registration results from scheduled job
1353
+ if (scheduledResult.steps?.engine) {
1354
+ diagnostics.engine_registration = scheduledResult.steps.engine;
1254
1355
  }
1255
- if (steps.variables) {
1256
- varsCreated = steps.variables.created || 0;
1356
+ // Extract trigger/action/variable results from scheduled job
1357
+ if (scheduledResult.steps?.trigger) {
1358
+ triggerCreated = !!scheduledResult.steps.trigger.success;
1359
+ if (!scheduledResult.steps.trigger.success && scheduledResult.steps.trigger.error) {
1360
+ factoryWarnings.push('Trigger: ' + scheduledResult.steps.trigger.error);
1361
+ }
1257
1362
  }
1258
- if (steps.version && !steps.version.success) {
1259
- factoryWarnings.push('Version record: ' + (steps.version.error || 'creation failed'));
1363
+ if (scheduledResult.steps?.actions) {
1364
+ actionsCreated = scheduledResult.steps.actions.created || 0;
1260
1365
  }
1261
- }
1262
- } catch (factoryError: any) {
1263
- // Flow Factory unavailable — fall through to Table API
1264
- var statusCode = factoryError.response?.status;
1265
- var factoryErrMsg = statusCode
1266
- ? 'HTTP ' + statusCode + ': ' + (factoryError.response?.data?.error?.message || factoryError.message || 'unknown')
1267
- : (factoryError.message || 'unknown');
1268
- diagnostics.factory_bootstrap = diagnostics.factory_bootstrap || ('error: ' + factoryErrMsg);
1269
- diagnostics.factory_call = diagnostics.factory_call || ('error: ' + factoryErrMsg);
1270
- if (statusCode !== 403) {
1271
- factoryWarnings.push('Flow Factory unavailable (' + factoryErrMsg + '), using Table API fallback');
1272
- }
1273
- }
1274
-
1275
- // ── Scheduled Job fallback (server-side GlideRecord) ────────
1276
- // This runs inside ServiceNow as a system job, so it CAN set
1277
- // computed fields like latest_version that Table API cannot.
1278
- if (!flowSysId) {
1279
- try {
1280
- var scheduledResult = await createFlowViaScheduledJob(client, {
1281
- name: flowName,
1282
- description: flowDescription,
1283
- internalName: sanitizeInternalName(flowName),
1284
- isSubflow: isSubflow,
1285
- category: flowCategory,
1286
- runAs: flowRunAs,
1287
- shouldActivate: shouldActivate
1288
- });
1289
- diagnostics.scheduled_job = {
1290
- success: scheduledResult.success,
1291
- tierUsed: scheduledResult.tierUsed,
1292
- latestVersionSet: scheduledResult.latestVersionSet,
1293
- latestVersionValue: scheduledResult.latestVersionValue,
1294
- steps: scheduledResult.steps,
1295
- error: scheduledResult.error
1296
- };
1297
- if (scheduledResult.success && scheduledResult.flowSysId) {
1298
- flowSysId = scheduledResult.flowSysId;
1299
- usedMethod = 'scheduled_job (' + (scheduledResult.tierUsed || 'unknown') + ')';
1300
- versionCreated = !!scheduledResult.versionSysId;
1301
- diagnostics.version_created = versionCreated;
1302
- diagnostics.version_method = 'scheduled_job';
1303
- diagnostics.latest_version_auto_set = scheduledResult.latestVersionSet;
1366
+ if (scheduledResult.steps?.variables) {
1367
+ varsCreated = scheduledResult.steps.variables.created || 0;
1304
1368
  }
1305
- } catch (schedErr: any) {
1306
- diagnostics.scheduled_job = { error: schedErr.message || 'unknown' };
1307
- factoryWarnings.push('Scheduled job fallback failed: ' + (schedErr.message || schedErr));
1308
1369
  }
1370
+ } catch (schedErr: any) {
1371
+ diagnostics.scheduled_job = { error: schedErr.message || 'unknown' };
1372
+ factoryWarnings.push('Scheduled job failed: ' + (schedErr.message || schedErr));
1309
1373
  }
1310
1374
 
1311
1375
  // ── Table API fallback (last resort) ─────────────────────────
@@ -1506,10 +1570,11 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
1506
1570
 
1507
1571
  }
1508
1572
 
1509
- // ── Register flow with Flow Designer engine ─────────────────
1510
- // This is the KEY step: without it, records exist but Flow Designer
1511
- // shows "Your flow cannot be found" because the engine hasn't compiled it.
1512
- if (flowSysId) {
1573
+ // ── Register flow with Flow Designer engine (Table API only) ──
1574
+ // For scheduled job path, engine registration is done server-side
1575
+ // inside the job script (via sn_fd APIs). Only call the external
1576
+ // REST-based registration for the Table API fallback path.
1577
+ if (flowSysId && usedMethod.startsWith('table_api')) {
1513
1578
  var engineResult = await registerFlowWithEngine(client, flowSysId, shouldActivate);
1514
1579
  diagnostics.engine_registration = {
1515
1580
  success: engineResult.success,
@@ -1624,29 +1689,38 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
1624
1689
 
1625
1690
  // Diagnostics section
1626
1691
  createSummary.blank().line('Diagnostics:');
1627
- if (diagnostics.instance_build) {
1628
- createSummary.indented('Instance build: ' + diagnostics.instance_build);
1629
- }
1630
- createSummary.indented('Factory bootstrap: ' + (diagnostics.factory_bootstrap || 'not attempted'));
1631
- createSummary.indented('Factory namespace: ' + (diagnostics.factory_namespace || 'n/a'));
1632
- createSummary.indented('Factory call: ' + (diagnostics.factory_call || 'not attempted'));
1633
- if (diagnostics.factory_tier) {
1634
- createSummary.indented('Factory tier used: ' + diagnostics.factory_tier);
1635
- }
1636
- if (diagnostics.available_apis && Object.keys(diagnostics.available_apis).length > 0) {
1637
- var apiStr = Object.keys(diagnostics.available_apis).map(function (k: string) { return k + '=' + diagnostics.available_apis[k]; }).join(', ');
1638
- createSummary.indented('Available APIs: ' + apiStr);
1692
+ if (diagnostics.scheduled_job) {
1693
+ var sj = diagnostics.scheduled_job;
1694
+ createSummary.indented('Scheduled job: ' + (sj.success ? 'success' : 'failed') + (sj.tierUsed ? ' (' + sj.tierUsed + ')' : ''));
1695
+ if (sj.error) createSummary.indented(' Error: ' + sj.error);
1639
1696
  }
1640
1697
  createSummary.indented('Table API used: ' + diagnostics.table_api_used);
1641
1698
  createSummary.indented('Version created: ' + diagnostics.version_created + (diagnostics.version_method ? ' (' + diagnostics.version_method + ')' : ''));
1642
1699
  if (diagnostics.engine_registration) {
1643
- createSummary.indented('Engine registration: ' + (diagnostics.engine_registration.success ? diagnostics.engine_registration.method : 'FAILED'));
1644
- if (diagnostics.engine_registration.attempts) {
1645
- for (var ea = 0; ea < diagnostics.engine_registration.attempts.length; ea++) {
1646
- createSummary.indented(' ' + diagnostics.engine_registration.attempts[ea]);
1700
+ var eng = diagnostics.engine_registration;
1701
+ if (eng.sn_fd) {
1702
+ // Server-side engine registration (from scheduled job)
1703
+ var engineLabel = 'sn_fd=' + eng.sn_fd;
1704
+ if (eng.apis_found && eng.apis_found.length > 0) {
1705
+ engineLabel += ', APIs=[' + eng.apis_found.join(', ') + ']';
1706
+ }
1707
+ if (eng.publish) engineLabel += ', publishFlow=' + eng.publish;
1708
+ if (eng.compile) engineLabel += ', compile=' + eng.compile;
1709
+ if (eng.error) engineLabel += ', error=' + eng.error;
1710
+ createSummary.indented('Engine (server-side): ' + engineLabel);
1711
+ } else if (eng.success !== undefined) {
1712
+ // REST-based engine registration (Table API path)
1713
+ createSummary.indented('Engine registration: ' + (eng.success ? eng.method : 'FAILED'));
1714
+ if (eng.attempts) {
1715
+ for (var ea = 0; ea < eng.attempts.length; ea++) {
1716
+ createSummary.indented(' ' + eng.attempts[ea]);
1717
+ }
1647
1718
  }
1648
1719
  }
1649
1720
  }
1721
+ if (diagnostics.latest_version_auto_set !== undefined) {
1722
+ createSummary.indented('latest_version: ' + (diagnostics.latest_version_auto_set ? 'set' : 'null'));
1723
+ }
1650
1724
  if (diagnostics.post_verify) {
1651
1725
  if (diagnostics.post_verify.error) {
1652
1726
  createSummary.indented('Post-verify: error — ' + diagnostics.post_verify.error);