import { NetService } from "@t3tools/shared/Net";import { Config, Effect, LogLevel, Option, Schema } from "effect";import { Command, Flag, GlobalFlag } from "effect/unstable/cli"; import { DEFAULT_PORT, deriveServerPaths, ensureServerDirectories, resolveStaticDir, ServerConfig, RuntimeMode, type ServerConfigShape,} from "./config";import { readBootstrapEnvelope } from "./bootstrap";import { resolveBaseDir } from "./os-jank";import { runServer } from "./server"; const PortSchema = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 })); const BootstrapEnvelopeSchema = Schema.Struct({ mode: Schema.optional(RuntimeMode), port: Schema.optional(PortSchema), host: Schema.optional(Schema.String), t3Home: Schema.optional(Schema.String), devUrl: Schema.optional(Schema.URLFromString), noBrowser: Schema.optional(Schema.Boolean), authToken: Schema.optional(Schema.String), autoBootstrapProjectFromCwd: Schema.optional(Schema.Boolean), logWebSocketEvents: Schema.optional(Schema.Boolean),}); const modeFlag = Flag.choice("mode", RuntimeMode.literals).pipe( Flag.withDescription("Runtime mode. `desktop` keeps loopback defaults unless overridden."), Flag.optional,);const portFlag = Flag.integer("port").pipe( Flag.withSchema(PortSchema), Flag.withDescription("Port for the HTTP/WebSocket server."), Flag.optional,);const hostFlag = Flag.string("host").pipe( Flag.withDescription("Host/interface to bind (for example 127.0.0.1, 0.0.0.0, or a Tailnet IP)."), Flag.optional,);const baseDirFlag = Flag.string("base-dir").pipe( Flag.withDescription("Base directory path (equivalent to T3CODE_HOME)."), Flag.optional,);const devUrlFlag = Flag.string("dev-url").pipe( Flag.withSchema(Schema.URLFromString), Flag.withDescription("Dev web URL to proxy/redirect to (equivalent to VITE_DEV_SERVER_URL)."), Flag.optional,);const noBrowserFlag = Flag.boolean("no-browser").pipe( Flag.withDescription("Disable automatic browser opening."), Flag.optional,);const authTokenFlag = Flag.string("auth-token").pipe( Flag.withDescription("Auth token required for WebSocket connections."), Flag.withAlias("token"), Flag.optional,);const bootstrapFdFlag = Flag.integer("bootstrap-fd").pipe( Flag.withSchema(Schema.Int), Flag.withDescription("Read one-time bootstrap secrets from the given file descriptor."), Flag.optional,);const autoBootstrapProjectFromCwdFlag = Flag.boolean("auto-bootstrap-project-from-cwd").pipe( Flag.withDescription( "Create a project for the current working directory on startup when missing.", ), Flag.optional,);const logWebSocketEventsFlag = Flag.boolean("log-websocket-events").pipe( Flag.withDescription( "Emit server-side logs for outbound WebSocket push traffic (equivalent to T3CODE_LOG_WS_EVENTS).", ), Flag.withAlias("log-ws-events"), Flag.optional,); const EnvServerConfig = Config.all({ logLevel: Config.logLevel("T3CODE_LOG_LEVEL").pipe(Config.withDefault("Info")), mode: Config.schema(RuntimeMode, "T3CODE_MODE").pipe( Config.option, Config.map(Option.getOrUndefined), ), port: Config.port("T3CODE_PORT").pipe(Config.option, Config.map(Option.getOrUndefined)), host: Config.string("T3CODE_HOST").pipe(Config.option, Config.map(Option.getOrUndefined)), t3Home: Config.string("T3CODE_HOME").pipe(Config.option, Config.map(Option.getOrUndefined)), devUrl: Config.url("VITE_DEV_SERVER_URL").pipe(Config.option, Config.map(Option.getOrUndefined)), noBrowser: Config.boolean("T3CODE_NO_BROWSER").pipe( Config.option, Config.map(Option.getOrUndefined), ), authToken: Config.string("T3CODE_AUTH_TOKEN").pipe( Config.option, Config.map(Option.getOrUndefined), ), bootstrapFd: Config.int("T3CODE_BOOTSTRAP_FD").pipe( Config.option, Config.map(Option.getOrUndefined), ), autoBootstrapProjectFromCwd: Config.boolean("T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD").pipe( Config.option, Config.map(Option.getOrUndefined), ), logWebSocketEvents: Config.boolean("T3CODE_LOG_WS_EVENTS").pipe( Config.option, Config.map(Option.getOrUndefined), ),}); interface CliServerFlags { readonly mode: Option.Option<RuntimeMode>; readonly port: Option.Option<number>; readonly host: Option.Option<string>; readonly baseDir: Option.Option<string>; readonly devUrl: Option.Option<URL>; readonly noBrowser: Option.Option<boolean>; readonly authToken: Option.Option<string>; readonly bootstrapFd: Option.Option<number>; readonly autoBootstrapProjectFromCwd: Option.Option<boolean>; readonly logWebSocketEvents: Option.Option<boolean>;} const resolveBooleanFlag = (flag: Option.Option<boolean>, envValue: boolean) => Option.getOrElse(Option.filter(flag, Boolean), () => envValue); const resolveOptionPrecedence = <Value>( ...values: ReadonlyArray<Option.Option<Value>>): Option.Option<Value> => Option.firstSomeOf(values); export const resolveServerConfig = ( flags: CliServerFlags, cliLogLevel: Option.Option<LogLevel.LogLevel>,) => Effect.gen(function* () { const { findAvailablePort } = yield* NetService; const env = yield* EnvServerConfig; const bootstrapFd = Option.getOrUndefined(flags.bootstrapFd) ?? env.bootstrapFd; const bootstrapEnvelope = bootstrapFd !== undefined ? yield* readBootstrapEnvelope(BootstrapEnvelopeSchema, bootstrapFd) : Option.none(); const mode: RuntimeMode = Option.getOrElse( resolveOptionPrecedence( flags.mode, Option.fromUndefinedOr(env.mode), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.mode)), ), () => "web", ); const port = yield* Option.match( resolveOptionPrecedence( flags.port, Option.fromUndefinedOr(env.port), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.port)), ), { onSome: (value) => Effect.succeed(value), onNone: () => { if (mode === "desktop") { return Effect.succeed(DEFAULT_PORT); } return findAvailablePort(DEFAULT_PORT); }, }, ); const devUrl = Option.getOrElse( resolveOptionPrecedence( flags.devUrl, Option.fromUndefinedOr(env.devUrl), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.devUrl)), ), () => undefined, ); const baseDir = yield* resolveBaseDir( Option.getOrUndefined( resolveOptionPrecedence( flags.baseDir, Option.fromUndefinedOr(env.t3Home), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.t3Home), ), ), ), ); const derivedPaths = yield* deriveServerPaths(baseDir, devUrl); yield* ensureServerDirectories(derivedPaths); const noBrowser = resolveBooleanFlag( flags.noBrowser, Option.getOrElse( resolveOptionPrecedence( Option.fromUndefinedOr(env.noBrowser), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.noBrowser), ), ), () => mode === "desktop", ), ); const authToken = Option.getOrUndefined( resolveOptionPrecedence( flags.authToken, Option.fromUndefinedOr(env.authToken), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.authToken), ), ), ); const autoBootstrapProjectFromCwd = resolveBooleanFlag( flags.autoBootstrapProjectFromCwd, Option.getOrElse( resolveOptionPrecedence( Option.fromUndefinedOr(env.autoBootstrapProjectFromCwd), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.autoBootstrapProjectFromCwd), ), ), () => mode === "web", ), ); const logWebSocketEvents = resolveBooleanFlag( flags.logWebSocketEvents, Option.getOrElse( resolveOptionPrecedence( Option.fromUndefinedOr(env.logWebSocketEvents), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.logWebSocketEvents), ), ), () => Boolean(devUrl), ), ); const staticDir = devUrl ? undefined : yield* resolveStaticDir(); const host = Option.getOrElse( resolveOptionPrecedence( flags.host, Option.fromUndefinedOr(env.host), Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.host)), ), () => (mode === "desktop" ? "127.0.0.1" : undefined), ); const logLevel = Option.getOrElse(cliLogLevel, () => env.logLevel); const config: ServerConfigShape = { logLevel, mode, port, cwd: process.cwd(), baseDir, ...derivedPaths, host, staticDir, devUrl, noBrowser, authToken, autoBootstrapProjectFromCwd, logWebSocketEvents, }; return config; }); const commandFlags = { mode: modeFlag, port: portFlag, host: hostFlag, baseDir: baseDirFlag, devUrl: devUrlFlag, noBrowser: noBrowserFlag, authToken: authTokenFlag, bootstrapFd: bootstrapFdFlag, autoBootstrapProjectFromCwd: autoBootstrapProjectFromCwdFlag, logWebSocketEvents: logWebSocketEventsFlag,} as const; const rootCommand = Command.make("t3", commandFlags).pipe( Command.withDescription("Run the T3 Code server."), Command.withHandler((flags) => Effect.gen(function* () { const logLevel = yield* GlobalFlag.LogLevel; const config = yield* resolveServerConfig(flags, logLevel); return yield* runServer.pipe(Effect.provideService(ServerConfig, config)); }), ),); export const cli = rootCommand;
import { NetService } from "@t3tools/shared/Net";
import { Config, Effect, LogLevel, Option, Schema } from "effect";
import { Command, Flag, GlobalFlag } from "effect/unstable/cli";
import {
DEFAULT_PORT,
deriveServerPaths,
ensureServerDirectories,
resolveStaticDir,
ServerConfig,
RuntimeMode,
type ServerConfigShape,
} from "./config";
import { readBootstrapEnvelope } from "./bootstrap";
import { resolveBaseDir } from "./os-jank";
import { runServer } from "./server";
const PortSchema = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 }));
const BootstrapEnvelopeSchema = Schema.Struct({
mode: Schema.optional(RuntimeMode),
port: Schema.optional(PortSchema),
host: Schema.optional(Schema.String),
t3Home: Schema.optional(Schema.String),
devUrl: Schema.optional(Schema.URLFromString),
noBrowser: Schema.optional(Schema.Boolean),
authToken: Schema.optional(Schema.String),
autoBootstrapProjectFromCwd: Schema.optional(Schema.Boolean),
logWebSocketEvents: Schema.optional(Schema.Boolean),
});
const modeFlag = Flag.choice("mode", RuntimeMode.literals).pipe(
Flag.withDescription("Runtime mode. `desktop` keeps loopback defaults unless overridden."),
Flag.optional,
);
const portFlag = Flag.integer("port").pipe(
Flag.withSchema(PortSchema),
Flag.withDescription("Port for the HTTP/WebSocket server."),
Flag.optional,
);
const hostFlag = Flag.string("host").pipe(
Flag.withDescription("Host/interface to bind (for example 127.0.0.1, 0.0.0.0, or a Tailnet IP)."),
Flag.optional,
);
const baseDirFlag = Flag.string("base-dir").pipe(
Flag.withDescription("Base directory path (equivalent to T3CODE_HOME)."),
Flag.optional,
);
const devUrlFlag = Flag.string("dev-url").pipe(
Flag.withSchema(Schema.URLFromString),
Flag.withDescription("Dev web URL to proxy/redirect to (equivalent to VITE_DEV_SERVER_URL)."),
Flag.optional,
);
const noBrowserFlag = Flag.boolean("no-browser").pipe(
Flag.withDescription("Disable automatic browser opening."),
Flag.optional,
);
const authTokenFlag = Flag.string("auth-token").pipe(
Flag.withDescription("Auth token required for WebSocket connections."),
Flag.withAlias("token"),
Flag.optional,
);
const bootstrapFdFlag = Flag.integer("bootstrap-fd").pipe(
Flag.withSchema(Schema.Int),
Flag.withDescription("Read one-time bootstrap secrets from the given file descriptor."),
Flag.optional,
);
const autoBootstrapProjectFromCwdFlag = Flag.boolean("auto-bootstrap-project-from-cwd").pipe(
Flag.withDescription(
"Create a project for the current working directory on startup when missing.",
),
Flag.optional,
);
const logWebSocketEventsFlag = Flag.boolean("log-websocket-events").pipe(
Flag.withDescription(
"Emit server-side logs for outbound WebSocket push traffic (equivalent to T3CODE_LOG_WS_EVENTS).",
),
Flag.withAlias("log-ws-events"),
Flag.optional,
);
const EnvServerConfig = Config.all({
logLevel: Config.logLevel("T3CODE_LOG_LEVEL").pipe(Config.withDefault("Info")),
mode: Config.schema(RuntimeMode, "T3CODE_MODE").pipe(
Config.option,
Config.map(Option.getOrUndefined),
),
port: Config.port("T3CODE_PORT").pipe(Config.option, Config.map(Option.getOrUndefined)),
host: Config.string("T3CODE_HOST").pipe(Config.option, Config.map(Option.getOrUndefined)),
t3Home: Config.string("T3CODE_HOME").pipe(Config.option, Config.map(Option.getOrUndefined)),
devUrl: Config.url("VITE_DEV_SERVER_URL").pipe(Config.option, Config.map(Option.getOrUndefined)),
noBrowser: Config.boolean("T3CODE_NO_BROWSER").pipe(
Config.option,
Config.map(Option.getOrUndefined),
),
authToken: Config.string("T3CODE_AUTH_TOKEN").pipe(
Config.option,
Config.map(Option.getOrUndefined),
),
bootstrapFd: Config.int("T3CODE_BOOTSTRAP_FD").pipe(
Config.option,
Config.map(Option.getOrUndefined),
),
autoBootstrapProjectFromCwd: Config.boolean("T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD").pipe(
Config.option,
Config.map(Option.getOrUndefined),
),
logWebSocketEvents: Config.boolean("T3CODE_LOG_WS_EVENTS").pipe(
Config.option,
Config.map(Option.getOrUndefined),
),
});
interface CliServerFlags {
readonly mode: Option.Option<RuntimeMode>;
readonly port: Option.Option<number>;
readonly host: Option.Option<string>;
readonly baseDir: Option.Option<string>;
readonly devUrl: Option.Option<URL>;
readonly noBrowser: Option.Option<boolean>;
readonly authToken: Option.Option<string>;
readonly bootstrapFd: Option.Option<number>;
readonly autoBootstrapProjectFromCwd: Option.Option<boolean>;
readonly logWebSocketEvents: Option.Option<boolean>;
}
const resolveBooleanFlag = (flag: Option.Option<boolean>, envValue: boolean) =>
Option.getOrElse(Option.filter(flag, Boolean), () => envValue);
const resolveOptionPrecedence = <Value>(
...values: ReadonlyArray<Option.Option<Value>>
): Option.Option<Value> => Option.firstSomeOf(values);
export const resolveServerConfig = (
flags: CliServerFlags,
cliLogLevel: Option.Option<LogLevel.LogLevel>,
) =>
Effect.gen(function* () {
const { findAvailablePort } = yield* NetService;
const env = yield* EnvServerConfig;
const bootstrapFd = Option.getOrUndefined(flags.bootstrapFd) ?? env.bootstrapFd;
const bootstrapEnvelope =
bootstrapFd !== undefined
? yield* readBootstrapEnvelope(BootstrapEnvelopeSchema, bootstrapFd)
: Option.none();
const mode: RuntimeMode = Option.getOrElse(
resolveOptionPrecedence(
flags.mode,
Option.fromUndefinedOr(env.mode),
Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.mode)),
),
() => "web",
);
const port = yield* Option.match(
resolveOptionPrecedence(
flags.port,
Option.fromUndefinedOr(env.port),
Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.port)),
),
{
onSome: (value) => Effect.succeed(value),
onNone: () => {
if (mode === "desktop") {
return Effect.succeed(DEFAULT_PORT);
}
return findAvailablePort(DEFAULT_PORT);
},
},
);
const devUrl = Option.getOrElse(
resolveOptionPrecedence(
flags.devUrl,
Option.fromUndefinedOr(env.devUrl),
Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.devUrl)),
),
() => undefined,
);
const baseDir = yield* resolveBaseDir(
Option.getOrUndefined(
resolveOptionPrecedence(
flags.baseDir,
Option.fromUndefinedOr(env.t3Home),
Option.flatMap(bootstrapEnvelope, (bootstrap) =>
Option.fromUndefinedOr(bootstrap.t3Home),
),
),
),
);
const derivedPaths = yield* deriveServerPaths(baseDir, devUrl);
yield* ensureServerDirectories(derivedPaths);
const noBrowser = resolveBooleanFlag(
flags.noBrowser,
Option.getOrElse(
resolveOptionPrecedence(
Option.fromUndefinedOr(env.noBrowser),
Option.flatMap(bootstrapEnvelope, (bootstrap) =>
Option.fromUndefinedOr(bootstrap.noBrowser),
),
),
() => mode === "desktop",
),
);
const authToken = Option.getOrUndefined(
resolveOptionPrecedence(
flags.authToken,
Option.fromUndefinedOr(env.authToken),
Option.flatMap(bootstrapEnvelope, (bootstrap) =>
Option.fromUndefinedOr(bootstrap.authToken),
),
),
);
const autoBootstrapProjectFromCwd = resolveBooleanFlag(
flags.autoBootstrapProjectFromCwd,
Option.getOrElse(
resolveOptionPrecedence(
Option.fromUndefinedOr(env.autoBootstrapProjectFromCwd),
Option.flatMap(bootstrapEnvelope, (bootstrap) =>
Option.fromUndefinedOr(bootstrap.autoBootstrapProjectFromCwd),
),
),
() => mode === "web",
),
);
const logWebSocketEvents = resolveBooleanFlag(
flags.logWebSocketEvents,
Option.getOrElse(
resolveOptionPrecedence(
Option.fromUndefinedOr(env.logWebSocketEvents),
Option.flatMap(bootstrapEnvelope, (bootstrap) =>
Option.fromUndefinedOr(bootstrap.logWebSocketEvents),
),
),
() => Boolean(devUrl),
),
);
const staticDir = devUrl ? undefined : yield* resolveStaticDir();
const host = Option.getOrElse(
resolveOptionPrecedence(
flags.host,
Option.fromUndefinedOr(env.host),
Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.host)),
),
() => (mode === "desktop" ? "127.0.0.1" : undefined),
);
const logLevel = Option.getOrElse(cliLogLevel, () => env.logLevel);
const config: ServerConfigShape = {
logLevel,
mode,
port,
cwd: process.cwd(),
baseDir,
...derivedPaths,
host,
staticDir,
devUrl,
noBrowser,
authToken,
autoBootstrapProjectFromCwd,
logWebSocketEvents,
};
return config;
});
const commandFlags = {
mode: modeFlag,
port: portFlag,
host: hostFlag,
baseDir: baseDirFlag,
devUrl: devUrlFlag,
noBrowser: noBrowserFlag,
authToken: authTokenFlag,
bootstrapFd: bootstrapFdFlag,
autoBootstrapProjectFromCwd: autoBootstrapProjectFromCwdFlag,
logWebSocketEvents: logWebSocketEventsFlag,
} as const;
const rootCommand = Command.make("t3", commandFlags).pipe(
Command.withDescription("Run the T3 Code server."),
Command.withHandler((flags) =>
Effect.gen(function* () {
const logLevel = yield* GlobalFlag.LogLevel;
const config = yield* resolveServerConfig(flags, logLevel);
return yield* runServer.pipe(Effect.provideService(ServerConfig, config));
}),
),
);
export const cli = rootCommand;