Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/sidecar/__tests__/file-watcher.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { join } from 'path'
import Database from 'better-sqlite3'
import { initTestDb } from '../../shared/__tests__/helpers/test-db'

Expand Down Expand Up @@ -176,3 +177,21 @@ describe('handleTrigger execution lock', () => {
expect(state.cooldownUntil).toBeLessThanOrEqual(afterExec + _testing.POST_EXEC_COOLDOWN_MS)
})
})

describe('watchRelativeDepth', () => {
const wp = join('root', 'watched')

it('treats a direct child as depth 1', () => {
expect(_testing.watchRelativeDepth(wp, join(wp, 'a.txt'))).toBe(1)
})

it('counts nested segments with the OS separator so the depth limit holds', () => {
// Within the limit (depth <= 2): not skipped.
expect(_testing.watchRelativeDepth(wp, join(wp, 'a')) > 2).toBe(false)
expect(_testing.watchRelativeDepth(wp, join(wp, 'a', 'b')) > 2).toBe(false)
// Deeper than 2: must exceed the limit. Splitting only on '/' regressed
// this on Windows (backslash paths counted as a single segment).
expect(_testing.watchRelativeDepth(wp, join(wp, 'a', 'b', 'c')) > 2).toBe(true)
expect(_testing.watchRelativeDepth(wp, join(wp, 'a', 'b', 'c', 'd.txt')) > 2).toBe(true)
})
})
14 changes: 9 additions & 5 deletions src/sidecar/file-watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ export function syncWatches(): void {
syncWatchesWithDatabase()
}

// Number of path segments `filePath` is below `watchPath`. path.relative()
// returns backslash-separated paths on Windows, so split on either separator
// (splitting only on '/' makes the depth limit inert on Windows).
function watchRelativeDepth(watchPath: string, filePath: string): number {
return relative(watchPath, filePath).split(/[/\\]/).length
}

function startWatch(watch: Watch): void {
if (activeWatchers.has(watch.id)) return
if (!watch.actionPrompt) {
Expand All @@ -76,11 +83,7 @@ function startWatch(watch: Watch): void {
const filePath = isDir ? join(watch.path, filename) : watch.path

// Limit depth to 1 (direct children + 1 level of subdirectories)
if (isDir) {
const rel = relative(watch.path, filePath)
const depth = rel.split('/').length
if (depth > 2) return
}
if (isDir && watchRelativeDepth(watch.path, filePath) > 2) return

handleTrigger(watch.id, actionPrompt, filePath)
})
Expand Down Expand Up @@ -157,6 +160,7 @@ export const _testing = {
handleTrigger: (watchId: number, actionPrompt: string, filePath: string) =>
handleTrigger(watchId, actionPrompt, filePath),
getWatchExecState,
watchRelativeDepth,
get lastTrigger() { return lastTrigger },
get watchExecState() { return watchExecState },
DEBOUNCE_MS,
Expand Down