111 lines · 3.3 KB · TypeScript
RawDownload
import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";import {  listLoginShellCandidates,  mergePathEntries,  readPathFromLoginShell,  readPathFromLaunchctl,  resolveWindowsEnvironment,} from "@t3tools/shared/shell";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Path from "effect/Path";import * as NodeOS from "node:os"; function logPathHydrationWarning(message: string, error?: unknown): void {  process.stderr.write(    `[server] ${message} ${error instanceof Error ? error.message : (error ?? "")}\n`,  );} function hydratePosixPath(env: NodeJS.ProcessEnv, platform: NodeJS.Platform): void {  let shellPath: string | undefined;  for (const shell of listLoginShellCandidates(platform, env.SHELL)) {    try {      shellPath = readPathFromLoginShell(shell);    } catch (error) {      logPathHydrationWarning(`Failed to read PATH from login shell ${shell}.`, error);    }     if (shellPath) break;  }   const launchctlPath = platform === "darwin" && !shellPath ? readPathFromLaunchctl() : undefined;  const mergedPath = mergePathEntries(shellPath ?? launchctlPath, env.PATH, platform);  if (mergedPath) {    env.PATH = mergedPath;  }} export function hydratePosixHome(  env: NodeJS.ProcessEnv,  resolveHomeDir = () => NodeOS.userInfo().homedir,): void {  if ((env.HOME?.trim() ?? "").length > 0) return;   const homeDir = resolveHomeDir();  if (homeDir.length > 0) {    env.HOME = homeDir;  }} export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return<  void,  never,  FileSystem.FileSystem | Path.Path> {  const platform = yield* HostProcessPlatform;  const env = yield* HostProcessEnvironment;   if (platform === "win32") {    const repairedEnvironment = yield* resolveWindowsEnvironment(env).pipe(      Effect.catchDefect((defect) =>        Effect.sync(() => {          logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect);          return {} as Partial<NodeJS.ProcessEnv>;        }),      ),    );    for (const [key, value] of Object.entries(repairedEnvironment)) {      if (value !== undefined) {        env[key] = value;      }    }    return;  }   if (platform !== "darwin" && platform !== "linux") return;   yield* Effect.sync(() => hydratePosixHome(env)).pipe(    Effect.catchDefect((defect) =>      Effect.sync(() => {        logPathHydrationWarning("Failed to hydrate HOME from the user account.", defect);      }),    ),  );  yield* Effect.sync(() => hydratePosixPath(env, platform)).pipe(    Effect.catchDefect((defect) =>      Effect.sync(() => {        logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect);      }),    ),  );}); export const expandHomePath = Effect.fn(function* (input: string) {  const { join } = yield* Path.Path;  if (input === "~") {    return NodeOS.homedir();  }  if (input.startsWith("~/") || input.startsWith("~\\")) {    return join(NodeOS.homedir(), input.slice(2));  }  return input;}); export const resolveBaseDir = Effect.fn(function* (raw: string | undefined) {  const { join, resolve } = yield* Path.Path;  if (!raw || raw.trim().length === 0) {    return join(NodeOS.homedir(), ".t3");  }  return resolve(yield* expandHomePath(raw.trim()));});