From 2cbd2a5a2db64b56e3f127f8715a4214e140a945 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Sun, 15 Mar 2026 09:39:13 -0400 Subject: [PATCH] fix(watcher): restore ALS context in native watcher callback The @parcel/watcher callback fires from a native C++ uv_async handle which does not preserve Node.js AsyncLocalStorage context. Wrap the callback in Instance.provide to restore the instance ALS context so Bus.publish can resolve instance-scoped state and directory. --- packages/opencode/src/file/watcher.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts index 8244f1c77c..56a3dcb70f 100644 --- a/packages/opencode/src/file/watcher.ts +++ b/packages/opencode/src/file/watcher.ts @@ -1,6 +1,7 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" import { InstanceContext } from "@/effect/instances" +import { Instance } from "@/project/instance" import z from "zod" import { Log } from "../util/log" import { FileIgnore } from "./ignore" @@ -88,13 +89,21 @@ export class FileWatcherService extends ServiceMap.Service Effect.promise(() => Promise.allSettled(subs.map((sub) => sub.unsubscribe())))) + const directory = instance.directory const cb: ParcelWatcher.SubscribeCallback = (err, evts) => { if (err) return - for (const evt of evts) { - if (evt.type === "create") Bus.publish(event.Updated, { file: evt.path, event: "add" }) - if (evt.type === "update") Bus.publish(event.Updated, { file: evt.path, event: "change" }) - if (evt.type === "delete") Bus.publish(event.Updated, { file: evt.path, event: "unlink" }) - } + // Instance.provide restores ALS context since native watcher callbacks + // fire outside the Instance async context + Instance.provide({ + directory, + fn: () => { + for (const evt of evts) { + if (evt.type === "create") Bus.publish(event.Updated, { file: evt.path, event: "add" }) + if (evt.type === "update") Bus.publish(event.Updated, { file: evt.path, event: "change" }) + if (evt.type === "delete") Bus.publish(event.Updated, { file: evt.path, event: "unlink" }) + } + }, + }) } const subscribe = (dir: string, ignore: string[]) =>