ultravisor 1.0.3 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.claude/ultravisor-dev-config.json +3 -0
  3. package/card-audit.json +1545 -0
  4. package/docs/_sidebar.md +17 -0
  5. package/docs/css/docuserve.css +73 -0
  6. package/docs/features/beacon-authentication.md +209 -0
  7. package/docs/features/beacon-providers.md +1299 -0
  8. package/docs/features/beacons.md +530 -0
  9. package/docs/features/capabilities.md +193 -0
  10. package/docs/features/llm-model-setup.md +505 -0
  11. package/docs/features/llm.md +262 -0
  12. package/docs/features/tasks-content-system.md +110 -0
  13. package/docs/features/tasks-data-transform.md +233 -0
  14. package/docs/features/tasks-extension.md +36 -0
  15. package/docs/features/tasks-file-system.md +203 -0
  16. package/docs/features/tasks-flow-control.md +125 -0
  17. package/docs/features/tasks-http-client.md +119 -0
  18. package/docs/features/tasks-llm.md +118 -0
  19. package/docs/features/tasks-meadow-api.md +163 -0
  20. package/docs/features/tasks-user-interaction.md +49 -0
  21. package/docs/features/tasks.md +14 -0
  22. package/docs/index.html +1 -1
  23. package/docs/retold-catalog.json +1 -1
  24. package/docs/retold-keyword-index.json +17374 -5
  25. package/operation-library/api-data-pipeline.json +143 -0
  26. package/operation-library/beacon-remote-command.json +72 -0
  27. package/operation-library/conditional-file-backup.json +143 -0
  28. package/operation-library/config-processor.json +136 -0
  29. package/operation-library/csv-data-analysis.json +228 -0
  30. package/operation-library/csv-to-json.json +160 -0
  31. package/operation-library/directory-inventory.json +128 -0
  32. package/operation-library/expression-calculator.json +114 -0
  33. package/operation-library/file-search-replace.json +175 -0
  34. package/operation-library/git-status-report.json +368 -0
  35. package/operation-library/health-check-ping.json +329 -0
  36. package/operation-library/json-config-merge.json +313 -0
  37. package/operation-library/llm-embedding-tool-use.json +314 -0
  38. package/operation-library/llm-multi-turn-analysis.json +322 -0
  39. package/operation-library/llm-summarize.json +264 -0
  40. package/operation-library/log-line-counter.json +185 -0
  41. package/operation-library/meadow-crud-lifecycle.json +264 -0
  42. package/operation-library/npm-project-validator.json +193 -0
  43. package/operation-library/rest-api-orchestrator.json +218 -0
  44. package/operation-library/shell-system-info.json +137 -0
  45. package/operation-library/simple-echo.json +95 -0
  46. package/operation-library/template-processor.json +299 -0
  47. package/operation-library/text-sanitizer.json +176 -0
  48. package/package.json +12 -8
  49. package/source/Ultravisor.cjs +30 -3
  50. package/source/beacon/Ultravisor-Beacon-CLI.cjs +143 -0
  51. package/source/beacon/Ultravisor-Beacon-CapabilityProvider.cjs +129 -0
  52. package/source/beacon/Ultravisor-Beacon-Client.cjs +568 -0
  53. package/source/beacon/Ultravisor-Beacon-Executor.cjs +500 -0
  54. package/source/beacon/Ultravisor-Beacon-ProviderRegistry.cjs +330 -0
  55. package/source/beacon/providers/Ultravisor-Beacon-Provider-FileSystem.cjs +331 -0
  56. package/source/beacon/providers/Ultravisor-Beacon-Provider-LLM.cjs +966 -0
  57. package/source/beacon/providers/Ultravisor-Beacon-Provider-Shell.cjs +95 -0
  58. package/source/cli/Ultravisor-CLIProgram.cjs +44 -22
  59. package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
  60. package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
  61. package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
  62. package/source/config/Ultravisor-Default-Command-Configuration.cjs +12 -3
  63. package/source/services/Ultravisor-Beacon-Coordinator.cjs +966 -0
  64. package/source/services/Ultravisor-ExecutionEngine.cjs +1093 -0
  65. package/source/services/Ultravisor-ExecutionManifest.cjs +629 -0
  66. package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
  67. package/source/services/Ultravisor-Hypervisor.cjs +185 -75
  68. package/source/services/Ultravisor-Schedule-Persistence-Base.cjs +45 -0
  69. package/source/services/Ultravisor-StateManager.cjs +253 -0
  70. package/source/services/Ultravisor-TaskTypeRegistry.cjs +213 -0
  71. package/source/services/persistence/Ultravisor-Schedule-Persistence-JSONFile.cjs +140 -0
  72. package/source/services/tasks/Ultravisor-BuiltIn-TaskConfigs.cjs +19 -0
  73. package/source/services/tasks/Ultravisor-TaskHelper-BeaconDispatch.cjs +107 -0
  74. package/source/services/tasks/Ultravisor-TaskType-Base.cjs +125 -0
  75. package/source/services/tasks/content-system/Ultravisor-TaskConfigs-ContentSystem.cjs +90 -0
  76. package/source/services/tasks/content-system/definitions/content-create-folder.json +24 -0
  77. package/source/services/tasks/content-system/definitions/content-list-files.json +27 -0
  78. package/source/services/tasks/content-system/definitions/content-read-file.json +26 -0
  79. package/source/services/tasks/content-system/definitions/content-save-file.json +26 -0
  80. package/source/services/tasks/data-transform/Ultravisor-TaskConfigs-DataTransform.cjs +577 -0
  81. package/source/services/tasks/data-transform/Ultravisor-TaskType-ReplaceString.cjs +80 -0
  82. package/source/services/tasks/data-transform/Ultravisor-TaskType-SetValues.cjs +74 -0
  83. package/source/services/tasks/data-transform/Ultravisor-TaskType-StringAppender.cjs +90 -0
  84. package/source/services/tasks/data-transform/definitions/comprehension-intersect.json +24 -0
  85. package/source/services/tasks/data-transform/definitions/csv-transform.json +24 -0
  86. package/source/services/tasks/data-transform/definitions/expression-solver.json +20 -0
  87. package/source/services/tasks/data-transform/definitions/histogram.json +23 -0
  88. package/source/services/tasks/data-transform/definitions/parse-csv.json +27 -0
  89. package/source/services/tasks/data-transform/definitions/replace-string.json +27 -0
  90. package/source/services/tasks/data-transform/definitions/set-values.json +17 -0
  91. package/source/services/tasks/data-transform/definitions/string-appender.json +22 -0
  92. package/source/services/tasks/data-transform/definitions/template-string.json +20 -0
  93. package/source/services/tasks/extension/Ultravisor-TaskConfigs-Extension.cjs +87 -0
  94. package/source/services/tasks/extension/definitions/beacon-dispatch.json +32 -0
  95. package/source/services/tasks/file-system/Ultravisor-TaskConfigs-FileSystem.cjs +509 -0
  96. package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFile.cjs +96 -0
  97. package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFileBuffered.cjs +123 -0
  98. package/source/services/tasks/file-system/Ultravisor-TaskType-WriteFile.cjs +106 -0
  99. package/source/services/tasks/file-system/definitions/copy-file.json +27 -0
  100. package/source/services/tasks/file-system/definitions/list-files.json +27 -0
  101. package/source/services/tasks/file-system/definitions/read-file-buffered.json +31 -0
  102. package/source/services/tasks/file-system/definitions/read-file.json +26 -0
  103. package/source/services/tasks/file-system/definitions/read-json.json +23 -0
  104. package/source/services/tasks/file-system/definitions/write-file.json +29 -0
  105. package/source/services/tasks/file-system/definitions/write-json.json +30 -0
  106. package/source/services/tasks/flow-control/Ultravisor-TaskConfigs-FlowControl.cjs +353 -0
  107. package/source/services/tasks/flow-control/Ultravisor-TaskType-IfConditional.cjs +125 -0
  108. package/source/services/tasks/flow-control/Ultravisor-TaskType-LaunchOperation.cjs +186 -0
  109. package/source/services/tasks/flow-control/Ultravisor-TaskType-SplitExecute.cjs +164 -0
  110. package/source/services/tasks/flow-control/definitions/if-conditional.json +25 -0
  111. package/source/services/tasks/flow-control/definitions/launch-operation.json +27 -0
  112. package/source/services/tasks/flow-control/definitions/split-execute.json +32 -0
  113. package/source/services/tasks/http-client/Ultravisor-TaskConfigs-HttpClient.cjs +281 -0
  114. package/source/services/tasks/http-client/definitions/get-json.json +26 -0
  115. package/source/services/tasks/http-client/definitions/get-text.json +26 -0
  116. package/source/services/tasks/http-client/definitions/rest-request.json +32 -0
  117. package/source/services/tasks/http-client/definitions/send-json.json +28 -0
  118. package/source/services/tasks/llm/Ultravisor-TaskConfigs-LLM.cjs +605 -0
  119. package/source/services/tasks/llm/definitions/llm-chat-completion.json +46 -0
  120. package/source/services/tasks/llm/definitions/llm-embedding.json +31 -0
  121. package/source/services/tasks/llm/definitions/llm-tool-use.json +42 -0
  122. package/source/services/tasks/meadow-api/Ultravisor-TaskConfigs-MeadowApi.cjs +341 -0
  123. package/source/services/tasks/meadow-api/definitions/meadow-count.json +26 -0
  124. package/source/services/tasks/meadow-api/definitions/meadow-create.json +26 -0
  125. package/source/services/tasks/meadow-api/definitions/meadow-delete.json +23 -0
  126. package/source/services/tasks/meadow-api/definitions/meadow-read.json +26 -0
  127. package/source/services/tasks/meadow-api/definitions/meadow-reads.json +29 -0
  128. package/source/services/tasks/meadow-api/definitions/meadow-update.json +26 -0
  129. package/source/services/tasks/shell/Ultravisor-TaskConfigs-Shell.cjs +63 -0
  130. package/source/services/tasks/shell/definitions/command.json +29 -0
  131. package/source/services/tasks/user-interaction/Ultravisor-TaskConfigs-UserInteraction.cjs +64 -0
  132. package/source/services/tasks/user-interaction/Ultravisor-TaskType-ErrorMessage.cjs +55 -0
  133. package/source/services/tasks/user-interaction/Ultravisor-TaskType-ValueInput.cjs +47 -0
  134. package/source/services/tasks/user-interaction/definitions/error-message.json +18 -0
  135. package/source/services/tasks/user-interaction/definitions/value-input.json +23 -0
  136. package/source/web_server/Ultravisor-API-Server.cjs +849 -124
  137. package/test/Ultravisor_browser_tests.js +2226 -0
  138. package/test/Ultravisor_operation_library_tests.js +894 -0
  139. package/test/Ultravisor_tests.js +4946 -5044
  140. package/test/workflows/test-content-concatenate-all.json +339 -0
  141. package/test/workflows/test-content-full-pipeline.json +159 -0
  142. package/test/workflows/test-content-list-files.json +76 -0
  143. package/test/workflows/test-content-save-and-read.json +106 -0
  144. package/webinterface/css/ultravisor-themes.css +668 -0
  145. package/webinterface/css/ultravisor.css +37 -14
  146. package/webinterface/docs/card-help/beacon-dispatch.md +30 -0
  147. package/webinterface/docs/card-help/command.md +27 -0
  148. package/webinterface/docs/card-help/comprehension-intersect.md +24 -0
  149. package/webinterface/docs/card-help/content-create-folder.md +22 -0
  150. package/webinterface/docs/card-help/content-list-files.md +25 -0
  151. package/webinterface/docs/card-help/content-read-file.md +24 -0
  152. package/webinterface/docs/card-help/content-save-file.md +24 -0
  153. package/webinterface/docs/card-help/copy-file.md +25 -0
  154. package/webinterface/docs/card-help/csv-transform.md +24 -0
  155. package/webinterface/docs/card-help/end.md +11 -0
  156. package/webinterface/docs/card-help/error-message.md +16 -0
  157. package/webinterface/docs/card-help/expression-solver.md +21 -0
  158. package/webinterface/docs/card-help/get-json.md +24 -0
  159. package/webinterface/docs/card-help/get-text.md +24 -0
  160. package/webinterface/docs/card-help/histogram.md +23 -0
  161. package/webinterface/docs/card-help/if-conditional.md +23 -0
  162. package/webinterface/docs/card-help/launch-operation.md +25 -0
  163. package/webinterface/docs/card-help/list-files.md +25 -0
  164. package/webinterface/docs/card-help/llm-chat-completion.md +43 -0
  165. package/webinterface/docs/card-help/llm-embedding.md +24 -0
  166. package/webinterface/docs/card-help/llm-tool-use.md +39 -0
  167. package/webinterface/docs/card-help/meadow-count.md +24 -0
  168. package/webinterface/docs/card-help/meadow-create.md +24 -0
  169. package/webinterface/docs/card-help/meadow-delete.md +19 -0
  170. package/webinterface/docs/card-help/meadow-read.md +24 -0
  171. package/webinterface/docs/card-help/meadow-reads.md +27 -0
  172. package/webinterface/docs/card-help/meadow-update.md +24 -0
  173. package/webinterface/docs/card-help/parse-csv.md +27 -0
  174. package/webinterface/docs/card-help/read-file-buffered.md +29 -0
  175. package/webinterface/docs/card-help/read-file.md +24 -0
  176. package/webinterface/docs/card-help/read-json.md +21 -0
  177. package/webinterface/docs/card-help/replace-string.md +25 -0
  178. package/webinterface/docs/card-help/rest-request.md +30 -0
  179. package/webinterface/docs/card-help/send-json.md +26 -0
  180. package/webinterface/docs/card-help/set-values.md +16 -0
  181. package/webinterface/docs/card-help/split-execute.md +35 -0
  182. package/webinterface/docs/card-help/start.md +11 -0
  183. package/webinterface/docs/card-help/string-appender.md +22 -0
  184. package/webinterface/docs/card-help/template-string.md +21 -0
  185. package/webinterface/docs/card-help/value-input.md +24 -0
  186. package/webinterface/docs/card-help/write-file.md +27 -0
  187. package/webinterface/docs/card-help/write-json.md +28 -0
  188. package/webinterface/html/index.html +5 -0
  189. package/webinterface/package.json +13 -4
  190. package/webinterface/source/Pict-Application-Ultravisor.js +564 -70
  191. package/webinterface/source/Ultravisor-TimingUtils.js +99 -0
  192. package/webinterface/source/card-help-content.js +46 -0
  193. package/webinterface/source/cards/Ultravisor-BuiltIn-CardConfigs.js +174 -0
  194. package/webinterface/source/cards/Ultravisor-CardConfigGenerator.js +431 -0
  195. package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
  196. package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
  197. package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
  198. package/webinterface/source/panels/Ultravisor-CardSettingsPanel.js +902 -0
  199. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +20 -8
  200. package/webinterface/source/views/PictView-Ultravisor-BeaconList.js +817 -0
  201. package/webinterface/source/views/PictView-Ultravisor-BottomBar.js +5 -5
  202. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +25 -25
  203. package/webinterface/source/views/PictView-Ultravisor-Documentation.js +856 -0
  204. package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +777 -0
  205. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +321 -58
  206. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +36 -91
  207. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +388 -16
  208. package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
  209. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +521 -65
  210. package/webinterface/source/views/PictView-Ultravisor-TimingView.js +333 -71
  211. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +257 -21
  212. package/webinterface/theme-sampler.html +645 -0
  213. package/debug/Harness.js +0 -6
  214. package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
  215. package/source/services/Ultravisor-Operation.cjs +0 -200
  216. package/source/services/Ultravisor-Task.cjs +0 -349
  217. package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
  218. package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
  219. package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
  220. package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
  221. package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
  222. package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
  223. package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
  224. package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
  225. package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
  226. package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
  227. package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
  228. package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
  229. package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
  230. package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
  231. package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
  232. package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
  233. package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
  234. package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
  235. package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
  236. package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
  237. package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
  238. package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
  239. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
  240. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
  241. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
  242. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
  243. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
  244. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
  245. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
  246. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
  247. package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
  248. package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
@@ -1,45 +1,137 @@
1
- const libPictService = require(`pict-serviceproviderbase`);
1
+ const libPictService = require('pict-serviceproviderbase');
2
2
 
3
3
  const libFS = require('fs');
4
4
  const libPath = require('path');
5
5
 
6
+ /**
7
+ * Persistent state store for Ultravisor.
8
+ *
9
+ * Stores Node Templates (reusable pre-configured task type instances)
10
+ * and Operation Definitions (graphs) in memory and persists to
11
+ * `.ultravisor.json` via fable's gatherProgramConfiguration system.
12
+ *
13
+ * Also manages GlobalState that persists across operation runs.
14
+ *
15
+ * Auto-generates meaningful hashes for new entities:
16
+ * Templates: TMPL-{TYPE}-{NNN} (e.g. TMPL-READFILE-001)
17
+ * Operations: OPR-{NNNN} (e.g. OPR-0001)
18
+ */
6
19
  class UltravisorHypervisorState extends libPictService
7
20
  {
8
21
  constructor(pPict, pOptions, pServiceHash)
9
22
  {
10
23
  super(pPict, pOptions, pServiceHash);
11
24
 
12
- this._Tasks = {};
25
+ this.serviceType = 'UltravisorHypervisorState';
26
+
27
+ // Node Templates (reusable pre-configured task type instances) keyed by Hash
28
+ this._NodeTemplates = {};
29
+
30
+ // Operation Definitions (with Graph) keyed by Hash
13
31
  this._Operations = {};
14
32
 
33
+ // Global state (persists across runs)
34
+ this._GlobalState = {};
35
+
36
+ // Auto-hash counters
37
+ this._TemplateCounters = {};
38
+ this._OperationCounter = 0;
39
+
40
+ // Gather configuration
15
41
  this._ConfigurationOutcome = this.fable.gatherProgramConfiguration(false);
16
42
 
17
- // Load tasks and operations from the gathered configuration
43
+ // Load from configuration
18
44
  let tmpConfig = this.fable.ProgramConfiguration || {};
19
45
 
20
- if (tmpConfig.Tasks && typeof(tmpConfig.Tasks) === 'object')
46
+ // Load Node Templates (with backward compat from old TaskDefinitions key)
47
+ let tmpTemplateSource = tmpConfig.NodeTemplates || tmpConfig.TaskDefinitions;
48
+ if (tmpTemplateSource && typeof(tmpTemplateSource) === 'object')
21
49
  {
22
- let tmpTaskKeys = Object.keys(tmpConfig.Tasks);
23
- for (let i = 0; i < tmpTaskKeys.length; i++)
50
+ let tmpKeys = Object.keys(tmpTemplateSource);
51
+ for (let i = 0; i < tmpKeys.length; i++)
24
52
  {
25
- this._Tasks[tmpTaskKeys[i]] = tmpConfig.Tasks[tmpTaskKeys[i]];
53
+ this._NodeTemplates[tmpKeys[i]] = tmpTemplateSource[tmpKeys[i]];
26
54
  }
27
55
  }
28
56
 
29
57
  if (tmpConfig.Operations && typeof(tmpConfig.Operations) === 'object')
30
58
  {
31
- let tmpOperationKeys = Object.keys(tmpConfig.Operations);
32
- for (let i = 0; i < tmpOperationKeys.length; i++)
59
+ let tmpKeys = Object.keys(tmpConfig.Operations);
60
+ for (let i = 0; i < tmpKeys.length; i++)
33
61
  {
34
- this._Operations[tmpOperationKeys[i]] = tmpConfig.Operations[tmpOperationKeys[i]];
62
+ this._Operations[tmpKeys[i]] = tmpConfig.Operations[tmpKeys[i]];
35
63
  }
36
64
  }
65
+
66
+ if (tmpConfig.GlobalState && typeof(tmpConfig.GlobalState) === 'object')
67
+ {
68
+ this._GlobalState = tmpConfig.GlobalState;
69
+ }
70
+
71
+ if (typeof(tmpConfig.OperationCounter) === 'number')
72
+ {
73
+ this._OperationCounter = tmpConfig.OperationCounter;
74
+ }
75
+
76
+ // Load template counters (with backward compat from old TaskCounters key)
77
+ let tmpCounterSource = tmpConfig.TemplateCounters || tmpConfig.TaskCounters;
78
+ if (tmpCounterSource && typeof(tmpCounterSource) === 'object')
79
+ {
80
+ this._TemplateCounters = tmpCounterSource;
81
+ }
37
82
  }
38
83
 
84
+ // ====================================================================
85
+ // Auto-Hash Generation
86
+ // ====================================================================
87
+
88
+ /**
89
+ * Generate a meaningful hash for a new node template.
90
+ *
91
+ * @param {string} pType - The task type (e.g. 'read-file').
92
+ * @returns {string} e.g. 'TMPL-READFILE-001'
93
+ */
94
+ generateTemplateHash(pType)
95
+ {
96
+ let tmpTypeKey = (pType || 'TEMPLATE').toUpperCase().replace(/[^A-Z0-9]/g, '');
97
+
98
+ if (!this._TemplateCounters[tmpTypeKey])
99
+ {
100
+ this._TemplateCounters[tmpTypeKey] = 0;
101
+ }
102
+
103
+ this._TemplateCounters[tmpTypeKey]++;
104
+
105
+ let tmpCounter = String(this._TemplateCounters[tmpTypeKey]).padStart(3, '0');
106
+
107
+ return `TMPL-${tmpTypeKey}-${tmpCounter}`;
108
+ }
109
+
110
+ /**
111
+ * Generate a meaningful hash for a new operation.
112
+ *
113
+ * @returns {string} e.g. 'OPR-0001'
114
+ */
115
+ generateOperationHash()
116
+ {
117
+ this._OperationCounter++;
118
+
119
+ return `OPR-${String(this._OperationCounter).padStart(4, '0')}`;
120
+ }
121
+
122
+ // ====================================================================
123
+ // Persistence
124
+ // ====================================================================
125
+
126
+ /**
127
+ * Persist current state to disk via gatherProgramConfiguration path.
128
+ *
129
+ * @returns {boolean} True if state was persisted successfully.
130
+ */
39
131
  persistState()
40
132
  {
41
- // Check the _ConfigurationOutcome to see where we should be persisting state
42
133
  let tmpFinalGatherPhasePath = false;
134
+
43
135
  for (let i = 0; i < this._ConfigurationOutcome.GatherPhases.length; i++)
44
136
  {
45
137
  let tmpGatherPhase = this._ConfigurationOutcome.GatherPhases[i];
@@ -52,162 +144,243 @@ class UltravisorHypervisorState extends libPictService
52
144
  if (!tmpFinalGatherPhasePath && this.fable.settings.ProgramConfigurationFileName)
53
145
  {
54
146
  tmpFinalGatherPhasePath = libPath.resolve(process.cwd(), this.fable.settings.ProgramConfigurationFileName);
55
- this.pict.log.warn(`Ultravisor Hypervisor State: persistState could not determine a valid configuration path to persist state to;.`);
147
+ this.log.warn('UltravisorHypervisorState: could not determine config path; using ProgramConfigurationFileName.');
56
148
  }
57
149
  else if (!tmpFinalGatherPhasePath)
58
150
  {
59
- this.pict.log.error(`Ultravisor Hypervisor State: persistState could not determine a valid configuration path to persist state to; state will not be saved.`);
60
- return;
151
+ this.log.error('UltravisorHypervisorState: no config path available; state will not be saved.');
152
+ return false;
61
153
  }
62
154
 
63
- // Now merge all the data
64
- const tmpStateToPersist = this._ConfigurationOutcome.ConfigurationOutcome;
155
+ let tmpStateToPersist = this._ConfigurationOutcome.ConfigurationOutcome || {};
65
156
 
66
- // Merge in Tasks
67
- if (!tmpStateToPersist.hasOwnProperty('Tasks'))
68
- {
69
- tmpStateToPersist.Tasks = {};
70
- }
71
- const tmpTaskKeys = Object.keys(this._Tasks);
72
- for (let i=0; i<tmpTaskKeys.length; i++)
73
- {
74
- if (tmpStateToPersist.Tasks.hasOwnProperty(tmpTaskKeys[i]))
75
- {
76
- tmpStateToPersist.Tasks[tmpTaskKeys[i]] = Object.assign({}, tmpStateToPersist.Tasks[tmpTaskKeys[i]], this._Tasks[tmpTaskKeys[i]]);
77
- }
78
- else
79
- {
80
- tmpStateToPersist.Tasks[tmpTaskKeys[i]] = this._Tasks[tmpTaskKeys[i]];
81
- }
82
- }
157
+ tmpStateToPersist.NodeTemplates = this._NodeTemplates;
158
+ tmpStateToPersist.Operations = this._Operations;
159
+ tmpStateToPersist.GlobalState = this._GlobalState;
160
+ tmpStateToPersist.OperationCounter = this._OperationCounter;
161
+ tmpStateToPersist.TemplateCounters = this._TemplateCounters;
83
162
 
84
- if (!tmpStateToPersist.hasOwnProperty('Operations'))
85
- {
86
- tmpStateToPersist.Operations = {};
87
- }
88
- const tmpOperationKeys = Object.keys(this._Operations);
89
- for (let i=0; i<tmpOperationKeys.length; i++)
90
- {
91
- if (tmpStateToPersist.Operations.hasOwnProperty(tmpOperationKeys[i]))
92
- {
93
- tmpStateToPersist.Operations[tmpOperationKeys[i]] = Object.assign({}, tmpStateToPersist.Operations[tmpOperationKeys[i]], this._Operations[tmpOperationKeys[i]]);
94
- }
95
- else
96
- {
97
- tmpStateToPersist.Operations[tmpOperationKeys[i]] = this._Operations[tmpOperationKeys[i]];
98
- }
99
- }
163
+ // Remove old keys if present (migration)
164
+ delete tmpStateToPersist.TaskDefinitions;
165
+ delete tmpStateToPersist.TaskCounters;
100
166
 
101
- this.fable.log.info(`Ultravisor Hypervisor State: persisting hypervisor state to ${tmpFinalGatherPhasePath}.`);
167
+ this.log.info(`UltravisorHypervisorState: persisting state to ${tmpFinalGatherPhasePath}`);
102
168
 
103
169
  try
104
170
  {
105
- libFS.writeFileSync(tmpFinalGatherPhasePath, JSON.stringify(tmpStateToPersist, null, 4), 'utf8');
171
+ libFS.writeFileSync(tmpFinalGatherPhasePath, JSON.stringify(tmpStateToPersist, null, '\t'), 'utf8');
106
172
  }
107
- catch(pError)
173
+ catch (pError)
108
174
  {
109
- this.fable.log.error(`Ultravisor Hypervisor State: an error occurred while attempting to persist hypervisor state to ${tmpFinalGatherPhasePath}: ${pError.message}`);
175
+ this.log.error(`UltravisorHypervisorState: persist error: ${pError.message}`);
110
176
  return false;
111
177
  }
112
178
 
113
- return true
179
+ return true;
114
180
  }
115
181
 
182
+ // ====================================================================
183
+ // Node Template CRUD
184
+ // ====================================================================
116
185
 
117
- updateOperation(pOperation, fCallback)
186
+ /**
187
+ * Create or update a node template.
188
+ *
189
+ * @param {object} pTemplate - The node template object.
190
+ * Must have a Hash (or one will be auto-generated from Type).
191
+ * @param {function} fCallback - function(pError, pTemplate)
192
+ */
193
+ updateNodeTemplate(pTemplate, fCallback)
118
194
  {
119
- if (typeof(pOperation) !== 'object' || pOperation === null)
195
+ if (typeof(pTemplate) !== 'object' || pTemplate === null)
120
196
  {
121
- return fCallback(new Error(`Ultravisor Hypervisor State: updateOperation requires a valid operation object.`));
197
+ return fCallback(new Error('updateNodeTemplate requires a valid object.'));
122
198
  }
123
- if (!pOperation.hasOwnProperty('GUIDOperation') || typeof(pOperation.GUIDOperation) !== 'string' || pOperation.GUIDOperation.length === 0)
199
+
200
+ // Auto-generate hash if not provided
201
+ if (!pTemplate.Hash || typeof(pTemplate.Hash) !== 'string' || pTemplate.Hash.length === 0)
124
202
  {
125
- return fCallback(new Error(`Ultravisor Hypervisor State: updateOperation requires the operation object to have a GUIDOperation property.`));
203
+ pTemplate.Hash = this.generateTemplateHash(pTemplate.Type || 'TEMPLATE');
126
204
  }
127
205
 
128
- if (this._Operations.hasOwnProperty(pOperation.GUIDOperation))
206
+ if (this._NodeTemplates.hasOwnProperty(pTemplate.Hash))
129
207
  {
130
- // Update the existing operation
131
- this._Operations[pOperation.GUIDOperation] = Object.assign(this._Operations[pOperation.GUIDOperation], pOperation);
208
+ this._NodeTemplates[pTemplate.Hash] = Object.assign(
209
+ this._NodeTemplates[pTemplate.Hash], pTemplate);
132
210
  }
133
211
  else
134
212
  {
135
- // Add a new operation
136
- this._Operations[pOperation.GUIDOperation] = pOperation;
213
+ this._NodeTemplates[pTemplate.Hash] = pTemplate;
137
214
  }
138
215
 
139
216
  this.persistState();
140
217
 
141
- return fCallback(null, this._Operations[pOperation.GUIDOperation]);
218
+ return fCallback(null, this._NodeTemplates[pTemplate.Hash]);
142
219
  }
143
220
 
144
- getOperationList(pFilters, fCallback)
221
+ /**
222
+ * Get a node template by hash.
223
+ */
224
+ getNodeTemplate(pHash, fCallback)
145
225
  {
146
- const tmpOperationKeys = Object.keys(this._Operations);
147
- const tmpOperations = [];
148
- for (let i=0; i<tmpOperationKeys.length; i++)
226
+ if (!this._NodeTemplates.hasOwnProperty(pHash))
149
227
  {
150
- tmpOperations.push(this._Operations[tmpOperationKeys[i]]);
228
+ return fCallback(new Error(`Node template [${pHash}] not found.`));
151
229
  }
152
- return fCallback(null, tmpOperations);
230
+ return fCallback(null, this._NodeTemplates[pHash]);
153
231
  }
154
232
 
155
- getOperation(pGUIDOperation, fCallback)
233
+ /**
234
+ * List all node templates.
235
+ */
236
+ getNodeTemplateList(fCallback)
156
237
  {
157
- if (!this._Operations.hasOwnProperty(pGUIDOperation))
238
+ let tmpList = [];
239
+ let tmpKeys = Object.keys(this._NodeTemplates);
240
+
241
+ for (let i = 0; i < tmpKeys.length; i++)
158
242
  {
159
- return fCallback(new Error(`Ultravisor Hypervisor State: getOperation could not find operation with GUID ${pGUIDOperation}.`));
243
+ tmpList.push(this._NodeTemplates[tmpKeys[i]]);
160
244
  }
161
- return fCallback(null, this._Operations[pGUIDOperation]);
245
+
246
+ return fCallback(null, tmpList);
162
247
  }
163
248
 
249
+ /**
250
+ * Delete a node template by hash.
251
+ */
252
+ deleteNodeTemplate(pHash, fCallback)
253
+ {
254
+ if (!this._NodeTemplates.hasOwnProperty(pHash))
255
+ {
256
+ return fCallback(new Error(`Node template [${pHash}] not found.`));
257
+ }
164
258
 
165
- updateTask(pTask, fCallback)
259
+ delete this._NodeTemplates[pHash];
260
+ this.persistState();
261
+
262
+ return fCallback(null, true);
263
+ }
264
+
265
+ // ====================================================================
266
+ // Operation CRUD
267
+ // ====================================================================
268
+
269
+ /**
270
+ * Create or update an operation.
271
+ *
272
+ * @param {object} pOperation - The operation definition.
273
+ * Must have a Hash (or one will be auto-generated).
274
+ * @param {function} fCallback - function(pError, pOperation)
275
+ */
276
+ updateOperation(pOperation, fCallback)
166
277
  {
167
- if (typeof(pTask) !== 'object' || pTask === null)
278
+ if (typeof(pOperation) !== 'object' || pOperation === null)
279
+ {
280
+ return fCallback(new Error('updateOperation requires a valid object.'));
281
+ }
282
+
283
+ // Auto-generate hash if not provided
284
+ if (!pOperation.Hash || typeof(pOperation.Hash) !== 'string' || pOperation.Hash.length === 0)
168
285
  {
169
- return fCallback(new Error(`Ultravisor Hypervisor State: updateTask requires a valid task object.`));
286
+ pOperation.Hash = this.generateOperationHash();
170
287
  }
171
- if (!pTask.hasOwnProperty('GUIDTask') || typeof(pTask.GUIDTask) !== 'string' || pTask.GUIDTask.length === 0)
288
+
289
+ // Ensure Graph structure exists
290
+ if (!pOperation.Graph)
172
291
  {
173
- return fCallback(new Error(`Ultravisor Hypervisor State: updateTask requires the task object to have a GUIDTask property.`));
292
+ pOperation.Graph = { Nodes: [], Connections: [], ViewState: {} };
174
293
  }
175
294
 
176
- if (this._Tasks.hasOwnProperty(pTask.GUIDTask))
295
+ if (this._Operations.hasOwnProperty(pOperation.Hash))
177
296
  {
178
- // Update the existing task
179
- this._Tasks[pTask.GUIDTask] = Object.assign(this._Tasks[pTask.GUIDTask], pTask);
297
+ this._Operations[pOperation.Hash] = Object.assign(
298
+ this._Operations[pOperation.Hash], pOperation);
180
299
  }
181
300
  else
182
301
  {
183
- // Add a new task
184
- this._Tasks[pTask.GUIDTask] = pTask;
302
+ pOperation.CreatedAt = pOperation.CreatedAt || new Date().toISOString();
303
+ this._Operations[pOperation.Hash] = pOperation;
185
304
  }
186
305
 
306
+ pOperation.UpdatedAt = new Date().toISOString();
307
+
187
308
  this.persistState();
188
309
 
189
- return fCallback(null, this._Tasks[pTask.GUIDTask]);
310
+ return fCallback(null, this._Operations[pOperation.Hash]);
190
311
  }
191
312
 
192
- getTaskList(pFilters, fCallback)
313
+ /**
314
+ * Get an operation by hash.
315
+ */
316
+ getOperation(pHash, fCallback)
193
317
  {
194
- const tmpTaskKeys = Object.keys(this._Tasks);
195
- const tmpTasks = [];
196
- for (let i=0; i<tmpTaskKeys.length; i++)
318
+ if (!this._Operations.hasOwnProperty(pHash))
197
319
  {
198
- tmpTasks.push(this._Tasks[tmpTaskKeys[i]]);
320
+ return fCallback(new Error(`Operation [${pHash}] not found.`));
199
321
  }
200
- return fCallback(null, tmpTasks);
322
+ return fCallback(null, this._Operations[pHash]);
323
+ }
324
+
325
+ /**
326
+ * List all operations.
327
+ */
328
+ getOperationList(fCallback)
329
+ {
330
+ let tmpList = [];
331
+ let tmpKeys = Object.keys(this._Operations);
332
+
333
+ for (let i = 0; i < tmpKeys.length; i++)
334
+ {
335
+ tmpList.push(this._Operations[tmpKeys[i]]);
336
+ }
337
+
338
+ return fCallback(null, tmpList);
339
+ }
340
+
341
+ /**
342
+ * Delete an operation by hash.
343
+ */
344
+ deleteOperation(pHash, fCallback)
345
+ {
346
+ if (!this._Operations.hasOwnProperty(pHash))
347
+ {
348
+ return fCallback(new Error(`Operation [${pHash}] not found.`));
349
+ }
350
+
351
+ delete this._Operations[pHash];
352
+ this.persistState();
353
+
354
+ return fCallback(null, true);
355
+ }
356
+
357
+ // ====================================================================
358
+ // Global State
359
+ // ====================================================================
360
+
361
+ /**
362
+ * Get the persisted global state.
363
+ *
364
+ * @returns {object} A copy of the global state.
365
+ */
366
+ getGlobalState()
367
+ {
368
+ return JSON.parse(JSON.stringify(this._GlobalState));
201
369
  }
202
370
 
203
- getTask(pGUIDTask, fCallback)
371
+ /**
372
+ * Update and persist global state.
373
+ *
374
+ * @param {object} pState - State to merge into global state.
375
+ */
376
+ updateGlobalState(pState)
204
377
  {
205
- if (!this._Tasks.hasOwnProperty(pGUIDTask))
378
+ if (typeof(pState) === 'object' && pState !== null)
206
379
  {
207
- return fCallback(new Error(`Ultravisor Hypervisor State: getTask could not find task with GUID ${pGUIDTask}.`));
380
+ Object.assign(this._GlobalState, pState);
381
+ this.persistState();
208
382
  }
209
- return fCallback(null, this._Tasks[pGUIDTask]);
210
383
  }
211
384
  }
212
385
 
213
- module.exports = UltravisorHypervisorState;
386
+ module.exports = UltravisorHypervisorState;