ultravisor 1.0.8 → 1.0.9

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 (80) hide show
  1. package/docs/_sidebar.md +8 -0
  2. package/docs/features/api.md +142 -0
  3. package/docs/features/beacons.md +52 -0
  4. package/docs/features/case-study-retold-remote.md +223 -0
  5. package/docs/features/platform-cards.md +145 -0
  6. package/docs/features/reachability-matrix.md +145 -0
  7. package/docs/features/tasks-file-system.md +103 -0
  8. package/docs/features/universal-addressing.md +117 -0
  9. package/docs/retold-catalog.json +437 -1
  10. package/docs/retold-keyword-index.json +47567 -7220
  11. package/operation-library/api-data-pipeline.json +259 -39
  12. package/operation-library/conditional-file-backup.json +260 -39
  13. package/operation-library/csv-data-analysis.json +618 -79
  14. package/operation-library/csv-to-json.json +357 -45
  15. package/operation-library/directory-inventory.json +297 -36
  16. package/operation-library/health-check-ping.json +45 -25
  17. package/operation-library/json-config-merge.json +105 -30
  18. package/operation-library/log-line-counter.json +445 -59
  19. package/operation-library/meadow-crud-lifecycle.json +525 -63
  20. package/operation-library/rest-api-orchestrator.json +471 -56
  21. package/operation-library/simple-echo.json +228 -24
  22. package/operation-library/template-processor.json +433 -68
  23. package/package.json +5 -4
  24. package/source/beacon/Ultravisor-Beacon-Client.cjs +15 -1
  25. package/source/beacon/Ultravisor-Beacon-ProviderRegistry.cjs +36 -0
  26. package/source/cli/Ultravisor-CLIProgram.cjs +64 -3
  27. package/source/config/Ultravisor-Default-Command-Configuration.cjs +2 -1
  28. package/source/services/Ultravisor-Beacon-Coordinator.cjs +1029 -1
  29. package/source/services/Ultravisor-Beacon-Reachability.cjs +403 -0
  30. package/source/services/Ultravisor-ExecutionEngine.cjs +358 -1
  31. package/source/services/Ultravisor-ExecutionManifest.cjs +391 -8
  32. package/source/services/Ultravisor-Hypervisor-State.cjs +50 -0
  33. package/source/services/persistence/Ultravisor-Beacon-QueueJournal.cjs +474 -0
  34. package/source/services/tasks/Ultravisor-BuiltIn-TaskConfigs.cjs +2 -0
  35. package/source/services/tasks/Ultravisor-TaskHelper-BeaconDispatch.cjs +11 -2
  36. package/source/services/tasks/data-collection/Ultravisor-TaskConfigs-DataCollection.cjs +66 -0
  37. package/source/services/tasks/data-collection/definitions/event-counter.json +26 -0
  38. package/source/services/tasks/data-transform/Ultravisor-TaskConfigs-DataTransform.cjs +177 -5
  39. package/source/services/tasks/data-transform/definitions/add-field-mapping.json +22 -0
  40. package/source/services/tasks/data-transform/definitions/set-value.json +23 -0
  41. package/source/services/tasks/extension/Ultravisor-TaskConfigs-Extension.cjs +57 -6
  42. package/source/services/tasks/http-client/Ultravisor-TaskConfigs-HttpClient.cjs +94 -9
  43. package/source/services/tasks/http-client/definitions/add-header.json +21 -0
  44. package/source/services/tasks/llm/Ultravisor-TaskConfigs-LLM.cjs +137 -3
  45. package/source/services/tasks/llm/definitions/add-message.json +21 -0
  46. package/source/services/tasks/llm/definitions/add-tool.json +22 -0
  47. package/source/services/tasks/platform/Ultravisor-TaskConfigs-Platform.cjs +449 -0
  48. package/source/services/tasks/platform/definitions/base64-decode.json +24 -0
  49. package/source/services/tasks/platform/definitions/base64-encode.json +25 -0
  50. package/source/services/tasks/platform/definitions/file-transfer.json +26 -0
  51. package/source/services/tasks/platform/definitions/resolve-address.json +32 -0
  52. package/source/services/tasks/platform/definitions/send-result.json +24 -0
  53. package/source/services/tasks/shell/Ultravisor-TaskConfigs-Shell.cjs +115 -4
  54. package/source/services/tasks/shell/definitions/add-env-var.json +21 -0
  55. package/source/services/tasks/user-interaction/Ultravisor-TaskConfigs-UserInteraction.cjs +53 -1
  56. package/source/services/tasks/user-interaction/definitions/add-option.json +21 -0
  57. package/source/web_server/Ultravisor-API-Server.cjs +919 -2
  58. package/test/Ultravisor_browser_tests.js +27 -20
  59. package/test/Ultravisor_tests.js +621 -65
  60. package/webinterface/build/build-codemirror-bundle.js +30 -0
  61. package/webinterface/build/codemirror-entry.js +13 -0
  62. package/webinterface/html/index.html +3 -1
  63. package/webinterface/package.json +17 -9
  64. package/webinterface/source/Pict-Application-Ultravisor.js +183 -0
  65. package/webinterface/source/panels/Ultravisor-CardSettingsPanel.js +208 -50
  66. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +9 -1
  67. package/webinterface/source/views/PictView-Ultravisor-BeaconList.js +47 -11
  68. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +18 -1
  69. package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +769 -40
  70. package/webinterface/source/views/PictView-Ultravisor-ManifestDetail.js +733 -0
  71. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +504 -315
  72. package/webinterface/source/views/PictView-Ultravisor-OperationDescriptionEditor.js +68 -0
  73. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +1 -1
  74. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +18 -2
  75. package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +242 -17
  76. package/webinterface/source/views/PictView-Ultravisor-ReachabilityMap.js +399 -0
  77. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +20 -4
  78. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +0 -3
  79. package/card-audit.json +0 -1545
  80. package/source/services/tasks/data-transform/Ultravisor-TaskType-SetValues.cjs +0 -74
package/docs/_sidebar.md CHANGED
@@ -10,6 +10,10 @@
10
10
  - [Capabilities](features/capabilities.md)
11
11
  - [Beacons](features/beacons.md)
12
12
  - [Building Beacon Providers](features/beacon-providers.md)
13
+ - [Beacon Authentication](features/beacon-authentication.md)
14
+ - [Universal Addressing](features/universal-addressing.md)
15
+ - [Reachability Matrix](features/reachability-matrix.md)
16
+ - [Platform Cards](features/platform-cards.md)
13
17
  - [LLM Integration](features/llm.md)
14
18
  - [LLM Model Setup Guide](features/llm-model-setup.md)
15
19
  - [Operations](features/operations.md)
@@ -33,3 +37,7 @@
33
37
  - [API Server](features/api.md)
34
38
  - [CLI Commands](features/cli.md)
35
39
  - [Configuration](features/configuration.md)
40
+
41
+ - Case Studies
42
+
43
+ - [retold-remote + orator-conversion](features/case-study-retold-remote.md)
@@ -210,6 +210,148 @@ Returns an array of all operation manifests from the current session.
210
210
  }
211
211
  ```
212
212
 
213
+ ### Beacons
214
+
215
+ | Method | Path | Description |
216
+ |--------|------|-------------|
217
+ | `POST` | `/Beacon/Register` | Register a new Beacon worker |
218
+ | `GET` | `/Beacon` | List all registered Beacons |
219
+ | `GET` | `/Beacon/:BeaconID` | Get a specific Beacon |
220
+ | `DELETE` | `/Beacon/:BeaconID` | Deregister a Beacon |
221
+ | `POST` | `/Beacon/:BeaconID/Heartbeat` | Send a Beacon heartbeat |
222
+ | `POST` | `/Beacon/Work/Poll` | Poll for available work |
223
+ | `POST` | `/Beacon/Work/:WorkItemHash/Complete` | Report work item completion |
224
+ | `POST` | `/Beacon/Work/:WorkItemHash/Error` | Report work item failure |
225
+ | `POST` | `/Beacon/Work/:WorkItemHash/Progress` | Report work item progress |
226
+ | `POST` | `/Beacon/Work/:WorkItemHash/Upload` | Upload a binary result file for a work item |
227
+ | `GET` | `/Beacon/Work` | List all work items |
228
+ | `GET` | `/Beacon/Affinity` | List active affinity bindings |
229
+ | `GET` | `/Beacon/Reachability` | Get the connectivity matrix between all beacon pairs |
230
+ | `POST` | `/Beacon/Reachability/Probe` | Trigger connectivity probes between all online beacon pairs |
231
+
232
+ #### POST /Beacon/Register
233
+
234
+ Register a new Beacon worker with the coordinator.
235
+
236
+ ```bash
237
+ curl -X POST http://localhost:54321/Beacon/Register \
238
+ -H "Content-Type: application/json" \
239
+ -d '{
240
+ "Name": "GPU-Worker-1",
241
+ "Capabilities": ["Shell", "FileSystem"],
242
+ "MaxConcurrent": 4
243
+ }'
244
+ ```
245
+
246
+ Response:
247
+
248
+ ```json
249
+ {
250
+ "BeaconID": "beacon-abc123",
251
+ "Name": "GPU-Worker-1",
252
+ "Capabilities": ["Shell", "FileSystem"],
253
+ "MaxConcurrent": 4,
254
+ "Status": "Online"
255
+ }
256
+ ```
257
+
258
+ #### POST /Beacon/Work/Poll
259
+
260
+ Poll for available work matching the Beacon's capabilities.
261
+
262
+ ```bash
263
+ curl -X POST http://localhost:54321/Beacon/Work/Poll \
264
+ -H "Content-Type: application/json" \
265
+ -d '{ "BeaconID": "beacon-abc123" }'
266
+ ```
267
+
268
+ Response:
269
+
270
+ ```json
271
+ {
272
+ "WorkItem": {
273
+ "WorkItemHash": "wi-xyz789",
274
+ "Capability": "Shell",
275
+ "Action": "Execute",
276
+ "Settings": { "Command": "echo hello" }
277
+ }
278
+ }
279
+ ```
280
+
281
+ #### POST /Beacon/Work/:WorkItemHash/Complete
282
+
283
+ Report successful completion of a work item.
284
+
285
+ ```bash
286
+ curl -X POST http://localhost:54321/Beacon/Work/wi-xyz789/Complete \
287
+ -H "Content-Type: application/json" \
288
+ -d '{
289
+ "Outputs": { "StdOut": "hello\n", "ExitCode": 0 },
290
+ "Log": ["Command executed successfully"]
291
+ }'
292
+ ```
293
+
294
+ #### POST /Beacon/Work/:WorkItemHash/Upload
295
+
296
+ Upload a binary result file for a work item. The Beacon sends raw file
297
+ bytes with `Content-Type: application/octet-stream` and an
298
+ `X-Output-Filename` header. The file is written to the operation's
299
+ staging directory. Requires session auth.
300
+
301
+ ```bash
302
+ curl -X POST http://localhost:54321/Beacon/Work/wi-xyz789/Upload \
303
+ -H "Content-Type: application/octet-stream" \
304
+ -H "X-Output-Filename: result.bin" \
305
+ --data-binary @result.bin
306
+ ```
307
+
308
+ Response:
309
+
310
+ ```json
311
+ {
312
+ "Status": "Uploaded",
313
+ "WorkItemHash": "wi-xyz789",
314
+ "FilePath": "/data/staging/my-pipeline/result.bin"
315
+ }
316
+ ```
317
+
318
+ #### GET /Beacon/Reachability
319
+
320
+ Returns the connectivity matrix between all beacon pairs. No auth
321
+ required (management UI).
322
+
323
+ ```bash
324
+ curl http://localhost:54321/Beacon/Reachability
325
+ ```
326
+
327
+ Response:
328
+
329
+ ```json
330
+ [
331
+ {
332
+ "SourceBeaconID": "beacon-abc123",
333
+ "TargetBeaconID": "beacon-def456",
334
+ "Status": "Reachable",
335
+ "ProbeLatencyMs": 12,
336
+ "LastProbeAt": "2026-03-21T10:00:00.000Z",
337
+ "ProbeURL": "http://192.168.1.10:54322/probe"
338
+ }
339
+ ]
340
+ ```
341
+
342
+ #### POST /Beacon/Reachability/Probe
343
+
344
+ Triggers connectivity probes between all online beacon pairs. Returns
345
+ the updated reachability matrix after probes complete. No auth required
346
+ (management UI).
347
+
348
+ ```bash
349
+ curl -X POST http://localhost:54321/Beacon/Reachability/Probe
350
+ ```
351
+
352
+ Response: Array of reachability records (same shape as
353
+ `GET /Beacon/Reachability`).
354
+
213
355
  ## Error Responses
214
356
 
215
357
  All error responses follow this format:
@@ -121,6 +121,7 @@ Register a new Beacon worker with the coordinator.
121
121
  | `Capabilities` | array | yes | List of capability strings |
122
122
  | `MaxConcurrent` | number | no | Maximum concurrent work items (default: 1) |
123
123
  | `Tags` | object | no | Arbitrary key-value metadata |
124
+ | `BindAddresses` | array | no | Network interfaces the Beacon is listening on. Each entry is `{ IP, Port, Protocol }`. Used by the reachability service to probe connectivity between Beacons. |
124
125
 
125
126
  **Response:** The created Beacon record including the assigned `BeaconID`.
126
127
 
@@ -224,6 +225,57 @@ List all active affinity bindings.
224
225
  **Response:** Array of affinity binding records, each containing
225
226
  `AffinityKey`, `BeaconID`, `CreatedAt`, and `ExpiresAt`.
226
227
 
228
+ ---
229
+
230
+ ### GET /Beacon/Reachability
231
+
232
+ Returns the connectivity matrix between all beacon pairs. No auth
233
+ required (management UI).
234
+
235
+ **Response:** Array of reachability records:
236
+
237
+ | Field | Type | Description |
238
+ |-------|------|-------------|
239
+ | `SourceBeaconID` | string | Beacon that initiated the probe |
240
+ | `TargetBeaconID` | string | Beacon that was probed |
241
+ | `Status` | string | Connectivity status (e.g. `Reachable`, `Unreachable`) |
242
+ | `ProbeLatencyMs` | number | Round-trip latency of the probe in milliseconds |
243
+ | `LastProbeAt` | string | ISO timestamp of the last probe |
244
+ | `ProbeURL` | string | URL that was probed |
245
+
246
+ ---
247
+
248
+ ### POST /Beacon/Reachability/Probe
249
+
250
+ Triggers connectivity probes between all online beacon pairs. Returns
251
+ the updated reachability matrix after probes complete. No auth required
252
+ (management UI).
253
+
254
+ **Response:** Array of reachability records (same shape as
255
+ `GET /Beacon/Reachability`).
256
+
257
+ ---
258
+
259
+ ### POST /Beacon/Work/:WorkItemHash/Upload
260
+
261
+ Uploads a binary result file for a work item. The Beacon sends raw file
262
+ bytes with `Content-Type: application/octet-stream` and an
263
+ `X-Output-Filename` header specifying the file name. The file is written
264
+ to the operation's staging directory.
265
+
266
+ Requires session auth.
267
+
268
+ **Request headers:**
269
+
270
+ | Header | Required | Description |
271
+ |--------|----------|-------------|
272
+ | `Content-Type` | yes | Must be `application/octet-stream` |
273
+ | `X-Output-Filename` | yes | Target file name for the uploaded file |
274
+
275
+ **Request body:** Raw binary file bytes.
276
+
277
+ **Response:** `{ Status: "Uploaded", WorkItemHash: "...", FilePath: "..." }`
278
+
227
279
  ## Custom Capability Providers
228
280
 
229
281
  Beacons use a pluggable **CapabilityProvider** system. Each provider handles
@@ -0,0 +1,223 @@
1
+ # Case Study: retold-remote + orator-conversion
2
+
3
+ This case study shows how retold-remote (a media browser) and orator-conversion (a media processing worker) integrate through Ultravisor's operation pipeline to generate thumbnails, previews, waveforms, and other derived media artifacts.
4
+
5
+ ## System Overview
6
+
7
+ ```mermaid
8
+ graph TB
9
+ subgraph "retold-remote (NAS)"
10
+ RR[retold-remote server]
11
+ FS[(Media Files<br/>/Users/steven)]
12
+ RR --- FS
13
+ end
14
+
15
+ subgraph "Ultravisor (Coordinator)"
16
+ UV[Ultravisor API Server]
17
+ OPS[(Operation Graphs)]
18
+ RM[Reachability Matrix]
19
+ UV --- OPS
20
+ UV --- RM
21
+ end
22
+
23
+ subgraph "orator-conversion (Worker)"
24
+ OC[orator-conversion beacon]
25
+ SHARP[Sharp / ffmpeg / pdftoppm]
26
+ OC --- SHARP
27
+ end
28
+
29
+ RR -->|"triggerOperation('rr-image-thumbnail', params)"| UV
30
+ UV -->|"Enqueue MediaConversion/ImageResize"| OC
31
+ OC -->|"Upload result binary"| UV
32
+ UV -->|"Stream binary response"| RR
33
+ ```
34
+
35
+ ## How It Connects
36
+
37
+ ### 1. Startup
38
+
39
+ All three services start independently:
40
+
41
+ ```bash
42
+ # Terminal 1: Ultravisor
43
+ ultravisor start -l
44
+
45
+ # Terminal 2: retold-remote
46
+ retold-remote serve ~/Media -u -l
47
+
48
+ # Terminal 3: orator-conversion
49
+ npm start -- -u -l
50
+ ```
51
+
52
+ ### 2. Registration
53
+
54
+ ```mermaid
55
+ sequenceDiagram
56
+ participant RR as retold-remote
57
+ participant UV as Ultravisor
58
+ participant OC as orator-conversion
59
+
60
+ OC->>UV: POST /Beacon/Register<br/>{Name: "orator-conversion", Capabilities: ["MediaConversion"],<br/>ActionSchemas: [ImageResize, VideoThumbnail, ...],<br/>BindAddresses: [{IP: "127.0.0.1", Port: 8765}]}
61
+ UV->>UV: Register beacon, auto-generate 14 task types
62
+ UV->>UV: Probe reachability (no other beacons yet)
63
+ UV-->>OC: {BeaconID: "bcn-orator-conversion-..."}
64
+
65
+ RR->>UV: WebSocket: BeaconRegister<br/>{Name: "retold-remote", Contexts: {File: {BaseURL: "http://localhost:7827/content/"}},<br/>BindAddresses: [{IP: "127.0.0.1", Port: 7827}],<br/>Operations: [rr-image-thumbnail, rr-video-thumbnail, ...]}
66
+ UV->>UV: Register beacon, store 9 operation definitions
67
+ UV->>UV: Probe: retold-remote ↔ orator-conversion = REACHABLE
68
+
69
+ Note over UV: Both beacons registered.<br/>14 beacon task types available.<br/>9 operations from retold-remote.<br/>Reachability: all pairs reachable.
70
+ ```
71
+
72
+ ### 3. Auto-Generated Operations
73
+
74
+ retold-remote registers 9 operation definitions during beacon connection. These are complete operation graphs with nodes, connections, and state wiring — built programmatically by `_buildPipelineOperation()`:
75
+
76
+ | Operation | Trigger Parameters | Pipeline |
77
+ |-----------|-------------------|----------|
78
+ | `rr-image-thumbnail` | ImageAddress, Width, Height, Format, Quality | resolve → transfer → resize → send-result |
79
+ | `rr-video-thumbnail` | VideoAddress, Timestamp, Width | resolve → transfer → extract frame → send-result |
80
+ | `rr-video-frame-extraction` | VideoAddress, Timestamp, Width | resolve → transfer → probe → extract → send-result |
81
+ | `rr-audio-waveform` | AudioAddress, SampleRate, Samples | resolve → transfer → waveform → send-result |
82
+ | `rr-audio-segment` | AudioAddress, Start, Duration, Codec | resolve → transfer → extract → send-result |
83
+ | `rr-pdf-page-render` | PdfAddress, Page, LongSidePixels | resolve → transfer → render → send-result |
84
+ | `rr-image-convert` | ImageAddress, Format, Quality | resolve → transfer → convert → send-result |
85
+ | `rr-ebook-convert` | EbookAddress | resolve → transfer → ebook-convert → send-result |
86
+ | `rr-media-probe` | MediaAddress | resolve → transfer → ffprobe → send-result |
87
+
88
+ Each pipeline follows the same pattern:
89
+
90
+ ```mermaid
91
+ graph LR
92
+ S[Start] --> R[resolve-address]
93
+ R -->|URL, Filename| T[file-transfer]
94
+ T -->|LocalPath| P[beacon-mediaconversion-*]
95
+ P -->|OutputFile| SR[send-result]
96
+ SR --> E[End]
97
+
98
+ R -.->|Error| E
99
+ T -.->|Error| E
100
+ P -.->|Error| E
101
+ SR -.->|Error| E
102
+ ```
103
+
104
+ State connections wire outputs from earlier nodes into inputs of later nodes:
105
+ - `resolve.URL` → `transfer.SourceURL`
106
+ - `resolve.Filename` → `transfer.Filename`
107
+ - `transfer.LocalPath` → `process.InputFile`
108
+
109
+ ## End-to-End: Image Thumbnail Generation
110
+
111
+ When a user navigates to a folder in retold-remote, the browser requests thumbnails. Here's the complete flow:
112
+
113
+ ```mermaid
114
+ sequenceDiagram
115
+ participant Browser
116
+ participant RR as retold-remote
117
+ participant UV as Ultravisor
118
+ participant OC as orator-conversion
119
+
120
+ Browser->>RR: GET /content/preview/photo.jpg?w=400&h=300
121
+
122
+ Note over RR: Check cache → miss
123
+
124
+ RR->>UV: POST /Operation/rr-image-thumbnail/Trigger<br/>{Parameters: {ImageAddress: ">retold-remote/File/photo.jpg",<br/>Width: 400, Height: 300, Format: "webp", Quality: 80}}
125
+
126
+ Note over UV: Start operation (sync mode)
127
+
128
+ UV->>UV: resolve-address<br/>>retold-remote/File/photo.jpg<br/>→ http://localhost:7827/content/photo.jpg
129
+
130
+ UV->>RR: HTTP GET http://localhost:7827/content/photo.jpg
131
+ RR-->>UV: 200 OK (image bytes)
132
+ UV->>UV: file-transfer saves to staging<br/>/staging/rr-image-thumbnail-.../photo.jpg
133
+
134
+ UV->>UV: beacon-mediaconversion-imageresize<br/>enqueue work item, WaitingForInput
135
+
136
+ OC->>UV: POST /Beacon/Work/Poll
137
+ UV-->>OC: WorkItem: {Action: "ImageResize",<br/>Settings: {InputFile: "/.../photo.jpg",<br/>OutputFile: "/.../thumbnail.jpg", Width: 400, ...}}
138
+
139
+ OC->>OC: Sharp: resize photo.jpg → thumbnail.jpg
140
+ OC->>UV: POST /Beacon/Work/{hash}/Upload<br/>(raw binary: thumbnail.jpg)
141
+ UV->>UV: Write to operation staging
142
+
143
+ OC->>UV: POST /Beacon/Work/{hash}/Complete
144
+ UV->>UV: resumeOperation → send-result<br/>finds thumbnail.jpg in staging
145
+
146
+ UV-->>RR: 200 OK<br/>Content-Type: application/octet-stream<br/>Body: (thumbnail bytes)
147
+
148
+ RR->>RR: Cache the thumbnail
149
+ RR-->>Browser: 200 OK (thumbnail image)
150
+ ```
151
+
152
+ ### Timing
153
+
154
+ On localhost, the full round-trip takes ~1-3 seconds:
155
+
156
+ | Step | Duration |
157
+ |------|----------|
158
+ | Address resolution | < 1ms |
159
+ | File transfer (50MB image) | ~200ms |
160
+ | Sharp resize | ~500ms |
161
+ | Binary upload | ~100ms |
162
+ | Total | ~1s |
163
+
164
+ ### Fallback
165
+
166
+ If Ultravisor is unreachable or the operation fails, retold-remote falls through to local processing:
167
+
168
+ ```javascript
169
+ this._dispatcher.triggerOperation('rr-image-thumbnail',
170
+ { ImageAddress: '>retold-remote/File/' + tmpRelPath, Width, Height, Format, Quality },
171
+ (pTriggerError, pResult) =>
172
+ {
173
+ if (!pTriggerError && pResult && pResult.OutputBuffer)
174
+ {
175
+ return fCallback(null, pResult.OutputBuffer);
176
+ }
177
+ // Fall through to local Sharp/ImageMagick
178
+ this._generateImageThumbnailLocal(pFullPath, pWidth, pHeight, pFormat, fCallback);
179
+ });
180
+ ```
181
+
182
+ ## Large File Support
183
+
184
+ orator-conversion handles arbitrarily large images (including 256MB+ scans):
185
+
186
+ - **File-path mode**: Sharp receives the file path directly instead of loading the entire file into a buffer
187
+ - **No pixel limit**: `sharp(filePath, { limitInputPixels: false })` — disables Sharp's default pixel limit
188
+ - **Streaming**: File transfer uses Node.js streams, avoiding full-file buffering
189
+ - **Binary upload**: Result files transfer as raw bytes over HTTP or WebSocket — no base64 encoding
190
+
191
+ ## Error Handling
192
+
193
+ When a beacon reports a non-zero exit code (e.g., Sharp can't process a corrupt file), the beacon client reports it as an error. The operation graph's Error event fires, routing to the End node. The trigger returns a JSON response with `Success: false`, and retold-remote falls back to local processing.
194
+
195
+ ```mermaid
196
+ flowchart TD
197
+ A[Beacon processes work item] --> B{ExitCode == 0?}
198
+ B -->|Yes| C[Upload output file]
199
+ C --> D[Report completion]
200
+ D --> E[Operation resumes → send-result → binary stream]
201
+ B -->|No| F[Report error]
202
+ F --> G[Operation resumes → Error event → End node]
203
+ G --> H[Trigger returns JSON with Success: false]
204
+ H --> I[retold-remote falls back to local processing]
205
+ ```
206
+
207
+ ## Logging
208
+
209
+ All three services support `-l` for file logging:
210
+
211
+ ```bash
212
+ ultravisor start -l # ultravisor-2026-03-21T...log
213
+ retold-remote serve ~/Media -u -l # retold-remote-2026-03-21T...log
214
+ npm start -- -u -l # orator-conversion-2026-03-21T...log
215
+ ```
216
+
217
+ Key log prefixes for tracing the pipeline:
218
+ - `[TriggerOp]` — retold-remote dispatcher
219
+ - `[Trigger]` — Ultravisor trigger endpoint
220
+ - `[Engine]` — Ultravisor execution engine
221
+ - `[Coordinator]` — Beacon coordinator (work queue, uploads)
222
+ - `[OratorConversion]` — orator-conversion provider
223
+ - `[Beacon]` — Beacon client (execution, upload, completion)
@@ -0,0 +1,145 @@
1
+ # Platform Cards & Task Types
2
+
3
+ Ultravisor's operation graphs are built from cards (task types). Platform cards handle the infrastructure layer — address resolution, file transfer, and result delivery. Extension cards handle beacon dispatch. Beacon cards are auto-generated from registered beacon capabilities.
4
+
5
+ ## Platform Cards
6
+
7
+ ### resolve-address
8
+
9
+ Resolves a universal address (`>beacon/context/path`) to a concrete URL with optional transfer strategy selection.
10
+
11
+ See [Universal Addressing](universal-addressing.md) for full details.
12
+
13
+ ### file-transfer
14
+
15
+ Downloads a file from a URL to the operation's staging directory.
16
+
17
+ | Setting | Type | Required | Description |
18
+ |---------|------|----------|-------------|
19
+ | `SourceURL` | String | Yes | URL to download from |
20
+ | `Filename` | String | Yes | Filename to save as in staging |
21
+
22
+ | Output | Type | Description |
23
+ |--------|------|-------------|
24
+ | `LocalPath` | String | Absolute path to the downloaded file |
25
+ | `BytesTransferred` | Number | File size in bytes |
26
+ | `DurationMs` | Number | Download duration |
27
+
28
+ Supports HTTP/HTTPS with single-redirect following. 5-minute timeout. Creates staging directory if needed.
29
+
30
+ ### send-result
31
+
32
+ Marks a staging file as the operation's binary output. The trigger endpoint streams this file directly to the caller.
33
+
34
+ | Setting | Type | Required | Description |
35
+ |---------|------|----------|-------------|
36
+ | `FilePath` | String | Yes | Path to the result file (relative to staging) |
37
+ | `OutputKey` | String | No | Key name for the output (default: `ResultFile`) |
38
+
39
+ | Output | Type | Description |
40
+ |--------|------|-------------|
41
+ | `StagingFilePath` | String | Absolute path to the result file |
42
+ | `BytesSent` | Number | File size in bytes |
43
+ | `DurationMs` | Number | Processing duration |
44
+
45
+ The trigger endpoint scans all task outputs for `StagingFilePath`. If found and the file exists, it streams the file as `application/octet-stream` with metadata in response headers (`X-Run-Hash`, `X-Status`, `X-Elapsed-Ms`).
46
+
47
+ ### base64-encode / base64-decode
48
+
49
+ Encode a staging file to a base64 string or decode a base64 string to a staging file. Used for embedding small binary payloads in operation state.
50
+
51
+ ## Extension Cards
52
+
53
+ ### beacon-dispatch
54
+
55
+ The generic card for dispatching work to beacon workers. Most users won't use this directly — catalog-generated beacon cards provide typed wrappers.
56
+
57
+ | Setting | Type | Required | Description |
58
+ |---------|------|----------|-------------|
59
+ | `RemoteCapability` | String | Yes | Required capability (e.g., `Shell`, `MediaConversion`) |
60
+ | `RemoteAction` | String | No | Specific action within the capability |
61
+ | `Command` | String | No | Shell command for Shell capability |
62
+ | `InputData` | String | No | JSON data with universal addresses (auto-resolved) |
63
+ | `OutputFile` | String | No | Expected output filename (triggers binary upload) |
64
+ | `AffinityKey` | String | No | Sticky routing key |
65
+ | `TimeoutMs` | Number | No | Work item timeout (default: 300000) |
66
+
67
+ When `OutputFile` is set, the executor:
68
+ 1. Sets up a work directory for the output
69
+ 2. After processing, collects the output file
70
+ 3. Uploads it to Ultravisor's staging directory via HTTP POST or WebSocket binary frame
71
+ 4. Reports JSON completion separately
72
+
73
+ ## Auto-Generated Beacon Cards
74
+
75
+ When a beacon registers with action schemas, Ultravisor auto-generates typed task cards. For example, orator-conversion's `MediaConversion` capability with `ImageResize` action becomes:
76
+
77
+ **`beacon-mediaconversion-imageresize`**
78
+
79
+ ```mermaid
80
+ flowchart LR
81
+ A[Action Schema<br/>from beacon registration] --> B[_registerCatalogTaskTypes]
82
+ B --> C["Task type: beacon-mediaconversion-imageresize<br/>Settings: InputFile, OutputFile, Width, Height, Format, Quality<br/>Execute: beaconDispatch → enqueueWorkItem → WaitingForInput"]
83
+ ```
84
+
85
+ The naming convention is: `beacon-{capability}-{action}` (lowercased, non-alphanumeric replaced with hyphens).
86
+
87
+ ### How Auto-Generation Works
88
+
89
+ 1. Beacon registers with `ActionSchemas` array containing capability, action name, settings schema, and description
90
+ 2. Coordinator's `_updateActionCatalog()` stores them persistently
91
+ 3. `_registerCatalogTaskTypes()` iterates the catalog and creates a task type config for each entry
92
+ 4. Each config gets an `Execute` function via `_createBeaconDispatchExecutor()` that:
93
+ - Coerces setting types (template-resolved strings → numbers/booleans per schema)
94
+ - Calls `beaconDispatch()` helper to enqueue the work item
95
+ - Returns `WaitingForInput` with `ResumeEventName: 'Complete'`
96
+ 5. Built-in task types take precedence — catalog types are only registered if no type with the same hash exists
97
+
98
+ ### Current orator-conversion Actions
99
+
100
+ | Hash | Action | Settings |
101
+ |------|--------|----------|
102
+ | `beacon-mediaconversion-imagejpgtopng` | ImageJpgToPng | InputFile, OutputFile |
103
+ | `beacon-mediaconversion-imagepngtojpg` | ImagePngToJpg | InputFile, OutputFile |
104
+ | `beacon-mediaconversion-imageresize` | ImageResize | InputFile, OutputFile, Width, Height, Format, Quality |
105
+ | `beacon-mediaconversion-imagerotate` | ImageRotate | InputFile, OutputFile, Angle |
106
+ | `beacon-mediaconversion-imageconvert` | ImageConvert | InputFile, OutputFile, Format, Quality |
107
+ | `beacon-mediaconversion-pdfpagetopng` | PdfPageToPng | InputFile, OutputFile, Page |
108
+ | `beacon-mediaconversion-pdfpagetojpg` | PdfPageToJpg | InputFile, OutputFile, Page |
109
+ | `beacon-mediaconversion-pdfpagetopngsized` | PdfPageToPngSized | InputFile, OutputFile, Page, LongSidePixels |
110
+ | `beacon-mediaconversion-pdfpagetojpgsized` | PdfPageToJpgSized | InputFile, OutputFile, Page, LongSidePixels |
111
+ | `beacon-mediaconversion-mediaprobe` | MediaProbe | InputFile |
112
+ | `beacon-mediaconversion-videoextractframe` | VideoExtractFrame | InputFile, OutputFile, Timestamp, Width |
113
+ | `beacon-mediaconversion-videothumbnail` | VideoThumbnail | InputFile, OutputFile, Timestamp, Width |
114
+ | `beacon-mediaconversion-audioextractsegment` | AudioExtractSegment | InputFile, OutputFile, Start, Duration, Codec |
115
+ | `beacon-mediaconversion-audiowaveform` | AudioWaveform | InputFile, SampleRate, Samples |
116
+
117
+ ## Binary Output Return
118
+
119
+ When a beacon processes a work item that produces a file output, the result is transferred back to Ultravisor's staging directory as raw binary — no base64 encoding.
120
+
121
+ ```mermaid
122
+ sequenceDiagram
123
+ participant Beacon as Beacon Worker
124
+ participant Exec as Beacon Executor
125
+ participant Client as Beacon Client
126
+ participant UV as Ultravisor
127
+
128
+ Beacon->>Exec: execute(workItem)
129
+ Exec->>Exec: Download source file
130
+ Exec->>Beacon: provider.execute(action, workItem, context)
131
+ Beacon-->>Exec: { Outputs: { Result: outputPath }, Log }
132
+ Exec->>Exec: _collectOutputFiles → set OutputFilePath
133
+
134
+ alt HTTP Transport
135
+ Client->>UV: POST /Beacon/Work/{hash}/Upload<br/>Content-Type: application/octet-stream<br/>X-Output-Filename: thumbnail.jpg<br/>Body: raw bytes
136
+ UV->>UV: recordResultUpload → write to operation staging
137
+ else WebSocket Transport
138
+ Client->>UV: JSON: { Action: "WorkResultUpload", WorkItemHash, OutputFilename, OutputSize }
139
+ Client->>UV: Binary frame: raw file bytes
140
+ UV->>UV: recordResultUpload → write to operation staging
141
+ end
142
+
143
+ Client->>UV: JSON completion: { Outputs, Log }
144
+ UV->>UV: resumeOperation → send-result finds file in staging
145
+ ```