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.
Files changed (121) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.claude/ultravisor-dev-config.json +3 -0
  3. package/.ultravisor.json +426 -0
  4. package/docs/README.md +63 -0
  5. package/package.json +12 -8
  6. package/source/Ultravisor.cjs +22 -3
  7. package/source/cli/Ultravisor-CLIProgram.cjs +35 -23
  8. package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
  9. package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
  10. package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
  11. package/source/config/Ultravisor-Default-Command-Configuration.cjs +5 -3
  12. package/source/services/Ultravisor-ExecutionEngine.cjs +1039 -0
  13. package/source/services/Ultravisor-ExecutionManifest.cjs +399 -0
  14. package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
  15. package/source/services/Ultravisor-Hypervisor.cjs +38 -83
  16. package/source/services/Ultravisor-StateManager.cjs +241 -0
  17. package/source/services/Ultravisor-TaskTypeRegistry.cjs +143 -0
  18. package/source/services/tasks/Ultravisor-TaskType-Base.cjs +105 -0
  19. package/source/services/tasks/control/Ultravisor-TaskType-IfConditional.cjs +148 -0
  20. package/source/services/tasks/control/Ultravisor-TaskType-LaunchOperation.cjs +187 -0
  21. package/source/services/tasks/control/Ultravisor-TaskType-SplitExecute.cjs +184 -0
  22. package/source/services/tasks/data/Ultravisor-TaskType-ReplaceString.cjs +82 -0
  23. package/source/services/tasks/data/Ultravisor-TaskType-SetValues.cjs +81 -0
  24. package/source/services/tasks/data/Ultravisor-TaskType-StringAppender.cjs +101 -0
  25. package/source/services/tasks/file-io/Ultravisor-TaskType-ReadFile.cjs +103 -0
  26. package/source/services/tasks/file-io/Ultravisor-TaskType-WriteFile.cjs +117 -0
  27. package/source/services/tasks/interaction/Ultravisor-TaskType-ErrorMessage.cjs +54 -0
  28. package/source/services/tasks/interaction/Ultravisor-TaskType-ValueInput.cjs +62 -0
  29. package/source/web_server/Ultravisor-API-Server.cjs +237 -124
  30. package/test/Ultravisor_browser_tests.js +2226 -0
  31. package/test/Ultravisor_tests.js +1143 -5830
  32. package/webinterface/css/ultravisor.css +23 -0
  33. package/webinterface/package.json +6 -3
  34. package/webinterface/source/Pict-Application-Ultravisor.js +93 -73
  35. package/webinterface/source/cards/FlowCard-CSVTransform.js +43 -0
  36. package/webinterface/source/cards/FlowCard-Command.js +86 -0
  37. package/webinterface/source/cards/FlowCard-ComprehensionIntersect.js +40 -0
  38. package/webinterface/source/cards/FlowCard-Conditional.js +87 -0
  39. package/webinterface/source/cards/FlowCard-CopyFile.js +55 -0
  40. package/webinterface/source/cards/FlowCard-End.js +29 -0
  41. package/webinterface/source/cards/FlowCard-GetJSON.js +55 -0
  42. package/webinterface/source/cards/FlowCard-GetText.js +54 -0
  43. package/webinterface/source/cards/FlowCard-Histogram.js +176 -0
  44. package/webinterface/source/cards/FlowCard-LaunchOperation.js +82 -0
  45. package/webinterface/source/cards/FlowCard-ListFiles.js +55 -0
  46. package/webinterface/source/cards/FlowCard-MeadowCount.js +44 -0
  47. package/webinterface/source/cards/FlowCard-MeadowCreate.js +44 -0
  48. package/webinterface/source/cards/FlowCard-MeadowDelete.js +45 -0
  49. package/webinterface/source/cards/FlowCard-MeadowRead.js +46 -0
  50. package/webinterface/source/cards/FlowCard-MeadowReads.js +46 -0
  51. package/webinterface/source/cards/FlowCard-MeadowUpdate.js +44 -0
  52. package/webinterface/source/cards/FlowCard-ParseCSV.js +85 -0
  53. package/webinterface/source/cards/FlowCard-ReadJSON.js +54 -0
  54. package/webinterface/source/cards/FlowCard-ReadText.js +54 -0
  55. package/webinterface/source/cards/FlowCard-RestRequest.js +59 -0
  56. package/webinterface/source/cards/FlowCard-SendJSON.js +57 -0
  57. package/webinterface/source/cards/FlowCard-Solver.js +77 -0
  58. package/webinterface/source/cards/FlowCard-Start.js +29 -0
  59. package/webinterface/source/cards/FlowCard-TemplateString.js +77 -0
  60. package/webinterface/source/cards/FlowCard-WriteJSON.js +54 -0
  61. package/webinterface/source/cards/FlowCard-WriteText.js +54 -0
  62. package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
  63. package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
  64. package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
  65. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +8 -8
  66. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +6 -6
  67. package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +436 -0
  68. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +45 -43
  69. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +34 -89
  70. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +128 -13
  71. package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
  72. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +18 -53
  73. package/webinterface/source/views/PictView-Ultravisor-TimingView.js +27 -14
  74. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +2 -1
  75. package/.babelrc +0 -6
  76. package/.browserslistrc +0 -1
  77. package/.browserslistrc-BACKUP +0 -1
  78. package/.gulpfile-quackage-config.json +0 -7
  79. package/.gulpfile-quackage.js +0 -2
  80. package/debug/Harness.js +0 -5
  81. package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
  82. package/source/services/Ultravisor-Operation.cjs +0 -200
  83. package/source/services/Ultravisor-Task.cjs +0 -349
  84. package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
  85. package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
  86. package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
  87. package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
  88. package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
  89. package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
  90. package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
  91. package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
  92. package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
  93. package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
  94. package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
  95. package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
  96. package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
  97. package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
  98. package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
  99. package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
  100. package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
  101. package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
  102. package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
  103. package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
  104. package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
  105. package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
  106. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
  107. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
  108. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
  109. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
  110. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
  111. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
  112. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
  113. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
  114. package/webinterface/.babelrc +0 -6
  115. package/webinterface/.browserslistrc +0 -1
  116. package/webinterface/.browserslistrc-BACKUP +0 -1
  117. package/webinterface/.gulpfile-quackage-config.json +0 -7
  118. package/webinterface/.gulpfile-quackage.js +0 -2
  119. package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
  120. package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
  121. /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;