retold-remote 0.0.23 → 0.0.26

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 (79) hide show
  1. package/css/retold-remote.css +343 -20
  2. package/docs/.nojekyll +0 -0
  3. package/docs/README.md +64 -12
  4. package/docs/_cover.md +6 -6
  5. package/docs/_sidebar.md +2 -0
  6. package/docs/_topbar.md +1 -1
  7. package/docs/_version.json +7 -0
  8. package/docs/collections.md +30 -0
  9. package/docs/css/docuserve.css +327 -0
  10. package/docs/ebook-reader.md +75 -1
  11. package/docs/image-explorer.md +62 -2
  12. package/docs/index.html +39 -0
  13. package/docs/retold-catalog.json +254 -0
  14. package/docs/retold-keyword-index.json +31216 -0
  15. package/docs/server-setup.md +122 -91
  16. package/docs/stack-launcher.md +218 -0
  17. package/docs/synology.md +585 -0
  18. package/docs/ultravisor-configuration.md +5 -5
  19. package/docs/ultravisor-integration.md +4 -2
  20. package/package.json +20 -14
  21. package/source/Pict-Application-RetoldRemote.js +22 -0
  22. package/source/RetoldRemote-ExtensionMaps.js +1 -1
  23. package/source/cli/RetoldRemote-Server-Setup.js +460 -7
  24. package/source/cli/RetoldRemote-Stack-Launcher.js +563 -0
  25. package/source/cli/RetoldRemote-Stack-Run.js +41 -0
  26. package/source/cli/commands/RetoldRemote-Command-Serve.js +129 -54
  27. package/source/providers/CollectionManager-AddItems.js +166 -0
  28. package/source/providers/Pict-Provider-GalleryNavigation.js +55 -0
  29. package/source/providers/Pict-Provider-OperationStatus.js +597 -0
  30. package/source/providers/keyboard-handlers/KeyHandler-ImageExplorer.js +20 -1
  31. package/source/providers/keyboard-handlers/KeyHandler-Viewer.js +23 -0
  32. package/source/server/RetoldRemote-AudioWaveformService.js +49 -3
  33. package/source/server/RetoldRemote-CollectionExportService.js +763 -0
  34. package/source/server/RetoldRemote-CollectionService.js +5 -0
  35. package/source/server/RetoldRemote-EbookService.js +218 -3
  36. package/source/server/RetoldRemote-ImageService.js +221 -46
  37. package/source/server/RetoldRemote-MediaService.js +63 -4
  38. package/source/server/RetoldRemote-MetadataCache.js +25 -5
  39. package/source/server/RetoldRemote-OperationBroadcaster.js +363 -0
  40. package/source/server/RetoldRemote-SubimageService.js +680 -0
  41. package/source/server/RetoldRemote-ToolDetector.js +50 -0
  42. package/source/server/RetoldRemote-UltravisorBeacon.js +18 -3
  43. package/source/server/RetoldRemote-UltravisorDispatcher.js +65 -491
  44. package/source/server/RetoldRemote-UltravisorOperations.js +133 -20
  45. package/source/server/RetoldRemote-VideoFrameService.js +302 -9
  46. package/source/views/MediaViewer-EbookViewer.js +419 -1
  47. package/source/views/MediaViewer-PdfViewer.js +1050 -0
  48. package/source/views/PictView-Remote-AudioExplorer.js +77 -1
  49. package/source/views/PictView-Remote-CollectionsPanel.js +213 -0
  50. package/source/views/PictView-Remote-Gallery.js +365 -64
  51. package/source/views/PictView-Remote-ImageExplorer.js +1529 -44
  52. package/source/views/PictView-Remote-ImageViewer.js +2 -2
  53. package/source/views/PictView-Remote-Layout.js +58 -0
  54. package/source/views/PictView-Remote-MediaViewer.js +100 -25
  55. package/source/views/PictView-Remote-RegionsBrowser.js +554 -0
  56. package/source/views/PictView-Remote-SubimagesPanel.js +353 -0
  57. package/source/views/PictView-Remote-TopBar.js +1 -0
  58. package/source/views/PictView-Remote-VideoExplorer.js +77 -1
  59. package/web-application/css/docuserve.css +277 -23
  60. package/web-application/css/retold-remote.css +343 -20
  61. package/web-application/docs/README.md +64 -12
  62. package/web-application/docs/_cover.md +6 -6
  63. package/web-application/docs/_sidebar.md +2 -0
  64. package/web-application/docs/_topbar.md +1 -1
  65. package/web-application/docs/collections.md +30 -0
  66. package/web-application/docs/ebook-reader.md +75 -1
  67. package/web-application/docs/image-explorer.md +62 -2
  68. package/web-application/docs/server-setup.md +122 -91
  69. package/web-application/docs/stack-launcher.md +218 -0
  70. package/web-application/docs/synology.md +585 -0
  71. package/web-application/docs/ultravisor-configuration.md +5 -5
  72. package/web-application/docs/ultravisor-integration.md +4 -2
  73. package/web-application/js/pict-docuserve.min.js +12 -12
  74. package/web-application/js/pict.min.js +2 -2
  75. package/web-application/js/pict.min.js.map +1 -1
  76. package/web-application/retold-remote.js +6596 -1784
  77. package/web-application/retold-remote.js.map +1 -1
  78. package/web-application/retold-remote.min.js +75 -23
  79. package/web-application/retold-remote.min.js.map +1 -1
@@ -21,31 +21,31 @@ The build step bundles the client-side JavaScript with Quackage and copies asset
21
21
 
22
22
  ## Running the Server
23
23
 
24
- ### CLI Command
24
+ ### CLI Commands
25
25
 
26
- ```bash
27
- retold-remote serve [content-path] [options]
28
- ```
29
-
30
- Or using the short alias:
26
+ There are three bin entries provided by the `retold-remote` package:
31
27
 
32
28
  ```bash
33
- rr serve /path/to/media
29
+ retold-remote serve [content-path] [options] # full form
30
+ rr serve [content-path] [options] # short alias
31
+ retold-stack [content-path] [options] # convenience: serve --stack
34
32
  ```
35
33
 
36
34
  If `content-path` is omitted, the current directory is served.
37
35
 
36
+ The `retold-stack` shortcut auto-injects `serve --stack`, which spawns Ultravisor as a child process and uses XDG-style data paths. See [Stack Launcher](stack-launcher.md) for the full story.
37
+
38
38
  ### Options
39
39
 
40
40
  | Flag | Description | Default |
41
41
  |------|-------------|---------|
42
42
  | `-p, --port [port]` | Port to listen on | Random 7000-7999 |
43
- | `-H, --hashed-filenames` | Enable hashed filename mode (hides real paths from browser) | Off |
44
- | `-c, --cache-path [path]` | Root cache directory | `./dist/retold-cache/` |
45
- | `--cache-thumbnails [path]` | Override thumbnail cache location | `<cache-root>/thumbnails/` |
46
- | `--cache-archives [path]` | Override archive extraction cache | `<cache-root>/archives/` |
47
- | `--cache-video-frames [path]` | Override video frame cache | `<cache-root>/video-frames/` |
48
- | `--cache-audio-waveforms [path]` | Override audio waveform cache | `<cache-root>/audio-waveforms/` |
43
+ | `--no-hash` | Disable hashed filename mode (use plain paths in URLs) | Hashing on |
44
+ | `-c, --cache-path [path]` | Root cache directory | `./dist/retold-cache/` (or `~/.cache/retold-remote/` in stack mode) |
45
+ | `--cache-server [url]` | URL of a remote Parime cache server | None |
46
+ | `-u, --ultravisor [url]` | Connect to an Ultravisor mesh; URL defaults to `http://localhost:54321` if omitted | None |
47
+ | `--stack` | Spawn Ultravisor as a child process and connect to it. Uses XDG-style data paths under `~/.local/share` and `~/.cache`. See [Stack Launcher](stack-launcher.md) | Off |
48
+ | `-l, --logfile [path]` | Write logs to a file (auto-generates timestamped name if path omitted) | Console only |
49
49
 
50
50
  ### Direct Node.js
51
51
 
@@ -65,20 +65,30 @@ Default port is `8086` when using `server.js` directly.
65
65
  ### Examples
66
66
 
67
67
  ```bash
68
- # Serve current directory on port 8086
69
- node server.js
68
+ # Serve current directory on a random port
69
+ retold-remote serve
70
70
 
71
71
  # Serve a specific folder
72
- node server.js /mnt/nas/media
72
+ retold-remote serve /mnt/nas/media
73
73
 
74
74
  # CLI with custom port
75
75
  retold-remote serve /mnt/nas/media -p 3000
76
76
 
77
- # Hashed filenames for privacy
78
- retold-remote serve /mnt/nas/media -H
77
+ # Plain paths in URLs (disable hashing)
78
+ retold-remote serve /mnt/nas/media --no-hash
79
79
 
80
80
  # Custom cache location (useful for Docker volumes)
81
81
  retold-remote serve /media -c /cache
82
+
83
+ # Connect to an existing Ultravisor mesh
84
+ retold-remote serve /media -u http://192.168.1.100:54321
85
+
86
+ # Full stack: spawn Ultravisor as a child process, embed Orator-Conversion,
87
+ # use XDG paths (~/.local/share/ultravisor, ~/.cache/retold-remote)
88
+ retold-stack /mnt/nas/media
89
+
90
+ # Same thing via the explicit flag
91
+ retold-remote serve --stack /mnt/nas/media
82
92
  ```
83
93
 
84
94
  ## Configuration
@@ -131,111 +141,132 @@ When enabled (`-H` flag or `RETOLD_HASHED_FILENAMES=true`), real file paths are
131
141
 
132
142
  ## Docker
133
143
 
134
- ### Using the Included Dockerfile
144
+ Retold Remote ships with two Dockerfiles, a `docker-compose.yml`, and a `docker-build-and-save.sh` helper. All images run the full stack (Ultravisor + Retold Remote + embedded Orator-Conversion) as a single container.
145
+
146
+ > **Running on Synology?** See the dedicated [Synology Container Manager](synology.md) guide for a step-by-step walkthrough including how to build the image on a dev machine and transfer it to the NAS.
135
147
 
136
- A `Dockerfile` is provided in the repository root:
148
+ ### Quick Start (any Docker host with the source tree)
149
+
150
+ The compose file defaults to `image: retold-stack:latest` so it works on hosts that already have the image loaded. To build and run from the source tree in one go:
137
151
 
138
152
  ```bash
139
- docker build -t retold-remote .
140
- docker run -p 8086:8086 -v /path/to/media:/media retold-remote
153
+ cd retold-remote
154
+
155
+ # Build the image and tag it as retold-stack:latest
156
+ docker build -t retold-stack:latest .
157
+
158
+ # Start the stack
159
+ MEDIA_PATH=/path/to/your/media docker compose up -d
141
160
  ```
142
161
 
143
- ### Inline Dockerfile
162
+ Then browse to `http://localhost:7777/`. The Ultravisor coordinator web interface is at `http://localhost:54321/`.
144
163
 
145
- If you need to create a Dockerfile from scratch, here is a complete working version:
164
+ If you'd rather have Compose build the image directly, edit `docker-compose.yml`:
165
+
166
+ ```yaml
167
+ services:
168
+ retold-stack:
169
+ # image: retold-stack:latest # <- comment this out
170
+ build: # <- uncomment this block
171
+ context: .
172
+ dockerfile: Dockerfile
173
+ ```
146
174
 
147
- ```dockerfile
148
- FROM node:20-slim
175
+ Then `docker compose up -d --build` will build and start in one step.
149
176
 
150
- # Install optional tools for full functionality
151
- RUN apt-get update && apt-get install -y --no-install-recommends \
152
- ffmpeg \
153
- imagemagick \
154
- p7zip-full \
155
- calibre \
156
- && rm -rf /var/lib/apt/lists/*
177
+ ### Dockerfile Variants
157
178
 
158
- WORKDIR /app
179
+ Both images have been verified to build and run the full stack on ARM64 (Apple Silicon) and should build identically on AMD64.
159
180
 
160
- # Copy package files and install dependencies
161
- COPY package.json package-lock.json ./
162
- RUN npm ci --omit=dev && npm cache clean --force
181
+ | File | Measured Size | Includes | Use for |
182
+ |------|---------------|----------|---------|
183
+ | `Dockerfile` | **3.0 GB** | Everything: ffmpeg, ImageMagick, 7z, poppler, pdftk, LibreOffice, Calibre, exiftool, dcraw | Full document conversion (DOC, DOCX, RTF, ODT, WPD, MOBI, PPT, XLS, etc.) |
184
+ | `Dockerfile.slim` | **1.81 GB** | Same but without LibreOffice and Calibre | Image/video/audio/PDF/EPUB only -- no doc/docx/mobi conversion |
163
185
 
164
- # Install sharp (optional image processing)
165
- RUN npm install sharp || true
186
+ > **Note on audiowaveform:** Neither image installs `audiowaveform` because it is not in the default Debian repositories. Retold Remote automatically falls back to ffprobe + ffmpeg for waveform generation, which is slower but works identically. If you need the BBC `audiowaveform` tool for faster generation, add it via a custom Dockerfile step (build from source or a PPA).
166
187
 
167
- # Copy application source and built assets
168
- COPY source/ source/
169
- COPY web-application/ web-application/
170
- COPY css/ css/
171
- COPY html/ html/
172
- COPY server.js ./
188
+ ### Building and Saving for Transfer
173
189
 
174
- # Create cache directory
175
- RUN mkdir -p /cache
190
+ For deploying to a NAS or any host that doesn't have the source tree, use the `docker-build-and-save.sh` helper:
176
191
 
177
- # Default port
178
- ENV PORT=8086
192
+ ```bash
193
+ ./docker-build-and-save.sh # full image, host architecture
194
+ ./docker-build-and-save.sh slim # slim variant
195
+ ./docker-build-and-save.sh --amd64 # cross-build for x86_64
196
+ ./docker-build-and-save.sh slim --arm64 # slim + arm64
197
+ ```
179
198
 
180
- EXPOSE 8086
199
+ This produces a compressed tar file (`retold-stack-image.tar.gz` or `retold-stack-image-slim.tar.gz`) that you can copy to the target host and load with:
181
200
 
182
- # Serve /media with cache at /cache
183
- CMD ["node", "server.js", "/media"]
201
+ ```bash
202
+ docker load -i retold-stack-image.tar.gz
184
203
  ```
185
204
 
186
- ### Docker Compose
205
+ Then start the stack with the included `docker-compose.yml` (which references `retold-stack:latest` by default). No source tree needed on the target host.
187
206
 
188
- ```yaml
189
- version: "3.8"
190
- services:
191
- retold-remote:
192
- build: .
193
- ports:
194
- - "8086:8086"
195
- volumes:
196
- - /path/to/media:/media:ro
197
- - retold-cache:/cache
198
- environment:
199
- - PORT=8086
200
- restart: unless-stopped
201
-
202
- volumes:
203
- retold-cache:
207
+ ### Manual Docker Run
208
+
209
+ If you prefer `docker run` over Compose:
210
+
211
+ ```bash
212
+ docker build -t retold-stack .
213
+
214
+ docker run -d \
215
+ --name retold-stack \
216
+ -p 7777:7777 \
217
+ -p 54321:54321 \
218
+ -v /path/to/media:/media:ro \
219
+ -v retold-cache:/cache \
220
+ -v ultravisor-data:/data \
221
+ -v retold-config:/config \
222
+ --restart unless-stopped \
223
+ retold-stack
204
224
  ```
205
225
 
206
- ### Docker Usage Notes
226
+ Then browse to `http://localhost:7777/`.
227
+
228
+ ### Volume Mounts
207
229
 
208
- - Mount your media folder to `/media` (read-only is fine with `:ro`)
209
- - Mount a volume to `/cache` for persistent thumbnail and frame caches
210
- - The `node:20-slim` base keeps the image small while the `apt-get` packages add full media processing
211
- - `calibre` is the largest optional package; omit it if you do not need MOBI/AZW ebook conversion
212
- - `sharp` is installed separately because it has native bindings that may fail on some architectures; the `|| true` ensures the build continues without it
230
+ The stack uses four volume mount points. The first is your media; the other three are for persistent state:
213
231
 
214
- ### Minimal Dockerfile (No Optional Tools)
232
+ | Container path | Purpose | Typical host mapping |
233
+ |----------------|---------|---------------------|
234
+ | `/media` | Media folder to browse (read-only) | `/path/to/media:/media:ro` |
235
+ | `/cache` | Thumbnails, frames, waveforms, conversions | Named volume `retold-cache` |
236
+ | `/data` | Ultravisor datastore + staging | Named volume `ultravisor-data` |
237
+ | `/config` | Stack config files | Named volume `retold-config` |
215
238
 
216
- If you only need basic browsing without thumbnails or media probing:
239
+ Inside the container, `XDG_CACHE_HOME`, `XDG_DATA_HOME`, and `XDG_CONFIG_HOME` are set to these paths so the stack launcher uses them automatically.
217
240
 
218
- ```dockerfile
219
- FROM node:20-slim
241
+ ### Published Ports
220
242
 
221
- WORKDIR /app
243
+ | Port | Purpose |
244
+ |------|---------|
245
+ | **7777** | Retold Remote web UI (the main thing you browse to) |
246
+ | **54321** | Ultravisor coordinator API + web interface (optional -- useful for monitoring) |
222
247
 
223
- COPY package.json package-lock.json ./
224
- RUN npm ci --omit=dev && npm cache clean --force
248
+ Both are pinned to fixed ports via the `-p 7777` flag in the default CMD, overriding the usual random 7000-7999 behavior.
225
249
 
226
- COPY source/ source/
227
- COPY web-application/ web-application/
228
- COPY css/ css/
229
- COPY html/ html/
230
- COPY server.js ./
250
+ ### Customizing the CMD
231
251
 
232
- ENV PORT=8086
233
- EXPOSE 8086
252
+ The default command launches `retold-stack` against `/media` on port 7777 with hashed filenames disabled. To override (e.g., to enable hashed filenames or change the port):
234
253
 
235
- CMD ["node", "server.js", "/media"]
254
+ ```yaml
255
+ command: ["node", "source/cli/RetoldRemote-Stack-Run.js", "/media", "-p", "7777"]
236
256
  ```
237
257
 
238
- This produces an image under 200MB. Images display directly (no thumbnails), videos play in the browser, and zip/cbz archives use native extraction.
258
+ Remove the `--no-hash` flag to re-enable hashed filenames, or change `/media` if you mounted your media to a different path.
259
+
260
+ ### Image Size Notes
261
+
262
+ - `node:20-slim` base: ~180 MB
263
+ - Full `Dockerfile` (with LibreOffice + Calibre): ~2.5 GB -- Calibre alone is ~1 GB, LibreOffice is ~600 MB
264
+ - `Dockerfile.slim`: ~1.8 GB -- drops both big dependencies
265
+ - Omit `ffmpeg` and `audiowaveform` too if you don't need video/audio processing, for a ~1 GB image
266
+
267
+ ### Child Process Note
268
+
269
+ The stack launcher spawns Ultravisor as a child process using `node` and the resolved `ultravisor` bin path. This works inside Docker without any special configuration -- the child runs in the same container PID namespace and its logs are streamed through the main process's stdout with `[ultravisor]` prefixes.
239
270
 
240
271
  ## Archive Browsing
241
272
 
@@ -0,0 +1,218 @@
1
+ # Stack Launcher
2
+
3
+ The `--stack` flag (and the `retold-stack` shortcut) brings up the full Retold stack as a single command: an embedded Ultravisor coordinator, the Retold Remote media browser, and Orator-Conversion (embedded inside Retold Remote). Point it at any directory and it just works -- sane XDG-style data paths, automatic readiness polling, and graceful shutdown of all child processes.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Run the full stack against the current directory
9
+ retold-stack
10
+
11
+ # Or against any directory
12
+ retold-stack /mnt/nas/media
13
+
14
+ # Or via the explicit flag
15
+ retold-remote serve --stack /mnt/nas/media
16
+ ```
17
+
18
+ That's it. No config files, no separate terminals, no manual port wiring.
19
+
20
+ ## What Gets Launched
21
+
22
+ | Component | Where it runs | Port |
23
+ |-----------|---------------|------|
24
+ | **Ultravisor** | Spawned as a child process | 54321 |
25
+ | **Retold Remote** | Main process (the one you started) | Random 7000-7999 (override with `-p`) |
26
+ | **Orator-Conversion** | Embedded inside Retold Remote (no separate process) | Same as Retold Remote |
27
+
28
+ The stack launcher:
29
+ 1. Resolves XDG-style data paths
30
+ 2. Detects whether Ultravisor is already running on port 54321 (and reuses it if so)
31
+ 3. Spawns Ultravisor as a child process with a generated config file
32
+ 4. Polls until Ultravisor is accepting connections (up to 30 seconds)
33
+ 5. Sets the `UltravisorURL` automatically so Retold Remote registers as a beacon
34
+ 6. Starts the Retold Remote server with Orator-Conversion embedded
35
+ 7. Streams the Ultravisor child's stdout/stderr through the main logger with an `[ultravisor]` prefix
36
+ 8. On `SIGINT`/`SIGTERM`, disconnects the beacon, kills the Ultravisor child gracefully, and exits
37
+
38
+ ## Default Data Paths
39
+
40
+ The stack launcher uses [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) defaults so data lives in predictable, user-scoped locations regardless of what directory you launched from.
41
+
42
+ | Purpose | Default Path | Override |
43
+ |---------|-------------|----------|
44
+ | Ultravisor datastore | `~/.local/share/ultravisor/datastore/` | `$XDG_DATA_HOME/ultravisor/datastore/` |
45
+ | Ultravisor staging | `~/.local/share/ultravisor/staging/` | `$XDG_DATA_HOME/ultravisor/staging/` |
46
+ | Retold Remote cache | `~/.cache/retold-remote/` | `$XDG_CACHE_HOME/retold-remote/`, or `-c` flag |
47
+ | Stack config files | `~/.config/retold-stack/` | `$XDG_CONFIG_HOME/retold-stack/` |
48
+
49
+ The cache directory holds thumbnails, video frames, audio waveforms, archive extractions, and converted ebooks/PDFs.
50
+
51
+ The Ultravisor datastore holds the work-queue journal and beacon registry.
52
+
53
+ These paths are created on first launch if they do not already exist.
54
+
55
+ ## CLI Reference
56
+
57
+ ### `retold-stack`
58
+
59
+ Convenience entry point that auto-injects `serve --stack`.
60
+
61
+ ```bash
62
+ retold-stack [content-path] [options]
63
+ ```
64
+
65
+ All options accepted by `retold-remote serve` are forwarded.
66
+
67
+ ### `retold-remote serve --stack`
68
+
69
+ The full form. Useful when you want to combine `--stack` with other flags.
70
+
71
+ ```bash
72
+ retold-remote serve --stack [content-path] [options]
73
+ ```
74
+
75
+ | Flag | Description |
76
+ |------|-------------|
77
+ | `--stack` | Spawn Ultravisor as a child process and connect to it. Sets cache root to `~/.cache/retold-remote/` if `-c` is not passed. Auto-sets the Ultravisor URL to `http://localhost:54321`. |
78
+
79
+ All other `serve` options still apply (`-p`, `--no-hash`, `-c`, `-l`, etc.).
80
+
81
+ ## Examples
82
+
83
+ ### Browse the current directory with the full stack
84
+
85
+ ```bash
86
+ cd ~/Pictures
87
+ retold-stack
88
+ ```
89
+
90
+ ### Browse a specific NAS share
91
+
92
+ ```bash
93
+ retold-stack /mnt/nas/media
94
+ ```
95
+
96
+ ### Pin the port and stash logs to a file
97
+
98
+ ```bash
99
+ retold-stack /mnt/nas/media -p 8086 -l ~/retold.log
100
+ ```
101
+
102
+ ### Override just the Retold cache location
103
+
104
+ ```bash
105
+ retold-remote serve --stack /mnt/nas/media -c /var/cache/retold
106
+ ```
107
+
108
+ ### Reuse an already-running Ultravisor
109
+
110
+ If port 54321 is already accepting connections, the stack launcher detects this and connects to the existing instance instead of spawning a new one. The log line will read:
111
+
112
+ ```
113
+ [stack] ultravisor already running on port 54321, reusing
114
+ ```
115
+
116
+ This means you can leave Ultravisor running across multiple Retold Remote launches without conflict.
117
+
118
+ ## Logging
119
+
120
+ The stack launcher streams the Ultravisor child process's output through Retold Remote's logger so you have a single log stream for both processes. Lines from the Ultravisor child are prefixed `[ultravisor]`, and stack-launcher events are prefixed `[stack]`:
121
+
122
+ ```
123
+ [stack] launching ultravisor (port 54321)
124
+ [stack] data: /Users/steven/.local/share/ultravisor/datastore
125
+ [stack] staging: /Users/steven/.local/share/ultravisor/staging
126
+ [ultravisor] UltravisorTaskTypeRegistry: 53 built-in task types registered.
127
+ [stack] ultravisor ready (after 1 attempts)
128
+ ==========================================================
129
+ Retold Remote running on http://localhost:7842
130
+ ==========================================================
131
+ Content: /mnt/nas/media
132
+ Cache: /Users/steven/.cache/retold-remote
133
+ Browse: http://localhost:7842/
134
+ Beacon: registered with Ultravisor at http://localhost:54321
135
+ Stack: ultravisor + retold-remote (orator-conversion embedded)
136
+ ==========================================================
137
+ ```
138
+
139
+ If you also pass `-l <path>`, both streams are written to the file as well.
140
+
141
+ ## Shutdown
142
+
143
+ Press `Ctrl+C` once. The launcher will:
144
+
145
+ 1. Log `Shutting down...`
146
+ 2. Disconnect the Ultravisor beacon (so Ultravisor knows the worker is leaving cleanly)
147
+ 3. Send `SIGTERM` to the Ultravisor child process
148
+ 4. Wait up to 1 second for graceful exit
149
+ 5. Send `SIGKILL` if it has not exited
150
+ 6. Exit the main process
151
+
152
+ If the launcher reused an already-running Ultravisor (rather than spawning one), it will not kill that Ultravisor -- it only manages processes it started itself.
153
+
154
+ ## Architecture
155
+
156
+ ```
157
+ ┌────────────────────────────────────────────────────────────┐
158
+ │ retold-stack /mnt/media │
159
+ │ │
160
+ │ ┌─────────────────────────────────────────────────────┐ │
161
+ │ │ Main process (retold-remote) │ │
162
+ │ │ ┌───────────────────────────────────────────────┐ │ │
163
+ │ │ │ Orator HTTP server (port 7000-7999) │ │ │
164
+ │ │ │ ├─ Retold Remote routes (/api/media/...) │ │ │
165
+ │ │ │ ├─ Orator-Conversion (/api/conversion/1.0/) │ │ │
166
+ │ │ │ └─ Static web app (/) │ │ │
167
+ │ │ └───────────────────────────────────────────────┘ │ │
168
+ │ │ ┌───────────────────────────────────────────────┐ │ │
169
+ │ │ │ Ultravisor Beacon client │ │ │
170
+ │ │ │ └─ Connects to localhost:54321 │ │ │
171
+ │ │ └───────────────────────────────────────────────┘ │ │
172
+ │ └─────────────────────────────────────────────────────┘ │
173
+ │ ▲ │
174
+ │ │ HTTP │
175
+ │ ▼ │
176
+ │ ┌─────────────────────────────────────────────────────┐ │
177
+ │ │ Child process (ultravisor) │ │
178
+ │ │ ├─ Coordinator API (port 54321) │ │
179
+ │ │ ├─ Beacon registry │ │
180
+ │ │ ├─ Work queue journal │ │
181
+ │ │ └─ Web interface │ │
182
+ │ │ Datastore: ~/.local/share/ultravisor/datastore/ │ │
183
+ │ └─────────────────────────────────────────────────────┘ │
184
+ └────────────────────────────────────────────────────────────┘
185
+ ```
186
+
187
+ ## Why Stack Mode?
188
+
189
+ Use `--stack` when you want a single command that brings up the full Retold experience:
190
+
191
+ - **Heavy media processing offloaded** through the Ultravisor beacon (video frame extraction, audio waveforms, ebook conversion, PDF page rendering)
192
+ - **Document conversion** via the embedded Orator-Conversion service (with the `doc-to-pdf` converter for Word, RTF, ODT, WordPerfect, etc.)
193
+ - **Persistent state** across launches (the Ultravisor datastore lives at a stable XDG location)
194
+ - **No port juggling** -- Ultravisor on its standard port 54321, Retold Remote on a random high port
195
+
196
+ Use the bare `retold-remote serve` command (without `--stack`) when you just want a quick gallery browser without the coordinator infrastructure.
197
+
198
+ ## Comparison
199
+
200
+ | Feature | `retold-remote serve` | `retold-stack` |
201
+ |---------|----------------------|----------------|
202
+ | Gallery browser | [x] | [x] |
203
+ | Image/video/audio viewers | [x] | [x] |
204
+ | Document conversion (doc, rtf, etc.) | Embedded only | Embedded + dispatched |
205
+ | Heavy work offloading | No | Yes (via Ultravisor) |
206
+ | Spawns child processes | No | Yes (Ultravisor) |
207
+ | Default cache location | `./dist/retold-cache/` | `~/.cache/retold-remote/` |
208
+ | Survives `cd` | Yes | Yes (XDG paths are absolute) |
209
+
210
+ ## Troubleshooting
211
+
212
+ | Symptom | Fix |
213
+ |---------|-----|
214
+ | `Could not locate the ultravisor package` | Run `npm install ultravisor` (or `npm install -g retold-remote` to get the bundled version) |
215
+ | `Ultravisor did not become ready within 30000ms` | Check the `[ultravisor]` log lines for an error. Common causes: port 54321 already bound by another process, missing dependencies, or invalid datastore path permissions |
216
+ | Stack mode hangs at `launching ultravisor` | Ultravisor's child process may be waiting on stdin or hitting an interactive prompt. Run with `-l <path>` to capture full logs |
217
+ | Beacon shows "not connected" | Ultravisor came up but the beacon registration failed. Check the Ultravisor child logs for errors and verify nothing is firewalling localhost:54321 |
218
+ | Want to override XDG paths | Set `XDG_DATA_HOME`, `XDG_CACHE_HOME`, or `XDG_CONFIG_HOME` in your environment before launching, or use the `-c` flag for the Retold Remote cache |