ultravisor 1.0.2 → 1.0.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/.claude/launch.json +11 -0
- package/.claude/ultravisor-dev-config.json +3 -0
- package/.ultravisor.json +426 -0
- package/docs/README.md +63 -0
- package/package.json +12 -8
- package/source/Ultravisor.cjs +22 -3
- package/source/cli/Ultravisor-CLIProgram.cjs +35 -23
- 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 +5 -3
- package/source/services/Ultravisor-ExecutionEngine.cjs +1039 -0
- package/source/services/Ultravisor-ExecutionManifest.cjs +399 -0
- package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
- package/source/services/Ultravisor-Hypervisor.cjs +38 -83
- package/source/services/Ultravisor-StateManager.cjs +241 -0
- package/source/services/Ultravisor-TaskTypeRegistry.cjs +143 -0
- package/source/services/tasks/Ultravisor-TaskType-Base.cjs +105 -0
- package/source/services/tasks/control/Ultravisor-TaskType-IfConditional.cjs +148 -0
- package/source/services/tasks/control/Ultravisor-TaskType-LaunchOperation.cjs +187 -0
- package/source/services/tasks/control/Ultravisor-TaskType-SplitExecute.cjs +184 -0
- package/source/services/tasks/data/Ultravisor-TaskType-ReplaceString.cjs +82 -0
- package/source/services/tasks/data/Ultravisor-TaskType-SetValues.cjs +81 -0
- package/source/services/tasks/data/Ultravisor-TaskType-StringAppender.cjs +101 -0
- package/source/services/tasks/file-io/Ultravisor-TaskType-ReadFile.cjs +103 -0
- package/source/services/tasks/file-io/Ultravisor-TaskType-WriteFile.cjs +117 -0
- package/source/services/tasks/interaction/Ultravisor-TaskType-ErrorMessage.cjs +54 -0
- package/source/services/tasks/interaction/Ultravisor-TaskType-ValueInput.cjs +62 -0
- package/source/web_server/Ultravisor-API-Server.cjs +237 -124
- package/test/Ultravisor_browser_tests.js +2226 -0
- package/test/Ultravisor_tests.js +1143 -5830
- package/webinterface/css/ultravisor.css +23 -0
- package/webinterface/package.json +6 -3
- package/webinterface/source/Pict-Application-Ultravisor.js +93 -73
- package/webinterface/source/cards/FlowCard-CSVTransform.js +43 -0
- package/webinterface/source/cards/FlowCard-Command.js +86 -0
- package/webinterface/source/cards/FlowCard-ComprehensionIntersect.js +40 -0
- package/webinterface/source/cards/FlowCard-Conditional.js +87 -0
- package/webinterface/source/cards/FlowCard-CopyFile.js +55 -0
- package/webinterface/source/cards/FlowCard-End.js +29 -0
- package/webinterface/source/cards/FlowCard-GetJSON.js +55 -0
- package/webinterface/source/cards/FlowCard-GetText.js +54 -0
- package/webinterface/source/cards/FlowCard-Histogram.js +176 -0
- package/webinterface/source/cards/FlowCard-LaunchOperation.js +82 -0
- package/webinterface/source/cards/FlowCard-ListFiles.js +55 -0
- package/webinterface/source/cards/FlowCard-MeadowCount.js +44 -0
- package/webinterface/source/cards/FlowCard-MeadowCreate.js +44 -0
- package/webinterface/source/cards/FlowCard-MeadowDelete.js +45 -0
- package/webinterface/source/cards/FlowCard-MeadowRead.js +46 -0
- package/webinterface/source/cards/FlowCard-MeadowReads.js +46 -0
- package/webinterface/source/cards/FlowCard-MeadowUpdate.js +44 -0
- package/webinterface/source/cards/FlowCard-ParseCSV.js +85 -0
- package/webinterface/source/cards/FlowCard-ReadJSON.js +54 -0
- package/webinterface/source/cards/FlowCard-ReadText.js +54 -0
- package/webinterface/source/cards/FlowCard-RestRequest.js +59 -0
- package/webinterface/source/cards/FlowCard-SendJSON.js +57 -0
- package/webinterface/source/cards/FlowCard-Solver.js +77 -0
- package/webinterface/source/cards/FlowCard-Start.js +29 -0
- package/webinterface/source/cards/FlowCard-TemplateString.js +77 -0
- package/webinterface/source/cards/FlowCard-WriteJSON.js +54 -0
- package/webinterface/source/cards/FlowCard-WriteText.js +54 -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/providers/PictRouter-Ultravisor-Configuration.json +8 -8
- package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +6 -6
- package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +436 -0
- package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +45 -43
- package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +34 -89
- package/webinterface/source/views/PictView-Ultravisor-OperationList.js +128 -13
- package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
- package/webinterface/source/views/PictView-Ultravisor-Schedule.js +18 -53
- package/webinterface/source/views/PictView-Ultravisor-TimingView.js +27 -14
- package/webinterface/source/views/PictView-Ultravisor-TopBar.js +2 -1
- package/.babelrc +0 -6
- package/.browserslistrc +0 -1
- package/.browserslistrc-BACKUP +0 -1
- package/.gulpfile-quackage-config.json +0 -7
- package/.gulpfile-quackage.js +0 -2
- package/debug/Harness.js +0 -5
- 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/.babelrc +0 -6
- package/webinterface/.browserslistrc +0 -1
- package/webinterface/.browserslistrc-BACKUP +0 -1
- package/webinterface/.gulpfile-quackage-config.json +0 -7
- package/webinterface/.gulpfile-quackage.js +0 -2
- package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
- package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
- /package/docs/{cover.md → _cover.md} +0 -0
|
@@ -0,0 +1,187 @@
|
|
|
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 {
|
|
29
|
+
Hash: 'launch-operation',
|
|
30
|
+
Type: 'launch-operation',
|
|
31
|
+
Name: 'Launch Operation',
|
|
32
|
+
Description: 'Executes a child operation by hash, with isolated operation state.',
|
|
33
|
+
Category: 'control',
|
|
34
|
+
|
|
35
|
+
EventInputs: [
|
|
36
|
+
{ Name: 'Launch' }
|
|
37
|
+
],
|
|
38
|
+
EventOutputs: [
|
|
39
|
+
{ Name: 'Completed' },
|
|
40
|
+
{ Name: 'Error', IsError: true }
|
|
41
|
+
],
|
|
42
|
+
SettingsInputs: [
|
|
43
|
+
{ Name: 'OperationHash', DataType: 'String', Required: true },
|
|
44
|
+
{ Name: 'InputData', DataType: 'String' }
|
|
45
|
+
],
|
|
46
|
+
StateOutputs: [
|
|
47
|
+
{ Name: 'Result', DataType: 'String' },
|
|
48
|
+
{ Name: 'Status', DataType: 'String' },
|
|
49
|
+
{ Name: 'ElapsedMs', DataType: 'Number' }
|
|
50
|
+
],
|
|
51
|
+
|
|
52
|
+
DefaultSettings: { OperationHash: '', InputData: '' }
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
execute(pResolvedSettings, pExecutionContext, fCallback, fFireIntermediateEvent)
|
|
57
|
+
{
|
|
58
|
+
let tmpOperationHash = pResolvedSettings.OperationHash;
|
|
59
|
+
|
|
60
|
+
if (!tmpOperationHash || typeof(tmpOperationHash) !== 'string' || tmpOperationHash.length === 0)
|
|
61
|
+
{
|
|
62
|
+
return fCallback(null, {
|
|
63
|
+
EventToFire: 'Error',
|
|
64
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
65
|
+
Log: ['No OperationHash specified.']
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Get the Hypervisor state service to look up the operation
|
|
70
|
+
let tmpStateService = this._getService('UltravisorHypervisorState');
|
|
71
|
+
|
|
72
|
+
if (!tmpStateService)
|
|
73
|
+
{
|
|
74
|
+
return fCallback(null, {
|
|
75
|
+
EventToFire: 'Error',
|
|
76
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
77
|
+
Log: ['UltravisorHypervisorState service not found.']
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Get the ExecutionEngine to run the child operation
|
|
82
|
+
let tmpEngine = this._getService('UltravisorExecutionEngine');
|
|
83
|
+
|
|
84
|
+
if (!tmpEngine)
|
|
85
|
+
{
|
|
86
|
+
return fCallback(null, {
|
|
87
|
+
EventToFire: 'Error',
|
|
88
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
89
|
+
Log: ['UltravisorExecutionEngine service not found.']
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Look up the target operation
|
|
94
|
+
tmpStateService.getOperation(tmpOperationHash,
|
|
95
|
+
(pError, pOperation) =>
|
|
96
|
+
{
|
|
97
|
+
if (pError)
|
|
98
|
+
{
|
|
99
|
+
return fCallback(null, {
|
|
100
|
+
EventToFire: 'Error',
|
|
101
|
+
Outputs: { Result: '', Status: 'Error', ElapsedMs: 0 },
|
|
102
|
+
Log: [`Operation [${tmpOperationHash}] not found: ${pError.message}`]
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Build initial state for the child operation
|
|
107
|
+
let tmpInitialState = {
|
|
108
|
+
// Share a copy of the parent's global state
|
|
109
|
+
GlobalState: JSON.parse(JSON.stringify(pExecutionContext.GlobalState || {})),
|
|
110
|
+
// Isolated operation state, optionally seeded from InputData
|
|
111
|
+
OperationState: {},
|
|
112
|
+
RunMode: pExecutionContext.RunMode || 'standard'
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Parse InputData if provided (expects JSON string)
|
|
116
|
+
if (pResolvedSettings.InputData && typeof(pResolvedSettings.InputData) === 'string' && pResolvedSettings.InputData.length > 0)
|
|
117
|
+
{
|
|
118
|
+
try
|
|
119
|
+
{
|
|
120
|
+
let tmpInputData = JSON.parse(pResolvedSettings.InputData);
|
|
121
|
+
if (typeof(tmpInputData) === 'object' && tmpInputData !== null)
|
|
122
|
+
{
|
|
123
|
+
tmpInitialState.OperationState = tmpInputData;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (pParseError)
|
|
127
|
+
{
|
|
128
|
+
// If not valid JSON, store as a raw string in OperationState.InputData
|
|
129
|
+
tmpInitialState.OperationState.InputData = pResolvedSettings.InputData;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let tmpStartTime = Date.now();
|
|
134
|
+
|
|
135
|
+
// Execute the child operation
|
|
136
|
+
tmpEngine.executeOperation(pOperation, tmpInitialState,
|
|
137
|
+
(pExecError, pContext) =>
|
|
138
|
+
{
|
|
139
|
+
let tmpElapsedMs = Date.now() - tmpStartTime;
|
|
140
|
+
|
|
141
|
+
if (pExecError)
|
|
142
|
+
{
|
|
143
|
+
return fCallback(null, {
|
|
144
|
+
EventToFire: 'Error',
|
|
145
|
+
Outputs: {
|
|
146
|
+
Result: pExecError.message,
|
|
147
|
+
Status: 'Error',
|
|
148
|
+
ElapsedMs: tmpElapsedMs
|
|
149
|
+
},
|
|
150
|
+
Log: [`Child operation [${tmpOperationHash}] failed: ${pExecError.message}`]
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let tmpStatus = pContext.Status || 'Unknown';
|
|
155
|
+
let tmpResultSummary = JSON.stringify({
|
|
156
|
+
Status: tmpStatus,
|
|
157
|
+
TaskOutputs: pContext.TaskOutputs || {},
|
|
158
|
+
Errors: pContext.Errors || []
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return fCallback(null, {
|
|
162
|
+
EventToFire: 'Completed',
|
|
163
|
+
Outputs: {
|
|
164
|
+
Result: tmpResultSummary,
|
|
165
|
+
Status: tmpStatus,
|
|
166
|
+
ElapsedMs: tmpElapsedMs
|
|
167
|
+
},
|
|
168
|
+
Log: [`Child operation [${tmpOperationHash}] completed with status: ${tmpStatus} (${tmpElapsedMs}ms)`]
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get a service instance from the fable services map.
|
|
176
|
+
*/
|
|
177
|
+
_getService(pTypeName)
|
|
178
|
+
{
|
|
179
|
+
if (this.fable.servicesMap[pTypeName])
|
|
180
|
+
{
|
|
181
|
+
return Object.values(this.fable.servicesMap[pTypeName])[0];
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
module.exports = UltravisorTaskTypeLaunchOperation;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const libTaskTypeBase = require('../Ultravisor-TaskType-Base.cjs');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SplitExecute Task Type
|
|
5
|
+
*
|
|
6
|
+
* Splits an input string by a delimiter and fires an event for each token.
|
|
7
|
+
* Operates as a state machine: each invocation processes exactly one token.
|
|
8
|
+
*
|
|
9
|
+
* Flow (driven by graph connections):
|
|
10
|
+
* PerformSplit -> split input, store tokens, emit first token via TokenDataSent
|
|
11
|
+
* StepComplete -> advance to next token, emit via TokenDataSent
|
|
12
|
+
* (or fire CompletedAllSubtasks when all tokens are done)
|
|
13
|
+
*
|
|
14
|
+
* The loop is driven by explicit graph connections:
|
|
15
|
+
* SplitExecute.TokenDataSent -> downstream tasks -> ... -> SplitExecute.StepComplete
|
|
16
|
+
*
|
|
17
|
+
* State is persisted between invocations in TaskOutputs[NodeHash]:
|
|
18
|
+
* _Tokens {Array} - the split token array (internal)
|
|
19
|
+
* CurrentToken {string} - the current token being processed
|
|
20
|
+
* TokenIndex {number} - 0-based index of the current token
|
|
21
|
+
* TokenCount {number} - total number of tokens
|
|
22
|
+
* CompletedCount {number} - number of tokens fully processed
|
|
23
|
+
*/
|
|
24
|
+
class UltravisorTaskTypeSplitExecute extends libTaskTypeBase
|
|
25
|
+
{
|
|
26
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
27
|
+
{
|
|
28
|
+
super(pFable, pOptions, pServiceHash);
|
|
29
|
+
|
|
30
|
+
this.serviceType = 'UltravisorTaskTypeSplitExecute';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get definition()
|
|
34
|
+
{
|
|
35
|
+
return {
|
|
36
|
+
Hash: 'split-execute',
|
|
37
|
+
Type: 'split-execute',
|
|
38
|
+
Name: 'Split Execute',
|
|
39
|
+
Description: 'Splits a string by delimiter and processes each token through a sub-graph.',
|
|
40
|
+
Category: 'control',
|
|
41
|
+
|
|
42
|
+
EventInputs: [
|
|
43
|
+
{ Name: 'PerformSplit' },
|
|
44
|
+
{ Name: 'StepComplete' }
|
|
45
|
+
],
|
|
46
|
+
EventOutputs: [
|
|
47
|
+
{ Name: 'TokenDataSent' },
|
|
48
|
+
{ Name: 'CompletedAllSubtasks' },
|
|
49
|
+
{ Name: 'Error', IsError: true }
|
|
50
|
+
],
|
|
51
|
+
SettingsInputs: [
|
|
52
|
+
{ Name: 'InputString', DataType: 'String', Required: true },
|
|
53
|
+
{ Name: 'SplitDelimiter', DataType: 'String', Required: true }
|
|
54
|
+
],
|
|
55
|
+
StateOutputs: [
|
|
56
|
+
{ Name: 'CurrentToken', DataType: 'String' },
|
|
57
|
+
{ Name: 'TokenIndex', DataType: 'Number' },
|
|
58
|
+
{ Name: 'TokenCount', DataType: 'Number' },
|
|
59
|
+
{ Name: 'CompletedCount', DataType: 'Number' }
|
|
60
|
+
],
|
|
61
|
+
|
|
62
|
+
DefaultSettings: { InputString: '', SplitDelimiter: '\n' }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
execute(pResolvedSettings, pExecutionContext, fCallback, fFireIntermediateEvent)
|
|
67
|
+
{
|
|
68
|
+
let tmpTriggeringEvent = pExecutionContext.TriggeringEventName;
|
|
69
|
+
|
|
70
|
+
if (tmpTriggeringEvent === 'StepComplete')
|
|
71
|
+
{
|
|
72
|
+
return this._handleStepComplete(pExecutionContext, fCallback);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Default: PerformSplit (initial trigger)
|
|
76
|
+
return this._handlePerformSplit(pResolvedSettings, pExecutionContext, fCallback);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Handle the PerformSplit event: split input and emit the first token.
|
|
81
|
+
*/
|
|
82
|
+
_handlePerformSplit(pResolvedSettings, pExecutionContext, fCallback)
|
|
83
|
+
{
|
|
84
|
+
let tmpInputString = pResolvedSettings.InputString;
|
|
85
|
+
let tmpDelimiter = pResolvedSettings.SplitDelimiter;
|
|
86
|
+
|
|
87
|
+
if (typeof(tmpInputString) !== 'string')
|
|
88
|
+
{
|
|
89
|
+
return fCallback(null, {
|
|
90
|
+
EventToFire: 'Error',
|
|
91
|
+
Outputs: { CurrentToken: '', TokenIndex: 0, TokenCount: 0, CompletedCount: 0 },
|
|
92
|
+
Log: ['InputString is not a string.']
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (tmpDelimiter === undefined || tmpDelimiter === null)
|
|
97
|
+
{
|
|
98
|
+
tmpDelimiter = '\n';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let tmpTokens = tmpInputString.split(tmpDelimiter);
|
|
102
|
+
let tmpTokenCount = tmpTokens.length;
|
|
103
|
+
let tmpLog = [`Splitting input (${tmpInputString.length} chars) by "${tmpDelimiter}" into ${tmpTokenCount} tokens.`];
|
|
104
|
+
|
|
105
|
+
if (tmpTokenCount === 0)
|
|
106
|
+
{
|
|
107
|
+
return fCallback(null, {
|
|
108
|
+
EventToFire: 'CompletedAllSubtasks',
|
|
109
|
+
Outputs: { CurrentToken: '', TokenIndex: 0, TokenCount: 0, CompletedCount: 0 },
|
|
110
|
+
Log: tmpLog.concat(['No tokens to process.'])
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let tmpFirstToken = tmpTokens[0];
|
|
115
|
+
tmpLog.push(`Emitting token 1/${tmpTokenCount}: "${tmpFirstToken.substring(0, 50)}"`);
|
|
116
|
+
|
|
117
|
+
return fCallback(null, {
|
|
118
|
+
EventToFire: 'TokenDataSent',
|
|
119
|
+
Outputs: {
|
|
120
|
+
_Tokens: tmpTokens,
|
|
121
|
+
CurrentToken: tmpFirstToken,
|
|
122
|
+
TokenIndex: 0,
|
|
123
|
+
TokenCount: tmpTokenCount,
|
|
124
|
+
CompletedCount: 0
|
|
125
|
+
},
|
|
126
|
+
Log: tmpLog
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Handle the StepComplete event: advance to the next token or finish.
|
|
132
|
+
*/
|
|
133
|
+
_handleStepComplete(pExecutionContext, fCallback)
|
|
134
|
+
{
|
|
135
|
+
let tmpStoredState = pExecutionContext.TaskOutputs[pExecutionContext.NodeHash] || {};
|
|
136
|
+
let tmpTokens = tmpStoredState._Tokens;
|
|
137
|
+
|
|
138
|
+
if (!Array.isArray(tmpTokens))
|
|
139
|
+
{
|
|
140
|
+
return fCallback(null, {
|
|
141
|
+
EventToFire: 'Error',
|
|
142
|
+
Outputs: { CurrentToken: '', TokenIndex: 0, TokenCount: 0, CompletedCount: 0 },
|
|
143
|
+
Log: ['StepComplete received but no stored tokens found. Was PerformSplit called first?']
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let tmpTokenCount = tmpTokens.length;
|
|
148
|
+
let tmpPreviousIndex = tmpStoredState.TokenIndex || 0;
|
|
149
|
+
let tmpCompletedCount = (tmpStoredState.CompletedCount || 0) + 1;
|
|
150
|
+
let tmpNextIndex = tmpPreviousIndex + 1;
|
|
151
|
+
|
|
152
|
+
if (tmpNextIndex >= tmpTokenCount)
|
|
153
|
+
{
|
|
154
|
+
// All tokens processed
|
|
155
|
+
return fCallback(null, {
|
|
156
|
+
EventToFire: 'CompletedAllSubtasks',
|
|
157
|
+
Outputs: {
|
|
158
|
+
_Tokens: tmpTokens,
|
|
159
|
+
CurrentToken: tmpTokens[tmpTokenCount - 1],
|
|
160
|
+
TokenIndex: tmpTokenCount - 1,
|
|
161
|
+
TokenCount: tmpTokenCount,
|
|
162
|
+
CompletedCount: tmpCompletedCount
|
|
163
|
+
},
|
|
164
|
+
Log: [`All ${tmpTokenCount} tokens processed (${tmpCompletedCount} completed).`]
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let tmpNextToken = tmpTokens[tmpNextIndex];
|
|
169
|
+
|
|
170
|
+
return fCallback(null, {
|
|
171
|
+
EventToFire: 'TokenDataSent',
|
|
172
|
+
Outputs: {
|
|
173
|
+
_Tokens: tmpTokens,
|
|
174
|
+
CurrentToken: tmpNextToken,
|
|
175
|
+
TokenIndex: tmpNextIndex,
|
|
176
|
+
TokenCount: tmpTokenCount,
|
|
177
|
+
CompletedCount: tmpCompletedCount
|
|
178
|
+
},
|
|
179
|
+
Log: [`Emitting token ${tmpNextIndex + 1}/${tmpTokenCount}: "${tmpNextToken.substring(0, 50)}"`]
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = UltravisorTaskTypeSplitExecute;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const libTaskTypeBase = require('../Ultravisor-TaskType-Base.cjs');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ReplaceString Task Type
|
|
5
|
+
*
|
|
6
|
+
* Performs string find-and-replace on InputString.
|
|
7
|
+
* Replaces all occurrences of SearchString with ReplaceString.
|
|
8
|
+
*/
|
|
9
|
+
class UltravisorTaskTypeReplaceString extends libTaskTypeBase
|
|
10
|
+
{
|
|
11
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
12
|
+
{
|
|
13
|
+
super(pFable, pOptions, pServiceHash);
|
|
14
|
+
|
|
15
|
+
this.serviceType = 'UltravisorTaskTypeReplaceString';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get definition()
|
|
19
|
+
{
|
|
20
|
+
return {
|
|
21
|
+
Hash: 'replace-string',
|
|
22
|
+
Type: 'replace-string',
|
|
23
|
+
Name: 'Replace String',
|
|
24
|
+
Description: 'Replaces all occurrences of a search string within the input.',
|
|
25
|
+
Category: 'data',
|
|
26
|
+
|
|
27
|
+
EventInputs: [{ Name: 'Replace' }],
|
|
28
|
+
EventOutputs: [
|
|
29
|
+
{ Name: 'ReplaceComplete' },
|
|
30
|
+
{ Name: 'Error', IsError: true }
|
|
31
|
+
],
|
|
32
|
+
SettingsInputs: [
|
|
33
|
+
{ Name: 'InputString', DataType: 'String', Required: true },
|
|
34
|
+
{ Name: 'SearchString', DataType: 'String', Required: true },
|
|
35
|
+
{ Name: 'ReplaceString', DataType: 'String', Required: false }
|
|
36
|
+
],
|
|
37
|
+
StateOutputs: [
|
|
38
|
+
{ Name: 'ReplacedString', DataType: 'String' }
|
|
39
|
+
],
|
|
40
|
+
|
|
41
|
+
DefaultSettings: { InputString: '', SearchString: '', ReplaceString: '' }
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
execute(pResolvedSettings, pExecutionContext, fCallback, fFireIntermediateEvent)
|
|
46
|
+
{
|
|
47
|
+
let tmpInputString = pResolvedSettings.InputString;
|
|
48
|
+
let tmpSearchString = pResolvedSettings.SearchString;
|
|
49
|
+
let tmpReplaceString = pResolvedSettings.ReplaceString || '';
|
|
50
|
+
|
|
51
|
+
if (typeof(tmpInputString) !== 'string')
|
|
52
|
+
{
|
|
53
|
+
return fCallback(null, {
|
|
54
|
+
EventToFire: 'Error',
|
|
55
|
+
Outputs: {},
|
|
56
|
+
Log: ['InputString is not a string.']
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!tmpSearchString || typeof(tmpSearchString) !== 'string')
|
|
61
|
+
{
|
|
62
|
+
return fCallback(null, {
|
|
63
|
+
EventToFire: 'Error',
|
|
64
|
+
Outputs: {},
|
|
65
|
+
Log: ['SearchString is empty or not a string.']
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Replace all occurrences
|
|
70
|
+
let tmpResult = tmpInputString.split(tmpSearchString).join(tmpReplaceString);
|
|
71
|
+
|
|
72
|
+
return fCallback(null, {
|
|
73
|
+
EventToFire: 'ReplaceComplete',
|
|
74
|
+
Outputs: {
|
|
75
|
+
ReplacedString: tmpResult
|
|
76
|
+
},
|
|
77
|
+
Log: [`Replaced "${tmpSearchString}" with "${tmpReplaceString}" (${tmpInputString.split(tmpSearchString).length - 1} occurrences).`]
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = UltravisorTaskTypeReplaceString;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const libTaskTypeBase = require('../Ultravisor-TaskType-Base.cjs');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SetValues Task Type
|
|
5
|
+
*
|
|
6
|
+
* Sets one or more values in state at specified addresses.
|
|
7
|
+
* Used for initializing state, transforming data between levels, or
|
|
8
|
+
* setting computed values.
|
|
9
|
+
*
|
|
10
|
+
* Settings.Mappings is an array of { Address, Value } objects.
|
|
11
|
+
* Each mapping sets the value at the given state address.
|
|
12
|
+
*/
|
|
13
|
+
class UltravisorTaskTypeSetValues extends libTaskTypeBase
|
|
14
|
+
{
|
|
15
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
16
|
+
{
|
|
17
|
+
super(pFable, pOptions, pServiceHash);
|
|
18
|
+
|
|
19
|
+
this.serviceType = 'UltravisorTaskTypeSetValues';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get definition()
|
|
23
|
+
{
|
|
24
|
+
return {
|
|
25
|
+
Hash: 'set-values',
|
|
26
|
+
Type: 'set-values',
|
|
27
|
+
Name: 'Set Values',
|
|
28
|
+
Description: 'Sets one or more values in state at specified addresses.',
|
|
29
|
+
Category: 'data',
|
|
30
|
+
|
|
31
|
+
EventInputs: [{ Name: 'Execute' }],
|
|
32
|
+
EventOutputs: [{ Name: 'Complete' }],
|
|
33
|
+
SettingsInputs: [
|
|
34
|
+
{ Name: 'Mappings', DataType: 'Array', Required: true }
|
|
35
|
+
],
|
|
36
|
+
StateOutputs: [],
|
|
37
|
+
|
|
38
|
+
DefaultSettings: { Mappings: [] }
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
execute(pResolvedSettings, pExecutionContext, fCallback, fFireIntermediateEvent)
|
|
43
|
+
{
|
|
44
|
+
let tmpMappings = pResolvedSettings.Mappings;
|
|
45
|
+
|
|
46
|
+
if (!Array.isArray(tmpMappings))
|
|
47
|
+
{
|
|
48
|
+
return fCallback(null, {
|
|
49
|
+
EventToFire: 'Complete',
|
|
50
|
+
Outputs: {},
|
|
51
|
+
Log: ['No mappings provided or Mappings is not an array.']
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let tmpStateWrites = {};
|
|
56
|
+
let tmpLog = [];
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < tmpMappings.length; i++)
|
|
59
|
+
{
|
|
60
|
+
let tmpMapping = tmpMappings[i];
|
|
61
|
+
|
|
62
|
+
if (!tmpMapping || !tmpMapping.Address)
|
|
63
|
+
{
|
|
64
|
+
tmpLog.push(`Mapping ${i}: skipped (no Address).`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
tmpStateWrites[tmpMapping.Address] = tmpMapping.Value;
|
|
69
|
+
tmpLog.push(`Set [${tmpMapping.Address}] = ${JSON.stringify(tmpMapping.Value)}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return fCallback(null, {
|
|
73
|
+
EventToFire: 'Complete',
|
|
74
|
+
Outputs: {},
|
|
75
|
+
StateWrites: tmpStateWrites,
|
|
76
|
+
Log: tmpLog
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = UltravisorTaskTypeSetValues;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const libTaskTypeBase = require('../Ultravisor-TaskType-Base.cjs');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* StringAppender Task Type
|
|
5
|
+
*
|
|
6
|
+
* Appends InputString to the value at OutputAddress.
|
|
7
|
+
* If the target address is empty/undefined, sets it to InputString.
|
|
8
|
+
* Useful for accumulating results across loop iterations (e.g., split-execute).
|
|
9
|
+
*/
|
|
10
|
+
class UltravisorTaskTypeStringAppender extends libTaskTypeBase
|
|
11
|
+
{
|
|
12
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
13
|
+
{
|
|
14
|
+
super(pFable, pOptions, pServiceHash);
|
|
15
|
+
|
|
16
|
+
this.serviceType = 'UltravisorTaskTypeStringAppender';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get definition()
|
|
20
|
+
{
|
|
21
|
+
return {
|
|
22
|
+
Hash: 'string-appender',
|
|
23
|
+
Type: 'string-appender',
|
|
24
|
+
Name: 'String Appender',
|
|
25
|
+
Description: 'Appends a string to a value at a specified state address.',
|
|
26
|
+
Category: 'data',
|
|
27
|
+
|
|
28
|
+
EventInputs: [{ Name: 'Append' }],
|
|
29
|
+
EventOutputs: [{ Name: 'Completed' }],
|
|
30
|
+
SettingsInputs: [
|
|
31
|
+
{ Name: 'InputString', DataType: 'String', Required: true },
|
|
32
|
+
{ Name: 'OutputAddress', DataType: 'String', Required: true },
|
|
33
|
+
{ Name: 'AppendNewline', DataType: 'Boolean', Required: false, Description: 'When true, append a newline after each InputString.' }
|
|
34
|
+
],
|
|
35
|
+
StateOutputs: [
|
|
36
|
+
{ Name: 'AppendedString', DataType: 'String' }
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
DefaultSettings: { InputString: '', OutputAddress: '', AppendNewline: false }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
execute(pResolvedSettings, pExecutionContext, fCallback, fFireIntermediateEvent)
|
|
44
|
+
{
|
|
45
|
+
let tmpInputString = pResolvedSettings.InputString;
|
|
46
|
+
let tmpOutputAddress = pResolvedSettings.OutputAddress;
|
|
47
|
+
|
|
48
|
+
if (typeof(tmpInputString) !== 'string')
|
|
49
|
+
{
|
|
50
|
+
tmpInputString = String(tmpInputString !== undefined ? tmpInputString : '');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!tmpOutputAddress || typeof(tmpOutputAddress) !== 'string')
|
|
54
|
+
{
|
|
55
|
+
// No output address — just pass through as output
|
|
56
|
+
return fCallback(null, {
|
|
57
|
+
EventToFire: 'Completed',
|
|
58
|
+
Outputs: {
|
|
59
|
+
AppendedString: tmpInputString
|
|
60
|
+
},
|
|
61
|
+
Log: ['No OutputAddress specified, returning InputString as AppendedString.']
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Read the existing value at the output address
|
|
66
|
+
let tmpStateManager = pExecutionContext.StateManager;
|
|
67
|
+
let tmpExistingValue = '';
|
|
68
|
+
|
|
69
|
+
if (tmpStateManager)
|
|
70
|
+
{
|
|
71
|
+
let tmpResolved = tmpStateManager.resolveAddress(tmpOutputAddress, pExecutionContext, pExecutionContext.NodeHash);
|
|
72
|
+
|
|
73
|
+
if (tmpResolved !== undefined && tmpResolved !== null)
|
|
74
|
+
{
|
|
75
|
+
tmpExistingValue = String(tmpResolved);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Optionally add a newline after the input string
|
|
80
|
+
if (pResolvedSettings.AppendNewline)
|
|
81
|
+
{
|
|
82
|
+
tmpInputString = tmpInputString + '\n';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let tmpAppendedValue = tmpExistingValue + tmpInputString;
|
|
86
|
+
|
|
87
|
+
let tmpStateWrites = {};
|
|
88
|
+
tmpStateWrites[tmpOutputAddress] = tmpAppendedValue;
|
|
89
|
+
|
|
90
|
+
return fCallback(null, {
|
|
91
|
+
EventToFire: 'Completed',
|
|
92
|
+
Outputs: {
|
|
93
|
+
AppendedString: tmpAppendedValue
|
|
94
|
+
},
|
|
95
|
+
StateWrites: tmpStateWrites,
|
|
96
|
+
Log: [`Appended ${tmpInputString.length} chars to [${tmpOutputAddress}] (total: ${tmpAppendedValue.length}).`]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = UltravisorTaskTypeStringAppender;
|