fix(watcher): stabilize daemon readiness and tests
This commit is contained in:
@@ -104,7 +104,7 @@ async function getOrCreateEntry(
|
||||
entries.delete(key);
|
||||
throw err;
|
||||
}
|
||||
attachWatcher(entry);
|
||||
await attachWatcher(entry);
|
||||
bumpIdle(entry);
|
||||
return entry;
|
||||
}
|
||||
@@ -113,9 +113,9 @@ async function getOrCreateEntry(
|
||||
// The first non-empty registration lazily creates the WorkspaceWatcher;
|
||||
// subsequent register/unregister calls update its pattern set in place.
|
||||
// Honors PI_LSP_DISABLE_WATCHERS for emergency rollback.
|
||||
function attachWatcher(entry: ClientEntry): void {
|
||||
async function attachWatcher(entry: ClientEntry): Promise<void> {
|
||||
if (process.env.PI_LSP_DISABLE_WATCHERS) return;
|
||||
const sync = () => {
|
||||
const sync = async () => {
|
||||
const patterns = entry.client.getFileWatchers();
|
||||
if (patterns.length === 0 && !entry.watcher) return;
|
||||
if (!entry.watcher) {
|
||||
@@ -128,11 +128,13 @@ function attachWatcher(entry: ClientEntry): void {
|
||||
log(`watcher patterns`, entry.server.id, JSON.stringify(patterns));
|
||||
}
|
||||
entry.watcher.setPatterns(patterns);
|
||||
if (patterns.length > 0) await entry.watcher.ready();
|
||||
};
|
||||
entry.unsubscribeWatchers = entry.client.onWatchersChanged(sync);
|
||||
entry.unsubscribeWatchers = entry.client.onWatchersChanged(() => void sync());
|
||||
// Initial Sync - Server may have already sent registerCapability during
|
||||
// initialize before we subscribed.
|
||||
sync();
|
||||
// initialize before we subscribed. Wait for chokidar's initial scan so
|
||||
// externally-created files are not swallowed as ignoreInitial events.
|
||||
await sync();
|
||||
}
|
||||
|
||||
// Forward Events - Sends a batched workspace/didChangeWatchedFiles to the
|
||||
|
||||
@@ -25,10 +25,11 @@ export const tsx = path.resolve(
|
||||
"cli.mjs",
|
||||
);
|
||||
|
||||
// Unique Test Socket — each test run gets its own Unix socket so we don't
|
||||
// touch any real session daemon.
|
||||
// Unique Test Socket — each suite gets its own Unix socket so parallel
|
||||
// integration tests don't race through the same daemon.
|
||||
export function testSocket(): string {
|
||||
return path.join(os.tmpdir(), `pi-lsp-test-${process.pid}.sock`);
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lsp-test-"));
|
||||
return path.join(dir, "daemon.sock");
|
||||
}
|
||||
|
||||
// Set Test Socket — sets PI_LSP_SOCKET_PATH for the current process and
|
||||
@@ -39,7 +40,7 @@ export function setTestSocket(env: Record<string, string | undefined>): () => vo
|
||||
return () => {
|
||||
delete env.PI_LSP_SOCKET_PATH;
|
||||
try {
|
||||
fs.unlinkSync(sock);
|
||||
fs.rmSync(path.dirname(sock), { recursive: true, force: true });
|
||||
} catch {
|
||||
// Socket may not exist — that's fine.
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ describe("cli daemon lifecycle", () => {
|
||||
const env = { ...process.env };
|
||||
let cleanup: () => void;
|
||||
|
||||
before(() => {
|
||||
before(async () => {
|
||||
cleanup = setTestSocket(env);
|
||||
// Stop any stale daemon on this socket before tests run.
|
||||
stopTestDaemon(env);
|
||||
await stopTestDaemon(env);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
after(async () => {
|
||||
// Tear down daemon and clean up socket after all tests.
|
||||
stopTestDaemon(env);
|
||||
await stopTestDaemon(env);
|
||||
cleanup();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user