ultravisor 1.0.0 → 1.0.3

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 (87) hide show
  1. package/CONTRIBUTING.md +50 -0
  2. package/README.md +34 -0
  3. package/debug/Harness.js +4 -2
  4. package/docs/.nojekyll +0 -0
  5. package/docs/README.md +63 -0
  6. package/docs/_cover.md +15 -0
  7. package/docs/_sidebar.md +18 -0
  8. package/docs/_topbar.md +7 -0
  9. package/docs/architecture.md +103 -0
  10. package/docs/features/api.md +230 -0
  11. package/docs/features/cli.md +182 -0
  12. package/docs/features/configuration.md +245 -0
  13. package/docs/features/manifests.md +177 -0
  14. package/docs/features/operations.md +292 -0
  15. package/docs/features/scheduling.md +179 -0
  16. package/docs/features/tasks.md +1857 -0
  17. package/docs/index.html +39 -0
  18. package/docs/overview.md +75 -0
  19. package/docs/quickstart.md +167 -0
  20. package/docs/retold-catalog.json +24 -0
  21. package/docs/retold-keyword-index.json +19 -0
  22. package/package.json +13 -7
  23. package/source/Ultravisor.cjs +2 -2
  24. package/source/cli/Ultravisor-CLIProgram.cjs +38 -0
  25. package/source/cli/commands/Ultravisor-Command-ScheduleOperation.cjs +26 -2
  26. package/source/cli/commands/Ultravisor-Command-ScheduleTask.cjs +26 -2
  27. package/source/cli/commands/Ultravisor-Command-ScheduleView.cjs +22 -0
  28. package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +49 -1
  29. package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +51 -1
  30. package/source/cli/commands/Ultravisor-Command-Stop.cjs +4 -0
  31. package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +91 -0
  32. package/source/config/Ultravisor-Default-Command-Configuration.cjs +6 -1
  33. package/source/services/Ultravisor-Hypervisor-Event-Base.cjs +18 -1
  34. package/source/services/Ultravisor-Hypervisor-State.cjs +213 -0
  35. package/source/services/Ultravisor-Hypervisor.cjs +225 -1
  36. package/source/services/Ultravisor-Operation-Manifest.cjs +150 -1
  37. package/source/services/Ultravisor-Operation.cjs +190 -1
  38. package/source/services/Ultravisor-Task.cjs +339 -1
  39. package/source/services/events/Ultravisor-Hypervisor-Event-Cron.cjs +71 -1
  40. package/source/services/tasks/Ultravisor-Task-Base.cjs +264 -0
  41. package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +188 -0
  42. package/source/services/tasks/Ultravisor-Task-Command.cjs +65 -0
  43. package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +190 -0
  44. package/source/services/tasks/Ultravisor-Task-Conditional.cjs +104 -0
  45. package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +72 -0
  46. package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +336 -0
  47. package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +143 -0
  48. package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +146 -0
  49. package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +158 -0
  50. package/source/services/tasks/Ultravisor-Task-Request.cjs +56 -0
  51. package/source/services/tasks/Ultravisor-Task-Solver.cjs +89 -0
  52. package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +93 -0
  53. package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +127 -0
  54. package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +119 -0
  55. package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +109 -0
  56. package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +112 -0
  57. package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +499 -0
  58. package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +150 -0
  59. package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +110 -0
  60. package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +89 -0
  61. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +87 -0
  62. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +67 -0
  63. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +66 -0
  64. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +69 -0
  65. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +95 -0
  66. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +96 -0
  67. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +99 -0
  68. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +102 -0
  69. package/source/web_server/Ultravisor-API-Server.cjs +463 -3
  70. package/test/Ultravisor_tests.js +6097 -1
  71. package/webinterface/css/ultravisor.css +121 -0
  72. package/webinterface/html/index.html +32 -0
  73. package/webinterface/package.json +39 -0
  74. package/webinterface/source/Pict-Application-Ultravisor-Configuration.json +15 -0
  75. package/webinterface/source/Pict-Application-Ultravisor.js +414 -0
  76. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +42 -0
  77. package/webinterface/source/views/PictView-Ultravisor-BottomBar.js +65 -0
  78. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +236 -0
  79. package/webinterface/source/views/PictView-Ultravisor-Layout.js +83 -0
  80. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +273 -0
  81. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +243 -0
  82. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +141 -0
  83. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +280 -0
  84. package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +220 -0
  85. package/webinterface/source/views/PictView-Ultravisor-TaskList.js +248 -0
  86. package/webinterface/source/views/PictView-Ultravisor-TimingView.js +420 -0
  87. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +147 -0
@@ -0,0 +1,182 @@
1
+ # CLI Commands
2
+
3
+ Ultravisor provides a command-line interface for managing tasks, operations,
4
+ schedules, and the API server. The CLI is invoked via the `ultravisor`
5
+ command (or `node source/cli/Ultravisor-Run.cjs`).
6
+
7
+ ## Command Reference
8
+
9
+ ### start
10
+
11
+ Start the API server.
12
+
13
+ ```bash
14
+ ultravisor start
15
+ ultravisor start --verbose
16
+ ```
17
+
18
+ | Option | Description |
19
+ |--------|-------------|
20
+ | `-v, --verbose` | Enable verbose console output |
21
+
22
+ The server starts on the port configured in `.ultravisor.json`
23
+ (`UltravisorAPIServerPort`, default `54321`).
24
+
25
+ ### stop
26
+
27
+ Stop the Hypervisor scheduler. Deactivates all running cron jobs.
28
+
29
+ ```bash
30
+ ultravisor stop
31
+ ```
32
+
33
+ ### updatetask
34
+
35
+ Add or update a task definition. The task is persisted to
36
+ `.ultravisor.json`.
37
+
38
+ ```bash
39
+ ultravisor updatetask -g disk-check -n "Check Disk" -t Command -p "df -h"
40
+ ```
41
+
42
+ | Option | Description | Default |
43
+ |--------|-------------|---------|
44
+ | `-g, --guid` | Task GUID | (none) |
45
+ | `-c, --code` | Task code | (none) |
46
+ | `-n, --name` | Task name | (none) |
47
+ | `-t, --type` | Task type | `CRON` |
48
+ | `-p, --parameters` | Task parameters | `0 0 * * * *` |
49
+ | `-f, --file` | Path to JSON task definition file | (none) |
50
+
51
+ When `-f` is provided, the JSON file is loaded and then any CLI parameters
52
+ override the file values:
53
+
54
+ ```bash
55
+ # Load from file, but override the GUID
56
+ ultravisor updatetask -f ./my-task.json -g custom-guid
57
+ ```
58
+
59
+ Example JSON file:
60
+
61
+ ```json
62
+ {
63
+ "GUIDTask": "api-health",
64
+ "Name": "API Health Check",
65
+ "Type": "Request",
66
+ "URL": "https://api.example.com/health"
67
+ }
68
+ ```
69
+
70
+ ### singletask (alias: task)
71
+
72
+ Execute a single task immediately.
73
+
74
+ ```bash
75
+ ultravisor singletask disk-check
76
+ ultravisor task disk-check
77
+ ultravisor singletask disk-check --dry_run
78
+ ```
79
+
80
+ | Argument | Description |
81
+ |----------|-------------|
82
+ | `<task>` | The task GUID to execute |
83
+
84
+ | Option | Description | Default |
85
+ |--------|-------------|---------|
86
+ | `-o, --operation` | Scope task to an operation | `Default` |
87
+ | `-d, --dry_run` | Print what would happen without executing | `false` |
88
+
89
+ ### singleoperation (alias: operation)
90
+
91
+ Execute a single operation immediately.
92
+
93
+ ```bash
94
+ ultravisor singleoperation etl-pipeline
95
+ ultravisor operation etl-pipeline
96
+ ultravisor singleoperation etl-pipeline --dry_run
97
+ ```
98
+
99
+ | Argument | Description |
100
+ |----------|-------------|
101
+ | `<operation>` | The operation GUID to execute |
102
+
103
+ | Option | Description | Default |
104
+ |--------|-------------|---------|
105
+ | `-d, --dry_run` | Print what would happen without executing | `false` |
106
+
107
+ ### schedule (alias: cal)
108
+
109
+ View the current schedule.
110
+
111
+ ```bash
112
+ ultravisor schedule
113
+ ultravisor cal
114
+ ```
115
+
116
+ | Option | Description | Default |
117
+ |--------|-------------|---------|
118
+ | `-f, --format` | Visualization format (day, week, month) | `day` |
119
+
120
+ Example output:
121
+
122
+ ```
123
+ === Ultravisor Schedule (2 entries) ===
124
+
125
+ [INACTIVE] Task: disk-check
126
+ Schedule: cron (*/5 * * * *)
127
+ GUID: sched-task-disk-check-1707566400000
128
+
129
+ [INACTIVE] Operation: etl-pipeline
130
+ Schedule: daily (0 2 * * *)
131
+ GUID: sched-op-etl-pipeline-1707566400001
132
+ ```
133
+
134
+ ### schedule_task (alias: st)
135
+
136
+ Add a task to the schedule.
137
+
138
+ ```bash
139
+ ultravisor schedule_task disk-check -t cron -p "*/5 * * * *"
140
+ ultravisor st disk-check -t hourly
141
+ ```
142
+
143
+ | Argument | Description |
144
+ |----------|-------------|
145
+ | `<task_guid>` | The task GUID to schedule |
146
+
147
+ | Option | Description | Default |
148
+ |--------|-------------|---------|
149
+ | `-t, --type` | Schedule type (cron, daily, hourly, solver) | `cron` |
150
+ | `-p, --parameters` | Cron expression or schedule parameters | (empty) |
151
+
152
+ ### schedule_operation (alias: so)
153
+
154
+ Add an operation to the schedule.
155
+
156
+ ```bash
157
+ ultravisor schedule_operation etl-pipeline -t daily -p "0 2 * * *"
158
+ ultravisor so etl-pipeline -t cron -p "0 6 * * 1-5"
159
+ ```
160
+
161
+ | Argument | Description |
162
+ |----------|-------------|
163
+ | `<operation_guid>` | The operation GUID to schedule |
164
+
165
+ | Option | Description | Default |
166
+ |--------|-------------|---------|
167
+ | `-t, --type` | Schedule type (cron, daily, hourly, solver) | `cron` |
168
+ | `-p, --parameters` | Cron expression or schedule parameters | (empty) |
169
+
170
+ ### configuration
171
+
172
+ Auto-generated command that explains how Ultravisor resolved its
173
+ configuration (which files were loaded, what values came from where).
174
+
175
+ ```bash
176
+ ultravisor configuration
177
+ ```
178
+
179
+ ## Exit Codes
180
+
181
+ - `0` -- command completed successfully
182
+ - Non-zero -- an error occurred during execution
@@ -0,0 +1,245 @@
1
+ # Configuration
2
+
3
+ Ultravisor uses a layered JSON configuration system. Configuration is
4
+ gathered automatically at startup and merged into a single object.
5
+
6
+ ## Configuration File
7
+
8
+ The primary configuration file is `.ultravisor.json`, located in the
9
+ working directory. This file stores both runtime settings and persisted
10
+ task/operation definitions.
11
+
12
+ ### Minimal Configuration
13
+
14
+ ```json
15
+ {
16
+ "UltravisorAPIServerPort": 54321
17
+ }
18
+ ```
19
+
20
+ ### Full Configuration
21
+
22
+ ```json
23
+ {
24
+ "UltravisorAPIServerPort": 54321,
25
+ "UltravisorFileStorePath": "/var/data/ultravisor_datastore",
26
+ "UltravisorStagingRoot": "/var/data/ultravisor_staging",
27
+ "UltravisorTickIntervalMilliseconds": 60000,
28
+ "Tasks": {
29
+ "my-task": {
30
+ "GUIDTask": "my-task",
31
+ "Name": "My Task",
32
+ "Type": "Command",
33
+ "Command": "echo hello"
34
+ }
35
+ },
36
+ "Operations": {
37
+ "my-op": {
38
+ "GUIDOperation": "my-op",
39
+ "Name": "My Operation",
40
+ "Tasks": ["my-task"]
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ## Configuration Options
47
+
48
+ | Key | Type | Default | Description |
49
+ |-----|------|---------|-------------|
50
+ | `UltravisorAPIServerPort` | Number | `54321` | Port for the REST API server |
51
+ | `UltravisorFileStorePath` | String | `${cwd}/dist/ultravisor_datastore` | Path for the output file store |
52
+ | `UltravisorStagingRoot` | String | `${cwd}/dist/ultravisor_staging` | Root folder for per-operation staging directories |
53
+ | `UltravisorTickIntervalMilliseconds` | Number | `60000` | Base tick interval in milliseconds |
54
+ | `UltravisorCommandTimeoutMilliseconds` | Number | `300000` | Timeout for command task execution (5 minutes) |
55
+ | `UltravisorCommandMaxBufferBytes` | Number | `10485760` | Max stdout/stderr buffer size for commands (10 MB) |
56
+ | `Tasks` | Object | `{}` | Map of task GUIDs to task definitions |
57
+ | `Operations` | Object | `{}` | Map of operation GUIDs to operation definitions |
58
+
59
+ ## Configuration Layering
60
+
61
+ Configuration is resolved in order (later layers override earlier):
62
+
63
+ 1. **Default Program Configuration** -- hardcoded defaults in
64
+ `source/config/Ultravisor-Default-Command-Configuration.cjs`:
65
+
66
+ ```json
67
+ {
68
+ "UltravisorAPIServerPort": 54321,
69
+ "UltravisorFileStorePath": "${cwd}/dist/ultravisor_datastore",
70
+ "UltravisorStagingRoot": "${cwd}/dist/ultravisor_staging",
71
+ "UltravisorTickIntervalMilliseconds": 60000,
72
+ "UltravisorCommandTimeoutMilliseconds": 300000,
73
+ "UltravisorCommandMaxBufferBytes": 10485760
74
+ }
75
+ ```
76
+
77
+ 2. **`.ultravisor.json`** -- project-level file searched from the current
78
+ working directory upward through parent directories
79
+
80
+ The merged result is available as `fable.ProgramConfiguration` within
81
+ services.
82
+
83
+ ## Viewing Configuration Resolution
84
+
85
+ Use the built-in `configuration` command to see how Ultravisor resolved
86
+ its configuration:
87
+
88
+ ```bash
89
+ ultravisor configuration
90
+ ```
91
+
92
+ This shows each gather phase, what file was loaded, and what values came
93
+ from where.
94
+
95
+ ## State Persistence
96
+
97
+ When tasks or operations are created/updated via the CLI (`updatetask`)
98
+ or the API (`POST /Task`, `POST /Operation`), the state service merges
99
+ the changes back into the `.ultravisor.json` file.
100
+
101
+ The merge logic:
102
+ - The existing file is read
103
+ - New or updated tasks/operations are merged (existing fields preserved,
104
+ new fields added)
105
+ - The entire configuration is written back to the file
106
+
107
+ This means the `.ultravisor.json` file serves as both configuration and
108
+ persistent storage.
109
+
110
+ ## Example Configurations
111
+
112
+ ### Simple API monitoring
113
+
114
+ ```json
115
+ {
116
+ "UltravisorAPIServerPort": 8080,
117
+ "Tasks": {
118
+ "health-check": {
119
+ "GUIDTask": "health-check",
120
+ "Name": "API Health Check",
121
+ "Type": "Request",
122
+ "URL": "https://api.example.com/health"
123
+ }
124
+ },
125
+ "Operations": {}
126
+ }
127
+ ```
128
+
129
+ ### Multi-task data pipeline
130
+
131
+ ```json
132
+ {
133
+ "UltravisorAPIServerPort": 54321,
134
+ "UltravisorFileStorePath": "/data/ultravisor",
135
+ "Tasks": {
136
+ "extract": {
137
+ "GUIDTask": "extract",
138
+ "Name": "Extract Data",
139
+ "Type": "Command",
140
+ "Command": "python3 /scripts/extract.py --output /tmp/extract.json"
141
+ },
142
+ "transform": {
143
+ "GUIDTask": "transform",
144
+ "Name": "Transform Data",
145
+ "Type": "Command",
146
+ "Command": "python3 /scripts/transform.py --input /tmp/extract.json --output /tmp/transformed.json"
147
+ },
148
+ "load": {
149
+ "GUIDTask": "load",
150
+ "Name": "Load Data",
151
+ "Type": "Command",
152
+ "Command": "python3 /scripts/load.py --input /tmp/transformed.json"
153
+ }
154
+ },
155
+ "Operations": {
156
+ "etl": {
157
+ "GUIDOperation": "etl",
158
+ "Name": "Full ETL Pipeline",
159
+ "Tasks": ["extract", "transform", "load"]
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### IoT sensor monitoring
166
+
167
+ ```json
168
+ {
169
+ "UltravisorAPIServerPort": 9000,
170
+ "Tasks": {
171
+ "read-temp-living": {
172
+ "GUIDTask": "read-temp-living",
173
+ "Name": "Read Living Room Temperature",
174
+ "Type": "Request",
175
+ "URL": "http://192.168.1.100/api/temperature"
176
+ },
177
+ "read-temp-bedroom": {
178
+ "GUIDTask": "read-temp-bedroom",
179
+ "Name": "Read Bedroom Temperature",
180
+ "Type": "Request",
181
+ "URL": "http://192.168.1.101/api/temperature"
182
+ },
183
+ "read-temp-garage": {
184
+ "GUIDTask": "read-temp-garage",
185
+ "Name": "Read Garage Temperature",
186
+ "Type": "Request",
187
+ "URL": "http://192.168.1.102/api/temperature"
188
+ },
189
+ "log-readings": {
190
+ "GUIDTask": "log-readings",
191
+ "Name": "Log Temperature Readings",
192
+ "Type": "Command",
193
+ "Command": "python3 /scripts/log_temps.py"
194
+ }
195
+ },
196
+ "Operations": {
197
+ "temp-sweep": {
198
+ "GUIDOperation": "temp-sweep",
199
+ "Name": "Temperature Sweep",
200
+ "Tasks": [
201
+ "read-temp-living",
202
+ "read-temp-bedroom",
203
+ "read-temp-garage",
204
+ "log-readings"
205
+ ]
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ ### Media processing
212
+
213
+ ```json
214
+ {
215
+ "UltravisorAPIServerPort": 54321,
216
+ "UltravisorFileStorePath": "/media/output",
217
+ "Tasks": {
218
+ "scan-input": {
219
+ "GUIDTask": "scan-input",
220
+ "Name": "Scan Input Directory",
221
+ "Type": "Command",
222
+ "Command": "ls -1 /media/input/*.avi > /tmp/pending_files.txt"
223
+ },
224
+ "transcode-batch": {
225
+ "GUIDTask": "transcode-batch",
226
+ "Name": "Transcode Video Batch",
227
+ "Type": "Command",
228
+ "Command": "bash /scripts/transcode_batch.sh /tmp/pending_files.txt /media/output"
229
+ },
230
+ "generate-thumbnails": {
231
+ "GUIDTask": "generate-thumbnails",
232
+ "Name": "Generate Thumbnails",
233
+ "Type": "Command",
234
+ "Command": "bash /scripts/thumbnails.sh /media/output"
235
+ }
236
+ },
237
+ "Operations": {
238
+ "media-ingest": {
239
+ "GUIDOperation": "media-ingest",
240
+ "Name": "Media Ingest Pipeline",
241
+ "Tasks": ["scan-input", "transcode-batch", "generate-thumbnails"]
242
+ }
243
+ }
244
+ }
245
+ ```
@@ -0,0 +1,177 @@
1
+ # Manifests (Metaoutput)
2
+
3
+ Manifests track the output from executing operations. Every operation
4
+ execution produces a manifest that records timing, success/failure, task
5
+ results and logs.
6
+
7
+ ## Manifest Model
8
+
9
+ ```json
10
+ {
11
+ "GUIDOperation": "etl-pipeline",
12
+ "GUIDRun": "etl-pipeline-1707566400000",
13
+ "Name": "ETL Pipeline",
14
+ "StagingPath": "/var/data/ultravisor_staging/etl-pipeline",
15
+ "ManifestFilePath": "/var/data/ultravisor_staging/etl-pipeline/Manifest_etl-pipeline.json",
16
+ "StartTime": "2026-02-10T02:00:00.000Z",
17
+ "StopTime": "2026-02-10T02:00:12.500Z",
18
+ "Status": "Complete",
19
+ "Success": true,
20
+ "Summary": "Operation etl-pipeline Complete: 3 task(s) executed.",
21
+ "TaskResults": [
22
+ {
23
+ "GUIDTask": "pull-data",
24
+ "Name": "Pull Data from API",
25
+ "Type": "Request",
26
+ "StartTime": "2026-02-10T02:00:00.100Z",
27
+ "StopTime": "2026-02-10T02:00:03.200Z",
28
+ "Status": "Complete",
29
+ "Success": true,
30
+ "Output": "{\"records\": 150}",
31
+ "Log": ["..."]
32
+ },
33
+ {
34
+ "GUIDTask": "process-data",
35
+ "Name": "Process Downloaded Data",
36
+ "Type": "Command",
37
+ "StartTime": "2026-02-10T02:00:03.300Z",
38
+ "StopTime": "2026-02-10T02:00:10.100Z",
39
+ "Status": "Complete",
40
+ "Success": true,
41
+ "Output": "Processed 150 records\n",
42
+ "Log": ["..."]
43
+ },
44
+ {
45
+ "GUIDTask": "notify",
46
+ "Name": "Send Notification",
47
+ "Type": "Command",
48
+ "StartTime": "2026-02-10T02:00:10.200Z",
49
+ "StopTime": "2026-02-10T02:00:12.400Z",
50
+ "Status": "Complete",
51
+ "Success": true,
52
+ "Output": "",
53
+ "Log": ["..."]
54
+ }
55
+ ],
56
+ "Log": [
57
+ "Operation etl-pipeline started at 2026-02-10T02:00:00.000Z",
58
+ "Task pull-data completed with status: Complete",
59
+ "Task process-data completed with status: Complete",
60
+ "Task notify completed with status: Complete",
61
+ "Operation etl-pipeline Complete: 3 task(s) executed."
62
+ ]
63
+ }
64
+ ```
65
+
66
+ ### Fields
67
+
68
+ | Field | Description |
69
+ |-------|-------------|
70
+ | `GUIDOperation` | The operation that was executed |
71
+ | `GUIDRun` | Unique ID for this specific execution run |
72
+ | `Name` | Operation name |
73
+ | `StartTime` | ISO timestamp when the operation started |
74
+ | `StopTime` | ISO timestamp when the operation finished |
75
+ | `Status` | `Running`, `Complete`, or `Error` |
76
+ | `Success` | `true` if all tasks succeeded, `false` otherwise |
77
+ | `Summary` | Human-readable one-line summary |
78
+ | `StagingPath` | Absolute path to the operation's staging folder |
79
+ | `ManifestFilePath` | Absolute path to the manifest JSON file on disk |
80
+ | `TaskResults` | Array of task manifest entries (see below) |
81
+ | `Log` | Array of log messages from the operation lifecycle |
82
+
83
+ ### Task Result Fields
84
+
85
+ | Field | Description |
86
+ |-------|-------------|
87
+ | `GUIDTask` | The task that was executed |
88
+ | `Name` | Task name |
89
+ | `Type` | Task type (Command, Request, etc.) |
90
+ | `StartTime` | ISO timestamp when the task started |
91
+ | `StopTime` | ISO timestamp when the task finished |
92
+ | `Status` | `Running`, `Complete`, `Error`, or `Unsupported` |
93
+ | `Success` | `true` if the task succeeded |
94
+ | `Output` | stdout or response body from the execution |
95
+ | `Log` | Array of log messages from the task execution |
96
+
97
+ ## Manifest Lifecycle
98
+
99
+ 1. **Create** -- `createManifest()` initializes a new manifest with status
100
+ `Running` and assigns a `GUIDRun`
101
+ 2. **Add Results** -- as each task completes, `addTaskResult()` appends the
102
+ task result to `TaskResults`
103
+ 3. **Finalize** -- `finalizeManifest()` sets `StopTime`, calculates overall
104
+ `Success` (all tasks must succeed), sets `Status` and `Summary`, and
105
+ writes the manifest JSON to the operation's staging folder
106
+
107
+ ## Success Determination
108
+
109
+ An operation manifest is marked as `Success: true` only if **every** task
110
+ in the `TaskResults` array has `Success: true`. If any task has
111
+ `Success: false`, the entire operation is marked as failed.
112
+
113
+ ## Storage
114
+
115
+ Manifests are stored in two places:
116
+
117
+ 1. **In memory** -- for the duration of the server session, accessible via
118
+ the API. Restarting the server clears the in-memory manifest store.
119
+
120
+ 2. **On disk** -- when an operation completes, a
121
+ `Manifest_{GUIDOperation}.json` file is written to the operation's
122
+ staging folder. This provides a persistent record that survives
123
+ restarts. The file path is recorded in the manifest's
124
+ `ManifestFilePath` field.
125
+
126
+ The on-disk manifest contains the complete manifest object including all
127
+ task results, timing data and logs. It is written as pretty-printed JSON
128
+ (4-space indentation).
129
+
130
+ The staging folder location defaults to
131
+ `./dist/ultravisor_staging/{GUIDOperation}/` and can be configured via
132
+ `UltravisorStagingRoot` in `.ultravisor.json` (see
133
+ [Configuration](configuration.md)).
134
+
135
+ ## Accessing Manifests
136
+
137
+ ### Via API
138
+
139
+ ```bash
140
+ # List all manifests
141
+ curl http://localhost:54321/Manifest
142
+
143
+ # Get a specific manifest
144
+ curl http://localhost:54321/Manifest/etl-pipeline-1707566400000
145
+ ```
146
+
147
+ ### Example: Checking if the last run succeeded
148
+
149
+ ```bash
150
+ # Get the manifest list and check the last entry
151
+ curl -s http://localhost:54321/Manifest | jq '.[-1].Success'
152
+ ```
153
+
154
+ ## Example: Partial Failure
155
+
156
+ When one task fails in an operation, the manifest captures it:
157
+
158
+ ```json
159
+ {
160
+ "GUIDOperation": "data-sync",
161
+ "Status": "Error",
162
+ "Success": false,
163
+ "Summary": "Operation data-sync Error: 2 task(s) executed.",
164
+ "TaskResults": [
165
+ {
166
+ "GUIDTask": "fetch-data",
167
+ "Status": "Complete",
168
+ "Success": true
169
+ },
170
+ {
171
+ "GUIDTask": "upload-data",
172
+ "Status": "Error",
173
+ "Success": false
174
+ }
175
+ ]
176
+ }
177
+ ```