# Ticket 10.3 — Live File Watching

**Phase**: 10 — Feature Parity Enhancements
**Priority**: Medium
**Depends on**: 10.2

## Description

Implement filesystem watching for two scenarios: (1) auto-refresh the file tree when files are added, removed, or renamed in the project directory, and (2) auto-reload the file preview when the currently-viewed file changes on disk. claude-relay uses `fs.watch` with debouncing to broadcast live-reload events to connected clients.

This requires server-side watchers that emit events over WebSocket. OpenCode already emits `file.edited` SSE events when it edits files, but this doesn't cover external edits or directory structure changes. The relay should add its own lightweight watcher for the currently-browsed directory and currently-viewed file.

## Acceptance Criteria

### AC1: File tree auto-refreshes on agent file operations
```gherkin
Given the file tree panel is open in the sidebar showing directory /src
When the agent creates a new file /src/utils.ts
Then the file tree updates to include utils.ts within 2 seconds
  And no manual refresh action is required from the user
```

### AC2: File preview auto-reloads on content change
```gherkin
Given the user is previewing /src/index.ts in the FileViewer
When the file is modified on disk (by the agent or externally)
Then the FileViewer content refreshes to show the updated file
  And the scroll position is preserved if possible
```

### AC3: Watcher events are debounced
```gherkin
Given the agent is performing a rapid series of file writes (e.g., formatting 20 files)
When multiple fs.watch events fire within 300ms
Then only a single update event is broadcast to connected clients
  And the UI updates once with the final state
```

### AC4: Watchers are scoped to visible context
```gherkin
Given the file tree has /src expanded and /test collapsed
When a file is added to /test
Then no watcher event fires for /test (it is not being watched)
  And expanding /test later shows the new file via a fresh directory read

Given the file tree has /src expanded
When the user collapses /src
Then the watcher for /src is removed
```

### AC5: Watchers are cleaned up on disconnect
```gherkin
Given a client has file watchers active for /src and /src/index.ts
When the client's WebSocket connection closes
Then all watchers associated with that client are cleaned up
  And no fs.watch handles remain for that client's subscriptions
```

### AC6: Ignored directories are excluded
```gherkin
Given the file tree is open at the project root
When a file changes inside node_modules/ or .git/
Then no watcher event is emitted
  And the directories node_modules/, .git/, and other common ignore patterns are never watched
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| Debounced fs.watch wrapper | Unit | Multiple rapid calls within 300ms produce a single callback invocation; calls spaced > 300ms apart produce separate invocations |
| Watcher lifecycle (create on expand, cleanup on collapse/navigate) | Unit | Creating a watcher returns a handle; calling cleanup closes the handle; no duplicate watchers for the same path |
| Directory change → WebSocket broadcast | Integration | When a mock fs.watch emits a `rename` event, the WebSocket server sends a `file_tree_changed` message to connected clients with the affected directory path |
| File change → file content refresh | E2E | Modifying a previewed file on disk causes the FileViewer to display the new content within 2 seconds |
| Ignored directory exclusion | Unit | Watcher creation for paths matching ignore patterns (`node_modules`, `.git`, `dist`, `.next`, `__pycache__`) is rejected and returns null |
| Client disconnect cleanup | Unit | After simulating a WebSocket close event, all watchers registered to that client's connection ID are closed and removed from the watcher registry |

## Reference

- claude-relay file watcher: `../claude-relay/lib/project.js` (fs.watch, debounced live-reload)
- claude-relay directory watcher: `../claude-relay/lib/project.js` (directory auto-refresh)
- OpenCode file.edited SSE events: `conduit/src/lib/event-translator.ts`
- Current file browser: `conduit/src/lib/public/components/features/FileBrowser.svelte`
- Node.js fs.watch docs: https://nodejs.org/api/fs.html#fswatchfilename-options-listener
