ultravisor 1.0.3 → 1.0.8
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/.claude/launch.json +11 -0
- package/.claude/ultravisor-dev-config.json +3 -0
- package/card-audit.json +1545 -0
- package/docs/_sidebar.md +17 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/features/beacon-authentication.md +209 -0
- package/docs/features/beacon-providers.md +1299 -0
- package/docs/features/beacons.md +530 -0
- package/docs/features/capabilities.md +193 -0
- package/docs/features/llm-model-setup.md +505 -0
- package/docs/features/llm.md +262 -0
- package/docs/features/tasks-content-system.md +110 -0
- package/docs/features/tasks-data-transform.md +233 -0
- package/docs/features/tasks-extension.md +36 -0
- package/docs/features/tasks-file-system.md +203 -0
- package/docs/features/tasks-flow-control.md +125 -0
- package/docs/features/tasks-http-client.md +119 -0
- package/docs/features/tasks-llm.md +118 -0
- package/docs/features/tasks-meadow-api.md +163 -0
- package/docs/features/tasks-user-interaction.md +49 -0
- package/docs/features/tasks.md +14 -0
- package/docs/index.html +1 -1
- package/docs/retold-catalog.json +1 -1
- package/docs/retold-keyword-index.json +17374 -5
- package/operation-library/api-data-pipeline.json +143 -0
- package/operation-library/beacon-remote-command.json +72 -0
- package/operation-library/conditional-file-backup.json +143 -0
- package/operation-library/config-processor.json +136 -0
- package/operation-library/csv-data-analysis.json +228 -0
- package/operation-library/csv-to-json.json +160 -0
- package/operation-library/directory-inventory.json +128 -0
- package/operation-library/expression-calculator.json +114 -0
- package/operation-library/file-search-replace.json +175 -0
- package/operation-library/git-status-report.json +368 -0
- package/operation-library/health-check-ping.json +329 -0
- package/operation-library/json-config-merge.json +313 -0
- package/operation-library/llm-embedding-tool-use.json +314 -0
- package/operation-library/llm-multi-turn-analysis.json +322 -0
- package/operation-library/llm-summarize.json +264 -0
- package/operation-library/log-line-counter.json +185 -0
- package/operation-library/meadow-crud-lifecycle.json +264 -0
- package/operation-library/npm-project-validator.json +193 -0
- package/operation-library/rest-api-orchestrator.json +218 -0
- package/operation-library/shell-system-info.json +137 -0
- package/operation-library/simple-echo.json +95 -0
- package/operation-library/template-processor.json +299 -0
- package/operation-library/text-sanitizer.json +176 -0
- package/package.json +12 -8
- package/source/Ultravisor.cjs +30 -3
- package/source/beacon/Ultravisor-Beacon-CLI.cjs +143 -0
- package/source/beacon/Ultravisor-Beacon-CapabilityProvider.cjs +129 -0
- package/source/beacon/Ultravisor-Beacon-Client.cjs +568 -0
- package/source/beacon/Ultravisor-Beacon-Executor.cjs +500 -0
- package/source/beacon/Ultravisor-Beacon-ProviderRegistry.cjs +330 -0
- package/source/beacon/providers/Ultravisor-Beacon-Provider-FileSystem.cjs +331 -0
- package/source/beacon/providers/Ultravisor-Beacon-Provider-LLM.cjs +966 -0
- package/source/beacon/providers/Ultravisor-Beacon-Provider-Shell.cjs +95 -0
- package/source/cli/Ultravisor-CLIProgram.cjs +44 -22
- package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
- package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
- package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
- package/source/config/Ultravisor-Default-Command-Configuration.cjs +12 -3
- package/source/services/Ultravisor-Beacon-Coordinator.cjs +966 -0
- package/source/services/Ultravisor-ExecutionEngine.cjs +1093 -0
- package/source/services/Ultravisor-ExecutionManifest.cjs +629 -0
- package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
- package/source/services/Ultravisor-Hypervisor.cjs +185 -75
- package/source/services/Ultravisor-Schedule-Persistence-Base.cjs +45 -0
- package/source/services/Ultravisor-StateManager.cjs +253 -0
- package/source/services/Ultravisor-TaskTypeRegistry.cjs +213 -0
- package/source/services/persistence/Ultravisor-Schedule-Persistence-JSONFile.cjs +140 -0
- package/source/services/tasks/Ultravisor-BuiltIn-TaskConfigs.cjs +19 -0
- package/source/services/tasks/Ultravisor-TaskHelper-BeaconDispatch.cjs +107 -0
- package/source/services/tasks/Ultravisor-TaskType-Base.cjs +125 -0
- package/source/services/tasks/content-system/Ultravisor-TaskConfigs-ContentSystem.cjs +90 -0
- package/source/services/tasks/content-system/definitions/content-create-folder.json +24 -0
- package/source/services/tasks/content-system/definitions/content-list-files.json +27 -0
- package/source/services/tasks/content-system/definitions/content-read-file.json +26 -0
- package/source/services/tasks/content-system/definitions/content-save-file.json +26 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskConfigs-DataTransform.cjs +577 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskType-ReplaceString.cjs +80 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskType-SetValues.cjs +74 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskType-StringAppender.cjs +90 -0
- package/source/services/tasks/data-transform/definitions/comprehension-intersect.json +24 -0
- package/source/services/tasks/data-transform/definitions/csv-transform.json +24 -0
- package/source/services/tasks/data-transform/definitions/expression-solver.json +20 -0
- package/source/services/tasks/data-transform/definitions/histogram.json +23 -0
- package/source/services/tasks/data-transform/definitions/parse-csv.json +27 -0
- package/source/services/tasks/data-transform/definitions/replace-string.json +27 -0
- package/source/services/tasks/data-transform/definitions/set-values.json +17 -0
- package/source/services/tasks/data-transform/definitions/string-appender.json +22 -0
- package/source/services/tasks/data-transform/definitions/template-string.json +20 -0
- package/source/services/tasks/extension/Ultravisor-TaskConfigs-Extension.cjs +87 -0
- package/source/services/tasks/extension/definitions/beacon-dispatch.json +32 -0
- package/source/services/tasks/file-system/Ultravisor-TaskConfigs-FileSystem.cjs +509 -0
- package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFile.cjs +96 -0
- package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFileBuffered.cjs +123 -0
- package/source/services/tasks/file-system/Ultravisor-TaskType-WriteFile.cjs +106 -0
- package/source/services/tasks/file-system/definitions/copy-file.json +27 -0
- package/source/services/tasks/file-system/definitions/list-files.json +27 -0
- package/source/services/tasks/file-system/definitions/read-file-buffered.json +31 -0
- package/source/services/tasks/file-system/definitions/read-file.json +26 -0
- package/source/services/tasks/file-system/definitions/read-json.json +23 -0
- package/source/services/tasks/file-system/definitions/write-file.json +29 -0
- package/source/services/tasks/file-system/definitions/write-json.json +30 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskConfigs-FlowControl.cjs +353 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskType-IfConditional.cjs +125 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskType-LaunchOperation.cjs +186 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskType-SplitExecute.cjs +164 -0
- package/source/services/tasks/flow-control/definitions/if-conditional.json +25 -0
- package/source/services/tasks/flow-control/definitions/launch-operation.json +27 -0
- package/source/services/tasks/flow-control/definitions/split-execute.json +32 -0
- package/source/services/tasks/http-client/Ultravisor-TaskConfigs-HttpClient.cjs +281 -0
- package/source/services/tasks/http-client/definitions/get-json.json +26 -0
- package/source/services/tasks/http-client/definitions/get-text.json +26 -0
- package/source/services/tasks/http-client/definitions/rest-request.json +32 -0
- package/source/services/tasks/http-client/definitions/send-json.json +28 -0
- package/source/services/tasks/llm/Ultravisor-TaskConfigs-LLM.cjs +605 -0
- package/source/services/tasks/llm/definitions/llm-chat-completion.json +46 -0
- package/source/services/tasks/llm/definitions/llm-embedding.json +31 -0
- package/source/services/tasks/llm/definitions/llm-tool-use.json +42 -0
- package/source/services/tasks/meadow-api/Ultravisor-TaskConfigs-MeadowApi.cjs +341 -0
- package/source/services/tasks/meadow-api/definitions/meadow-count.json +26 -0
- package/source/services/tasks/meadow-api/definitions/meadow-create.json +26 -0
- package/source/services/tasks/meadow-api/definitions/meadow-delete.json +23 -0
- package/source/services/tasks/meadow-api/definitions/meadow-read.json +26 -0
- package/source/services/tasks/meadow-api/definitions/meadow-reads.json +29 -0
- package/source/services/tasks/meadow-api/definitions/meadow-update.json +26 -0
- package/source/services/tasks/shell/Ultravisor-TaskConfigs-Shell.cjs +63 -0
- package/source/services/tasks/shell/definitions/command.json +29 -0
- package/source/services/tasks/user-interaction/Ultravisor-TaskConfigs-UserInteraction.cjs +64 -0
- package/source/services/tasks/user-interaction/Ultravisor-TaskType-ErrorMessage.cjs +55 -0
- package/source/services/tasks/user-interaction/Ultravisor-TaskType-ValueInput.cjs +47 -0
- package/source/services/tasks/user-interaction/definitions/error-message.json +18 -0
- package/source/services/tasks/user-interaction/definitions/value-input.json +23 -0
- package/source/web_server/Ultravisor-API-Server.cjs +849 -124
- package/test/Ultravisor_browser_tests.js +2226 -0
- package/test/Ultravisor_operation_library_tests.js +894 -0
- package/test/Ultravisor_tests.js +4946 -5044
- package/test/workflows/test-content-concatenate-all.json +339 -0
- package/test/workflows/test-content-full-pipeline.json +159 -0
- package/test/workflows/test-content-list-files.json +76 -0
- package/test/workflows/test-content-save-and-read.json +106 -0
- package/webinterface/css/ultravisor-themes.css +668 -0
- package/webinterface/css/ultravisor.css +37 -14
- package/webinterface/docs/card-help/beacon-dispatch.md +30 -0
- package/webinterface/docs/card-help/command.md +27 -0
- package/webinterface/docs/card-help/comprehension-intersect.md +24 -0
- package/webinterface/docs/card-help/content-create-folder.md +22 -0
- package/webinterface/docs/card-help/content-list-files.md +25 -0
- package/webinterface/docs/card-help/content-read-file.md +24 -0
- package/webinterface/docs/card-help/content-save-file.md +24 -0
- package/webinterface/docs/card-help/copy-file.md +25 -0
- package/webinterface/docs/card-help/csv-transform.md +24 -0
- package/webinterface/docs/card-help/end.md +11 -0
- package/webinterface/docs/card-help/error-message.md +16 -0
- package/webinterface/docs/card-help/expression-solver.md +21 -0
- package/webinterface/docs/card-help/get-json.md +24 -0
- package/webinterface/docs/card-help/get-text.md +24 -0
- package/webinterface/docs/card-help/histogram.md +23 -0
- package/webinterface/docs/card-help/if-conditional.md +23 -0
- package/webinterface/docs/card-help/launch-operation.md +25 -0
- package/webinterface/docs/card-help/list-files.md +25 -0
- package/webinterface/docs/card-help/llm-chat-completion.md +43 -0
- package/webinterface/docs/card-help/llm-embedding.md +24 -0
- package/webinterface/docs/card-help/llm-tool-use.md +39 -0
- package/webinterface/docs/card-help/meadow-count.md +24 -0
- package/webinterface/docs/card-help/meadow-create.md +24 -0
- package/webinterface/docs/card-help/meadow-delete.md +19 -0
- package/webinterface/docs/card-help/meadow-read.md +24 -0
- package/webinterface/docs/card-help/meadow-reads.md +27 -0
- package/webinterface/docs/card-help/meadow-update.md +24 -0
- package/webinterface/docs/card-help/parse-csv.md +27 -0
- package/webinterface/docs/card-help/read-file-buffered.md +29 -0
- package/webinterface/docs/card-help/read-file.md +24 -0
- package/webinterface/docs/card-help/read-json.md +21 -0
- package/webinterface/docs/card-help/replace-string.md +25 -0
- package/webinterface/docs/card-help/rest-request.md +30 -0
- package/webinterface/docs/card-help/send-json.md +26 -0
- package/webinterface/docs/card-help/set-values.md +16 -0
- package/webinterface/docs/card-help/split-execute.md +35 -0
- package/webinterface/docs/card-help/start.md +11 -0
- package/webinterface/docs/card-help/string-appender.md +22 -0
- package/webinterface/docs/card-help/template-string.md +21 -0
- package/webinterface/docs/card-help/value-input.md +24 -0
- package/webinterface/docs/card-help/write-file.md +27 -0
- package/webinterface/docs/card-help/write-json.md +28 -0
- package/webinterface/html/index.html +5 -0
- package/webinterface/package.json +13 -4
- package/webinterface/source/Pict-Application-Ultravisor.js +564 -70
- package/webinterface/source/Ultravisor-TimingUtils.js +99 -0
- package/webinterface/source/card-help-content.js +46 -0
- package/webinterface/source/cards/Ultravisor-BuiltIn-CardConfigs.js +174 -0
- package/webinterface/source/cards/Ultravisor-CardConfigGenerator.js +431 -0
- package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
- package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
- package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
- package/webinterface/source/panels/Ultravisor-CardSettingsPanel.js +902 -0
- package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +20 -8
- package/webinterface/source/views/PictView-Ultravisor-BeaconList.js +817 -0
- package/webinterface/source/views/PictView-Ultravisor-BottomBar.js +5 -5
- package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +25 -25
- package/webinterface/source/views/PictView-Ultravisor-Documentation.js +856 -0
- package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +777 -0
- package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +321 -58
- package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +36 -91
- package/webinterface/source/views/PictView-Ultravisor-OperationList.js +388 -16
- package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
- package/webinterface/source/views/PictView-Ultravisor-Schedule.js +521 -65
- package/webinterface/source/views/PictView-Ultravisor-TimingView.js +333 -71
- package/webinterface/source/views/PictView-Ultravisor-TopBar.js +257 -21
- package/webinterface/theme-sampler.html +645 -0
- package/debug/Harness.js +0 -6
- package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
- package/source/services/Ultravisor-Operation.cjs +0 -200
- package/source/services/Ultravisor-Task.cjs +0 -349
- package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
- package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
- package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
- package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
- package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
- package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
- package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
- package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
- package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
- package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
- package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
- package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
- package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
- package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
- package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
- package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
- package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
- package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
- package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
- package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
- package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
- package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
- package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow Control task configurations for Ultravisor.
|
|
3
|
+
*
|
|
4
|
+
* Contains task types for controlling execution flow:
|
|
5
|
+
* if-conditional, split-execute, launch-operation
|
|
6
|
+
*
|
|
7
|
+
* Each entry defines a task type as a config object with:
|
|
8
|
+
* Definition {object} - Port schema, metadata, default settings
|
|
9
|
+
* Execute {function} - Runtime logic: function(pTask, pSettings, pContext, fCb, fFireEvent)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// ── Module-scoped helpers ───────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get a service instance from the fable services map.
|
|
17
|
+
*/
|
|
18
|
+
function _getService(pTask, pTypeName)
|
|
19
|
+
{
|
|
20
|
+
if (pTask.fable.servicesMap[pTypeName])
|
|
21
|
+
{
|
|
22
|
+
return Object.values(pTask.fable.servicesMap[pTypeName])[0];
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Compare two values using an operator (used by if-conditional).
|
|
29
|
+
*/
|
|
30
|
+
function _compare(pLeft, pRight, pOperator)
|
|
31
|
+
{
|
|
32
|
+
switch (pOperator)
|
|
33
|
+
{
|
|
34
|
+
case '==':
|
|
35
|
+
return String(pLeft) == String(pRight);
|
|
36
|
+
case '===':
|
|
37
|
+
return pLeft === pRight;
|
|
38
|
+
case '!=':
|
|
39
|
+
return String(pLeft) != String(pRight);
|
|
40
|
+
case '!==':
|
|
41
|
+
return pLeft !== pRight;
|
|
42
|
+
case '>':
|
|
43
|
+
return Number(pLeft) > Number(pRight);
|
|
44
|
+
case '<':
|
|
45
|
+
return Number(pLeft) < Number(pRight);
|
|
46
|
+
case '>=':
|
|
47
|
+
return Number(pLeft) >= Number(pRight);
|
|
48
|
+
case '<=':
|
|
49
|
+
return Number(pLeft) <= Number(pRight);
|
|
50
|
+
case 'contains':
|
|
51
|
+
return String(pLeft).indexOf(String(pRight)) > -1;
|
|
52
|
+
case 'startsWith':
|
|
53
|
+
return String(pLeft).startsWith(String(pRight));
|
|
54
|
+
case 'endsWith':
|
|
55
|
+
return String(pLeft).endsWith(String(pRight));
|
|
56
|
+
case 'truthy':
|
|
57
|
+
return !!pLeft;
|
|
58
|
+
case 'falsy':
|
|
59
|
+
return !pLeft;
|
|
60
|
+
default:
|
|
61
|
+
return String(pLeft) == String(pRight);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Handle PerformSplit event for split-execute.
|
|
67
|
+
*/
|
|
68
|
+
function _handlePerformSplit(pSettings, pContext, fCallback)
|
|
69
|
+
{
|
|
70
|
+
let tmpInputString = pSettings.InputString;
|
|
71
|
+
let tmpDelimiter = pSettings.SplitDelimiter;
|
|
72
|
+
|
|
73
|
+
if (typeof(tmpInputString) !== 'string')
|
|
74
|
+
{
|
|
75
|
+
return fCallback(null, {
|
|
76
|
+
EventToFire: 'Error',
|
|
77
|
+
Outputs: { CurrentToken: '', TokenIndex: 0, TokenCount: 0, CompletedCount: 0 },
|
|
78
|
+
Log: ['InputString is not a string.']
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (tmpDelimiter === undefined || tmpDelimiter === null)
|
|
83
|
+
{
|
|
84
|
+
tmpDelimiter = '\n';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let tmpTokens = tmpInputString.split(tmpDelimiter);
|
|
88
|
+
if (pSettings.TrimTokens)
|
|
89
|
+
{
|
|
90
|
+
tmpTokens = tmpTokens.map(function (pT) { return pT.trim(); });
|
|
91
|
+
}
|
|
92
|
+
if (pSettings.SkipEmpty)
|
|
93
|
+
{
|
|
94
|
+
tmpTokens = tmpTokens.filter(function (pT) { return pT.length > 0; });
|
|
95
|
+
}
|
|
96
|
+
let tmpTokenCount = tmpTokens.length;
|
|
97
|
+
let tmpLog = [`Splitting input (${tmpInputString.length} chars) by "${tmpDelimiter}" into ${tmpTokenCount} tokens.`];
|
|
98
|
+
|
|
99
|
+
if (tmpTokenCount === 0)
|
|
100
|
+
{
|
|
101
|
+
return fCallback(null, {
|
|
102
|
+
EventToFire: 'CompletedAllSubtasks',
|
|
103
|
+
Outputs: { CurrentToken: '', TokenIndex: 0, TokenCount: 0, CompletedCount: 0 },
|
|
104
|
+
Log: tmpLog.concat(['No tokens to process.'])
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let tmpFirstToken = tmpTokens[0];
|
|
109
|
+
tmpLog.push(`Emitting token 1/${tmpTokenCount}: "${tmpFirstToken.substring(0, 50)}"`);
|
|
110
|
+
|
|
111
|
+
return fCallback(null, {
|
|
112
|
+
EventToFire: 'TokenDataSent',
|
|
113
|
+
Outputs: {
|
|
114
|
+
_Tokens: tmpTokens,
|
|
115
|
+
CurrentToken: tmpFirstToken,
|
|
116
|
+
TokenIndex: 0,
|
|
117
|
+
TokenCount: tmpTokenCount,
|
|
118
|
+
CompletedCount: 0
|
|
119
|
+
},
|
|
120
|
+
Log: tmpLog
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Handle StepComplete event for split-execute.
|
|
126
|
+
*/
|
|
127
|
+
function _handleStepComplete(pContext, fCallback)
|
|
128
|
+
{
|
|
129
|
+
let tmpStoredState = pContext.TaskOutputs[pContext.NodeHash] || {};
|
|
130
|
+
let tmpTokens = tmpStoredState._Tokens;
|
|
131
|
+
|
|
132
|
+
if (!Array.isArray(tmpTokens))
|
|
133
|
+
{
|
|
134
|
+
return fCallback(null, {
|
|
135
|
+
EventToFire: 'Error',
|
|
136
|
+
Outputs: { CurrentToken: '', TokenIndex: 0, TokenCount: 0, CompletedCount: 0 },
|
|
137
|
+
Log: ['StepComplete received but no stored tokens found. Was PerformSplit called first?']
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let tmpTokenCount = tmpTokens.length;
|
|
142
|
+
let tmpPreviousIndex = tmpStoredState.TokenIndex || 0;
|
|
143
|
+
let tmpCompletedCount = (tmpStoredState.CompletedCount || 0) + 1;
|
|
144
|
+
let tmpNextIndex = tmpPreviousIndex + 1;
|
|
145
|
+
|
|
146
|
+
if (tmpNextIndex >= tmpTokenCount)
|
|
147
|
+
{
|
|
148
|
+
return fCallback(null, {
|
|
149
|
+
EventToFire: 'CompletedAllSubtasks',
|
|
150
|
+
Outputs: {
|
|
151
|
+
_Tokens: tmpTokens,
|
|
152
|
+
CurrentToken: tmpTokens[tmpTokenCount - 1],
|
|
153
|
+
TokenIndex: tmpTokenCount - 1,
|
|
154
|
+
TokenCount: tmpTokenCount,
|
|
155
|
+
CompletedCount: tmpCompletedCount
|
|
156
|
+
},
|
|
157
|
+
Log: [`All ${tmpTokenCount} tokens processed (${tmpCompletedCount} completed).`]
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let tmpNextToken = tmpTokens[tmpNextIndex];
|
|
162
|
+
|
|
163
|
+
return fCallback(null, {
|
|
164
|
+
EventToFire: 'TokenDataSent',
|
|
165
|
+
Outputs: {
|
|
166
|
+
_Tokens: tmpTokens,
|
|
167
|
+
CurrentToken: tmpNextToken,
|
|
168
|
+
TokenIndex: tmpNextIndex,
|
|
169
|
+
TokenCount: tmpTokenCount,
|
|
170
|
+
CompletedCount: tmpCompletedCount
|
|
171
|
+
},
|
|
172
|
+
Log: [`Emitting token ${tmpNextIndex + 1}/${tmpTokenCount}: "${tmpNextToken.substring(0, 50)}"`]
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
178
|
+
// FLOW CONTROL TASK CONFIGS
|
|
179
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
180
|
+
|
|
181
|
+
module.exports =
|
|
182
|
+
[
|
|
183
|
+
// ── if-conditional ─────────────────────────────────────────
|
|
184
|
+
{
|
|
185
|
+
Definition: require('./definitions/if-conditional.json'),
|
|
186
|
+
Execute: function (pTask, pResolvedSettings, pExecutionContext, fCallback)
|
|
187
|
+
{
|
|
188
|
+
let tmpResult = false;
|
|
189
|
+
|
|
190
|
+
if (pResolvedSettings.Expression && typeof(pResolvedSettings.Expression) === 'string')
|
|
191
|
+
{
|
|
192
|
+
try
|
|
193
|
+
{
|
|
194
|
+
if (pTask.fable.ExpressionParser)
|
|
195
|
+
{
|
|
196
|
+
tmpResult = pTask.fable.ExpressionParser.resolve(pResolvedSettings.Expression, pExecutionContext);
|
|
197
|
+
}
|
|
198
|
+
else
|
|
199
|
+
{
|
|
200
|
+
tmpResult = !!pResolvedSettings.Expression;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (pError)
|
|
204
|
+
{
|
|
205
|
+
return fCallback(null, {
|
|
206
|
+
EventToFire: 'False',
|
|
207
|
+
Outputs: { Result: false },
|
|
208
|
+
Log: [`Expression error: ${pError.message}`]
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (pResolvedSettings.DataAddress)
|
|
213
|
+
{
|
|
214
|
+
let tmpDataValue = undefined;
|
|
215
|
+
let tmpStateManager = pExecutionContext.StateManager;
|
|
216
|
+
|
|
217
|
+
if (tmpStateManager)
|
|
218
|
+
{
|
|
219
|
+
tmpDataValue = tmpStateManager.resolveAddress(pResolvedSettings.DataAddress, pExecutionContext, pExecutionContext.NodeHash);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
tmpResult = _compare(tmpDataValue, pResolvedSettings.CompareValue, pResolvedSettings.Operator || '==');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return fCallback(null, {
|
|
226
|
+
EventToFire: tmpResult ? 'True' : 'False',
|
|
227
|
+
Outputs: { Result: tmpResult },
|
|
228
|
+
Log: [`Condition evaluated to ${tmpResult}.`]
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
// ── split-execute ──────────────────────────────────────────
|
|
234
|
+
{
|
|
235
|
+
Definition: require('./definitions/split-execute.json'),
|
|
236
|
+
Execute: function (pTask, pResolvedSettings, pExecutionContext, fCallback)
|
|
237
|
+
{
|
|
238
|
+
if (pExecutionContext.TriggeringEventName === 'StepComplete')
|
|
239
|
+
{
|
|
240
|
+
return _handleStepComplete(pExecutionContext, fCallback);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return _handlePerformSplit(pResolvedSettings, pExecutionContext, fCallback);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
// ── launch-operation ───────────────────────────────────────
|
|
248
|
+
{
|
|
249
|
+
Definition: require('./definitions/launch-operation.json'),
|
|
250
|
+
Execute: function (pTask, pResolvedSettings, pExecutionContext, fCallback)
|
|
251
|
+
{
|
|
252
|
+
let tmpOperationHash = pResolvedSettings.OperationHash;
|
|
253
|
+
|
|
254
|
+
if (!tmpOperationHash || typeof(tmpOperationHash) !== 'string' || tmpOperationHash.length === 0)
|
|
255
|
+
{
|
|
256
|
+
return fCallback(null, { EventToFire: 'Error', Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 }, Log: ['No OperationHash specified.'] });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
let tmpStateService = _getService(pTask, 'UltravisorHypervisorState');
|
|
260
|
+
if (!tmpStateService)
|
|
261
|
+
{
|
|
262
|
+
return fCallback(null, { EventToFire: 'Error', Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 }, Log: ['UltravisorHypervisorState service not found.'] });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let tmpEngine = _getService(pTask, 'UltravisorExecutionEngine');
|
|
266
|
+
if (!tmpEngine)
|
|
267
|
+
{
|
|
268
|
+
return fCallback(null, { EventToFire: 'Error', Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 }, Log: ['UltravisorExecutionEngine service not found.'] });
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
tmpStateService.getOperation(tmpOperationHash,
|
|
272
|
+
function (pError, pOperation)
|
|
273
|
+
{
|
|
274
|
+
if (pError)
|
|
275
|
+
{
|
|
276
|
+
return fCallback(null, { EventToFire: 'Error', Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 }, Log: [`Operation [${tmpOperationHash}] not found: ${pError.message}`] });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
let tmpInitialState = {
|
|
280
|
+
GlobalState: (pResolvedSettings.InheritGlobalState === false) ? {} : JSON.parse(JSON.stringify(pExecutionContext.GlobalState || {})),
|
|
281
|
+
OperationState: {},
|
|
282
|
+
RunMode: pExecutionContext.RunMode || 'standard'
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
if (pResolvedSettings.InputData && typeof(pResolvedSettings.InputData) === 'string' && pResolvedSettings.InputData.length > 0)
|
|
286
|
+
{
|
|
287
|
+
try
|
|
288
|
+
{
|
|
289
|
+
let tmpInputData = JSON.parse(pResolvedSettings.InputData);
|
|
290
|
+
if (typeof(tmpInputData) === 'object' && tmpInputData !== null)
|
|
291
|
+
{
|
|
292
|
+
tmpInitialState.OperationState = tmpInputData;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch (pParseError)
|
|
296
|
+
{
|
|
297
|
+
tmpInitialState.OperationState.InputData = pResolvedSettings.InputData;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let tmpStartTime = Date.now();
|
|
302
|
+
let tmpTimeoutMs = parseInt(pResolvedSettings.TimeoutMs, 10) || 0;
|
|
303
|
+
let tmpCompleted = false;
|
|
304
|
+
let tmpTimeoutHandle = null;
|
|
305
|
+
|
|
306
|
+
if (tmpTimeoutMs > 0)
|
|
307
|
+
{
|
|
308
|
+
tmpTimeoutHandle = setTimeout(function()
|
|
309
|
+
{
|
|
310
|
+
if (!tmpCompleted)
|
|
311
|
+
{
|
|
312
|
+
tmpCompleted = true;
|
|
313
|
+
let tmpElapsedMs = Date.now() - tmpStartTime;
|
|
314
|
+
return fCallback(null, {
|
|
315
|
+
EventToFire: 'Error',
|
|
316
|
+
Outputs: { Result: 'Operation timed out', Status: 'Timeout', ElapsedMs: tmpElapsedMs },
|
|
317
|
+
Log: [`Child operation [${tmpOperationHash}] timed out after ${tmpTimeoutMs}ms`]
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}, tmpTimeoutMs);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
tmpEngine.executeOperation(pOperation, tmpInitialState,
|
|
324
|
+
function (pExecError, pContext)
|
|
325
|
+
{
|
|
326
|
+
if (tmpCompleted) { return; }
|
|
327
|
+
tmpCompleted = true;
|
|
328
|
+
if (tmpTimeoutHandle) { clearTimeout(tmpTimeoutHandle); }
|
|
329
|
+
|
|
330
|
+
let tmpElapsedMs = Date.now() - tmpStartTime;
|
|
331
|
+
|
|
332
|
+
if (pExecError)
|
|
333
|
+
{
|
|
334
|
+
return fCallback(null, {
|
|
335
|
+
EventToFire: 'Error',
|
|
336
|
+
Outputs: { Result: pExecError.message, Status: 'Error', ElapsedMs: tmpElapsedMs },
|
|
337
|
+
Log: [`Child operation [${tmpOperationHash}] failed: ${pExecError.message}`]
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let tmpStatus = pContext.Status || 'Unknown';
|
|
342
|
+
let tmpResultSummary = JSON.stringify({ Status: tmpStatus, TaskOutputs: pContext.TaskOutputs || {}, Errors: pContext.Errors || [] });
|
|
343
|
+
|
|
344
|
+
return fCallback(null, {
|
|
345
|
+
EventToFire: 'Completed',
|
|
346
|
+
Outputs: { Result: tmpResultSummary, Status: tmpStatus, ElapsedMs: tmpElapsedMs },
|
|
347
|
+
Log: [`Child operation [${tmpOperationHash}] completed with status: ${tmpStatus} (${tmpElapsedMs}ms)`]
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const libTaskTypeBase = require('../Ultravisor-TaskType-Base.cjs');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* IfConditional Task Type
|
|
5
|
+
*
|
|
6
|
+
* Evaluates a simple expression and fires either the True or False event.
|
|
7
|
+
* Supports comparisons via DataAddress and CompareValue, or a direct Expression string.
|
|
8
|
+
*
|
|
9
|
+
* If DataAddress is set, reads the value at that address and compares
|
|
10
|
+
* it to CompareValue using the Operator (default: '==').
|
|
11
|
+
*
|
|
12
|
+
* If Expression is set instead, evaluates it using fable.ExpressionParser.
|
|
13
|
+
*/
|
|
14
|
+
class UltravisorTaskTypeIfConditional extends libTaskTypeBase
|
|
15
|
+
{
|
|
16
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
17
|
+
{
|
|
18
|
+
super(pFable, pOptions, pServiceHash);
|
|
19
|
+
|
|
20
|
+
this.serviceType = 'UltravisorTaskTypeIfConditional';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get definition()
|
|
24
|
+
{
|
|
25
|
+
return require('./definitions/if-conditional.json');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
execute(pResolvedSettings, pExecutionContext, fCallback, fFireIntermediateEvent)
|
|
29
|
+
{
|
|
30
|
+
let tmpResult = false;
|
|
31
|
+
|
|
32
|
+
if (pResolvedSettings.Expression && typeof(pResolvedSettings.Expression) === 'string')
|
|
33
|
+
{
|
|
34
|
+
// Expression-based evaluation using Fable's ExpressionParser
|
|
35
|
+
try
|
|
36
|
+
{
|
|
37
|
+
if (this.fable.ExpressionParser)
|
|
38
|
+
{
|
|
39
|
+
tmpResult = this.fable.ExpressionParser.resolve(pResolvedSettings.Expression, pExecutionContext);
|
|
40
|
+
}
|
|
41
|
+
else
|
|
42
|
+
{
|
|
43
|
+
// Simple truthy evaluation fallback
|
|
44
|
+
tmpResult = !!pResolvedSettings.Expression;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (pError)
|
|
48
|
+
{
|
|
49
|
+
return fCallback(null, {
|
|
50
|
+
EventToFire: 'False',
|
|
51
|
+
Outputs: { Result: false },
|
|
52
|
+
Log: [`Expression error: ${pError.message}`]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (pResolvedSettings.DataAddress)
|
|
57
|
+
{
|
|
58
|
+
// Address-based comparison
|
|
59
|
+
let tmpDataValue = undefined;
|
|
60
|
+
let tmpStateManager = pExecutionContext.StateManager;
|
|
61
|
+
|
|
62
|
+
if (tmpStateManager)
|
|
63
|
+
{
|
|
64
|
+
tmpDataValue = tmpStateManager.resolveAddress(
|
|
65
|
+
pResolvedSettings.DataAddress, pExecutionContext, pExecutionContext.NodeHash);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let tmpCompareValue = pResolvedSettings.CompareValue;
|
|
69
|
+
let tmpOperator = pResolvedSettings.Operator || '==';
|
|
70
|
+
|
|
71
|
+
tmpResult = this._compare(tmpDataValue, tmpCompareValue, tmpOperator);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return fCallback(null, {
|
|
75
|
+
EventToFire: tmpResult ? 'True' : 'False',
|
|
76
|
+
Outputs: { Result: tmpResult },
|
|
77
|
+
Log: [`Condition evaluated to ${tmpResult}.`]
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Compare two values using an operator.
|
|
83
|
+
*
|
|
84
|
+
* @param {*} pLeft - Left operand.
|
|
85
|
+
* @param {*} pRight - Right operand.
|
|
86
|
+
* @param {string} pOperator - The comparison operator.
|
|
87
|
+
* @returns {boolean} Result of comparison.
|
|
88
|
+
*/
|
|
89
|
+
_compare(pLeft, pRight, pOperator)
|
|
90
|
+
{
|
|
91
|
+
switch (pOperator)
|
|
92
|
+
{
|
|
93
|
+
case '==':
|
|
94
|
+
return String(pLeft) == String(pRight);
|
|
95
|
+
case '===':
|
|
96
|
+
return pLeft === pRight;
|
|
97
|
+
case '!=':
|
|
98
|
+
return String(pLeft) != String(pRight);
|
|
99
|
+
case '!==':
|
|
100
|
+
return pLeft !== pRight;
|
|
101
|
+
case '>':
|
|
102
|
+
return Number(pLeft) > Number(pRight);
|
|
103
|
+
case '<':
|
|
104
|
+
return Number(pLeft) < Number(pRight);
|
|
105
|
+
case '>=':
|
|
106
|
+
return Number(pLeft) >= Number(pRight);
|
|
107
|
+
case '<=':
|
|
108
|
+
return Number(pLeft) <= Number(pRight);
|
|
109
|
+
case 'contains':
|
|
110
|
+
return String(pLeft).indexOf(String(pRight)) > -1;
|
|
111
|
+
case 'startsWith':
|
|
112
|
+
return String(pLeft).startsWith(String(pRight));
|
|
113
|
+
case 'endsWith':
|
|
114
|
+
return String(pLeft).endsWith(String(pRight));
|
|
115
|
+
case 'truthy':
|
|
116
|
+
return !!pLeft;
|
|
117
|
+
case 'falsy':
|
|
118
|
+
return !pLeft;
|
|
119
|
+
default:
|
|
120
|
+
return String(pLeft) == String(pRight);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = UltravisorTaskTypeIfConditional;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
const libTaskTypeBase = require('../Ultravisor-TaskType-Base.cjs');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* LaunchOperation Task Type
|
|
5
|
+
*
|
|
6
|
+
* Executes a child operation within the current operation's graph.
|
|
7
|
+
* Looks up the target operation by hash from the Hypervisor's state,
|
|
8
|
+
* creates an isolated execution context for it, and runs it via the
|
|
9
|
+
* ExecutionEngine.
|
|
10
|
+
*
|
|
11
|
+
* The child operation gets its own OperationState (optionally seeded
|
|
12
|
+
* from InputData) but shares the parent's GlobalState (as a copy).
|
|
13
|
+
*
|
|
14
|
+
* Flow:
|
|
15
|
+
* Launch -> (execute child operation) -> Completed or Error
|
|
16
|
+
*/
|
|
17
|
+
class UltravisorTaskTypeLaunchOperation extends libTaskTypeBase
|
|
18
|
+
{
|
|
19
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
20
|
+
{
|
|
21
|
+
super(pFable, pOptions, pServiceHash);
|
|
22
|
+
|
|
23
|
+
this.serviceType = 'UltravisorTaskTypeLaunchOperation';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get definition()
|
|
27
|
+
{
|
|
28
|
+
return require('./definitions/launch-operation.json');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
execute(pResolvedSettings, pExecutionContext, fCallback, fFireIntermediateEvent)
|
|
32
|
+
{
|
|
33
|
+
let tmpOperationHash = pResolvedSettings.OperationHash;
|
|
34
|
+
|
|
35
|
+
if (!tmpOperationHash || typeof(tmpOperationHash) !== 'string' || tmpOperationHash.length === 0)
|
|
36
|
+
{
|
|
37
|
+
return fCallback(null, {
|
|
38
|
+
EventToFire: 'Error',
|
|
39
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
40
|
+
Log: ['No OperationHash specified.']
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Get the Hypervisor state service to look up the operation
|
|
45
|
+
let tmpStateService = this._getService('UltravisorHypervisorState');
|
|
46
|
+
|
|
47
|
+
if (!tmpStateService)
|
|
48
|
+
{
|
|
49
|
+
return fCallback(null, {
|
|
50
|
+
EventToFire: 'Error',
|
|
51
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
52
|
+
Log: ['UltravisorHypervisorState service not found.']
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Get the ExecutionEngine to run the child operation
|
|
57
|
+
let tmpEngine = this._getService('UltravisorExecutionEngine');
|
|
58
|
+
|
|
59
|
+
if (!tmpEngine)
|
|
60
|
+
{
|
|
61
|
+
return fCallback(null, {
|
|
62
|
+
EventToFire: 'Error',
|
|
63
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
64
|
+
Log: ['UltravisorExecutionEngine service not found.']
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Look up the target operation
|
|
69
|
+
tmpStateService.getOperation(tmpOperationHash,
|
|
70
|
+
(pError, pOperation) =>
|
|
71
|
+
{
|
|
72
|
+
if (pError)
|
|
73
|
+
{
|
|
74
|
+
return fCallback(null, {
|
|
75
|
+
EventToFire: 'Error',
|
|
76
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
77
|
+
Log: [`Operation [${tmpOperationHash}] not found: ${pError.message}`]
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Build initial state for the child operation
|
|
82
|
+
let tmpInitialState = {
|
|
83
|
+
// Share a copy of the parent's global state (unless InheritGlobalState is false)
|
|
84
|
+
GlobalState: (pResolvedSettings.InheritGlobalState === false) ? {} : JSON.parse(JSON.stringify(pExecutionContext.GlobalState || {})),
|
|
85
|
+
// Isolated operation state, optionally seeded from InputData
|
|
86
|
+
OperationState: {},
|
|
87
|
+
RunMode: pExecutionContext.RunMode || 'standard'
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Parse InputData if provided (expects JSON string)
|
|
91
|
+
if (pResolvedSettings.InputData && typeof(pResolvedSettings.InputData) === 'string' && pResolvedSettings.InputData.length > 0)
|
|
92
|
+
{
|
|
93
|
+
try
|
|
94
|
+
{
|
|
95
|
+
let tmpInputData = JSON.parse(pResolvedSettings.InputData);
|
|
96
|
+
if (typeof(tmpInputData) === 'object' && tmpInputData !== null)
|
|
97
|
+
{
|
|
98
|
+
tmpInitialState.OperationState = tmpInputData;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (pParseError)
|
|
102
|
+
{
|
|
103
|
+
// If not valid JSON, store as a raw string in OperationState.InputData
|
|
104
|
+
tmpInitialState.OperationState.InputData = pResolvedSettings.InputData;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let tmpStartTime = Date.now();
|
|
109
|
+
let tmpTimeoutMs = parseInt(pResolvedSettings.TimeoutMs, 10) || 0;
|
|
110
|
+
let tmpCompleted = false;
|
|
111
|
+
let tmpTimeoutHandle = null;
|
|
112
|
+
|
|
113
|
+
if (tmpTimeoutMs > 0)
|
|
114
|
+
{
|
|
115
|
+
tmpTimeoutHandle = setTimeout(function()
|
|
116
|
+
{
|
|
117
|
+
if (!tmpCompleted)
|
|
118
|
+
{
|
|
119
|
+
tmpCompleted = true;
|
|
120
|
+
let tmpElapsedMs = Date.now() - tmpStartTime;
|
|
121
|
+
return fCallback(null, {
|
|
122
|
+
EventToFire: 'Error',
|
|
123
|
+
Outputs: { Result: 'Operation timed out', Status: 'Timeout', ElapsedMs: tmpElapsedMs },
|
|
124
|
+
Log: [`Child operation [${tmpOperationHash}] timed out after ${tmpTimeoutMs}ms`]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}, tmpTimeoutMs);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Execute the child operation
|
|
131
|
+
tmpEngine.executeOperation(pOperation, tmpInitialState,
|
|
132
|
+
(pExecError, pContext) =>
|
|
133
|
+
{
|
|
134
|
+
if (tmpCompleted) { return; }
|
|
135
|
+
tmpCompleted = true;
|
|
136
|
+
if (tmpTimeoutHandle) { clearTimeout(tmpTimeoutHandle); }
|
|
137
|
+
|
|
138
|
+
let tmpElapsedMs = Date.now() - tmpStartTime;
|
|
139
|
+
|
|
140
|
+
if (pExecError)
|
|
141
|
+
{
|
|
142
|
+
return fCallback(null, {
|
|
143
|
+
EventToFire: 'Error',
|
|
144
|
+
Outputs: {
|
|
145
|
+
Result: pExecError.message,
|
|
146
|
+
Status: 'Error',
|
|
147
|
+
ElapsedMs: tmpElapsedMs
|
|
148
|
+
},
|
|
149
|
+
Log: [`Child operation [${tmpOperationHash}] failed: ${pExecError.message}`]
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let tmpStatus = pContext.Status || 'Unknown';
|
|
154
|
+
let tmpResultSummary = JSON.stringify({
|
|
155
|
+
Status: tmpStatus,
|
|
156
|
+
TaskOutputs: pContext.TaskOutputs || {},
|
|
157
|
+
Errors: pContext.Errors || []
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return fCallback(null, {
|
|
161
|
+
EventToFire: 'Completed',
|
|
162
|
+
Outputs: {
|
|
163
|
+
Result: tmpResultSummary,
|
|
164
|
+
Status: tmpStatus,
|
|
165
|
+
ElapsedMs: tmpElapsedMs
|
|
166
|
+
},
|
|
167
|
+
Log: [`Child operation [${tmpOperationHash}] completed with status: ${tmpStatus} (${tmpElapsedMs}ms)`]
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get a service instance from the fable services map.
|
|
175
|
+
*/
|
|
176
|
+
_getService(pTypeName)
|
|
177
|
+
{
|
|
178
|
+
if (this.fable.servicesMap[pTypeName])
|
|
179
|
+
{
|
|
180
|
+
return Object.values(this.fable.servicesMap[pTypeName])[0];
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = UltravisorTaskTypeLaunchOperation;
|