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
5 changes: 5 additions & 0 deletions .changeset/fix-windows-unc-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Fix startup on Windows network shares by normalizing UNC paths before opening native filesystem watchers.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { watch as fsWatch } from 'node:fs';
import { basename, isAbsolute, join, relative } from 'node:path';
import { basename, isAbsolute, join, relative, win32 } from 'node:path';

import { FSWatcher } from 'chokidar';

Expand Down Expand Up @@ -159,13 +159,16 @@ class SignalWatchHandle implements IHostFsWatchHandle {
private startNativeLeg(): void {
if (this.disposed) return;
try {
const watcher = this.runtime.watchNative(this.root, (_eventType, filename) => {
if (this.disposed) return;
this.retryAttempts = 0;
const absPath = resolveNativeSignalPath(this.root, filename);
if (absPath !== this.root && this.ignored(absPath)) return;
this.fireInvalidation();
});
const watcher = this.runtime.watchNative(
toNativeWatchRoot(this.root, this.runtime.platform),
(_eventType, filename) => {
if (this.disposed) return;
this.retryAttempts = 0;
const absPath = resolveNativeSignalPath(this.root, filename);
if (absPath !== this.root && this.ignored(absPath)) return;
this.fireInvalidation();
},
);
watcher.on('error', (error: NodeJS.ErrnoException) => {
this.onNativeError(watcher, error);
});
Expand Down Expand Up @@ -255,6 +258,10 @@ function useNativeRecursive(
);
}

function toNativeWatchRoot(root: string, platform: NodeJS.Platform): string {
return platform === 'win32' ? win32.normalize(root) : root;
}

function resolveNativeSignalPath(root: string, filename: string | null): string {
if (filename === null || filename === '' || filename === basename(root)) return root;
return clampToRoot(root, isAbsolute(filename) ? filename : join(root, filename));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class TestNativeWatcher {
}

interface TestNativeAttempt {
readonly root: string;
readonly watcher: TestNativeWatcher;
emit(filename: string | null): void;
}
Expand All @@ -58,7 +59,10 @@ interface TestRetry {
run(): void;
}

function signalRig(options?: { readonly synchronousFailures?: number }): {
function signalRig(options?: {
readonly platform?: NodeJS.Platform;
readonly synchronousFailures?: number;
}): {
readonly service: IHostFsWatchService;
readonly attempts: TestNativeAttempt[];
readonly retries: TestRetry[];
Expand All @@ -69,14 +73,15 @@ function signalRig(options?: { readonly synchronousFailures?: number }): {
const retries: TestRetry[] = [];
let synchronousFailures = options?.synchronousFailures ?? 0;
const runtime: HostFsWatchRuntime = {
platform: 'darwin',
watchNative: (_root, listener) => {
platform: options?.platform ?? 'darwin',
watchNative: (root, listener) => {
if (synchronousFailures > 0) {
synchronousFailures -= 1;
throw Object.assign(new Error('native watch creation failed'), { code: 'EIO' });
}
const watcher = new TestNativeWatcher();
attempts.push({
root,
watcher,
emit: (filename) => {
listener('rename', filename);
Expand Down Expand Up @@ -164,6 +169,13 @@ describe('host filesystem change notifications', () => {
expect(events).toEqual([{ path: '/repo', action: 'modified', kind: 'directory' }]);
});

it('passes Windows UNC roots to the native watcher with native separators', () => {
const rig = signalRig({ platform: 'win32' });
handle = rig.service.watch('//server/share/repo', { signal: true });

expect(rig.attempt(0).root).toBe('\\\\server\\share\\repo');
});

it('does not invalidate when a native signal path is ignored', () => {
const rig = signalRig();
const events: HostFsChange[] = [];
Expand Down