iOfficeAI / iOfficeAI/OfficeCLI
watch: preview stuck at "Waiting for first update..." when watch and mutations use different path forms (relative vs absolute)
- Dominant language
- C#
- Stars
- 30.7k
- Forks
- 2.1k
- Avg merge
- 9d 8h
- Merged PRs (30d)
- 5
Description
## Summary
`officecli watch` never pushes the first render (browser stuck at "Waiting for first update... Run an officecli command to see the preview") when the watch command and the mutation commands refer to the same file with **different path forms** (relative vs. absolute).
The watch↔CLI notification pipe name appears to be hashed from the path string **as typed**, without normalizing to an absolute path first. `watch test.pptx` and `set /full/path/test.pptx ...` therefore produce two different pipe names, the mutation notification goes to a pipe nobody listens on, and the browser waits forever.
## Environment
- officecli 1.0.143 (single binary, `~/.local/bin/officecli`)
- macOS 26 (Darwin 25.5.0), Apple Silicon
- Shell: zsh
## Reproduction
```bash
cd /tmp && mkdir watch-repro && cd watch-repro
officecli create test.pptx
officecli add test.pptx / --type slide --prop title="t"
# Terminal A: start watch with a RELATIVE path
officecli watch test.pptx --port 26399
# Terminal B: mutate with an ABSOLUTE path
officecli set /tmp/watch-repro/test.pptx '/slide[1]/shape[1]' --prop text="hello"
```
Open `http://localhost:26399` → page stays at "Waiting for first update..." forever.
Verified matrix (all combinations tested live, SSE `/events` stream captured with curl):
| watch started with | mutation command uses | update pushed? |
|---|---|---|
| relative (`test.pptx`) | absolute (`/tmp/.../test.pptx`) | ❌ never |
| absolute | absolute | ✅ `{"action":"replace",...}` arrives immediately |
| relative | relative (same cwd) | ✅ |
## Evidence
With a mismatched path form, the SSE stream only ever carries the connect-time state events, even after multiple successful `set`/`add` mutations (and a manual `save`):
```
event: update
data: {"action":"selection-update","paths":[]}
event: update
data: {"action":"mark-update","version":0,"marks":[]}
```
With matching path forms the same stream immediately gets `{"action":"replace","slide":1,"version":1,"html":"..."}`.
The pipe registration files in `$TMPDIR` confirm the hash input differs by path form: a running watch registers `CoreFxPipe_officecli-watch-` / `officecli-watch-.port` (containing `\n`), and mutations presumably compute the target pipe name from their own path argument string.
## Suggested fix
Normalize the document path (e.g. `Path.GetFullPath`) before hashing it into the pipe/registry name, on **both** sides: `watch` registration and the mutation-side notify lookup. That makes the notification channel identity path-form-independent.
## Workaround (for users hitting this)
Use the exact same path string for `watch` and all subsequent mutation commands — simplest is to use absolute paths everywhere.
Contributor guide
Research direction
Reproduce the mismatch with the relative and absolute path commands, then locate the watch registration and mutation-side notification lookup that derive the pipe name. Trace how each path is converted before hashing; done means both path forms reach the same pipe and the SSE stream receives the first mutation update.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100