diff --git a/apps/server/src/cli-config.test.ts b/apps/server/src/cli-config.test.ts index 038d22e8f3..ef2f9f55d8 100644 --- a/apps/server/src/cli-config.test.ts +++ b/apps/server/src/cli-config.test.ts @@ -40,6 +40,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { port: Option.none(), host: Option.none(), baseDir: Option.none(), + cwd: Option.none(), devUrl: Option.none(), noBrowser: Option.none(), authToken: Option.none(), @@ -102,6 +103,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { port: Option.some(8788), host: Option.some("127.0.0.1"), baseDir: Option.some(baseDir), + cwd: Option.none(), devUrl: Option.some(new URL("http://127.0.0.1:4173")), noBrowser: Option.some(true), authToken: Option.some("flag-token"), @@ -178,6 +180,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { port: Option.none(), host: Option.none(), baseDir: Option.none(), + cwd: Option.none(), devUrl: Option.none(), noBrowser: Option.none(), authToken: Option.none(), @@ -228,6 +231,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-cli-config-dirs-" }); + const customCwd = path.join(baseDir, "nested", "project"); const resolved = yield* resolveServerConfig( { @@ -235,6 +239,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { port: Option.some(4888), host: Option.none(), baseDir: Option.some(baseDir), + cwd: Option.some(customCwd), devUrl: Option.some(new URL("http://127.0.0.1:5173")), noBrowser: Option.none(), authToken: Option.none(), @@ -253,6 +258,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { ); for (const directory of [ + customCwd, resolved.stateDir, resolved.logsDir, resolved.providerLogsDir, @@ -264,6 +270,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { ]) { expect(yield* fs.exists(directory)).toBe(true); } + expect(resolved.cwd).toBe(path.resolve(customCwd)); }), ); @@ -290,6 +297,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { port: Option.some(8788), host: Option.some("127.0.0.1"), baseDir: Option.none(), + cwd: Option.none(), devUrl: Option.some(new URL("http://127.0.0.1:4173")), noBrowser: Option.none(), authToken: Option.some("flag-token"), @@ -360,6 +368,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { port: Option.some(4888), host: Option.none(), baseDir: Option.some(baseDir), + cwd: Option.none(), devUrl: Option.none(), noBrowser: Option.none(), authToken: Option.none(), diff --git a/apps/server/src/cli.ts b/apps/server/src/cli.ts index 09c17278a5..9ece02a0d3 100644 --- a/apps/server/src/cli.ts +++ b/apps/server/src/cli.ts @@ -1,7 +1,7 @@ import { NetService } from "@t3tools/shared/Net"; import { parsePersistedServerObservabilitySettings } from "@t3tools/shared/serverSettings"; import { Config, Effect, FileSystem, LogLevel, Option, Path, Schema } from "effect"; -import { Command, Flag, GlobalFlag } from "effect/unstable/cli"; +import { Argument, Command, Flag, GlobalFlag } from "effect/unstable/cli"; import { DEFAULT_PORT, @@ -13,7 +13,7 @@ import { type ServerConfigShape, } from "./config"; import { readBootstrapEnvelope } from "./bootstrap"; -import { resolveBaseDir } from "./os-jank"; +import { expandHomePath, resolveBaseDir } from "./os-jank"; import { runServer } from "./server"; const PortSchema = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 })); @@ -140,6 +140,7 @@ interface CliServerFlags { readonly port: Option.Option; readonly host: Option.Option; readonly baseDir: Option.Option; + readonly cwd: Option.Option; readonly devUrl: Option.Option; readonly noBrowser: Option.Option; readonly authToken: Option.Option; @@ -225,6 +226,9 @@ export const resolveServerConfig = ( ), ), ); + const rawCwd = Option.getOrElse(flags.cwd, () => process.cwd()); + const cwd = path.resolve(yield* expandHomePath(rawCwd.trim())); + yield* fs.makeDirectory(cwd, { recursive: true }); const derivedPaths = yield* deriveServerPaths(baseDir, devUrl); yield* ensureServerDirectories(derivedPaths); const persistedObservabilitySettings = yield* loadPersistedObservabilitySettings( @@ -315,7 +319,7 @@ export const resolveServerConfig = ( otlpServiceName: env.otlpServiceName, mode, port, - cwd: process.cwd(), + cwd, baseDir, ...derivedPaths, serverTracePath, @@ -336,6 +340,12 @@ const commandFlags = { port: portFlag, host: hostFlag, baseDir: baseDirFlag, + cwd: Argument.string("cwd").pipe( + Argument.withDescription( + "Working directory for provider sessions (defaults to the current directory).", + ), + Argument.optional, + ), devUrl: devUrlFlag, noBrowser: noBrowserFlag, authToken: authTokenFlag,