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
@@ -1,160 +0,0 @@
1
- const libPictService = require(`pict-serviceproviderbase`);
2
-
3
- const libFS = require('fs');
4
- const libPath = require('path');
5
-
6
- class UltravisorOperationManifest extends libPictService
7
- {
8
- constructor(pPict, pOptions, pServiceHash)
9
- {
10
- super(pPict, pOptions, pServiceHash);
11
-
12
- // In-memory store of recent operation manifests
13
- this._Manifests = {};
14
- }
15
-
16
- createManifest(pOperationDefinition)
17
- {
18
- let tmpManifest = {
19
- GUIDOperation: pOperationDefinition.GUIDOperation,
20
- Name: pOperationDefinition.Name || pOperationDefinition.GUIDOperation,
21
- StartTime: new Date().toISOString(),
22
- StopTime: null,
23
- Status: 'Running',
24
- Success: false,
25
- TaskResults: [],
26
- Summary: '',
27
- Log: []
28
- };
29
-
30
- tmpManifest.Log.push(`Operation ${tmpManifest.GUIDOperation} started at ${tmpManifest.StartTime}`);
31
-
32
- // Store it keyed by a run ID
33
- let tmpRunGUID = `${tmpManifest.GUIDOperation}-${Date.now()}`;
34
- tmpManifest.GUIDRun = tmpRunGUID;
35
- this._Manifests[tmpRunGUID] = tmpManifest;
36
-
37
- return tmpManifest;
38
- }
39
-
40
- addTaskResult(pManifest, pTaskResult)
41
- {
42
- if (!pManifest || !pTaskResult)
43
- {
44
- return;
45
- }
46
- pManifest.TaskResults.push(pTaskResult);
47
- pManifest.Log.push(`Task ${pTaskResult.GUIDTask} completed with status: ${pTaskResult.Status}`);
48
- }
49
-
50
- finalizeManifest(pManifest, pStagingPath)
51
- {
52
- if (!pManifest)
53
- {
54
- return;
55
- }
56
- pManifest.StopTime = new Date().toISOString();
57
-
58
- // Determine overall success from task results
59
- let tmpAllSucceeded = true;
60
- for (let i = 0; i < pManifest.TaskResults.length; i++)
61
- {
62
- if (!pManifest.TaskResults[i].Success)
63
- {
64
- tmpAllSucceeded = false;
65
- }
66
- }
67
-
68
- pManifest.Success = tmpAllSucceeded;
69
- pManifest.Status = tmpAllSucceeded ? 'Complete' : 'Error';
70
-
71
- // Compute elapsed time from ISO timestamps
72
- let tmpElapsedMs = new Date(pManifest.StopTime).getTime() - new Date(pManifest.StartTime).getTime();
73
- if (!pManifest.ElapsedMs)
74
- {
75
- pManifest.ElapsedMs = tmpElapsedMs;
76
- }
77
- if (!pManifest.ElapsedFormatted)
78
- {
79
- pManifest.ElapsedFormatted = this.fable.ProgressTime.formatTimeDuration(tmpElapsedMs);
80
- }
81
-
82
- pManifest.Summary = `Operation ${pManifest.GUIDOperation} ${pManifest.Status}: ${pManifest.TaskResults.length} task(s) executed in ${pManifest.ElapsedFormatted}.`;
83
- pManifest.Log.push(pManifest.Summary);
84
-
85
- // Write the manifest JSON to the staging folder
86
- if (pStagingPath && typeof(pStagingPath) === 'string' && pStagingPath.length > 0)
87
- {
88
- try
89
- {
90
- if (!libFS.existsSync(pStagingPath))
91
- {
92
- libFS.mkdirSync(pStagingPath, { recursive: true });
93
- }
94
-
95
- let tmpManifestFileName = `Manifest_${pManifest.GUIDOperation}.json`;
96
- let tmpManifestFilePath = libPath.resolve(pStagingPath, tmpManifestFileName);
97
- let tmpContent = JSON.stringify(pManifest, null, 4);
98
- libFS.writeFileSync(tmpManifestFilePath, tmpContent, 'utf8');
99
-
100
- pManifest.ManifestFilePath = tmpManifestFilePath;
101
- pManifest.Log.push(`Manifest written to ${tmpManifestFilePath}`);
102
- }
103
- catch (pError)
104
- {
105
- pManifest.Log.push(`Error writing manifest file: ${pError.message}`);
106
- }
107
- }
108
-
109
- return pManifest;
110
- }
111
-
112
- /**
113
- * Create and store a manifest for a standalone task execution result.
114
- */
115
- createTaskManifest(pTaskResult)
116
- {
117
- if (!pTaskResult)
118
- {
119
- return null;
120
- }
121
-
122
- let tmpRunGUID = `Task-${pTaskResult.GUIDTask}-${Date.now()}`;
123
-
124
- let tmpManifest = {
125
- GUIDRun: tmpRunGUID,
126
- GUIDOperation: null,
127
- GUIDTask: pTaskResult.GUIDTask,
128
- Name: pTaskResult.Name || pTaskResult.GUIDTask,
129
- StartTime: pTaskResult.StartTime || new Date().toISOString(),
130
- StopTime: pTaskResult.StopTime || new Date().toISOString(),
131
- Status: pTaskResult.Status || 'Unknown',
132
- Success: pTaskResult.Success || false,
133
- TaskResults: [pTaskResult],
134
- Summary: `Task ${pTaskResult.GUIDTask} ${pTaskResult.Status}: standalone execution.`,
135
- Log: pTaskResult.Log || []
136
- };
137
-
138
- this._Manifests[tmpRunGUID] = tmpManifest;
139
-
140
- return tmpManifest;
141
- }
142
-
143
- getManifest(pRunGUID)
144
- {
145
- return this._Manifests[pRunGUID] || null;
146
- }
147
-
148
- getManifestList()
149
- {
150
- let tmpManifests = [];
151
- let tmpKeys = Object.keys(this._Manifests);
152
- for (let i = 0; i < tmpKeys.length; i++)
153
- {
154
- tmpManifests.push(this._Manifests[tmpKeys[i]]);
155
- }
156
- return tmpManifests;
157
- }
158
- }
159
-
160
- module.exports = UltravisorOperationManifest;
@@ -1,200 +0,0 @@
1
- const libPictService = require(`pict-serviceproviderbase`);
2
-
3
- const libFS = require('fs');
4
- const libPath = require('path');
5
-
6
- class UltravisorOperation extends libPictService
7
- {
8
- constructor(pPict, pOptions, pServiceHash)
9
- {
10
- super(pPict, pOptions, pServiceHash);
11
- }
12
-
13
- /**
14
- * Resolve the base staging root folder.
15
- *
16
- * Priority:
17
- * 1. UltravisorStagingRoot from ProgramConfiguration
18
- * 2. ./dist/ultravisor_staging (relative to cwd)
19
- *
20
- * @returns {string} Absolute path to the staging root.
21
- */
22
- resolveStagingRoot()
23
- {
24
- return (this.fable?.ProgramConfiguration?.UltravisorStagingRoot)
25
- || libPath.resolve(process.cwd(), 'dist', 'ultravisor_staging');
26
- }
27
-
28
- /**
29
- * Generate a timestamp suffix for unique folder naming.
30
- *
31
- * Format: YYYY-MM-DD-HH-MM-SS-MS_SALT
32
- * where SALT is a random two-digit number (00–99).
33
- *
34
- * @returns {string} The formatted timestamp suffix.
35
- */
36
- generateOperationTimestamp()
37
- {
38
- let tmpNow = new Date();
39
- let tmpYear = tmpNow.getFullYear();
40
- let tmpMonth = String(tmpNow.getMonth() + 1).padStart(2, '0');
41
- let tmpDay = String(tmpNow.getDate()).padStart(2, '0');
42
- let tmpHours = String(tmpNow.getHours()).padStart(2, '0');
43
- let tmpMinutes = String(tmpNow.getMinutes()).padStart(2, '0');
44
- let tmpSeconds = String(tmpNow.getSeconds()).padStart(2, '0');
45
- let tmpMilliseconds = String(tmpNow.getMilliseconds()).padStart(3, '0');
46
- let tmpSalt = String(Math.floor(Math.random() * 100)).padStart(2, '0');
47
-
48
- return `${tmpYear}-${tmpMonth}-${tmpDay}-${tmpHours}-${tmpMinutes}-${tmpSeconds}-${tmpMilliseconds}_${tmpSalt}`;
49
- }
50
-
51
- /**
52
- * Build and ensure the per-operation staging folder exists.
53
- *
54
- * Creates: {StagingRoot}/{GUIDOperation}-{Timestamp}_{Salt}/
55
- *
56
- * @param {string} pGUIDOperation - The operation GUID.
57
- * @returns {string} Absolute path to the operation staging folder.
58
- */
59
- ensureOperationStagingFolder(pGUIDOperation)
60
- {
61
- let tmpStagingRoot = this.resolveStagingRoot();
62
- let tmpTimestamp = this.generateOperationTimestamp();
63
- let tmpFolderName = `${pGUIDOperation}-${tmpTimestamp}`;
64
- let tmpOperationStagingPath = libPath.resolve(tmpStagingRoot, tmpFolderName);
65
-
66
- if (!libFS.existsSync(tmpOperationStagingPath))
67
- {
68
- libFS.mkdirSync(tmpOperationStagingPath, { recursive: true });
69
- }
70
-
71
- return tmpOperationStagingPath;
72
- }
73
-
74
- /**
75
- * Execute an operation (a set of tasks run in sequence).
76
- *
77
- * @param {object} pOperationDefinition - The operation definition from state.
78
- * @param {function} fCallback - Callback with (pError, pManifest).
79
- */
80
- executeOperation(pOperationDefinition, fCallback)
81
- {
82
- if (typeof(pOperationDefinition) !== 'object' || pOperationDefinition === null)
83
- {
84
- return fCallback(new Error(`Ultravisor Operation: executeOperation requires a valid operation definition.`));
85
- }
86
- if (!pOperationDefinition.GUIDOperation)
87
- {
88
- return fCallback(new Error(`Ultravisor Operation: executeOperation requires GUIDOperation.`));
89
- }
90
-
91
- let tmpManifestService = this.fable['Ultravisor-Operation-Manifest'];
92
- let tmpTaskService = this.fable['Ultravisor-Task'];
93
- let tmpStateService = this.fable['Ultravisor-Hypervisor-State'];
94
-
95
- // Create the per-operation staging folder
96
- let tmpStagingPath = pOperationDefinition.StagingPath || '';
97
-
98
- if (!tmpStagingPath || tmpStagingPath.length === 0)
99
- {
100
- tmpStagingPath = this.ensureOperationStagingFolder(pOperationDefinition.GUIDOperation);
101
- }
102
-
103
- let tmpManifest = tmpManifestService.createManifest(pOperationDefinition);
104
- tmpManifest.StagingPath = tmpStagingPath;
105
-
106
- // Gather the task GUIDs for this operation
107
- let tmpTaskGUIDs = pOperationDefinition.Tasks || [];
108
- if (!Array.isArray(tmpTaskGUIDs) || tmpTaskGUIDs.length === 0)
109
- {
110
- tmpManifest.Log.push(`Operation has no tasks to execute.`);
111
- tmpManifestService.finalizeManifest(tmpManifest, tmpStagingPath);
112
- return fCallback(null, tmpManifest);
113
- }
114
-
115
- let tmpContext = {
116
- GlobalState: pOperationDefinition.GlobalState || {},
117
- NodeState: pOperationDefinition.NodeState || {},
118
- StagingPath: tmpStagingPath
119
- };
120
-
121
- // Expose GlobalState via AppData so that fable services
122
- // (e.g. ExpressionParser) can resolve addresses against it.
123
- if (!this.fable.AppData || typeof(this.fable.AppData) !== 'object')
124
- {
125
- this.fable.AppData = {};
126
- }
127
- this.fable.AppData.GlobalState = tmpContext.GlobalState;
128
-
129
- this.log.info(`Ultravisor Operation: executing operation ${pOperationDefinition.GUIDOperation} with ${tmpTaskGUIDs.length} task(s).`);
130
-
131
- // Set up progress tracking for the operation
132
- let tmpProgressTrackerSet = this.fable.instantiateServiceProviderIfNotExists('ProgressTrackerSet');
133
- let tmpProgressTrackerHash = `Op-${tmpManifest.GUIDRun}`;
134
- tmpProgressTrackerSet.createProgressTracker(tmpProgressTrackerHash, tmpTaskGUIDs.length);
135
- tmpProgressTrackerSet.startProgressTracker(tmpProgressTrackerHash);
136
-
137
- // Execute tasks in sequence using anticipate
138
- let tmpAnticipate = this.fable.newAnticipate();
139
-
140
- for (let i = 0; i < tmpTaskGUIDs.length; i++)
141
- {
142
- let tmpTaskGUID = tmpTaskGUIDs[i];
143
-
144
- tmpAnticipate.anticipate(
145
- function (fNext)
146
- {
147
- tmpStateService.getTask(tmpTaskGUID,
148
- (pError, pTaskDefinition) =>
149
- {
150
- if (pError)
151
- {
152
- tmpManifest.Log.push(`Could not find task ${tmpTaskGUID}: ${pError.message}`);
153
- tmpProgressTrackerSet.incrementProgressTracker(tmpProgressTrackerHash);
154
- return fNext();
155
- }
156
-
157
- tmpTaskService.executeTask(pTaskDefinition, tmpContext,
158
- (pTaskError, pTaskResult) =>
159
- {
160
- if (pTaskError)
161
- {
162
- tmpManifest.Log.push(`Error executing task ${tmpTaskGUID}: ${pTaskError.message}`);
163
- tmpProgressTrackerSet.incrementProgressTracker(tmpProgressTrackerHash);
164
- return fNext();
165
- }
166
-
167
- tmpManifestService.addTaskResult(tmpManifest, pTaskResult);
168
- tmpProgressTrackerSet.incrementProgressTracker(tmpProgressTrackerHash);
169
- tmpProgressTrackerSet.logProgressTrackerStatus(tmpProgressTrackerHash);
170
- return fNext();
171
- });
172
- });
173
- });
174
- }
175
-
176
- tmpAnticipate.wait(
177
- (pError) =>
178
- {
179
- if (pError)
180
- {
181
- tmpManifest.Log.push(`Error during operation execution: ${pError.message}`);
182
- }
183
-
184
- tmpProgressTrackerSet.endProgressTracker(tmpProgressTrackerHash);
185
- let tmpTrackerData = tmpProgressTrackerSet.getProgressTrackerData(tmpProgressTrackerHash);
186
- tmpManifest.ElapsedMs = tmpTrackerData.ElapsedTime;
187
- tmpManifest.ElapsedFormatted = this.fable.ProgressTime.formatTimeDuration(tmpTrackerData.ElapsedTime);
188
- tmpManifest.AverageTaskMs = tmpTrackerData.AverageOperationTime;
189
- tmpManifest.Log.push(tmpProgressTrackerSet.getProgressTrackerStatusString(tmpProgressTrackerHash));
190
-
191
- tmpManifestService.finalizeManifest(tmpManifest, tmpStagingPath);
192
-
193
- this.log.info(`Ultravisor Operation: operation ${pOperationDefinition.GUIDOperation} completed in ${tmpManifest.ElapsedFormatted}. Status: ${tmpManifest.Status}`);
194
-
195
- return fCallback(null, tmpManifest);
196
- });
197
- }
198
- }
199
-
200
- module.exports = UltravisorOperation;
@@ -1,349 +0,0 @@
1
- const libPictService = require(`pict-serviceproviderbase`);
2
-
3
- const _TaskTypes = {
4
- 'command': require('./tasks/Ultravisor-Task-Command.cjs'),
5
- 'request': require('./tasks/Ultravisor-Task-Request.cjs'),
6
- 'conditional': require('./tasks/Ultravisor-Task-Conditional.cjs'),
7
- 'solver': require('./tasks/Ultravisor-Task-Solver.cjs'),
8
- 'linematch': require('./tasks/Ultravisor-Task-LineMatch.cjs'),
9
-
10
- 'listfiles': require('./tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs'),
11
- 'readjson': require('./tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs'),
12
- 'writejson': require('./tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs'),
13
- 'readtext': require('./tasks/stagingfiles/Ultravisor-Task-ReadText.cjs'),
14
- 'writetext': require('./tasks/stagingfiles/Ultravisor-Task-WriteText.cjs'),
15
- 'readxml': require('./tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs'),
16
- 'writexml': require('./tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs'),
17
- 'readbinary': require('./tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs'),
18
- 'writebinary': require('./tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs'),
19
- 'copyfile': require('./tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs'),
20
-
21
- 'getjson': require('./tasks/rest/Ultravisor-Task-GetJSON.cjs'),
22
- 'getbinary': require('./tasks/rest/Ultravisor-Task-GetBinary.cjs'),
23
- 'gettext': require('./tasks/rest/Ultravisor-Task-GetText.cjs'),
24
- 'getxml': require('./tasks/rest/Ultravisor-Task-GetXML.cjs'),
25
- 'sendjson': require('./tasks/rest/Ultravisor-Task-SendJSON.cjs'),
26
- 'restrequest': require('./tasks/rest/Ultravisor-Task-RestRequest.cjs'),
27
-
28
- 'generatepagedoperation': require('./tasks/Ultravisor-Task-GeneratePagedOperation.cjs'),
29
-
30
- 'collectvalues': require('./tasks/Ultravisor-Task-CollectValues.cjs'),
31
- 'commandeach': require('./tasks/Ultravisor-Task-CommandEach.cjs'),
32
-
33
- 'datewindow': require('./tasks/Ultravisor-Task-DateWindow.cjs'),
34
- 'templatestring': require('./tasks/Ultravisor-Task-TemplateString.cjs'),
35
-
36
- 'launchoperation': require('./tasks/Ultravisor-Task-LaunchOperation.cjs'),
37
- 'launchtask': require('./tasks/Ultravisor-Task-LaunchTask.cjs'),
38
- };
39
-
40
- class UltravisorTask extends libPictService
41
- {
42
- constructor(pPict, pOptions, pServiceHash)
43
- {
44
- super(pPict, pOptions, pServiceHash);
45
- }
46
-
47
- /**
48
- * Execute a task based on its type, then run any subsequent task sets.
49
- *
50
- * Subsequent task sets are optional arrays of task GUIDs on the task
51
- * definition. They run in order after the core task completes:
52
- *
53
- * onBefore -- runs before the core task executes
54
- * onCompletion -- runs after the core task succeeds (Status === 'Complete')
55
- * onSubsequent -- runs after the core task regardless of outcome
56
- * onFailure -- runs after the core task when Success is false
57
- * onError -- runs after the core task when Status is 'Error'
58
- *
59
- * Each set is an array of task GUIDs executed sequentially.
60
- *
61
- * @param {object} pTaskDefinition - The task definition object from state.
62
- * @param {object} pContext - Execution context (GlobalState, NodeState, StagingPath).
63
- * @param {function} fCallback - Callback with (pError, pManifestEntry).
64
- */
65
- executeTask(pTaskDefinition, pContext, fCallback)
66
- {
67
- if (typeof(pTaskDefinition) !== 'object' || pTaskDefinition === null)
68
- {
69
- return fCallback(new Error(`Ultravisor Task: executeTask requires a valid task definition object.`));
70
- }
71
- if (!pTaskDefinition.GUIDTask)
72
- {
73
- return fCallback(new Error(`Ultravisor Task: executeTask requires the task definition to have a GUIDTask.`));
74
- }
75
-
76
- let tmpManifestEntry = {
77
- GUIDTask: pTaskDefinition.GUIDTask,
78
- Name: pTaskDefinition.Name || pTaskDefinition.GUIDTask,
79
- Type: pTaskDefinition.Type || 'Command',
80
- StartTime: new Date().toISOString(),
81
- StopTime: null,
82
- Status: 'Running',
83
- Success: false,
84
- Output: null,
85
- Log: [],
86
- SubsequentResults: {}
87
- };
88
-
89
- tmpManifestEntry.Log.push(`Task ${tmpManifestEntry.GUIDTask} started at ${tmpManifestEntry.StartTime}`);
90
-
91
- // Set up per-task progress timing
92
- let tmpProgressTrackerSet = this.fable.instantiateServiceProviderIfNotExists('ProgressTrackerSet');
93
- let tmpTaskTimerHash = `Task-${pTaskDefinition.GUIDTask}-${Date.now()}`;
94
- tmpProgressTrackerSet.createProgressTracker(tmpTaskTimerHash, 1);
95
- tmpProgressTrackerSet.startProgressTracker(tmpTaskTimerHash);
96
-
97
- // Ensure GlobalState is accessible via AppData for fable services
98
- if (!pContext.GlobalState || typeof(pContext.GlobalState) !== 'object')
99
- {
100
- pContext.GlobalState = {};
101
- }
102
- if (!this.fable.AppData || typeof(this.fable.AppData) !== 'object')
103
- {
104
- this.fable.AppData = {};
105
- }
106
- this.fable.AppData.GlobalState = pContext.GlobalState;
107
-
108
- // --- onBefore ---
109
- this.executeSubsequentSet(pTaskDefinition, 'onBefore', pContext, tmpManifestEntry,
110
- (pBeforeError) =>
111
- {
112
- if (pBeforeError)
113
- {
114
- tmpManifestEntry.Log.push(`Error in onBefore: ${pBeforeError.message}`);
115
- }
116
-
117
- // --- Core task execution ---
118
- this.executeCoreTask(pTaskDefinition, pContext, tmpManifestEntry,
119
- (pCoreError) =>
120
- {
121
- if (pCoreError)
122
- {
123
- tmpManifestEntry.Log.push(`Core task error: ${pCoreError.message}`);
124
- }
125
-
126
- // --- Determine which subsequent sets to run ---
127
- let tmpSubsequentPhases = [];
128
-
129
- // onCompletion: only when core task succeeded
130
- if (tmpManifestEntry.Status === 'Complete' && tmpManifestEntry.Success)
131
- {
132
- tmpSubsequentPhases.push('onCompletion');
133
- }
134
-
135
- // onFailure: when the task did not succeed
136
- if (!tmpManifestEntry.Success)
137
- {
138
- tmpSubsequentPhases.push('onFailure');
139
- }
140
-
141
- // onError: specifically when Status is 'Error'
142
- if (tmpManifestEntry.Status === 'Error')
143
- {
144
- tmpSubsequentPhases.push('onError');
145
- }
146
-
147
- // onSubsequent: always runs after core task
148
- tmpSubsequentPhases.push('onSubsequent');
149
-
150
- this.executeSubsequentPhases(pTaskDefinition, tmpSubsequentPhases, pContext, tmpManifestEntry,
151
- () =>
152
- {
153
- // Record task timing
154
- tmpProgressTrackerSet.endProgressTracker(tmpTaskTimerHash);
155
- let tmpTrackerData = tmpProgressTrackerSet.getProgressTrackerData(tmpTaskTimerHash);
156
- tmpManifestEntry.ElapsedMs = tmpTrackerData.ElapsedTime;
157
- tmpManifestEntry.ElapsedFormatted = this.fable.ProgressTime.formatTimeDuration(tmpTrackerData.ElapsedTime);
158
- tmpManifestEntry.Log.push(`Task ${tmpManifestEntry.Name} completed in ${tmpManifestEntry.ElapsedFormatted}`);
159
- this.log.info(`Ultravisor Task: ${tmpManifestEntry.Name} [${tmpManifestEntry.Status}] completed in ${tmpManifestEntry.ElapsedFormatted}`);
160
- return fCallback(null, tmpManifestEntry);
161
- });
162
- });
163
- });
164
- }
165
-
166
- /**
167
- * Execute the core task logic by dispatching to the appropriate task type service.
168
- */
169
- executeCoreTask(pTaskDefinition, pContext, pManifestEntry, fCallback)
170
- {
171
- let tmpType = (pTaskDefinition.Type || 'Command').toLowerCase();
172
-
173
- let tmpTaskTypeClass = _TaskTypes[tmpType];
174
-
175
- if (!tmpTaskTypeClass)
176
- {
177
- pManifestEntry.StopTime = new Date().toISOString();
178
- pManifestEntry.Status = 'Unsupported';
179
- pManifestEntry.Log.push(`Task type "${pTaskDefinition.Type}" is not yet implemented.`);
180
- return fCallback(null);
181
- }
182
-
183
- let tmpTaskTypeInstance = new tmpTaskTypeClass(this.fable);
184
- tmpTaskTypeInstance.execute(pTaskDefinition, pContext, pManifestEntry,
185
- () => { return fCallback(null); });
186
- }
187
-
188
- /**
189
- * Execute a list of subsequent phases in order.
190
- *
191
- * @param {object} pTaskDefinition - The parent task definition.
192
- * @param {array} pPhases - Array of phase names to execute in order.
193
- * @param {object} pContext - Execution context.
194
- * @param {object} pManifestEntry - The parent manifest entry.
195
- * @param {function} fCallback - Callback when all phases are done.
196
- */
197
- executeSubsequentPhases(pTaskDefinition, pPhases, pContext, pManifestEntry, fCallback)
198
- {
199
- if (!Array.isArray(pPhases) || pPhases.length === 0)
200
- {
201
- return fCallback();
202
- }
203
-
204
- let tmpPhaseIndex = 0;
205
-
206
- let fRunNextPhase = () =>
207
- {
208
- if (tmpPhaseIndex >= pPhases.length)
209
- {
210
- return fCallback();
211
- }
212
-
213
- let tmpPhaseName = pPhases[tmpPhaseIndex];
214
- tmpPhaseIndex++;
215
-
216
- this.executeSubsequentSet(pTaskDefinition, tmpPhaseName, pContext, pManifestEntry,
217
- () =>
218
- {
219
- fRunNextPhase();
220
- });
221
- };
222
-
223
- fRunNextPhase();
224
- }
225
-
226
- /**
227
- * Execute a single subsequent task set by name (e.g. "onBefore",
228
- * "onCompletion").
229
- *
230
- * The set is an array of task GUIDs on the task definition keyed by
231
- * pSetName. Each GUID is looked up from state and executed sequentially.
232
- * Results are stored in pManifestEntry.SubsequentResults[pSetName].
233
- *
234
- * @param {object} pTaskDefinition - The parent task definition.
235
- * @param {string} pSetName - The subsequent set name.
236
- * @param {object} pContext - Execution context.
237
- * @param {object} pManifestEntry - The parent manifest entry.
238
- * @param {function} fCallback - Callback when done.
239
- */
240
- executeSubsequentSet(pTaskDefinition, pSetName, pContext, pManifestEntry, fCallback)
241
- {
242
- let tmpTaskGUIDs = pTaskDefinition[pSetName];
243
-
244
- if (!Array.isArray(tmpTaskGUIDs) || tmpTaskGUIDs.length === 0)
245
- {
246
- return fCallback();
247
- }
248
-
249
- pManifestEntry.Log.push(`Executing subsequent set "${pSetName}" with ${tmpTaskGUIDs.length} task(s).`);
250
- pManifestEntry.SubsequentResults[pSetName] = [];
251
-
252
- let tmpStateService = this.fable['Ultravisor-Hypervisor-State'];
253
- let tmpIndex = 0;
254
-
255
- let fRunNext = () =>
256
- {
257
- if (tmpIndex >= tmpTaskGUIDs.length)
258
- {
259
- pManifestEntry.Log.push(`Subsequent set "${pSetName}" complete.`);
260
- return fCallback();
261
- }
262
-
263
- let tmpGUID = tmpTaskGUIDs[tmpIndex];
264
- tmpIndex++;
265
-
266
- tmpStateService.getTask(tmpGUID,
267
- (pError, pSubTaskDefinition) =>
268
- {
269
- if (pError)
270
- {
271
- pManifestEntry.Log.push(`${pSetName}: could not find task ${tmpGUID}: ${pError.message}`);
272
- pManifestEntry.SubsequentResults[pSetName].push(
273
- {
274
- GUIDTask: tmpGUID,
275
- Status: 'Error',
276
- Success: false,
277
- Log: [`Task not found: ${pError.message}`]
278
- });
279
- return fRunNext();
280
- }
281
-
282
- // Execute the subsequent task (without its own subsequent
283
- // chains to avoid infinite recursion)
284
- this.executeCoreTaskStandalone(pSubTaskDefinition, pContext,
285
- (pExecError, pResult) =>
286
- {
287
- if (pExecError)
288
- {
289
- pManifestEntry.Log.push(`${pSetName}: error executing task ${tmpGUID}: ${pExecError.message}`);
290
- pManifestEntry.SubsequentResults[pSetName].push(
291
- {
292
- GUIDTask: tmpGUID,
293
- Status: 'Error',
294
- Success: false,
295
- Log: [`Execution error: ${pExecError.message}`]
296
- });
297
- }
298
- else
299
- {
300
- pManifestEntry.Log.push(`${pSetName}: task ${tmpGUID} completed with status: ${pResult.Status}`);
301
- pManifestEntry.SubsequentResults[pSetName].push(pResult);
302
- }
303
-
304
- return fRunNext();
305
- });
306
- });
307
- };
308
-
309
- fRunNext();
310
- }
311
-
312
- /**
313
- * Execute a task as a standalone core task (no subsequent chains).
314
- * Used for subsequent tasks to avoid recursive subsequent execution.
315
- */
316
- executeCoreTaskStandalone(pTaskDefinition, pContext, fCallback)
317
- {
318
- if (typeof(pTaskDefinition) !== 'object' || pTaskDefinition === null)
319
- {
320
- return fCallback(new Error(`Invalid task definition.`));
321
- }
322
- if (!pTaskDefinition.GUIDTask)
323
- {
324
- return fCallback(new Error(`Task definition missing GUIDTask.`));
325
- }
326
-
327
- let tmpManifestEntry = {
328
- GUIDTask: pTaskDefinition.GUIDTask,
329
- Name: pTaskDefinition.Name || pTaskDefinition.GUIDTask,
330
- Type: pTaskDefinition.Type || 'Command',
331
- StartTime: new Date().toISOString(),
332
- StopTime: null,
333
- Status: 'Running',
334
- Success: false,
335
- Output: null,
336
- Log: []
337
- };
338
-
339
- tmpManifestEntry.Log.push(`Task ${tmpManifestEntry.GUIDTask} started at ${tmpManifestEntry.StartTime}`);
340
-
341
- this.executeCoreTask(pTaskDefinition, pContext, tmpManifestEntry,
342
- (pError) =>
343
- {
344
- return fCallback(null, tmpManifestEntry);
345
- });
346
- }
347
- }
348
-
349
- module.exports = UltravisorTask;