Skip to content

Commit 4a8ced1

Browse files
committed
fix(cli): match daemon scope before reuse
1 parent 9590eef commit 4a8ced1

1 file changed

Lines changed: 34 additions & 8 deletions

File tree

apps/cli/src/main.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { randomUUID } from "node:crypto";
2+
import { existsSync, realpathSync } from "node:fs";
23
import { dirname, join, resolve } from "node:path";
34
// Make sibling binaries (if any are added later) discoverable on $PATH so
45
// child processes spawned without an absolute path still find them.
@@ -139,27 +140,51 @@ const waitForShutdownSignal = () =>
139140
const isRecord = (value: unknown): value is Record<string, unknown> =>
140141
typeof value === "object" && value !== null && !Array.isArray(value);
141142

142-
const isServerReachable = (baseUrl: string): Effect.Effect<boolean> =>
143+
interface DaemonScopeInfo {
144+
readonly id: string;
145+
readonly name: string;
146+
readonly dir: string;
147+
}
148+
149+
const readDaemonScopeInfo = (baseUrl: string): Effect.Effect<DaemonScopeInfo | null> =>
143150
Effect.tryPromise(() =>
144151
fetch(`${baseUrl}/api/scope`, { signal: AbortSignal.timeout(2000) }),
145152
).pipe(
146153
Effect.flatMap((res) => {
147-
if (!res.ok) return Effect.succeed(false);
154+
if (!res.ok) return Effect.succeed(null);
148155
return Effect.tryPromise(() => res.json()).pipe(
149156
Effect.map((payload) => {
150-
if (!isRecord(payload)) return false;
151-
return (
157+
if (!isRecord(payload)) return null;
158+
if (
152159
typeof payload.id === "string" &&
153160
typeof payload.name === "string" &&
154161
typeof payload.dir === "string"
155-
);
162+
) {
163+
return {
164+
id: payload.id,
165+
name: payload.name,
166+
dir: payload.dir,
167+
};
168+
}
169+
return null;
156170
}),
157-
Effect.catchCause(() => Effect.succeed(false)),
171+
Effect.catchCause(() => Effect.succeed(null)),
158172
);
159173
}),
160-
Effect.catchCause(() => Effect.succeed(false)),
174+
Effect.catchCause(() => Effect.succeed(null)),
161175
);
162176

177+
const isServerReachable = (baseUrl: string): Effect.Effect<boolean> =>
178+
readDaemonScopeInfo(baseUrl).pipe(Effect.map((scopeInfo) => scopeInfo !== null));
179+
180+
const normalizeDaemonScopeDir = (dir: string): string => {
181+
const resolved = resolve(dir);
182+
return existsSync(resolved) ? realpathSync.native(resolved) : resolved;
183+
};
184+
185+
const currentDaemonScopeDir = (): string =>
186+
normalizeDaemonScopeDir(process.env.EXECUTOR_SCOPE_DIR ?? process.cwd());
187+
163188
const script = process.argv[1];
164189
const isDevMode = isDevCliEntrypoint(script);
165190
const cliPrefix = isDevMode ? `bun run ${script}` : "executor";
@@ -302,7 +327,8 @@ const ensureDaemon = (
302327
): Effect.Effect<string, Error, FileSystem.FileSystem | PlatformPath.Path> =>
303328
Effect.gen(function* () {
304329
const resolvedTarget = yield* resolveDaemonTarget(baseUrl);
305-
if (yield* isServerReachable(resolvedTarget.baseUrl)) {
330+
const reachableScope = yield* readDaemonScopeInfo(resolvedTarget.baseUrl);
331+
if (reachableScope && normalizeDaemonScopeDir(reachableScope.dir) === currentDaemonScopeDir()) {
306332
return resolvedTarget.baseUrl;
307333
}
308334

0 commit comments

Comments
 (0)