summaryrefslogtreecommitdiffhomepage
path: root/packages/core/src
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-04 16:16:45 +0900
committerAdam Malczewski <[email protected]>2026-06-04 16:16:45 +0900
commit81a9cdbadf8c9d940d4fe9a2a0de607dee1f5f1a (patch)
treedff8ce0e55f27b490445ddaf9fb6536d1313ffcf /packages/core/src
parent24bdaa6ca0333b91369ac50b23e929f83af01c3a (diff)
downloaddispatch-v2-deprecated.tar.gz
dispatch-v2-deprecated.zip
feat(config): add subdirectory LSP config watchers and fix permission orderingv2-deprecated
- Add watchDirConfig() for per-directory config watching - Register watchers for subdirectories with their own dispatch.toml - Fix permission ordering: move "*" wildcard to front so findLast reaches specific rules first (was silently breaking all specific bash permission rules) - Add comprehensive tests for watcher functionality - Update mocks in test files
Diffstat (limited to 'packages/core/src')
-rw-r--r--packages/core/src/config/index.ts2
-rw-r--r--packages/core/src/config/watcher.ts58
-rw-r--r--packages/core/src/index.ts1
3 files changed, 60 insertions, 1 deletions
diff --git a/packages/core/src/config/index.ts b/packages/core/src/config/index.ts
index 4806409..7f76dd7 100644
--- a/packages/core/src/config/index.ts
+++ b/packages/core/src/config/index.ts
@@ -6,4 +6,4 @@ export {
mergeConfigs,
} from "./loader.js";
export { validateConfig } from "./schema.js";
-export { createConfigWatcher } from "./watcher.js";
+export { createConfigWatcher, watchDirConfig } from "./watcher.js";
diff --git a/packages/core/src/config/watcher.ts b/packages/core/src/config/watcher.ts
index 9414ef6..ad55804 100644
--- a/packages/core/src/config/watcher.ts
+++ b/packages/core/src/config/watcher.ts
@@ -69,3 +69,61 @@ export function createConfigWatcher(
},
};
}
+
+/**
+ * Watch a SINGLE directory's `dispatch.toml` (no global merge, no reload — just
+ * a debounced change signal). Used by the agent manager to invalidate its
+ * per-directory LSP cache when a tab's effective working directory is a
+ * SUBDIRECTORY with its own `dispatch.toml`: the main `createConfigWatcher`
+ * only watches the root + global configs, so without this a nested config edit
+ * would never clear `lspServersByDir[subdir]` and agents there would keep using
+ * stale LSP servers until a root-config change or restart.
+ *
+ * `onChange` fires (debounced) on add/change/unlink of `<dir>/dispatch.toml`.
+ */
+export function watchDirConfig(dir: string, onChange: () => void): { close(): void } {
+ const tomlPath = join(dir, "dispatch.toml");
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null;
+
+ const watcher = watch(tomlPath, {
+ ignoreInitial: true,
+ persistent: false,
+ });
+
+ const handleChange = () => {
+ if (debounceTimer !== null) clearTimeout(debounceTimer);
+ debounceTimer = setTimeout(() => {
+ debounceTimer = null;
+ try {
+ onChange();
+ } catch (err) {
+ console.warn(
+ `dispatch: dir config watcher onChange error: ${err instanceof Error ? err.message : String(err)}`,
+ );
+ }
+ }, 300);
+ };
+
+ watcher.on("change", handleChange);
+ watcher.on("add", handleChange);
+ watcher.on("unlink", handleChange);
+ watcher.on("error", (err) => {
+ console.warn(
+ `dispatch: dir config watcher error: ${err instanceof Error ? err.message : String(err)}`,
+ );
+ });
+
+ return {
+ close() {
+ if (debounceTimer !== null) {
+ clearTimeout(debounceTimer);
+ debounceTimer = null;
+ }
+ watcher.close().catch((err) => {
+ console.warn(
+ `dispatch: error closing dir config watcher: ${err instanceof Error ? err.message : String(err)}`,
+ );
+ });
+ },
+ };
+}
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index b636cde..e951d08 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -44,6 +44,7 @@ export {
loadGlobalConfig,
mergeConfigs,
validateConfig,
+ watchDirConfig,
} from "./config/index.js";
// Credentials
export * from "./credentials/index.js";