Skip to content

feat(office): word/excel live preview via officecli watch + auto-preview on file generation#1869

Merged
piorpua merged 11 commits intomainfrom
feat/word-excel-watch
Mar 29, 2026
Merged

feat(office): word/excel live preview via officecli watch + auto-preview on file generation#1869
piorpua merged 11 commits intomainfrom
feat/word-excel-watch

Conversation

@IceyLiu
Copy link
Copy Markdown
Collaborator

@IceyLiu IceyLiu commented Mar 29, 2026

Summary

  • Add `officecli watch` integration for live Word, Excel, and PPT preview via a local HTTP server rendered in a webview or iframe
  • Auto-open preview tab when a new office file appears in the workspace while the user is watching the conversation — never triggers on historical sessions
  • Refactor three near-identical viewer components into a shared `OfficeWatchViewer` parameterised by `docType`

Changes

Main process

  • `officeWatchBridge.ts`: manages `officecli watch` child processes (one per file), session reuse on re-mount, 500ms delayed kill for React Strict Mode, auto-install on ENOENT, `findFreePort` + `waitForPort` for race-free startup
  • `fileWatchBridge.ts`: added `workspaceOfficeWatch` IPC — watches workspace directory with `fs.watch({ recursive: true })`, emits `fileAdded` for new `.pptx/.docx/.xlsx` only
  • `apiRoutes.ts`: added `/api/office-watch-proxy/:port/` route for web server mode
  • `database/index.ts`: per-row try/catch in `getUserConversations` so unknown conversation types no longer blank the conversation list

Renderer

  • `OfficeWatchViewer.tsx`: shared viewer component; replaces duplicate PptViewer / OfficeDocViewer / ExcelViewer implementations
  • `useAutoPreviewOfficeFiles.ts`: listens for `workspaceOfficeWatch.fileAdded` IPC events — starts watcher on mount, stops on unmount, so switching conversations resets the session
  • i18n keys added for `preview.word.watch.` and `preview.excel.watch.`

Tests

  • `officeWatchBridge.test.ts` (500 lines): process lifecycle, session reuse, auto-install, timeout, stop/cleanup
  • `useAutoPreviewOfficeFiles.dom.test.ts`: watcher lifecycle, cross-workspace filter, tab dedup
  • `OfficeDocViewer.dom.test.tsx`: rewritten for watch-mode viewer

Related Issue

Closes #1876

Test Plan

  • Ask AI to generate a `.pptx` / `.docx` / `.xlsx` in a workspace — preview tab auto-opens
  • Navigate away and back to an old conversation — no auto-open
  • Open the same file twice — preview tab deduped (no duplicate tab)
  • Web server mode: preview renders via `/api/office-watch-proxy/` iframe
  • officecli not installed: auto-install triggers, then preview opens
  • Conversation list loads correctly when unknown-type conversations exist in DB

IceyLiu added 11 commits March 29, 2026 14:20
- Add wordPreview/excelPreview IPC bridge entries
- Add officeWatchBridge.ts (mirrors pptPreviewBridge, handles word+excel)
- Refactor proxy routes into shared registerOfficecliWatchProxy helper
- Replace static Word/Excel viewers with officecli watch mode
- Add useAutoPreviewOfficeFiles hook: auto-opens preview on tool completion
  - Handles tool_group (Claude/Gemini/ACP) and codex_tool_call (Claude Code)
  - Deduped by toolCallId, conversation-scoped
- Update readme wx group image to wx-5.png (all language variants)
- 20 unit tests for officeWatchBridge, 7 for useAutoPreviewOfficeFiles
…event historical openings

Only fire auto-preview for tool calls observed in Executing/Pending/Confirming
state during the current component mount. Tool calls already in Success state
at mount time (historical messages) are never added to seenInProgress and
therefore never trigger. Navigating away remounts the component and resets
seenInProgress, so returning to an old conversation does not re-open tabs.
Replace message-state tracking (seenInProgress) with a filesystem watcher.
The main process watches the workspace directory via fs.watch and emits
workspaceOfficeWatch.fileAdded for any new .pptx/.docx/.xlsx that appears
while the conversation is active.

The renderer hook starts the watcher on mount and stops it on unmount, so
switching conversations resets the watch session. Pre-existing files are
never emitted. This approach works regardless of how the file was created
(WriteFile tool, Bash/officecli, or any other method).
…omments

Consolidate the three near-identical watch viewers (PptViewer, OfficeDocViewer,
ExcelViewer) into a single OfficeWatchViewer component parameterised by
docType. Each viewer is now a one-line wrapper. No behaviour changes.

Also add comments clarifying the settle()-without-resolve pattern in
startWatch and the fs.watch recursive Linux limitation.
…parsing stdout

When spawned as a child process stdout is fully-buffered (non-TTY), so the
"Watch:" readiness line never flushes within the 15s timeout window.
Replace stdout parsing with direct TCP port polling: once the port is
reachable the server is ready, regardless of output buffering.

Also extend waitForPort max retries from 20 to 150 (matches 15s outer timeout)
and update tests to control port-connect success/failure per scenario.
@piorpua piorpua added the bot:reviewing Review in progress (mutex) label Mar 29, 2026
@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Mar 29, 2026

Code Review:feat(office): word/excel live preview via officecli watch + auto-preview on file generation (#1869)

变更概述

本 PR 为 Word 和 Excel 文件引入了基于 officecli watch 的实时预览功能,使用子进程启动本地 HTTP 服务器、webview/iframe 加载渲染。同时新增工作空间级别的 Office 文件监听 IPC(workspaceOfficeWatch),在当前会话激活时自动弹出新生成 Office 文件的预览 tab。核心重构将原来三个近乎重复的 PPT/Word/Excel 查看组件统一为参数化的 OfficeWatchViewer,消除了大量重复代码。


方案评估

结论:✅ 方案合理

整体方案架构清晰,主进程(officeWatchBridge)负责进程生命周期管理,渲染侧通过 IPC 驱动,符合项目的进程分层规范。端口校验(isActiveOfficeWatchPort)在 web server 模式下防止了 SSRF,与现有 PPT 代理的实现一致。500ms 延迟 kill 正确处理了 React Strict Mode 的双重挂载场景。emitted 去重集合保证了同一 session 内不重复触发 fileAdded 事件。


问题清单

🔵 LOW — 未使用的 catch 参数 e

文件src/process/services/database/index.ts,第 649 行

问题代码

} catch (e) {
  console.warn('[Database] Skipping conversation row with unknown type:', row.type, row.id);
}

问题说明e 被声明但从未使用,oxlint 报告 no-unused-vars 警告。本次 PR 新增此 catch 块时引入。

修复建议

} catch {
  console.warn('[Database] Skipping conversation row with unknown type:', row.type, row.id);
}

汇总

# 严重级别 文件 问题
1 🔵 LOW src/process/services/database/index.ts:649 未使用的 catch 参数 e

结论

批准合并 — 无阻塞性问题

代码质量良好,架构设计合理,测试覆盖全面(officeWatchBridge 500+ 行测试)。唯一问题是一个 LOW 级别的未使用 catch 参数,不影响功能。


本报告由本地 pr-review skill 生成,包含完整项目上下文,无截断限制。

@piorpua
Copy link
Copy Markdown
Contributor

piorpua commented Mar 29, 2026

✅ 已自动 review,无阻塞性问题,正在触发自动合并。

@piorpua piorpua merged commit 17da6f3 into main Mar 29, 2026
17 checks passed
@piorpua piorpua deleted the feat/word-excel-watch branch March 29, 2026 10:12
@piorpua piorpua added bot:done Auto-merged by bot and removed bot:reviewing Review in progress (mutex) labels Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:done Auto-merged by bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(preview): live Word/Excel/PPT preview via officecli watch

2 participants