How the OfficeCLI Watch Command Provides Real-Time Browser Preview with Auto-Refresh
The officecli watch command creates a lightweight HTTP server that streams live document updates to the browser via Server-Sent Events (SSE), enabling instant auto-refresh without external file watchers.
The iOfficeAI/OfficeCLI repository implements a self-contained live preview system that eliminates the need for traditional file-watching utilities. When you invoke the OfficeCLI watch command, it initializes a multi-layered architecture combining a C#-based HTTP server, named-pipe IPC, and browser-side JavaScript to deliver real-time browser preview capabilities. This system pushes incremental DOM patches rather than full page reloads, ensuring near-instantaneous visual feedback as you modify Office documents.
CLI-Side Orchestration and Server Initialization
The entry point for the preview functionality resides in CommandBuilder.Watch.cs. When the user executes officecli watch <file>, the command builder constructs a WatchServer instance at lines 81-84, supplying the document path, HTTP port (defaulting to 26315), and an optional initial HTML snapshot.
// CommandBuilder.Watch.cs (lines 81-84)
var server = new WatchServer(
documentPath: file,
port: options.Port,
initialHtml: residentProcess?.GetHtmlView() ?? RenderDirectly(file)
);
server.Start();
If a resident Office process is already running, the CLI requests a rendered HTML view from it; otherwise, it opens the file directly and renders it via the appropriate document handler. This ensures the browser immediately displays the current document state upon connection.
The Watch Server Process
WatchServer.cs hosts a small HTTP endpoint that serves both the preview page and a dedicated Server-Sent Events (SSE) endpoint at /events. During construction (lines 90-98), the server loads two critical embedded JavaScript resources that handle the client-side update logic:
watch-sse-core.js– Establishes the SSE connection and exposes global hookswatch-overlay.js– Applies fine-grained DOM mutations and re-executes scripts
The server injects these scripts directly into the HTML response sent to the browser, creating a zero-dependency preview environment.
// WatchServer.cs – Loading embedded resources (lines 90-98)
var coreJs = LoadWatchResource("Resources.watch-sse-core.js");
var overlayJs = LoadWatchResource("Resources.watch-overlay.js");
await response.WriteAsync($"<script>{coreJs}</script>");
await response.WriteAsync($"<script>{overlayJs}</script>");
The server also implements graceful shutdown handling (lines 84-99), ensuring the TCP listener cleans up properly when receiving SIGTERM or SIGINT signals.
Browser-Side Update Mechanism
Layer 1: SSE Connection Core
The watch-sse-core.js file creates an EventSource connection to the /events endpoint and exposes it as window._watchEs. After every DOM mutation performed by the overlay layer, it invokes window._watchReapplyHook() to restore selection highlights and visual marks.
// watch-sse-core.js (lines 11-18)
(function () {
var es = new EventSource('/events');
window._watchEs = es;
window._watchReapplyHook = function() {
// Re-applies selection highlights and marks
restoreSelectionState();
};
})();
Layer 2: DOM Patching and Script Re-execution
The watch-overlay.js layer receives JSON messages from the SSE stream and performs surgical DOM updates—including node replacement, insertion, and removal. It re-executes any <script> tags found in the updated content to ensure interactive elements function correctly, then calls the re-apply hook established by Layer 1 to synchronize UI decorations like scroll positions and colored marks.
Bidirectional IPC and Message Flow
The CLI communicates with the running watch server through a named-pipe client implemented in WatchNotifier.cs. When document mutations occur (e.g., via officecli set or officecli watch mark), the notifier serializes a WatchMessage to JSON and writes it to the pipe at lines 15-25.
// WatchNotifier.cs (lines 15-25)
public void Notify(WatchMessage message)
{
if (!IsWatchProcessRunning()) return;
using var pipe = new NamedPipeClientStream(".", "OfficeCLIMonitor",
PipeDirection.Out);
pipe.Connect(100); // 100ms timeout
var json = JsonSerializer.Serialize(message);
using var writer = new StreamWriter(pipe);
writer.WriteLine(json);
}
If no watch process is listening, the notifier silently discards the call. Otherwise, the WatchServer receives the payload and forwards it to all connected browser clients via the SSE stream, triggering the DOM patching sequence described above.
Complete Data Flow Architecture
officecli watch <file> ──► WatchServer (HTTP + SSE)
│ │
│ 1. Render initial HTML │
│ (resident or direct) │
▼ ▼
Browser loads preview page EventSource connects to /events
│ │
│ 2. CLI sends updates via ──► SSE pushes JSON messages
│ WatchNotifier (named pipe) │
▼ ▼
watch-overlay.js applies DOM patches,
re-executes scripts, updates selection,
and calls window._watchReapplyHook()
Because the preview runs purely in the browser and receives only incremental patches, the page refreshes instantly after each officecli modification. No external file-watcher is required; the preview remains "watch-aware" only while the officecli watch process is alive.
Usage Examples
Start a live preview for a presentation on the default port:
officecli watch my-presentation.pptx
While the preview runs, modify the document—the browser updates automatically:
officecli set slide 2 "Title" "Updated content"
Add visual marks to the current selection in the preview window:
officecli watch mark --color=yellow selected
Summary
- CommandBuilder.Watch.cs instantiates the
WatchServerwith document context and port configuration at lines 81-84. - WatchServer.cs hosts an HTTP server with an SSE endpoint at
/events, serving embeddedwatch-sse-core.jsandwatch-overlay.jsresources (lines 90-98). - WatchNotifier.cs enables CLI-to-server communication via named pipes, serializing
WatchMessageobjects to JSON (lines 15-25). - The browser-side architecture uses two JavaScript layers: one for SSE connection management and one for DOM patching and script re-execution.
- The system pushes incremental updates rather than full page reloads, achieving real-time preview with minimal latency.
- Graceful shutdown handling ensures proper resource cleanup when the watch process terminates (lines 84-99 in WatchServer.cs).
Frequently Asked Questions
What port does the OfficeCLI watch server use by default?
The officecli watch command defaults to port 26315 unless overridden with the --port flag. You can specify an alternative port when starting the watch server: officecli watch document.pptx --port 8080.
How does the browser connect to the OfficeCLI watch server?
The browser establishes an EventSource connection to the /events endpoint served by the WatchServer instance. This Server-Sent Events (SSE) connection, implemented in watch-sse-core.js (lines 11-18), maintains a persistent channel through which the server pushes JSON update messages whenever the document changes.
Can I use the watch command with any Office document type?
Yes, the architecture supports any document format that OfficeCLI can render to HTML. The CommandBuilder.Watch.cs logic either requests an HTML view from a resident Office process or renders the file directly using the appropriate handler, making the preview system agnostic to specific document extensions as long as a rendering backend exists.
What happens if the watch process is not running when I make changes?
If no watch server is listening, the WatchNotifier.cs client silently discards the update message after detecting the absence of a named pipe listener. Your CLI commands will still execute successfully, but no browser refresh will occur until you restart the officecli watch process and reload the preview page.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →