1526 lines · 50.0 KB · TypeScript
RawDownload
import { randomUUID } from "node:crypto";import { dirname, join, resolve } from "node:path";// Make sibling binaries (if any are added later) discoverable on $PATH so// child processes spawned without an absolute path still find them.const execDir = dirname(process.execPath);if (process.env.PATH && !process.env.PATH.includes(execDir)) {  process.env.PATH = `${execDir}:${process.env.PATH}`;} // Point the keychain plugin at the colocated @napi-rs/keyring binding.// bun --compile doesn't include .node files in bunfs, so the loader's// normal `require('@napi-rs/keyring-<plat>-<arch>')` walk fails inside the// binary. We can't use NAPI_RS_NATIVE_LIBRARY_PATH because @napi-rs/keyring// 1.2.0 has a bug where the env-var branch assigns to a local variable that// gets overwritten before the binding is returned. build.ts copies the// platform .node next to the executor; the keychain plugin reads this var// and loads the file directly via createRequire, bypassing the broken// loader.const keyringNodeOnDisk = join(execDir, "keyring.node");if (  typeof Bun !== "undefined" &&  !process.env.EXECUTOR_KEYRING_NATIVE_PATH &&  (await Bun.file(keyringNodeOnDisk).exists())) {  process.env.EXECUTOR_KEYRING_NATIVE_PATH = keyringNodeOnDisk;} // Pre-load QuickJS WASM for compiled binaries — must run before server importsconst wasmOnDisk = join(execDir, "emscripten-module.wasm");if (typeof Bun !== "undefined" && (await Bun.file(wasmOnDisk).exists())) {  const { setQuickJSModule } = await import("@executor-js/runtime-quickjs");  const { newQuickJSWASMModule } = await import("quickjs-emscripten");  type QuickJSSyncVariant = import("quickjs-emscripten").QuickJSSyncVariant;  const wasmBinary = await Bun.file(wasmOnDisk).arrayBuffer();  const importFFI: QuickJSSyncVariant["importFFI"] = () =>    import("@jitl/quickjs-wasmfile-release-sync/ffi").then((m) => m.QuickJSFFI);  const importModuleLoader: QuickJSSyncVariant["importModuleLoader"] = async () => {    const { default: original } =      await import("@jitl/quickjs-wasmfile-release-sync/emscripten-module");    return (moduleArg = {}) => original({ ...moduleArg, wasmBinary });  };  const variant: QuickJSSyncVariant = {    type: "sync" as const,    importFFI,    importModuleLoader,  };  const mod = await newQuickJSWASMModule(variant);  setQuickJSModule(mod);} import { Argument as Args, Command, Flag as Options } from "effect/unstable/cli";import { BunRuntime, BunServices } from "@effect/platform-bun";import { HttpApiClient } from "effect/unstable/httpapi";import { FetchHttpClient } from "effect/unstable/http";import { FileSystem, Path as PlatformPath } from "effect";import * as Effect from "effect/Effect";import * as Option from "effect/Option";import * as Cause from "effect/Cause"; import { ExecutorApi } from "@executor-js/api";import { startServer, runMcpStdioServer, getExecutor } from "@executor-js/local";import { makeQuickJsExecutor } from "@executor-js/runtime-quickjs";import { fetchIntegrations } from "./integrations";import {  buildDaemonSpawnSpec,  chooseDaemonPort,  canAutoStartLocalDaemonForHost,  isDevCliEntrypoint,  parseDaemonBaseUrl,  spawnDetached,  waitForReachable,  waitForUnreachable,} from "./daemon";import {  acquireDaemonStartLock,  canonicalDaemonHost,  currentDaemonScopeId,  isPidAlive,  readDaemonPointer,  readDaemonRecord,  releaseDaemonStartLock,  removeDaemonPointer,  removeDaemonRecord,  terminatePid,  writeDaemonPointer,  writeDaemonRecord,} from "./daemon-state";import {  buildResumeContentTemplate,  buildToolPath,  buildDescribeToolCode,  filterToolPathChildren,  buildInvokeToolCode,  buildListSourcesCode,  buildSearchToolsCode,  extractExecutionId,  extractPausedInteraction,  extractExecutionResult,  inspectToolPath,  normalizeCliErrorText,  parseJsonObjectInput,  sanitizeCliOutputText,  shellQuoteArg,} from "./tooling"; // Embedded web UI — baked into compiled binaries via `with { type: "file" }`import embeddedWebUI from "./embedded-web-ui.gen"; // ---------------------------------------------------------------------------// Constants// --------------------------------------------------------------------------- const { version: CLI_VERSION } = await import("../package.json");const DEFAULT_PORT = 4788;const DEFAULT_BASE_URL = `http://localhost:${DEFAULT_PORT}`;const DAEMON_BOOT_TIMEOUT_MS = 15_000;const DAEMON_BOOT_POLL_MS = 150;const DAEMON_STOP_TIMEOUT_MS = 10_000; // ---------------------------------------------------------------------------// Helpers// --------------------------------------------------------------------------- const waitForShutdownSignal = () =>  Effect.callback<void, never>((resume) => {    const shutdown = () => resume(Effect.void);    process.once("SIGINT", shutdown);    process.once("SIGTERM", shutdown);    return Effect.sync(() => {      process.off("SIGINT", shutdown);      process.off("SIGTERM", shutdown);    });  }); // ---------------------------------------------------------------------------// Background server management// --------------------------------------------------------------------------- const isRecord = (value: unknown): value is Record<string, unknown> =>  typeof value === "object" && value !== null && !Array.isArray(value); const isServerReachable = (baseUrl: string): Effect.Effect<boolean> =>  Effect.tryPromise(() =>    fetch(`${baseUrl}/api/scope`, { signal: AbortSignal.timeout(2000) }),  ).pipe(    Effect.flatMap((res) => {      if (!res.ok) return Effect.succeed(false);      return Effect.tryPromise(() => res.json()).pipe(        Effect.map((payload) => {          if (!isRecord(payload)) return false;          return (            typeof payload.id === "string" &&            typeof payload.name === "string" &&            typeof payload.dir === "string"          );        }),        Effect.catchCause(() => Effect.succeed(false)),      );    }),    Effect.catchCause(() => Effect.succeed(false)),  ); const script = process.argv[1];const isDevMode = isDevCliEntrypoint(script);const cliPrefix = isDevMode ? `bun run ${script}` : "executor"; const toError = (cause: unknown): Error =>  cause instanceof Error ? cause : new Error(String(cause)); const parseDaemonUrl = (baseUrl: string) =>  Effect.try({    try: () => parseDaemonBaseUrl(baseUrl, DEFAULT_PORT),    catch: (cause) =>      cause instanceof Error ? cause : new Error(`Invalid base URL: ${String(cause)}`),  }); const daemonBaseUrl = (hostname: string, port: number): string =>  `http://${canonicalDaemonHost(hostname)}:${port}`; const cleanupPointer = (input: { hostname: string; scopeId: string; port: number }) =>  Effect.gen(function* () {    yield* removeDaemonPointer({ hostname: input.hostname, scopeId: input.scopeId }).pipe(      Effect.ignore,    );    yield* removeDaemonRecord({ hostname: input.hostname, port: input.port }).pipe(Effect.ignore);  }); const resolveDaemonTarget = (baseUrl: string) =>  Effect.gen(function* () {    const parsed = yield* parseDaemonUrl(baseUrl);    const host = canonicalDaemonHost(parsed.hostname);    const scopeId = currentDaemonScopeId();    const pointer = yield* readDaemonPointer({ hostname: host, scopeId });     if (pointer) {      const pointerUrl = daemonBaseUrl(pointer.hostname, pointer.port);      if (isPidAlive(pointer.pid) && (yield* isServerReachable(pointerUrl))) {        return {          baseUrl: pointerUrl,          hostname: pointer.hostname,          port: pointer.port,          scopeId,        };      }       yield* cleanupPointer({ hostname: pointer.hostname, scopeId, port: pointer.port });    }     return {      baseUrl: daemonBaseUrl(host, parsed.port),      hostname: host,      port: parsed.port,      scopeId,    };  }); // Serialize daemon startup behind a filesystem lock so concurrent CLI invocations don't// each spawn their own daemon. The post-lock pointer recheck catches the case where// another invocation finished bootstrapping while we were waiting for the lock.const spawnAndWaitForDaemon = (input: {  host: string;  scopeId: string;  preferredPort: number;  allowedHosts: ReadonlyArray<string>;}): Effect.Effect<string, Error, FileSystem.FileSystem | PlatformPath.Path> =>  Effect.gen(function* () {    const lock = yield* acquireDaemonStartLock({ hostname: input.host, scopeId: input.scopeId });     try {      const existing = yield* readDaemonPointer({ hostname: input.host, scopeId: input.scopeId });      if (existing && isPidAlive(existing.pid)) {        const existingUrl = daemonBaseUrl(existing.hostname, existing.port);        if (yield* isServerReachable(existingUrl)) {          return existingUrl;        }      }       const selectedPort = yield* chooseDaemonPort({        preferredPort: input.preferredPort,        hostname: input.host,      });       if (selectedPort !== input.preferredPort) {        console.error(          `Port ${input.preferredPort} is in use. Starting daemon on available port ${selectedPort} instead.`,        );      }       const spec = yield* Effect.try({        try: () =>          buildDaemonSpawnSpec({            port: selectedPort,            hostname: input.host,            isDevMode,            scriptPath: script,            executablePath: process.execPath,            allowedHosts: input.allowedHosts,          }),        catch: (cause) =>          cause instanceof Error            ? cause            : new Error(`Failed to build daemon command: ${String(cause)}`),      });       const startBaseUrl = daemonBaseUrl(input.host, selectedPort);      console.error(`Starting daemon on ${input.host}:${selectedPort}...`);      yield* spawnDetached({        command: spec.command,        args: spec.args,        env: process.env,      });       const ready = yield* waitForReachable({        check: isServerReachable(startBaseUrl),        timeoutMs: DAEMON_BOOT_TIMEOUT_MS,        intervalMs: DAEMON_BOOT_POLL_MS,      });       if (!ready) {        return yield* Effect.fail(          new Error(            [              `Daemon did not become reachable at ${startBaseUrl} within ${DAEMON_BOOT_TIMEOUT_MS}ms.`,              `Run in foreground to inspect logs: ${cliPrefix} daemon run --foreground --port ${selectedPort} --hostname ${input.host}`,            ].join("\n"),          ),        );      }       return startBaseUrl;    } finally {      yield* releaseDaemonStartLock(lock).pipe(Effect.ignore);    }  }); // Auto-start a local daemon on demand so commands like `executor call` work without the// user having to run `daemon run` first. Refuses non-local hosts because spawning a// daemon process on the user's behalf only makes sense when "the user's machine" is// also where the request will land.const ensureDaemon = (  baseUrl: string,): Effect.Effect<string, Error, FileSystem.FileSystem | PlatformPath.Path> =>  Effect.gen(function* () {    const resolvedTarget = yield* resolveDaemonTarget(baseUrl);    if (yield* isServerReachable(resolvedTarget.baseUrl)) {      return resolvedTarget.baseUrl;    }     const parsed = yield* parseDaemonUrl(baseUrl);    const host = canonicalDaemonHost(parsed.hostname);     if (!canAutoStartLocalDaemonForHost(host)) {      return yield* Effect.fail(        new Error(          [            `Executor daemon is not reachable at ${baseUrl}.`,            "Auto-start is only supported for local hosts.",            `Start it manually: ${cliPrefix} daemon run --port ${parsed.port} --hostname ${host}`,          ].join("\n"),        ),      );    }     return yield* spawnAndWaitForDaemon({      host,      scopeId: resolvedTarget.scopeId,      preferredPort: parsed.port,      allowedHosts: [],    });  }).pipe(Effect.mapError(toError)); const stopDaemon = (  baseUrl: string,): Effect.Effect<void, Error, FileSystem.FileSystem | PlatformPath.Path> =>  Effect.gen(function* () {    const target = yield* resolveDaemonTarget(baseUrl);    const host = canonicalDaemonHost(target.hostname);    const scopeId = target.scopeId;    const record = yield* readDaemonRecord({ hostname: host, port: target.port });    const reachable = yield* isServerReachable(target.baseUrl);     if (!record) {      if (reachable) {        return yield* Effect.fail(          new Error(            [              `Executor is reachable at ${target.baseUrl} but no daemon record exists.`,              "It may not be managed by this CLI process.",              "Stop it from the terminal/session where it was started.",            ].join("\n"),          ),        );      }      console.log(`No daemon running at ${target.baseUrl}.`);      return;    }     if (!isPidAlive(record.pid)) {      yield* removeDaemonRecord({ hostname: host, port: target.port });      yield* removeDaemonPointer({ hostname: host, scopeId }).pipe(Effect.ignore);      if (reachable) {        return yield* Effect.fail(          new Error(            [              `Daemon record for ${target.baseUrl} points to dead pid ${record.pid}, but endpoint is still reachable.`,              "Refusing to stop an unknown process without ownership metadata.",            ].join("\n"),          ),        );      }      console.log(        `No daemon running at ${target.baseUrl} (removed stale record for pid ${record.pid}).`,      );      return;    }     console.log(`Stopping daemon at ${target.baseUrl} (pid ${record.pid})...`);     yield* terminatePid(record.pid);     const stopped = yield* waitForUnreachable({      check: isServerReachable(target.baseUrl),      timeoutMs: DAEMON_STOP_TIMEOUT_MS,      intervalMs: DAEMON_BOOT_POLL_MS,    });     if (!stopped) {      return yield* Effect.fail(        new Error(          [            `Daemon at ${target.baseUrl} did not stop within ${DAEMON_STOP_TIMEOUT_MS}ms.`,            "Try terminating the process manually.",          ].join("\n"),        ),      );    }     yield* removeDaemonRecord({ hostname: host, port: target.port });    yield* removeDaemonPointer({ hostname: host, scopeId }).pipe(Effect.ignore);    console.log(`Daemon stopped at ${target.baseUrl}.`);  }).pipe(Effect.mapError(toError)); type ExecuteCodeOutcome =  | {      readonly status: "completed";      readonly result: unknown;    }  | {      readonly status: "paused";      readonly text: string;      readonly executionId: string | undefined;      readonly interaction:        | {            readonly kind: "url" | "form";            readonly message: string;            readonly url?: string;            readonly requestedSchema?: Record<string, unknown>;          }        | undefined;    }; const executeCode = (input: {  baseUrl: string;  code: string;}): Effect.Effect<ExecuteCodeOutcome, Error, FileSystem.FileSystem | PlatformPath.Path> =>  Effect.gen(function* () {    const daemonUrl = yield* ensureDaemon(input.baseUrl);    const client = yield* makeApiClient(daemonUrl);    const response = yield* client.executions.execute({      payload: {        code: input.code,      },    });     if (response.status === "paused") {      return {        status: "paused" as const,        text: response.text,        executionId: extractExecutionId(response.structured),        interaction: extractPausedInteraction(response.structured),      };    }     if (response.isError) {      return yield* Effect.fail(new Error(response.text));    }     return {      status: "completed" as const,      result: extractExecutionResult(response.structured),    };  }).pipe(Effect.mapError(toError)); const printExecutionOutcome = (input: { baseUrl: string; outcome: ExecuteCodeOutcome }) =>  Effect.sync(() => {    if (input.outcome.status === "paused") {      console.log(input.outcome.text);      if (input.outcome.executionId) {        const commandPrefix = `${cliPrefix} resume --execution-id ${input.outcome.executionId} --base-url ${input.baseUrl}`;        if (input.outcome.interaction?.kind === "form") {          const requestedSchema = input.outcome.interaction.requestedSchema;          if (requestedSchema && Object.keys(requestedSchema).length > 0) {            console.log(`\nRequested schema:\n${JSON.stringify(requestedSchema, null, 2)}`);          }          const template = buildResumeContentTemplate(requestedSchema);          const contentArg = shellQuoteArg(JSON.stringify(template));          console.log("\nResume commands:");          console.log(`  ${commandPrefix} --action accept --content ${contentArg}`);          console.log(`  ${commandPrefix} --action decline`);          console.log(`  ${commandPrefix} --action cancel`);        } else {          console.log("\nResume command:");          console.log(`  ${commandPrefix} --action accept`);        }      }      return;    }     if (typeof input.outcome.result === "string") {      console.log(input.outcome.result);      return;    }     console.log(JSON.stringify(input.outcome.result, null, 2));  }); // ---------------------------------------------------------------------------// Typed API client// --------------------------------------------------------------------------- const makeApiClient = (baseUrl: string) =>  HttpApiClient.make(ExecutorApi, { baseUrl: `${baseUrl}/api` }).pipe(    Effect.provide(FetchHttpClient.layer),  ); // ---------------------------------------------------------------------------// Foreground session// --------------------------------------------------------------------------- const runForegroundSession = (input: {

Lines 1–500 of 1526.