Skip to content

Commit 6402966

Browse files
Aitomatesclaude
andcommitted
docs: Phase 1 FS Watcher planning artifacts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent fbf6062 commit 6402966

1 file changed

Lines changed: 159 additions & 0 deletions

File tree

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
---
2+
phase: 01-fs-watcher
3+
plan: 01
4+
type: execute
5+
wave: 1
6+
depends_on: []
7+
files_modified:
8+
- universal-refiner/src/watcher/file-watcher.ts
9+
- universal-refiner/src/watcher/index.ts
10+
- universal-refiner/tests/file-watcher.test.ts
11+
- universal-refiner/src/index.ts
12+
autonomous: true
13+
requirements:
14+
- AUTO-01
15+
- AUTO-02
16+
must_haves:
17+
truths:
18+
- "FileWatcher emits a 'change' event when a watched .ts file is written"
19+
- "FileWatcher emits an 'add' event when a new .ts file appears"
20+
- "FileWatcher does not emit for files inside node_modules"
21+
- "FileWatcher does not emit for *.log or *.tmp files"
22+
- "FileWatcher.stop() prevents any further events"
23+
- "Detected changes are logged via RuntimeLogger on server startup"
24+
artifacts:
25+
- path: "universal-refiner/src/watcher/file-watcher.ts"
26+
provides: "FileWatcher class with start/stop/on('change') interface"
27+
exports: ["FileWatcher", "FileChangeEvent", "FileEventKind"]
28+
- path: "universal-refiner/src/watcher/index.ts"
29+
provides: "Re-exports for the watcher module"
30+
- path: "universal-refiner/tests/file-watcher.test.ts"
31+
provides: "5 Vitest tests covering AUTO-01 and AUTO-02"
32+
key_links:
33+
- from: "universal-refiner/src/index.ts"
34+
to: "universal-refiner/src/watcher/index.ts"
35+
via: "import FileWatcher, call start() at server init"
36+
---
37+
38+
<objective>
39+
Implement a real-time file system watcher (Phase 1) for the universal-refiner MCP server.
40+
41+
Purpose: Satisfy AUTO-01 (detect meaningful file save events) and AUTO-02 (filter noise paths) as the foundation for the Background Autonomy milestone.
42+
43+
Output:
44+
- src/watcher/file-watcher.ts — FileWatcher class wrapping chokidar v5
45+
- src/watcher/index.ts — re-exports
46+
- tests/file-watcher.test.ts — 5 passing Vitest tests
47+
- src/index.ts updated to start watcher on server init
48+
</objective>
49+
50+
<execution_context>
51+
chokidar v5.0.0 is already in dependencies. No new packages needed.
52+
Uses RuntimeLogger (stderr, JSON-RPC safe) for all output.
53+
</execution_context>
54+
55+
<context>
56+
@.planning/ROADMAP.md
57+
@.planning/REQUIREMENTS.md
58+
@universal-refiner/src/core/logger.ts
59+
@universal-refiner/src/index.ts
60+
</context>
61+
62+
<tasks>
63+
64+
<task type="auto">
65+
<name>Task 1: Create FileWatcher module (AUTO-01, AUTO-02)</name>
66+
<files>
67+
universal-refiner/src/watcher/file-watcher.ts
68+
universal-refiner/src/watcher/index.ts
69+
</files>
70+
<action>
71+
FileWatcher extends EventEmitter. Constructor takes rootPath: string.
72+
start(): watches rootPath via chokidar.watch() with ignored: CHOKIDAR_IGNORE patterns.
73+
stop(): closes the chokidar watcher, nulls inner reference.
74+
emitChange() applies two-layer filter before emitting:
75+
1. Path segment check: reject paths containing /node_modules/, /dist/, /.git/, /coverage/
76+
2. Extension check: only emit for .ts, .js, .md, .txt, .prompt
77+
3. Suffix noise check: reject .log, .tmp
78+
Emits: { path: string, event: 'add'|'change'|'unlink', timestamp: Date }
79+
Logs start/stop and per-event debug via RuntimeLogger.
80+
index.ts re-exports FileWatcher, FileChangeEvent, FileEventKind.
81+
</action>
82+
<verify>npm run build -- succeeds with zero type errors</verify>
83+
<done>Both files exist, TypeScript compiles clean, exports are correct.</done>
84+
</task>
85+
86+
<task type="auto" tdd="true">
87+
<name>Task 2: Write Vitest tests (AUTO-01, AUTO-02)</name>
88+
<files>universal-refiner/tests/file-watcher.test.ts</files>
89+
<behavior>
90+
- Test: write to existing .ts file in tmp dir -> 'change' event emitted with correct path and Date timestamp
91+
- Test: write new .ts file -> 'add' event emitted
92+
- Test: write .ts file inside node_modules subdirectory -> no event emitted (AUTO-02)
93+
- Test: write .log file -> no event emitted (AUTO-02)
94+
- Test: stop() called -> subsequent file write produces no events
95+
</behavior>
96+
<action>
97+
Use vitest describe/it/expect. beforeEach creates a unique tmp dir via fs.mkdtempSync.
98+
afterEach calls watcher.stop() and fs.rmSync.
99+
Use a polling waitFor() helper with 6000ms timeout for positive assertions.
100+
Allow 1500ms settle time after watcher.start() before writing files (Windows FS listener warm-up).
101+
Set per-test timeout to 15_000.
102+
</action>
103+
<verify>npm test -- shows 5/5 file-watcher tests passing</verify>
104+
<done>All 48 total tests pass including the 5 new watcher tests.</done>
105+
</task>
106+
107+
<task type="auto">
108+
<name>Task 3: Wire FileWatcher into server entry point</name>
109+
<files>universal-refiner/src/index.ts</files>
110+
<action>
111+
Import FileWatcher from "./watcher/index.js".
112+
After CommandCenterDashboard.start() and before runBackgroundTasks():
113+
const fileWatcher = new FileWatcher(rootPath);
114+
fileWatcher.on('change', (evt) => {
115+
RuntimeLogger.info(`[FS] ${evt.event}: ${evt.path}`);
116+
CommandCenterDashboard.log(`[FS] ${evt.event}: ${path.relative(rootPath, evt.path)}`);
117+
});
118+
fileWatcher.start();
119+
BackgroundAutonomyService is left intact — FileWatcher is additive.
120+
</action>
121+
<verify>npm run build succeeds; server starts without error</verify>
122+
<done>File watcher starts automatically when the MCP server initialises.</done>
123+
</task>
124+
125+
</tasks>
126+
127+
<threat_model>
128+
## Trust Boundaries
129+
130+
| Boundary | Description |
131+
|----------|-------------|
132+
| FS path → emitChange | File paths from chokidar are OS-provided and not sanitised before logging |
133+
134+
## STRIDE Threat Register
135+
136+
| Threat ID | Category | Component | Disposition | Mitigation Plan |
137+
|-----------|----------|-----------|-------------|-----------------|
138+
| T-01-01 | Information Disclosure | RuntimeLogger path output | accept | Logs go to stderr/runtime.log, not stdout (JSON-RPC channel). No PII in paths. |
139+
| T-01-02 | Denial of Service | Rapid file changes flood emitChange | mitigate | awaitWriteFinish debounce (100ms stability) prevents event storms. |
140+
| T-01-03 | Tampering | Malicious path with path-traversal characters | accept | FileWatcher is read-only (no FS writes). Path is logged, not executed. |
141+
</threat_model>
142+
143+
<verification>
144+
- npm run build -- zero TypeScript errors
145+
- npm test -- 48/48 tests pass (5 new FileWatcher tests)
146+
- Server starts and logs "[FileWatcher] Starting file system watcher" on init
147+
</verification>
148+
149+
<success_criteria>
150+
1. Writing a .ts file in the watched directory emits a change event within 3 seconds.
151+
2. Files under node_modules, dist, .git, coverage are never emitted.
152+
3. .log and .tmp files are never emitted.
153+
4. stop() terminates all event delivery immediately.
154+
5. Build and full test suite remain green.
155+
</success_criteria>
156+
157+
<output>
158+
Create .planning/phases/01-fs-watcher/01-01-SUMMARY.md after execution.
159+
</output>

0 commit comments

Comments
 (0)