authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-10-09 16:38:41-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-09 16:38:41-07:00
loge30852213ed3954037091582057f71918918e19f
tree51e589b0a25d66a2141abdd66d4c7b483f0a1c1c
parent58916b6554f45ac518bd8150dd10f1f536e40aac
signature Signed by PGP key B5690EEEBB952194

refactor(shared): host process references live in a HostProcess module (#17641)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

235 files changed, 1028 insertions(+), 1225 deletions(-)

apps/desktop/src/app/DesktopApp.ts+2-2
......@@ -35,7 +35,7 @@ import * as DesktopUpdates from "../updates/DesktopUpdates.ts";
3535import * as DesktopSnapShot from "../snapShot/DesktopSnapShot.ts";
3636import * as DesktopWslBackend from "../wsl/DesktopWslBackend.ts";
3737import * as DesktopRendererHistory from "../telemetry/DesktopRendererHistory.ts";
38import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
38import * as HostProcess from "@t3tools/shared/HostProcess";
3939
4040const DEFAULT_DESKTOP_BACKEND_PORT = 3773;
4141const MAX_TCP_PORT = 65_535;
......@@ -286,7 +286,7 @@ const startup = Effect.gen(function* () {
286286 const linuxElectronOptions =
287287 environment.platform === "linux" && !hasCommandLinePasswordStore
288288 ? DesktopPreReadyPlatform.resolveEarlyLinuxElectronOptionsFromProcess(
289 yield* HostProcessHomeDirectory,
289 yield* HostProcess.HomeDirectory,
290290 )
291291 : preReadyElectronOptions.linux;
292292 if (linuxElectronOptions !== null && !hasCommandLinePasswordStore) {
apps/desktop/src/app/DesktopAppActivation.test.ts+9-9
......@@ -11,7 +11,7 @@ import {
1111 type DesktopAppActivationResponse,
1212} from "@t3tools/contracts";
1313import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
14import { HostProcessPlatform, HostProcessUserId } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515import { it } from "@effect/vitest";
1616import * as Effect from "effect/Effect";
1717import { afterEach, describe, expect } from "vite-plus/test";
......@@ -83,8 +83,8 @@ function exchange(address: string, payload: DesktopAppActivationRequest) {
8383describe("desktop app control server", () => {
8484 it.effect("roundtrips a request and removes its socket on shutdown", () =>
8585 Effect.gen(function* () {
86 const platform = yield* HostProcessPlatform;
87 const userId = yield* HostProcessUserId;
86 const platform = yield* HostProcess.Platform;
87 const userId = yield* HostProcess.UserId;
8888 yield* Effect.promise(async () => {
8989 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-control-test-"));
9090 const target = makeTarget(NodePath.join(root, "userdata"), platform, userId);
......@@ -123,8 +123,8 @@ describe("desktop app control server", () => {
123123
124124 it.effect("cancels a queued request when the client disconnects", () =>
125125 Effect.gen(function* () {
126 const platform = yield* HostProcessPlatform;
127 const userId = yield* HostProcessUserId;
126 const platform = yield* HostProcess.Platform;
127 const userId = yield* HostProcess.UserId;
128128 yield* Effect.promise(async () => {
129129 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-cancel-test-"));
130130 const target = makeTarget(NodePath.join(root, "userdata"), platform, userId);
......@@ -162,8 +162,8 @@ describe("desktop app control server", () => {
162162 // Two desktop apps can share one state dir, such as nightly and a preview build.
163163 it.effect("keeps a newer app's socket when an older app on the same state dir quits", () =>
164164 Effect.gen(function* () {
165 const platform = yield* HostProcessPlatform;
166 const userId = yield* HostProcessUserId;
165 const platform = yield* HostProcess.Platform;
166 const userId = yield* HostProcess.UserId;
167167 if (platform === "win32") return;
168168 yield* Effect.promise(async () => {
169169 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-takeover-test-"));
......@@ -183,8 +183,8 @@ describe("desktop app control server", () => {
183183
184184 it.effect("binds its address again after the socket file is removed", () =>
185185 Effect.gen(function* () {
186 const platform = yield* HostProcessPlatform;
187 const userId = yield* HostProcessUserId;
186 const platform = yield* HostProcess.Platform;
187 const userId = yield* HostProcess.UserId;
188188 if (platform === "win32") return;
189189 yield* Effect.promise(async () => {
190190 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-reclaim-test-"));
apps/desktop/src/app/DesktopAppActivation.ts+2-2
......@@ -12,7 +12,7 @@ import {
1212 type DesktopAppActivationResponse,
1313} from "@t3tools/contracts";
1414import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
15import { HostProcessUserId } from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
1616import * as Context from "effect/Context";
1717import * as Effect from "effect/Effect";
1818import * as Layer from "effect/Layer";
......@@ -315,7 +315,7 @@ export const make = Effect.gen(function* () {
315315 const desktopWindow = yield* DesktopWindow.DesktopWindow;
316316 const electronWindow = yield* ElectronWindow.ElectronWindow;
317317 const path = yield* Path.Path;
318 const userId = yield* HostProcessUserId;
318 const userId = yield* HostProcess.UserId;
319319 const runPromise = Effect.runPromiseWith(yield* Effect.context<never>());
320320 const address = resolveDesktopAppControlAddress({
321321 stateDir: path.resolve(desktopEnvironment.stateDir),
apps/desktop/src/app/DesktopClerk.test.ts+2-2
......@@ -3,7 +3,7 @@ import * as NodeHttp from "node:http";
33import * as NodePath from "@effect/platform-node/NodePath";
44import { codexAuthHandoffUrl, readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff";
55import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts";
6import { HostProcessArguments } from "@t3tools/shared/hostProcess";
6import * as HostProcess from "@t3tools/shared/HostProcess";
77import { assert, describe, it } from "@effect/vitest";
88import * as Cause from "effect/Cause";
99import * as Effect from "effect/Effect";
......@@ -375,7 +375,7 @@ it.effect.each(["startup", "open-url"] as const)(
375375 assert.strictEqual(delivery?.returnUrl, request.returnUrl);
376376 }).pipe(
377377 Effect.provide(layerDesktopClerk(true, [], "darwin", undefined, shell)),
378 Effect.provideService(HostProcessArguments, entry === "startup" ? ["t3", link] : ["t3"]),
378 Effect.provideService(HostProcess.Arguments, entry === "startup" ? ["t3", link] : ["t3"]),
379379 Effect.provideService(ElectronApp.ElectronApp, electronApp),
380380 Effect.provideService(
381381 ElectronWindow.ElectronWindow,
apps/desktop/src/app/DesktopClerk.ts+2-2
......@@ -11,7 +11,7 @@ import { codexAuthDeliveryUrl, readCodexAuthHandoff } from "@t3tools/shared/code
1111import { receiveCodexAuthCallback, CodexAuthCallbackError } from "./CodexAuthCallback.ts";
1212import * as ElectronShell from "../electron/ElectronShell.ts";
1313import { providerAuthReturnUrl } from "@t3tools/shared/providerAuthReturnUrl";
14import { HostProcessArguments } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";
1616import * as ElectronApp from "../electron/ElectronApp.ts";
1717import * as ElectronProtocol from "../electron/ElectronProtocol.ts";
......@@ -182,7 +182,7 @@ export const make = Effect.gen(function* () {
182182 );
183183 return true;
184184 };
185 const args = yield* HostProcessArguments;
185 const args = yield* HostProcess.Arguments;
186186 args.some((value) => startProviderAuthHandoff(value));
187187 yield* electronApp.on("open-url", (event: { preventDefault: () => void }, url: string) => {
188188 if (startProviderAuthHandoff(url) || resumeProviderAuth(url)) event.preventDefault();
apps/desktop/src/app/DesktopPreReadyFileSystem.test.ts+2-2
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, it } from "@effect/vitest";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Effect from "effect/Effect";
55import * as Exit from "effect/Exit";
66import * as FileSystem from "effect/FileSystem";
......@@ -32,7 +32,7 @@ it.layer(NodeServices.layer)("DesktopPreReadyFileSystem", (it) => {
3232 }),
3333 );
3434
35 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32" || process.getuid?.() === 0)(
35 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32" || process.getuid?.() === 0)(
3636 "fails instead of treating an unreadable profile as missing",
3737 () =>
3838 Effect.gen(function* () {
apps/desktop/src/app/DesktopPreReadyPlatform.test.ts+6-6
......@@ -1,5 +1,5 @@
11import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Context from "effect/Context";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
......@@ -75,7 +75,7 @@ describe("DesktopPreReadyPlatform", () => {
7575 }).pipe(
7676 Effect.provide(
7777 DesktopPreReadyPlatform.layer.pipe(
78 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),
78 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
7979 ),
8080 ),
8181 );
......@@ -111,7 +111,7 @@ describe("DesktopPreReadyPlatform", () => {
111111 }));
112112 yield* Layer.build(
113113 DesktopPreReadyPlatform.layer.pipe(
114 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),
114 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
115115 ),
116116 );
117117 const identity = yield* Effect.promise(() => portalIdentity);
......@@ -135,7 +135,7 @@ describe("DesktopPreReadyPlatform", () => {
135135 });
136136
137137 return DesktopPreReadyPlatform.make.pipe(
138 Effect.provideService(HostProcessPlatform, "linux"),
138 Effect.provideService(HostProcess.Platform, "linux"),
139139 Effect.asVoid,
140140 );
141141 });
......@@ -151,7 +151,7 @@ describe("DesktopPreReadyPlatform", () => {
151151 assert.include(contents, "MimeType=x-scheme-handler/t3code;");
152152 assert.include(contents, "Icon=");
153153 assert.equal(setDesktopNameMock.mock.calls.length, 1);
154 }).pipe(Effect.provideService(HostProcessPlatform, "linux"));
154 }).pipe(Effect.provideService(HostProcess.Platform, "linux"));
155155 });
156156
157157 it.effect(
......@@ -168,7 +168,7 @@ describe("DesktopPreReadyPlatform", () => {
168168 });
169169
170170 const layerPreReady = DesktopPreReadyPlatform.layer.pipe(
171 Layer.provide(Layer.succeed(HostProcessPlatform, "darwin")),
171 Layer.provide(Layer.succeed(HostProcess.Platform, "darwin")),
172172 );
173173
174174 const layerClerkShaped = Layer.effect(
apps/desktop/src/app/DesktopPreReadyPlatform.ts+3-3
......@@ -6,7 +6,7 @@ import * as Effect from "effect/Effect";
66import * as Layer from "effect/Layer";
77
88import * as Electron from "electron";
9import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1010
1111import * as DesktopEarlyElectronStartup from "./DesktopEarlyElectronStartup.ts";
1212import { resolveDesktopAppBranding } from "./DesktopEnvironment.ts";
......@@ -50,8 +50,8 @@ export class DesktopPreReadyElectronOptions extends Context.Service<
5050
5151/** @public Service construction is part of the canonical Effect module API. */
5252export const make = Effect.gen(function* () {
53 const platform = yield* HostProcessPlatform;
54 const homeDirectory = yield* HostProcessHomeDirectory;
53 const platform = yield* HostProcess.Platform;
54 const homeDirectory = yield* HostProcess.HomeDirectory;
5555 return yield* Effect.sync((): DesktopPreReadyElectronOptions["Service"] => {
5656 const linuxPasswordStoreCommandLine =
5757 platform === "linux"
apps/desktop/src/backend/DesktopNetworkInterfaces.test.ts+2-2
......@@ -1,5 +1,5 @@
11import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Cause from "effect/Cause";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
......@@ -16,7 +16,7 @@ vi.mock("node:os", () => ({
1616import * as DesktopNetworkInterfaces from "./DesktopNetworkInterfaces.ts";
1717
1818const layerTest = DesktopNetworkInterfaces.layer.pipe(
19 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),
19 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
2020);
2121
2222describe("DesktopNetworkInterfaces", () => {
apps/desktop/src/backend/DesktopNetworkInterfaces.ts+2-2
......@@ -1,6 +1,6 @@
11import * as NodeOS from "node:os";
22
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Context from "effect/Context";
55import * as Effect from "effect/Effect";
66import * as Layer from "effect/Layer";
......@@ -41,7 +41,7 @@ export class DesktopNetworkInterfaces extends Context.Service<
4141
4242/** @public Service construction is part of the canonical Effect module API. */
4343export const make = Effect.gen(function* () {
44 const platform = yield* HostProcessPlatform;
44 const platform = yield* HostProcess.Platform;
4545 return DesktopNetworkInterfaces.of({
4646 read: Effect.try({
4747 try: () => NodeOS.networkInterfaces(),
apps/desktop/src/electron/ElectronMenu.test.ts+2-2
......@@ -1,5 +1,5 @@
11import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Cause from "effect/Cause";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
......@@ -28,7 +28,7 @@ vi.mock("electron", () => ({
2828import * as ElectronMenu from "./ElectronMenu.ts";
2929
3030const layerTest = ElectronMenu.layer.pipe(
31 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),
31 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
3232);
3333
3434const makeWindow = (zoomFactor = 1): Electron.BrowserWindow =>
apps/desktop/src/electron/ElectronMenu.ts+2-2
......@@ -1,5 +1,5 @@
11import type { ContextMenuItem } from "@t3tools/contracts";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Context from "effect/Context";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
......@@ -114,7 +114,7 @@ const normalizePosition = (
114114
115115/** @public Service construction is part of the canonical Effect module API. */
116116export const make = Effect.gen(function* () {
117 const platform = yield* HostProcessPlatform;
117 const platform = yield* HostProcess.Platform;
118118 let destructiveMenuIconCache: Option.Option<Electron.NativeImage> | undefined;
119119
120120 const getDestructiveMenuIcon = (): Option.Option<Electron.NativeImage> => {
apps/desktop/src/electron/ElectronSafeStorage.ts+2-2
......@@ -5,7 +5,7 @@ import * as Option from "effect/Option";
55import * as Schema from "effect/Schema";
66
77import * as Electron from "electron";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99
1010const electronSafeStorageErrorFields = {
1111 cause: Schema.Defect(),
......@@ -67,7 +67,7 @@ export class ElectronSafeStorage extends Context.Service<
6767
6868/** @public Service construction is part of the canonical Effect module API. */
6969export const make = Effect.gen(function* () {
70 const platform = yield* HostProcessPlatform;
70 const platform = yield* HostProcess.Platform;
7171
7272 return ElectronSafeStorage.of({
7373 isEncryptionAvailable: Effect.try({
apps/desktop/src/electron/ElectronWindow.test.ts+2-2
......@@ -1,5 +1,5 @@
11import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Cause from "effect/Cause";
44import * as Effect from "effect/Effect";
55import * as Fiber from "effect/Fiber";
......@@ -58,7 +58,7 @@ vi.mock("electron", () => ({
5858import * as ElectronWindow from "./ElectronWindow.ts";
5959
6060const layerTestFor = (platform: NodeJS.Platform) =>
61 ElectronWindow.layer.pipe(Layer.provide(Layer.succeed(HostProcessPlatform, platform)));
61 ElectronWindow.layer.pipe(Layer.provide(Layer.succeed(HostProcess.Platform, platform)));
6262
6363const layerTest = layerTestFor("linux");
6464
apps/desktop/src/electron/ElectronWindow.ts+2-2
......@@ -2,7 +2,7 @@
22
33import * as NodePath from "node:path";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66import type * as Cause from "effect/Cause";
77import * as Context from "effect/Context";
88import * as Effect from "effect/Effect";
......@@ -129,7 +129,7 @@ export class ElectronWindow extends Context.Service<
129129
130130/** @public Service construction is part of the canonical Effect module API. */
131131export const make = Effect.gen(function* () {
132 const platform = yield* HostProcessPlatform;
132 const platform = yield* HostProcess.Platform;
133133 // The focus worker loads a native accessibility module. Start it on the first
134134 // capture reveal so users who never capture pay nothing at launch.
135135 let windowsForegroundFocus: ReturnType<typeof startWindowsForegroundFocusThread> | undefined;
apps/desktop/src/ipc/methods/notificationBadge.test.ts+2-2
......@@ -1,7 +1,7 @@
11import * as Effect from "effect/Effect";
22import { beforeEach, expect, vi } from "vite-plus/test";
33import { it } from "@effect/vitest";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55
66const native = vi.hoisted(() => ({
77 setBadgeCount: vi.fn(),
......@@ -122,7 +122,7 @@ it.effect("validates IPC and clears on native focus, quit, and disposal", () =>
122122 expect(native.setBadgeCount).toHaveBeenLastCalledWith(0);
123123 }),
124124 ).pipe(
125 Effect.provideService(HostProcessPlatform, "linux"),
125 Effect.provideService(HostProcess.Platform, "linux"),
126126 Effect.provide([
127127 ElectronApp.layer,
128128 DesktopIpc.layer({
apps/desktop/src/ipc/methods/notificationBadge.ts+2-2
......@@ -1,7 +1,7 @@
11import * as Electron from "electron";
22import * as Effect from "effect/Effect";
33import * as Schema from "effect/Schema";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55
66import * as ElectronApp from "../../electron/ElectronApp.ts";
77import * as DesktopIpc from "../DesktopIpc.ts";
......@@ -45,7 +45,7 @@ export const installNotificationBadge = Effect.fn("desktop.ipc.installNotificati
4545 function* () {
4646 const ipc = yield* DesktopIpc.DesktopIpc;
4747 const app = yield* ElectronApp.ElectronApp;
48 const platform = yield* HostProcessPlatform;
48 const platform = yield* HostProcess.Platform;
4949 const clear = () => {
5050 applyNotificationBadge(platform, { count: 0, image: null });
5151 for (const window of Electron.BrowserWindow.getAllWindows()) {
apps/desktop/src/ipc/methods/window.test.ts+4-4
......@@ -1,6 +1,6 @@
11import { assert, describe, it } from "@effect/vitest";
22import * as NodeServices from "@effect/platform-node/NodeServices";
3import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as FileSystem from "effect/FileSystem";
55import * as Path from "effect/Path";
66import * as Effect from "effect/Effect";
......@@ -314,7 +314,7 @@ describe("pickProjectFavicon", () => {
314314 );
315315});
316316
317it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
317it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
318318 "finds remote editors installed without PATH launchers",
319319 () =>
320320 Effect.gen(function* () {
......@@ -333,11 +333,11 @@ it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
333333 yield* fs.chmod(executable, 0o755);
334334 }
335335 const editors = yield* probeRemoteEditors.handler(undefined).pipe(
336 Effect.provideService(HostProcessEnvironment, {
336 Effect.provideService(HostProcess.Environment, {
337337 HOME: home,
338338 PATH: path.join(home, "empty"),
339339 }),
340 Effect.provideService(HostProcessPlatform, "darwin"),
340 Effect.provideService(HostProcess.Platform, "darwin"),
341341 );
342342 assert.include(editors, "cursor");
343343 assert.include(editors, "vscode");
apps/desktop/src/ipc/methods/window.ts+3-4
......@@ -15,7 +15,7 @@ import {
1515} from "@t3tools/contracts";
1616import { WORKSPACE_IMAGE_PREVIEW_EXTENSIONS } from "@t3tools/shared/filePreview";
1717import { resolveEditorCommand } from "@t3tools/shared/editor";
18import * as HostProcess from "@t3tools/shared/hostProcess";
18import * as HostProcess from "@t3tools/shared/HostProcess";
1919import * as FileSystem from "effect/FileSystem";
2020import * as Path from "effect/Path";
2121import * as Effect from "effect/Effect";
......@@ -45,7 +45,6 @@ import {
4545 resolveWslPickFolderDefaultPath,
4646 wslUncPathToLinuxPath,
4747} from "../../wsl/wslPathParsing.ts";
48import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
4948
5049const ContextMenuPosition = Schema.Struct({
5150 x: Schema.Number,
......@@ -345,7 +344,7 @@ export const probeRemoteEditors = DesktopIpc.makeIpcMethod({
345344 result: Schema.Array(EditorId),
346345 handler: Effect.fn("desktop.ipc.window.probeRemoteEditors")(function* () {
347346 const available: Array<EditorId> = [];
348 const env = yield* HostProcess.HostProcessEnvironment;
347 const env = yield* HostProcess.Environment;
349348 for (const editorId of REMOTE_CAPABLE_EDITOR_IDS) {
350349 const editor = EDITORS.find((editor) => editor.id === editorId);
351350 if (editor && Option.isSome(yield* resolveEditorCommand(editor, env))) {
......@@ -398,7 +397,7 @@ export const pickThemeFiles = DesktopIpc.makeIpcMethod({
398397 // The VS Code extensions directory is the same dotfolder on Windows,
399398 // macOS, and Linux; when it is missing the picker opens wherever the
400399 // platform would by default.
401 const extensionsDir = path.join(yield* HostProcessHomeDirectory, ".vscode", "extensions");
400 const extensionsDir = path.join(yield* HostProcess.HomeDirectory, ".vscode", "extensions");
402401 const defaultPath = yield* fileSystem
403402 .exists(extensionsDir)
404403 .pipe(Effect.orElseSucceed(() => false));
apps/desktop/src/main.ts+3-3
......@@ -18,7 +18,7 @@ import * as Option from "effect/Option";
1818import * as Electron from "electron";
1919
2020import * as NetService from "@t3tools/shared/Net";
21import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
21import * as HostProcess from "@t3tools/shared/HostProcess";
2222import type { RemoteT3RunnerOptions } from "@t3tools/ssh/tunnel";
2323import serverPackageJson from "../../server/package.json" with { type: "json" };
2424
......@@ -90,8 +90,8 @@ const layerDesktopEnvironment = Layer.unwrap(
9090 const metadata = yield* Effect.service(ElectronApp.ElectronApp).pipe(
9191 Effect.flatMap((app) => app.metadata),
9292 );
93 const platform = yield* HostProcessPlatform;
94 const processArch = yield* HostProcessArchitecture;
93 const platform = yield* HostProcess.Platform;
94 const processArch = yield* HostProcess.Architecture;
9595 return DesktopEnvironment.layer({
9696 dirname: __dirname,
9797 homeDirectory: NodeOS.homedir(),
apps/desktop/src/preview/BrowserImport/BrowserImport.test.ts+6-10
......@@ -1,10 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, describe, it } from "@effect/vitest";
3import {
4 HostProcessEnvironment,
5 HostProcessExecutablePath,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
84import * as Effect from "effect/Effect";
95import * as FileSystem from "effect/FileSystem";
106import * as Fiber from "effect/Fiber";
......@@ -52,10 +48,10 @@ const layerRejectedBeforeSession = Layer.succeed(
5248const withImporter = Effect.fnUntraced(function* () {
5349 const fileSystem = yield* FileSystem.FileSystem;
5450 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-import-" });
55 const layerEnvironment = Layer.succeed(HostProcessEnvironment, { HOME: home });
51 const layerEnvironment = Layer.succeed(HostProcess.Environment, { HOME: home });
5652 const context = yield* sourcePathContext.pipe(
57 Effect.provideService(HostProcessEnvironment, { HOME: home }),
58 Effect.provideService(HostProcessPlatform, "darwin"),
53 Effect.provideService(HostProcess.Environment, { HOME: home }),
54 Effect.provideService(HostProcess.Platform, "darwin"),
5955 );
6056 const root = helium.userDataDirectory(context);
6157 if (root === undefined) throw new Error("Helium has no macOS user-data directory");
......@@ -69,8 +65,8 @@ const withImporter = Effect.fnUntraced(function* () {
6965 BrowserImport.layer.pipe(
7066 Layer.provide(layerRejectedBeforeSession),
7167 Layer.provide(layerEnvironment),
72 Layer.provide(Layer.succeed(HostProcessPlatform, "darwin")),
73 Layer.provide(Layer.succeed(HostProcessExecutablePath, "/Applications/T3 Code.app")),
68 Layer.provide(Layer.succeed(HostProcess.Platform, "darwin")),
69 Layer.provide(Layer.succeed(HostProcess.ExecutablePath, "/Applications/T3 Code.app")),
7470 Layer.provide(NodeServices.layer),
7571 ),
7672 ),
apps/desktop/src/preview/BrowserImport/BrowserImport.ts+3-3
......@@ -21,7 +21,7 @@ import * as Schema from "effect/Schema";
2121import * as Scope from "effect/Scope";
2222import { ChildProcessSpawner } from "effect/process";
2323
24import { HostProcessExecutablePath, HostProcessPlatform } from "@t3tools/shared/hostProcess";
24import * as HostProcess from "@t3tools/shared/HostProcess";
2525
2626import * as BrowserSession from "../BrowserSession.ts";
2727import { ChromiumCookieReadError, readChromiumCookies } from "./ChromiumCookies.ts";
......@@ -169,8 +169,8 @@ export const writeCookies = Effect.fn("BrowserImport.writeCookies")(function* (
169169/** @public Service construction is part of the canonical Effect module API. */
170170export const make = Effect.gen(function* BrowserImportMake() {
171171 const browserSession = yield* BrowserSession.BrowserSession;
172 const platform = yield* HostProcessPlatform;
173 const executablePath = yield* HostProcessExecutablePath;
172 const platform = yield* HostProcess.Platform;
173 const executablePath = yield* HostProcess.ExecutablePath;
174174 // Captured here so the service's methods stay free of a requirements
175175 // channel: the layer is built where NodeServices is already in scope.
176176 const platformServices = yield* Effect.context<
apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts+1-1
......@@ -315,7 +315,7 @@ export interface ChromiumCookieSource {
315315 readonly keychainAccount: string | undefined;
316316 readonly linuxSecretApplication: string | undefined;
317317 readonly windowsLocalStatePath?: string;
318 /** Supplied by the caller from `HostProcessPlatform` rather than read here. */
318 /** Supplied by the caller from `HostProcess.Platform` rather than read here. */
319319 readonly platform: NodeJS.Platform;
320320}
321321
apps/desktop/src/preview/BrowserImport/ChromiumKeys.test.ts+3-3
......@@ -1,5 +1,5 @@
11import { describe, expect, it } from "@effect/vitest";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Deferred from "effect/Deferred";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
......@@ -232,7 +232,7 @@ describe("Linux Chromium secrets", () => {
232232 capture: (value) => (captured = value),
233233 }),
234234 ),
235 Effect.provideService(HostProcessEnvironment, {
235 Effect.provideService(HostProcess.Environment, {
236236 PATH: "/synthetic/bin",
237237 SESSION_MARKER: "kept",
238238 LC_ALL: "localized",
......@@ -322,7 +322,7 @@ describe("Windows Chromium secrets", () => {
322322 Effect.provide(
323323 layerHelper({ stdout: key.toString("base64"), capture: (value) => (captured = value) }),
324324 ),
325 Effect.provideService(HostProcessEnvironment, { SystemRoot: "C:\\Windows" }),
325 Effect.provideService(HostProcess.Environment, { SystemRoot: "C:\\Windows" }),
326326 );
327327 });
328328});
apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts+3-3
......@@ -19,7 +19,7 @@
1919 */
2020import * as NodeCrypto from "node:crypto";
2121
22import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
22import * as HostProcess from "@t3tools/shared/HostProcess";
2323
2424import * as Effect from "effect/Effect";
2525import * as Base64 from "effect/encoding/Base64";
......@@ -138,7 +138,7 @@ export const readLinuxSecret = Effect.fn("ChromiumKeys.readLinuxSecret")(functio
138138 return yield* Effect.scoped(
139139 Effect.gen(function* () {
140140 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
141 const environment = yield* HostProcessEnvironment;
141 const environment = yield* HostProcess.Environment;
142142 const helper = yield* LinuxBrowserSecretPath;
143143 if (helper === undefined) {
144144 return yield* new ChromiumKeyError({ reason: "keychainUnavailable" });
......@@ -219,7 +219,7 @@ export const decodeWindowsWrappedKey = Effect.fn("ChromiumKeys.decodeWindowsWrap
219219export const unwrapWindowsDpapiKey = Effect.fn("ChromiumKeys.unwrapWindowsDpapiKey")(function* (
220220 wrapped: Buffer,
221221) {
222 const environment = yield* HostProcessEnvironment;
222 const environment = yield* HostProcess.Environment;
223223 return yield* Effect.scoped(
224224 Effect.gen(function* () {
225225 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
apps/desktop/src/preview/BrowserImport/SafariPermission.test.ts+5-5
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, it } from "@effect/vitest";
3import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Effect from "effect/Effect";
55import * as FileSystem from "effect/FileSystem";
66import * as PlatformError from "effect/PlatformError";
......@@ -30,8 +30,8 @@ it.effect("detects Safari access becoming available without reading or importing
3030 ),
3131 });
3232 const check = yield* safariPermissionCheck.pipe(
33 Effect.provideService(HostProcessEnvironment, { HOME: home }),
34 Effect.provideService(HostProcessPlatform, "darwin"),
33 Effect.provideService(HostProcess.Environment, { HOME: home }),
34 Effect.provideService(HostProcess.Platform, "darwin"),
3535 Effect.provideService(FileSystem.FileSystem, guardedFs),
3636 );
3737 assert.isFalse(yield* Effect.promise(check));
......@@ -47,8 +47,8 @@ it.effect("recognizes access when cookies exist only in a named Safari profile",
4747 const fs = yield* FileSystem.FileSystem;
4848 const home = yield* fs.makeTempDirectoryScoped({ prefix: "t3-safari-named-access-" });
4949 const check = yield* safariPermissionCheck.pipe(
50 Effect.provideService(HostProcessEnvironment, { HOME: home }),
51 Effect.provideService(HostProcessPlatform, "darwin"),
50 Effect.provideService(HostProcess.Environment, { HOME: home }),
51 Effect.provideService(HostProcess.Platform, "darwin"),
5252 );
5353 assert.isFalse(yield* Effect.promise(check));
5454 const directory = `${home}/Library/Containers/com.apple.Safari/Data/Library/WebKit/WebsiteDataStore/12345678-1234-1234-1234-123456789abc/Cookies`;
apps/desktop/src/preview/BrowserImport/Sources.test.ts+30-34
......@@ -3,11 +3,7 @@
33import * as NodePath from "node:path";
44import * as NodeServices from "@effect/platform-node/NodeServices";
55import { assert, describe, it } from "@effect/vitest";
6import {
7 HostProcessEnvironment,
8 HostProcessHostname,
9 HostProcessPlatform,
10} from "@t3tools/shared/hostProcess";
6import * as HostProcess from "@t3tools/shared/HostProcess";
117import * as Effect from "effect/Effect";
128import * as FileSystem from "effect/FileSystem";
139import * as Path from "effect/Path";
......@@ -80,8 +76,8 @@ const withSourceHome = Effect.fnUntraced(function* () {
8076 const fileSystem = yield* FileSystem.FileSystem;
8177 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-sources-" });
8278 const context = yield* sourcePathContext.pipe(
83 Effect.provideService(HostProcessEnvironment, { HOME: home }),
84 Effect.provideService(HostProcessPlatform, "darwin"),
79 Effect.provideService(HostProcess.Environment, { HOME: home }),
80 Effect.provideService(HostProcess.Platform, "darwin"),
8581 );
8682 yield* fileSystem.makeDirectory(userDataDirectory(context), { recursive: true });
8783 return context;
......@@ -133,8 +129,8 @@ describe("Helium on Linux", () => {
133129 const fileSystem = yield* FileSystem.FileSystem;
134130 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-helium-linux-" });
135131 const context = yield* sourcePathContext.pipe(
136 Effect.provideService(HostProcessEnvironment, { HOME: home }),
137 Effect.provideService(HostProcessPlatform, "linux"),
132 Effect.provideService(HostProcess.Environment, { HOME: home }),
133 Effect.provideService(HostProcess.Platform, "linux"),
138134 );
139135 const root = `${home}/.config/net.imput.helium`;
140136 yield* fileSystem.makeDirectory(`${root}/Default`, { recursive: true });
......@@ -162,11 +158,11 @@ describe("Helium on Windows", () => {
162158 run(
163159 Effect.gen(function* () {
164160 const context = yield* sourcePathContext.pipe(
165 Effect.provideService(HostProcessEnvironment, {
161 Effect.provideService(HostProcess.Environment, {
166162 USERPROFILE: "C:\\Users\\browser-user",
167163 LOCALAPPDATA: "C:\\Users\\browser-user\\AppData\\Local",
168164 }),
169 Effect.provideService(HostProcessPlatform, "win32"),
165 Effect.provideService(HostProcess.Platform, "win32"),
170166 );
171167
172168 assert.include(helium.platforms, "win32");
......@@ -198,11 +194,11 @@ describe("isSourceRunning", () => {
198194 prefix: "t3code-helium-windows-lock-",
199195 });
200196 const context = yield* sourcePathContext.pipe(
201 Effect.provideService(HostProcessEnvironment, {
197 Effect.provideService(HostProcess.Environment, {
202198 HOME: home,
203199 LOCALAPPDATA: home,
204200 }),
205 Effect.provideService(HostProcessPlatform, "win32"),
201 Effect.provideService(HostProcess.Platform, "win32"),
206202 );
207203 const profile = context.path.join(helium.userDataDirectory(context)!, "Default");
208204 const database = context.path.join(profile, "Network", "Cookies");
......@@ -259,12 +255,12 @@ describe("isSourceRunning", () => {
259255
260256 assert.isTrue(
261257 yield* isSourceRunning(helium, paths).pipe(
262 Effect.provideService(HostProcessHostname, "another-host"),
258 Effect.provideService(HostProcess.Hostname, "another-host"),
263259 ),
264260 );
265261 assert.isFalse(
266262 yield* isSourceRunning(helium, paths).pipe(
267 Effect.provideService(HostProcessHostname, "lock-owner"),
263 Effect.provideService(HostProcess.Hostname, "lock-owner"),
268264 ),
269265 );
270266 }),
......@@ -656,8 +652,8 @@ describe("cookieDatabaseCandidatePaths", () => {
656652 Effect.gen(function* () {
657653 const path = yield* Path.Path;
658654 const context = yield* sourcePathContext.pipe(
659 Effect.provideService(HostProcessEnvironment, { HOME: "/tmp/test" }),
660 Effect.provideService(HostProcessPlatform, "darwin"),
655 Effect.provideService(HostProcess.Environment, { HOME: "/tmp/test" }),
656 Effect.provideService(HostProcess.Platform, "darwin"),
661657 );
662658 const candidates = cookieDatabaseCandidatePaths(firefox, context, "Profiles/abc.default");
663659 assert.deepEqual(candidates, [
......@@ -684,8 +680,8 @@ describe("Firefox Snap profiles", () => {
684680 prefix: "t3code-firefox-snap-",
685681 });
686682 const context = yield* sourcePathContext.pipe(
687 Effect.provideService(HostProcessEnvironment, { HOME: home }),
688 Effect.provideService(HostProcessPlatform, "linux"),
683 Effect.provideService(HostProcess.Environment, { HOME: home }),
684 Effect.provideService(HostProcess.Platform, "linux"),
689685 );
690686 const root = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox");
691687 const directory = context.path.join(root, "abcd.default");
......@@ -724,8 +720,8 @@ describe("Firefox Snap profiles", () => {
724720 const fileSystem = yield* FileSystem.FileSystem;
725721 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-snap-" });
726722 const context = yield* sourcePathContext.pipe(
727 Effect.provideService(HostProcessEnvironment, { HOME: home }),
728 Effect.provideService(HostProcessPlatform, "linux"),
723 Effect.provideService(HostProcess.Environment, { HOME: home }),
724 Effect.provideService(HostProcess.Platform, "linux"),
729725 );
730726 const native = context.path.join(home, ".mozilla", "firefox");
731727 const snap = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox");
......@@ -775,11 +771,11 @@ describe("listSourceProfiles Firefox fallback", () => {
775771 });
776772 const appData = path.join(home, "AppData", "Roaming");
777773 const context = yield* sourcePathContext.pipe(
778 Effect.provideService(HostProcessEnvironment, {
774 Effect.provideService(HostProcess.Environment, {
779775 HOME: home,
780776 APPDATA: appData,
781777 }),
782 Effect.provideService(HostProcessPlatform, platform),
778 Effect.provideService(HostProcess.Platform, platform),
783779 );
784780 const root = firefox.userDataDirectory(context)!;
785781 const scanRoot = platform === "linux" ? root : path.join(root, "Profiles");
......@@ -812,8 +808,8 @@ describe("listSourceProfiles Firefox fallback", () => {
812808 prefix: "t3code-firefox-stale-ini-",
813809 });
814810 const context = yield* sourcePathContext.pipe(
815 Effect.provideService(HostProcessEnvironment, { HOME: home }),
816 Effect.provideService(HostProcessPlatform, "darwin"),
811 Effect.provideService(HostProcess.Environment, { HOME: home }),
812 Effect.provideService(HostProcess.Platform, "darwin"),
817813 );
818814 const root = firefox.userDataDirectory(context)!;
819815 // `profiles.ini` names a profile that was never launched (no cookie
......@@ -851,8 +847,8 @@ describe("listSourceProfiles Firefox fallback", () => {
851847 prefix: "t3code-firefox-counts-",
852848 });
853849 const context = yield* sourcePathContext.pipe(
854 Effect.provideService(HostProcessEnvironment, { HOME: home }),
855 Effect.provideService(HostProcessPlatform, "darwin"),
850 Effect.provideService(HostProcess.Environment, { HOME: home }),
851 Effect.provideService(HostProcess.Platform, "darwin"),
856852 );
857853 const root = firefox.userDataDirectory(context)!;
858854 const declaredDirectory = path.join(root, "Profiles", "declared.default");
......@@ -902,8 +898,8 @@ describe("isSourceRunning for Firefox", () => {
902898 const fileSystem = yield* FileSystem.FileSystem;
903899 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" });
904900 const context = yield* sourcePathContext.pipe(
905 Effect.provideService(HostProcessEnvironment, { HOME: home }),
906 Effect.provideService(HostProcessPlatform, "darwin"),
901 Effect.provideService(HostProcess.Environment, { HOME: home }),
902 Effect.provideService(HostProcess.Platform, "darwin"),
907903 );
908904 const root = firefox.userDataDirectory(context)!;
909905 const profile = `${root}/Profiles/abcd.default-release`;
......@@ -952,7 +948,7 @@ describe("isSourceRunning for Firefox", () => {
952948 );
953949
954950 // Holds the lock with python3's fcntl, which does not exist on Windows.
955 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
951 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
956952 "detects a live fcntl lock on .parentlock, as macOS Firefox leaves it",
957953 () =>
958954 run(
......@@ -961,8 +957,8 @@ describe("isSourceRunning for Firefox", () => {
961957 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
962958 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" });
963959 const context = yield* sourcePathContext.pipe(
964 Effect.provideService(HostProcessEnvironment, { HOME: home }),
965 Effect.provideService(HostProcessPlatform, "darwin"),
960 Effect.provideService(HostProcess.Environment, { HOME: home }),
961 Effect.provideService(HostProcess.Platform, "darwin"),
966962 );
967963 const root = firefox.userDataDirectory(context)!;
968964 const profile = `${root}/Profiles/abcd.default-release`;
......@@ -1033,11 +1029,11 @@ describe("isSourceRunning for Firefox", () => {
10331029 const context = yield* sourcePathContext.pipe(
10341030 // Firefox's win32 root hangs off %APPDATA%; without it the root is
10351031 // undefined and the fixture would escape the sandbox into the repo.
1036 Effect.provideService(HostProcessEnvironment, {
1032 Effect.provideService(HostProcess.Environment, {
10371033 HOME: home,
10381034 APPDATA: `${home}/AppData/Roaming`,
10391035 }),
1040 Effect.provideService(HostProcessPlatform, "win32"),
1036 Effect.provideService(HostProcess.Platform, "win32"),
10411037 );
10421038 const root = firefox.userDataDirectory(context)!;
10431039 const profile = `${root}/Profiles/gx7x7fqx.default-release`;
apps/desktop/src/preview/BrowserImport/Sources.ts+6-11
......@@ -17,12 +17,7 @@
1717 */
1818import type { BrowserImportSourceId, BrowserImportSourceProfile } from "@t3tools/contracts";
1919import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
20import {
21 HostProcessEnvironment,
22 HostProcessAddresses,
23 HostProcessHostname,
24 HostProcessPlatform,
25} from "@t3tools/shared/hostProcess";
20import * as HostProcess from "@t3tools/shared/HostProcess";
2621import * as Effect from "effect/Effect";
2722import * as FileSystem from "effect/FileSystem";
2823import * as Path from "effect/Path";
......@@ -335,8 +330,8 @@ export function parseFirefoxProfiles(
335330 */
336331export const sourcePathContext = Effect.gen(function* () {
337332 const path = yield* Path.Path;
338 const platform = yield* HostProcessPlatform;
339 const environment = yield* HostProcessEnvironment;
333 const platform = yield* HostProcess.Platform;
334 const environment = yield* HostProcess.Environment;
340335 return {
341336 path,
342337 platform,
......@@ -782,7 +777,7 @@ export const posixLockIsHeld = Effect.fnUntraced(function* (
782777 interpreters: ReadonlyArray<string> = FCNTL_PROBE_INTERPRETERS,
783778) {
784779 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
785 const environment = yield* HostProcessEnvironment;
780 const environment = yield* HostProcess.Environment;
786781 for (const interpreter of interpreters) {
787782 const verdict = yield* Effect.scoped(
788783 Effect.gen(function* () {
......@@ -872,7 +867,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning")
872867 if (context.platform === "win32") {
873868 return yield* windowsChromiumCookiesAreHeld(definition, context);
874869 }
875 const currentHost = yield* HostProcessHostname;
870 const currentHost = yield* HostProcess.Hostname;
876871 const lock = context.path.join(root, "SingletonLock");
877872 return yield* fileSystem.readLink(lock).pipe(
878873 Effect.flatMap((target) => chromiumSingletonLockIsHeld(target, currentHost, processIsAlive)),
......@@ -883,7 +878,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning")
883878 const profiles = yield* listSourceProfiles(definition, context);
884879 // Only the Linux `lock` symlink names an address, so Windows skips the lookup.
885880 const localAddresses: ReadonlySet<string> =
886 context.platform === "win32" ? new Set() : yield* yield* HostProcessAddresses;
881 context.platform === "win32" ? new Set() : yield* yield* HostProcess.Addresses;
887882 const found = yield* Effect.forEach(profiles, (profile) => {
888883 const directory = context.path.isAbsolute(profile.directory)
889884 ? profile.directory
apps/desktop/src/preview/Manager.test.ts+2-2
......@@ -5,7 +5,7 @@ import type {
55 DesktopPreviewRecordingFrame,
66 DesktopPreviewRecordingInputEvent,
77} from "@t3tools/contracts";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99import { parseKeybindingShortcut } from "@t3tools/shared/keybindings";
1010import * as Cause from "effect/Cause";
1111import * as Deferred from "effect/Deferred";
......@@ -313,7 +313,7 @@ const managerLayer = (platform: NodeJS.Platform = "darwin") =>
313313 Layer.provideMerge(layerFileSystem),
314314 Layer.provideMerge(Path.layer),
315315 Layer.provideMerge(NodeCrypto.layer),
316 Layer.provideMerge(Layer.succeed(HostProcessPlatform, platform)),
316 Layer.provideMerge(Layer.succeed(HostProcess.Platform, platform)),
317317 );
318318
319319const withManager = <A>(
apps/desktop/src/preview/Manager.ts+2-2
......@@ -25,7 +25,7 @@ import type {
2525 DesktopPreviewTabDefaults,
2626 PreviewForwardedShortcut,
2727} from "@t3tools/contracts";
28import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
28import * as HostProcess from "@t3tools/shared/HostProcess";
2929import { matchesKeybindingShortcut } from "@t3tools/shared/keybindings";
3030import { normalizePreviewUrl } from "@t3tools/shared/preview";
3131import {
......@@ -544,7 +544,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
544544) {
545545 const fileSystem = yield* FileSystem.FileSystem;
546546 const rendererHistory = yield* DesktopRendererHistory.DesktopRendererHistory;
547 const hostPlatform = yield* HostProcessPlatform;
547 const hostPlatform = yield* HostProcess.Platform;
548548 const path = yield* Path.Path;
549549 const crypto = yield* Crypto.Crypto;
550550 const parentScope = yield* Scope.Scope;
apps/desktop/src/snapShot/DesktopSnapShot.ts+2-2
......@@ -88,7 +88,7 @@ import {
8888 snapShotShortcutRegistrationFailureMessage,
8989 snapShotShortcutSystemConflict,
9090} from "./snapShot.ts";
91import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
91import * as HostProcess from "@t3tools/shared/HostProcess";
9292
9393const MAX_CAPTURE_WIDTH = 2_560;
9494const MAX_CAPTURE_HEIGHT = 1_600;
......@@ -728,7 +728,7 @@ export const make = Effect.gen(function* () {
728728 const runPromise = Effect.runPromiseWith(context);
729729 const captureDirectory = path.join(environment.stateDir, "snap-shots");
730730 const linuxAppId = environment.linuxDesktopEntryName.replace(/\.desktop$/, "");
731 const home = yield* HostProcessHomeDirectory;
731 const home = yield* HostProcess.HomeDirectory;
732732 let shortcutVerified = false;
733733 const gnomeSetupPaths = {
734734 bundle: environment.isPackaged
apps/desktop/src/snapShot/snapShot.test.ts+2-2
......@@ -1,5 +1,5 @@
11import { it as effectIt } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Effect from "effect/Effect";
44import { describe, expect, it, vi } from "vite-plus/test";
55
......@@ -703,7 +703,7 @@ describe("isWaylandSession", () => {
703703 "falls back to a live runtime directory socket when session variables are stripped",
704704 () =>
705705 Effect.gen(function* () {
706 if ((yield* HostProcessPlatform) !== "linux") return;
706 if ((yield* HostProcess.Platform) !== "linux") return;
707707 yield* Effect.promise(async () => {
708708 const { mkdtemp, rm, writeFile } = await import("node:fs/promises");
709709 const { createServer } = await import("node:net");
apps/server/scripts/record-codex-app-server-replay-fixture.ts+3-2
......@@ -5,7 +5,7 @@ import { revertCodexThread } from "../src/provider/CodexThreadRevert.ts";
55import { buildCodexInitializeParams } from "../src/provider/CodexProvider.ts";
66import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
77import * as NodeServices from "@effect/platform-node/NodeServices";
8import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99import { resolveSpawnCommand } from "@t3tools/shared/shell";
1010import * as Console from "effect/Console";
1111import * as Deferred from "effect/Deferred";
......@@ -1211,7 +1211,8 @@ function layerCodex({ recorder }: { readonly recorder: Recorder }) {
12111211 Effect.gen(function* () {
12121212 // The vp node shim marks its children with VP_TOOL_RECURSION, which makes every
12131213 // `node` the agent runs through a shell fail. Codex must not inherit it.
1214 const { VP_TOOL_RECURSION: _vpToolRecursion, ...environment } = yield* HostProcessEnvironment;
1214 const { VP_TOOL_RECURSION: _vpToolRecursion, ...environment } =
1215 yield* HostProcess.Environment;
12151216 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
12161217 const commandName = environment.T3_CODEX_BIN ?? environment.CODEX_BIN ?? "codex";
12171218 const spawnCommand = yield* resolveSpawnCommand(commandName, ["app-server"], {
apps/server/scripts/record-grok-acp-replay-fixture.ts+3-3
......@@ -12,7 +12,7 @@
1212import * as NodeServices from "@effect/platform-node/NodeServices";
1313import { type ProviderReplayEntry } from "@t3tools/contracts";
1414import { GrokSettings } from "@t3tools/provider-grok/settings";
15import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
1616import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
1717import * as Clock from "effect/Clock";
1818import * as Console from "effect/Console";
......@@ -442,12 +442,12 @@ const recordScenario = Effect.fn("recordGrokScenario")(function* (fixtureName: s
442442 const settings = { ...DEFAULT_GROK_SETTINGS, binaryPath: process.env.T3_GROK_BIN ?? "grok" };
443443 const layerRegistry = ProviderAdapterRegistry.layerFromAdaptersEffect(
444444 Effect.gen(function* () {
445 const environment = yield* HostProcessEnvironment;
445 const environment = yield* HostProcess.Environment;
446446 const adapter = yield* makeGrokAdapterV2({
447447 instanceId: GROK_DEFAULT_INSTANCE_ID,
448448 settings,
449449 environment,
450 hostPlatform: yield* HostProcessPlatform,
450 hostPlatform: yield* HostProcess.Platform,
451451 selfInvocation: yield* resolveSelfInvocation(),
452452 continuationRequests: yield* ProviderContinuationRequests.ProviderContinuationRequests,
453453 // Production's runtime factory, with the protocol logger teeing raw lines.
apps/server/scripts/t3-sqlite-state.test.ts+2-2
......@@ -7,7 +7,7 @@ import * as SqlClient from "effect/sql/SqlClient";
77
88import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
99import { runSqliteState } from "./t3-sqlite-state.ts";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
1212
1313const createFixtureDatabase = Effect.fn("createSqliteStateFixtureDatabase")(function* (
......@@ -90,7 +90,7 @@ it.layer(NodeServices.layer)("t3-sqlite-state", (it) => {
9090 sql: "INSERT INTO fixtures (id, label) VALUES (2, 'seeded')",
9191 });
9292 assert.equal(mutation.operation, "exec");
93 if (mutation.operation === "exec" && (yield* HostProcessPlatform) !== "win32") {
93 if (mutation.operation === "exec" && (yield* HostProcess.Platform) !== "win32") {
9494 // NTFS has no POSIX mode bits to report.
9595 assert.equal((yield* fs.stat(mutation.backup)).mode & 0o777, 0o600);
9696 }
apps/server/src/assets/AssetAccess.test.ts+2-2
......@@ -36,7 +36,7 @@ import { openMediaFile } from "./MediaFile.ts";
3636import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
3737import * as GitHubCredentials from "@t3tools/source-control-github/server/GitHubCredentials";
3838import { githubMediaResponse } from "./GitHubMediaFetch.ts";
39import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
39import * as HostProcess from "@t3tools/shared/HostProcess";
4040
4141vi.mock("node:fs/promises", async (importOriginal) => {
4242 const actual = await importOriginal<typeof NodeFSP>();
......@@ -326,7 +326,7 @@ describe("AssetAccess", () => {
326326 expect(yield* Effect.promise(() => response.text())).toBe("recording bytes");
327327 }
328328 }
329 }).pipe(Effect.provideService(HostProcessHomeDirectory, home));
329 }).pipe(Effect.provideService(HostProcess.HomeDirectory, home));
330330 }).pipe(Effect.provide(layerTest)),
331331 );
332332
apps/server/src/assets/AssetAccess.ts+2-2
......@@ -58,7 +58,7 @@ import * as ProjectFaviconResolver from "../project/ProjectFaviconResolver.ts";
5858import * as WorkspacePaths from "../workspace/WorkspacePaths.ts";
5959import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";
6060import { openMediaFile, readMediaFileHeader, type OpenMediaFile } from "./MediaFile.ts";
61import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
61import * as HostProcess from "@t3tools/shared/HostProcess";
6262
6363export const ASSET_ROUTE_PREFIX = "/api/assets";
6464
......@@ -470,7 +470,7 @@ export const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (i
470470
471471 switch (input.resource._tag) {
472472 case "media-file": {
473 let requestedPath = expandHomePath(input.resource.path, yield* HostProcessHomeDirectory);
473 let requestedPath = expandHomePath(input.resource.path, yield* HostProcess.HomeDirectory);
474474 if (!path.isAbsolute(requestedPath)) {
475475 if (!input.workspaceRoot) {
476476 return yield* new AssetWorkspaceContextNotFoundError({ resource: input.resource });
apps/server/src/assets/NativeAppIconResolver.test.ts+2-2
......@@ -5,7 +5,7 @@ import * as Layer from "effect/Layer";
55import * as Sink from "effect/Sink";
66import * as Stream from "effect/Stream";
77import { ChildProcessSpawner } from "effect/process";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99
1010import * as ServerConfig from "../config.ts";
1111import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";
......@@ -44,7 +44,7 @@ describe("resolveNativeAppIcon", () => {
4444 });
4545 const layerDependencies = Layer.mergeAll(
4646 layerConfig,
47 Layer.succeed(HostProcessPlatform, "darwin"),
47 Layer.succeed(HostProcess.Platform, "darwin"),
4848 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner),
4949 ).pipe(Layer.provideMerge(NodeServices.layer));
5050 const layerTest = NativeAppIconResolver.layer.pipe(Layer.provide(layerDependencies));
apps/server/src/assets/NativeAppIconResolver.ts+2-2
......@@ -15,7 +15,7 @@ import * as PlatformError from "effect/PlatformError";
1515import * as Semaphore from "effect/Semaphore";
1616import * as Hex from "effect/encoding/Hex";
1717import { ChildProcess, ChildProcessSpawner } from "effect/process";
18import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
18import * as HostProcess from "@t3tools/shared/HostProcess";
1919
2020import * as ServerConfig from "../config.ts";
2121
......@@ -214,7 +214,7 @@ const resolveNativeAppIconUncached = Effect.fn("NativeAppIconResolver.resolveUnc
214214/** @public Service construction is part of the canonical Effect module API. */
215215export const make = Effect.gen(function* () {
216216 const fileSystem = yield* FileSystem.FileSystem;
217 const hostPlatform = yield* HostProcessPlatform;
217 const hostPlatform = yield* HostProcess.Platform;
218218 const resolutionSemaphore = yield* Semaphore.make(2);
219219 const resolutionCache: Cache.Cache<
220220 string,
apps/server/src/bootstrap.test.ts+4-4
......@@ -11,7 +11,7 @@ import * as Effect from "effect/Effect";
1111import * as Fiber from "effect/Fiber";
1212import * as TestClock from "effect/testing/TestClock";
1313import { vi } from "vite-plus/test";
14import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515
1616import {
1717 BootstrapEnvelopeDecodeError,
......@@ -55,7 +55,7 @@ vi.mock("node:fs", async (importOriginal) => {
5555 };
5656});
5757
58const windowsHost = HostProcessPlatform.defaultValue() === "win32";
58const windowsHost = HostProcess.Platform.defaultValue() === "win32";
5959const nullDevice = windowsHost ? "\\\\.\\NUL" : "/dev/null";
6060const closeIfOpen = (fd: number) => {
6161 try {
......@@ -116,7 +116,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
116116 try {
117117 const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
118118 timeoutMs: 100,
119 }).pipe(Effect.provideService(HostProcessPlatform, "linux"));
119 }).pipe(Effect.provideService(HostProcess.Platform, "linux"));
120120 assertSome(payload, {
121121 mode: "desktop",
122122 });
......@@ -141,7 +141,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
141141 try {
142142 const error = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
143143 timeoutMs: 100,
144 }).pipe(Effect.provideService(HostProcessPlatform, "linux"), Effect.flip);
144 }).pipe(Effect.provideService(HostProcess.Platform, "linux"), Effect.flip);
145145
146146 assert.instanceOf(error, BootstrapInputStreamOpenError);
147147 assert.equal(error.fd, fd);
apps/server/src/bootstrap.ts+2-2
......@@ -10,7 +10,7 @@ import * as Predicate from "effect/Predicate";
1010import * as Result from "effect/Result";
1111import * as Schema from "effect/Schema";
1212import { decodeJsonResult } from "@t3tools/shared/schemaJson";
13import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
13import * as HostProcess from "@t3tools/shared/HostProcess";
1414
1515export class BootstrapFdStatError extends Schema.TaggedError<BootstrapFdStatError>()(
1616 "BootstrapFdStatError",
......@@ -168,7 +168,7 @@ const isFdReady = (fd: number) =>
168168
169169const makeBootstrapInputStream = (fd: number) =>
170170 Effect.gen(function* () {
171 const platform = yield* HostProcessPlatform;
171 const platform = yield* HostProcess.Platform;
172172 const fdPath = resolveFdPath(fd, platform);
173173 return yield* Effect.try<NodeStream.Readable, BootstrapInputStreamOpenError>({
174174 try: () => {
apps/server/src/checkpointing/CheckpointStore.test.ts+2-2
......@@ -4,7 +4,7 @@ import * as NodePath from "node:path";
44import * as NodeServices from "@effect/platform-node/NodeServices";
55import { it } from "@effect/vitest";
66import { ThreadId, type VcsError } from "@t3tools/contracts";
7import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
88import * as Effect from "effect/Effect";
99import * as FileSystem from "effect/FileSystem";
1010import * as Layer from "effect/Layer";
......@@ -329,7 +329,7 @@ it.layer(layerTest)("CheckpointStore.layer", (it) => {
329329 const copiedText = Array.from({ length: 20 }, (_, index) => `copy line ${index}\n`).join(
330330 "",
331331 );
332 const platform = yield* HostProcessPlatform;
332 const platform = yield* HostProcess.Platform;
333333 const renamedPath = platform === "win32" ? "renamed café.txt" : "renamed\tcafé\nname.txt";
334334 const addedPath = platform === "win32" ? "new café.txt" : "new\tfile\n名.txt";
335335 for (const [path, contents] of Object.entries({
apps/server/src/cli/app.test.ts+15-20
......@@ -8,12 +8,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
88import { it } from "@effect/vitest";
99import type { DesktopAppActivationRequest } from "@t3tools/contracts";
1010import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
11import {
12 HostProcessHomeDirectory,
13 HostProcessPlatform,
14 HostProcessUserId,
15 HostProcessWorkingDirectory,
16} from "@t3tools/shared/hostProcess";
11import * as HostProcess from "@t3tools/shared/HostProcess";
1712import * as NetService from "@t3tools/shared/Net";
1813import * as ConfigProvider from "effect/ConfigProvider";
1914import * as Effect from "effect/Effect";
......@@ -110,8 +105,8 @@ async function startFakeDesktop(input: {
110105const fakeDesktop = Effect.fn(function* (
111106 input: Omit<Parameters<typeof startFakeDesktop>[0], "platform" | "userId">,
112107) {
113 const platform = yield* HostProcessPlatform;
114 const userId = yield* HostProcessUserId;
108 const platform = yield* HostProcess.Platform;
109 const userId = yield* HostProcess.UserId;
115110 return yield* Effect.acquireRelease(
116111 Effect.promise(() => startFakeDesktop({ ...input, platform, userId })),
117112 (server) => Effect.promise(() => server.close()),
......@@ -142,7 +137,7 @@ describe("t3 server command safety", () => {
142137 "C:new-project",
143138 ]) {
144139 const error = yield* runCli([word, "--base-dir", baseDir]).pipe(
145 Effect.provideService(HostProcessPlatform, "linux"),
140 Effect.provideService(HostProcess.Platform, "linux"),
146141 Effect.flip,
147142 );
148143 expect(String(error)).toContain(`Unknown command "${word}"`);
......@@ -181,7 +176,7 @@ describe("t3 server command safety", () => {
181176 yield* Effect.promise(() => NodeFSP.mkdir(stateDir, { recursive: true }));
182177 yield* Effect.promise(() => NodeFSP.writeFile(statePath, record));
183178 const newDirectory = NodePath.join(root, "new-project");
184 const platform = yield* HostProcessPlatform;
179 const platform = yield* HostProcess.Platform;
185180 for (const args of [
186181 [],
187182 ["start"],
......@@ -193,7 +188,7 @@ describe("t3 server command safety", () => {
193188 ]) {
194189 const error = yield* runCli(args, { T3CODE_HOME: baseDir }).pipe(
195190 Effect.provideService(
196 HostProcessPlatform,
191 HostProcess.Platform,
197192 args[0] === "C:new-project" ? "win32" : platform,
198193 ),
199194 Effect.flip,
......@@ -234,7 +229,7 @@ describe("t3 app", () => {
234229 Effect.gen(function* () {
235230 const baseDir = NodePath.join(root, "missing-t3-home");
236231 const error = yield* runCli(["app", "--base-dir", baseDir]).pipe(
237 Effect.provideService(HostProcessPlatform, "freebsd"),
232 Effect.provideService(HostProcess.Platform, "freebsd"),
238233 Effect.flip,
239234 );
240235
......@@ -257,7 +252,7 @@ describe("t3 app", () => {
257252 expect(error).toMatchObject({
258253 _tag: "DesktopAppUnreachableError",
259254 candidateAddresses: [expect.any(String)],
260 workspaceRoot: yield* HostProcessWorkingDirectory,
255 workspaceRoot: yield* HostProcess.WorkingDirectory,
261256 message: expect.stringContaining("Could not reach the T3 Code desktop app."),
262257 cause: { code: "ENOENT" },
263258 });
......@@ -271,8 +266,8 @@ describe("t3 app", () => {
271266 Effect.gen(function* () {
272267 const baseDir = NodePath.join(root, "t3-home");
273268 const explicitPath = NodePath.join(root, "project");
274 const platform = yield* HostProcessPlatform;
275 const workingDirectory = yield* HostProcessWorkingDirectory;
269 const platform = yield* HostProcess.Platform;
270 const workingDirectory = yield* HostProcess.WorkingDirectory;
276271 const desktop = yield* fakeDesktop({ baseDir });
277272
278273 yield* runCli(["app"], { T3CODE_HOME: baseDir });
......@@ -298,7 +293,7 @@ describe("t3 app", () => {
298293
299294 expect(desktop.received).toHaveLength(1);
300295 expect(development.received).toHaveLength(0);
301 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),
296 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
302297 ),
303298 );
304299
......@@ -313,7 +308,7 @@ describe("t3 app", () => {
313308
314309 expect(development.received).toHaveLength(2);
315310 expect(yield* pathExists(baseDir)).toBe(false);
316 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),
311 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
317312 ),
318313 );
319314
......@@ -329,7 +324,7 @@ describe("t3 app", () => {
329324 expect(flagError).toMatchObject({ _tag: "DesktopAppUnreachableError" });
330325 expect(envError).toMatchObject({ _tag: "DesktopAppUnreachableError" });
331326 expect(development.received).toHaveLength(0);
332 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),
327 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
333328 ),
334329 );
335330
......@@ -363,7 +358,7 @@ describe("t3 app", () => {
363358 _tag: "DesktopAppRequestFailedError",
364359 code: "project-create-failed",
365360 requestId: desktop.received[0]?.requestId,
366 workspaceRoot: yield* HostProcessWorkingDirectory,
361 workspaceRoot: yield* HostProcess.WorkingDirectory,
367362 message: expect.stringContaining("project-create-failed"),
368363 cause: {
369364 ok: false,
......@@ -377,7 +372,7 @@ describe("t3 app", () => {
377372 cause: { message: "The desktop app response is invalid." },
378373 });
379374 }
380 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),
375 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
381376 ),
382377 );
383378});
apps/server/src/cli/app.ts+4-8
......@@ -10,11 +10,7 @@ import {
1010 type DesktopAppActivationRequest,
1111} from "@t3tools/contracts";
1212import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
13import {
14 HostProcessPlatform,
15 HostProcessUserId,
16 HostProcessWorkingDirectory,
17} from "@t3tools/shared/hostProcess";
13import * as HostProcess from "@t3tools/shared/HostProcess";
1814import * as Config from "effect/Config";
1915import * as Console from "effect/Console";
2016import * as Crypto from "effect/Crypto";
......@@ -188,7 +184,7 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: {
188184 readonly workspaceRoot: Option.Option<string>;
189185}) {
190186 const environment = yield* appEnvironment;
191 const hostPlatform = yield* HostProcessPlatform;
187 const hostPlatform = yield* HostProcess.Platform;
192188 if (Option.isSome(environment.sshConnection) || Option.isSome(environment.sshTty)) {
193189 return yield* new DesktopAppSshUnsupportedError({});
194190 }
......@@ -201,9 +197,9 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: {
201197 const baseDir = yield* resolveBaseDir(configuredBaseDir);
202198 const allowDevFallback = Option.isNone(flags.baseDir) && !environment.t3Home?.trim();
203199 const rawWorkspaceRoot =
204 Option.getOrUndefined(flags.workspaceRoot) ?? (yield* HostProcessWorkingDirectory);
200 Option.getOrUndefined(flags.workspaceRoot) ?? (yield* HostProcess.WorkingDirectory);
205201 const workspaceRoot = path.resolve(yield* expandHomePath(rawWorkspaceRoot));
206 const userId = yield* HostProcessUserId;
202 const userId = yield* HostProcess.UserId;
207203 const resolveAddress = (stateSubdirectory: "userdata" | "dev") =>
208204 resolveDesktopAppControlAddress({
209205 stateDir: path.join(baseDir, stateSubdirectory),
apps/server/src/cli/browser.ts+4-8
......@@ -10,11 +10,7 @@
1010 * Both need root. Without it, the command prints what it would change and the
1111 * `sudo` line to run. It is safe to run again; it skips what is already done.
1212 */
13import {
14 HostProcessEnvironment,
15 HostProcessPlatform,
16 HostProcessUserId,
17} from "@t3tools/shared/hostProcess";
13import * as HostProcess from "@t3tools/shared/HostProcess";
1814import * as Console from "effect/Console";
1915import * as Effect from "effect/Effect";
2016import * as FileSystem from "effect/FileSystem";
......@@ -61,7 +57,7 @@ const runStep = Effect.fn("browserSetup.runStep")(function* (
6157 * unspecified home falls back to the invoking user's `~/.t3`.
6258 */
6359const setupBaseDir = Effect.fn("browserSetup.baseDir")(function* (explicit: Option.Option<string>) {
64 const env = yield* HostProcessEnvironment;
60 const env = yield* HostProcess.Environment;
6561 const raw = Option.getOrUndefined(explicit) ?? env.T3CODE_HOME;
6662 if (raw !== undefined || env.SUDO_USER === undefined) return yield* resolveBaseDir(raw);
6763 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
......@@ -109,11 +105,11 @@ const browserSetupCommand = Command.make("setup", { baseDir: baseDirFlag }).pipe
109105 ),
110106 Command.withHandler(({ baseDir }) =>
111107 Effect.gen(function* () {
112 if ((yield* HostProcessPlatform) !== "linux") {
108 if ((yield* HostProcess.Platform) !== "linux") {
113109 return yield* Console.log("Nothing to set up: T3's browser runs as is on this system.");
114110 }
115111 const fs = yield* FileSystem.FileSystem;
116 const isRoot = (yield* HostProcessUserId) === 0;
112 const isRoot = (yield* HostProcess.UserId) === 0;
117113 const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND);
118114
119115 const needsProfile = yield* PreviewBrowserHost.sandboxBlocked;
apps/server/src/cli/connect.ts+2-2
......@@ -5,7 +5,7 @@ import {
55 type RelayClientInstallProgressStage,
66} from "@t3tools/contracts";
77import { RelayOkResponse } from "@t3tools/contracts/relay";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99import * as RelayClient from "@t3tools/shared/relayClient";
1010import { withRelayClientTracing } from "@t3tools/shared/relayTracing";
1111import * as Cause from "effect/Cause";
......@@ -686,7 +686,7 @@ export const connectCommand = Command.make("connect", {
686686 // show how to run the server manually.
687687 const background = yield* recoverServiceOnboardingOffer(offerServiceDuringOnboarding);
688688 if (background) {
689 const platform = yield* HostProcessPlatform;
689 const platform = yield* HostProcess.Platform;
690690 yield* Console.log(
691691 platform === "darwin"
692692 ? "\n✓ Background service ready\n\nT3 Code is set to run while you are logged in to this Mac. The server establishes the T3 Connect link on startup."
apps/server/src/cli/invocation.test.ts+18-24
......@@ -1,12 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, expect, it } from "@effect/vitest";
3import {
4 HostProcessArguments,
5 HostProcessEnvironment,
6 HostProcessExecutablePath,
7 HostProcessIsExecutable,
8 HostProcessPlatform,
9} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
104import * as Effect from "effect/Effect";
115import * as FileSystem from "effect/FileSystem";
126import * as Path from "effect/Path";
......@@ -113,11 +107,11 @@ it.layer(NodeServices.layer)("root CLI commands", (it) => {
113107 readonly executable?: boolean;
114108 }) =>
115109 resolveRootCliCommand("browser setup").pipe(
116 Effect.provideService(HostProcessExecutablePath, input.node),
117 Effect.provideService(HostProcessArguments, [input.node, input.entry]),
118 Effect.provideService(HostProcessIsExecutable, input.executable ?? false),
119 Effect.provideService(HostProcessPlatform, "linux"),
120 Effect.provideService(HostProcessEnvironment, { PATH: input.path ?? "", ...input.env }),
110 Effect.provideService(HostProcess.ExecutablePath, input.node),
111 Effect.provideService(HostProcess.Arguments, [input.node, input.entry]),
112 Effect.provideService(HostProcess.IsExecutable, input.executable ?? false),
113 Effect.provideService(HostProcess.Platform, "linux"),
114 Effect.provideService(HostProcess.Environment, { PATH: input.path ?? "", ...input.env }),
121115 );
122116
123117 /** A directory holding an executable `t3`, to stand in for one on PATH. */
......@@ -201,9 +195,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
201195 yield* fs.makeDirectory(path.dirname(entry), { recursive: true });
202196 yield* fs.writeFileString(entry, "");
203197 const installation = yield* resolveServerInstallation.pipe(
204 Effect.provideService(HostProcessArguments, ["node", entry]),
205 Effect.provideService(HostProcessExecutablePath, entry),
206 Effect.provideService(HostProcessIsExecutable, entry.endsWith("/t3")),
198 Effect.provideService(HostProcess.Arguments, ["node", entry]),
199 Effect.provideService(HostProcess.ExecutablePath, entry),
200 Effect.provideService(HostProcess.IsExecutable, entry.endsWith("/t3")),
207201 );
208202 expect(installation).toEqual({ kind });
209203 }
......@@ -227,9 +221,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
227221 '{"name":"t3","version":"0.0.45","bin":{"t3":"./dist/bin.mjs"}}',
228222 );
229223 const resolve = resolveServerInstallation.pipe(
230 Effect.provideService(HostProcessArguments, ["node", entry]),
231 Effect.provideService(HostProcessIsExecutable, false),
232 Effect.provideService(HostProcessPlatform, "linux"),
224 Effect.provideService(HostProcess.Arguments, ["node", entry]),
225 Effect.provideService(HostProcess.IsExecutable, false),
226 Effect.provideService(HostProcess.Platform, "linux"),
233227 );
234228 expect(yield* resolve).toBeNull();
235229 yield* fs.symlink(entry, globalBin);
......@@ -237,7 +231,7 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
237231 yield* fs.remove(globalBin);
238232 yield* fs.writeFileString(globalBin, "an unrelated t3 command");
239233 expect(yield* resolve).toBeNull();
240 expect(yield* resolve.pipe(Effect.provideService(HostProcessPlatform, "win32"))).toBeNull();
234 expect(yield* resolve.pipe(Effect.provideService(HostProcess.Platform, "win32"))).toBeNull();
241235 }),
242236 );
243237
......@@ -261,9 +255,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
261255 );
262256 yield* fs.symlink(launcher, path.join(prefix, "bin/t3"));
263257 const resolve = resolveServerInstallation.pipe(
264 Effect.provideService(HostProcessExecutablePath, entry),
265 Effect.provideService(HostProcessIsExecutable, true),
266 Effect.provideService(HostProcessPlatform, "linux"),
258 Effect.provideService(HostProcess.ExecutablePath, entry),
259 Effect.provideService(HostProcess.IsExecutable, true),
260 Effect.provideService(HostProcess.Platform, "linux"),
267261 );
268262 for (const [version, expected] of [
269263 ["0.0.44", null],
......@@ -296,8 +290,8 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
296290 }
297291 expect(
298292 yield* resolveServerInstallation.pipe(
299 Effect.provideService(HostProcessArguments, ["node", entry]),
300 Effect.provideService(HostProcessIsExecutable, false),
293 Effect.provideService(HostProcess.Arguments, ["node", entry]),
294 Effect.provideService(HostProcess.IsExecutable, false),
301295 ),
302296 ).toBeNull();
303297 }
apps/server/src/cli/invocation.ts+10-16
......@@ -5,13 +5,7 @@ import * as Path from "effect/Path";
55import * as Schema from "effect/Schema";
66
77import type { ServerInstallation } from "@t3tools/contracts";
8import {
9 HostProcessArguments,
10 HostProcessEnvironment,
11 HostProcessExecutablePath,
12 HostProcessIsExecutable,
13 HostProcessPlatform,
14} from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
159import { isCommandAvailable } from "@t3tools/shared/shell";
1610
1711import packageJson from "../../package.json" with { type: "json" };
......@@ -60,10 +54,10 @@ const decodeInstallManifest = Schema.decodeUnknownEffect(Schema.fromJsonString(I
6054export const resolveServerInstallation = Effect.gen(function* () {
6155 const fs = yield* FileSystem.FileSystem;
6256 const path = yield* Path.Path;
63 const args = yield* HostProcessArguments;
64 const executable = yield* HostProcessIsExecutable;
65 const executablePath = yield* HostProcessExecutablePath;
66 const platform = yield* HostProcessPlatform;
57 const args = yield* HostProcess.Arguments;
58 const executable = yield* HostProcess.IsExecutable;
59 const executablePath = yield* HostProcess.ExecutablePath;
60 const platform = yield* HostProcess.Platform;
6761 const entry = yield* fs.realPath(executable ? executablePath : (args[1] ?? ""));
6862 const match =
6963 /^(.*)\/lib\/node_modules\/t3\/(?:dist\/bin\.mjs|bin\/t3\.js|node_modules\/@t3code\/t3-[^/]+\/t3)$/.exec(
......@@ -141,7 +135,7 @@ export function formatCliCommand(input: {
141135
142136/** `formatCliCommand` against this process's real entry path and version. */
143137export const resolveCliCommand = (subcommand: string) =>
144 Effect.map(HostProcessArguments, (processArguments) =>
138 Effect.map(HostProcess.Arguments, (processArguments) =>
145139 formatCliCommand({
146140 subcommand,
147141 entryPath: processArguments[1] ?? "",
......@@ -161,12 +155,12 @@ const shellWord = (value: string) =>
161155 */
162156const resolveInstallLauncher = Effect.gen(function* () {
163157 const fs = yield* FileSystem.FileSystem;
164 const shim = (yield* HostProcessEnvironment).T3CODE_CLI_PATH?.trim();
158 const shim = (yield* HostProcess.Environment).T3CODE_CLI_PATH?.trim();
165159 if (shim && (yield* fs.exists(shim).pipe(Effect.orElseSucceed(() => false)))) {
166160 return Option.some(shim);
167161 }
168 return (yield* HostProcessIsExecutable)
169 ? Option.some(yield* HostProcessExecutablePath)
162 return (yield* HostProcess.IsExecutable)
163 ? Option.some(yield* HostProcess.ExecutablePath)
170164 : Option.none<string>();
171165});
172166
......@@ -197,7 +191,7 @@ export const resolveRootCliCommand = (subcommand: string) =>
197191 Effect.gen(function* () {
198192 const { command, launcher } = yield* resolveHostCliCommand(subcommand);
199193 if (launcher) return `sudo ${command}`;
200 const executablePath = yield* HostProcessExecutablePath;
194 const executablePath = yield* HostProcess.ExecutablePath;
201195 const systemNode = ROOT_PATH_DIRECTORIES.some((directory) =>
202196 executablePath.startsWith(`${directory}/`),
203197 );
apps/server/src/cli/pair.test.ts+2-2
......@@ -7,7 +7,7 @@ import * as NodePath from "node:path";
77import * as NodeServices from "@effect/platform-node/NodeServices";
88import { AuthStandardClientScopes } from "@t3tools/contracts";
99import * as NetService from "@t3tools/shared/Net";
10import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111import { assert, describe, expect, it } from "@effect/vitest";
1212import * as Effect from "effect/Effect";
1313import * as Layer from "effect/Layer";
......@@ -184,7 +184,7 @@ describe("t3 pair", () => {
184184 }),
185185 ).pipe(
186186 Effect.provide(NodeServices.layer),
187 Effect.provideService(HostProcessEnvironment, {
187 Effect.provideService(HostProcess.Environment, {
188188 ...process.env,
189189 [SERVICE_LAUNCHER_CONTEXT_ENV]: JSON.stringify({
190190 protocol: SERVICE_LAUNCHER_PROTOCOL,
apps/server/src/cli/server.ts+2-2
......@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as Effect from "effect/Effect";
33import * as FileSystem from "effect/FileSystem";
44import * as Option from "effect/Option";
......@@ -32,7 +32,7 @@ export const runDefaultServerCommand = (flags: CliServerFlags) =>
3232 if (Option.isSome(flags.cwd)) {
3333 const cwd = flags.cwd.value.trim();
3434 const fs = yield* FileSystem.FileSystem;
35 const platform = yield* HostProcessPlatform;
35 const platform = yield* HostProcess.Platform;
3636 const explicitPath =
3737 cwd === "." ||
3838 cwd === ".." ||
apps/server/src/cli/service.test.ts+4-4
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, expect, it } from "@effect/vitest";
3import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as NetService from "@t3tools/shared/Net";
55import * as ConfigProvider from "effect/ConfigProvider";
66import * as Effect from "effect/Effect";
......@@ -136,7 +136,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands
136136 "--base-dir",
137137 baseDir,
138138 ]).pipe(
139 Effect.provideService(HostProcessEnvironment, {}),
139 Effect.provideService(HostProcess.Environment, {}),
140140 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),
141141 );
142142
......@@ -161,7 +161,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands
161161 "--base-dir",
162162 baseDir,
163163 ]).pipe(
164 Effect.provideService(HostProcessEnvironment, {}),
164 Effect.provideService(HostProcess.Environment, {}),
165165 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),
166166 Effect.flip,
167167 );
......@@ -190,7 +190,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands
190190 baseDir,
191191 "--allow-downgrade",
192192 ]).pipe(
193 Effect.provideService(HostProcessEnvironment, {}),
193 Effect.provideService(HostProcess.Environment, {}),
194194 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),
195195 );
196196
apps/server/src/cli/service.ts+2-2
......@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as Console from "effect/Console";
33import * as Effect from "effect/Effect";
44import * as Layer from "effect/Layer";
......@@ -241,7 +241,7 @@ export const offerServiceDuringOnboarding = Effect.gen(function* () {
241241 }
242242 // A LaunchAgent starts at login and dies at logout; there is no
243243 // enable-linger equivalent on macOS. Do not promise more than that.
244 const platform = yield* HostProcessPlatform;
244 const platform = yield* HostProcess.Platform;
245245 const wanted = yield* Prompt.run(
246246 Prompt.Confirm({
247247 message: installed
apps/server/src/cli/theme.test.ts+2-2
......@@ -14,11 +14,11 @@ import { Command } from "effect/cli";
1414
1515import { cli } from "../binCli.ts";
1616import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
17import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
17import * as HostProcess from "@t3tools/shared/HostProcess";
1818
1919// These force a failure with chmod, which Windows ignores for directories and
2020// cannot use to make a file unreadable, so the failure never happens there.
21const windowsHost = HostProcessPlatform.defaultValue() === "win32";
21const windowsHost = HostProcess.Platform.defaultValue() === "win32";
2222
2323const runCli = (args: ReadonlyArray<string>) =>
2424 Command.runWith(cli, { version: "0.0.0" })(args).pipe(
apps/server/src/cli/triage.ts+2-2
......@@ -14,7 +14,7 @@ import * as NodeChildProcess from "node:child_process";
1414import * as NodeOS from "node:os";
1515import * as NodeReadlinePromises from "node:readline/promises";
1616
17import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
17import * as HostProcess from "@t3tools/shared/HostProcess";
1818import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell";
1919import * as Config from "effect/Config";
2020import * as Console from "effect/Console";
......@@ -193,7 +193,7 @@ export const triageCommand = Command.make("triage", {
193193 releaseTag: /^[^-+]+-(?:nightly|preview)\./.test(version)
194194 ? `v${version} (prerelease build; if this tag does not exist, clone main)`
195195 : `v${version}`,
196 os: `${yield* HostProcessPlatform} ${yield* HostProcessArchitecture} (${NodeOS.release()})`,
196 os: `${yield* HostProcess.Platform} ${yield* HostProcess.Architecture} (${NodeOS.release()})`,
197197 nodeVersion: process.version,
198198 launchedAs: yield* resolveCliCommand("triage"),
199199 server: yield* describeServerProcess(paths.serverRuntimeStatePath),
apps/server/src/cli/uninstall.test.ts+2-2
......@@ -3,7 +3,7 @@ import { assert, it } from "@effect/vitest";
33import * as Effect from "effect/Effect";
44import * as FileSystem from "effect/FileSystem";
55import * as Path from "effect/Path";
6import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
6import * as HostProcess from "@t3tools/shared/HostProcess";
77
88import { findOwnedLauncher } from "./uninstall.ts";
99
......@@ -32,6 +32,6 @@ it.layer(NodeServices.layer)("t3 uninstall launcher", (it) => {
3232 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: theirs, versionsDir }));
3333 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: copy, versionsDir }));
3434 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: undefined, versionsDir }));
35 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),
35 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
3636 );
3737});
apps/server/src/cli/uninstall.ts+6-10
......@@ -4,11 +4,7 @@
44// cannot express: it kills the child when the scope closes.
55import * as NodeChildProcess from "node:child_process";
66
7import {
8 HostProcessEnvironment,
9 HostProcessIsExecutable,
10 HostProcessPlatform,
11} from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
128import * as Console from "effect/Console";
139import * as Effect from "effect/Effect";
1410import * as FileSystem from "effect/FileSystem";
......@@ -58,7 +54,7 @@ export const findOwnedLauncher = Effect.fn("cli.uninstall.find_launcher")(functi
5854}) {
5955 const fs = yield* FileSystem.FileSystem;
6056 const path = yield* Path.Path;
61 const platform = yield* HostProcessPlatform;
57 const platform = yield* HostProcess.Platform;
6258 if (input.launchedAs === undefined) return undefined;
6359 if (platform === "win32") {
6460 const shimPath = yield* findWindowsShim(input.launchedAs);
......@@ -87,7 +83,7 @@ const planUninstall = Effect.fn("cli.uninstall.plan")(function* (input: {
8783 path.resolve(status.installedBaseDir) === path.resolve(input.baseDir);
8884 const versionsDir = pinnedRuntimeVersionsDir(path, input.baseDir);
8985 const runtimeDir = path.dirname(versionsDir);
90 const launchedAs = (yield* HostProcessIsExecutable) ? yield* resolveLauncherPath : undefined;
86 const launchedAs = (yield* HostProcess.IsExecutable) ? yield* resolveLauncherPath : undefined;
9187 const plan: UninstallPlan = {
9288 service: status.supported && status.installed && servesThisHome,
9389 launcher: yield* findOwnedLauncher({ launchedAs, versionsDir }),
......@@ -128,14 +124,14 @@ const runUninstall = Effect.fn("cli.uninstall.run")(function* (input: {
128124 readonly assumeYes: boolean;
129125}) {
130126 const fs = yield* FileSystem.FileSystem;
131 const platform = yield* HostProcessPlatform;
132 const environment = yield* HostProcessEnvironment;
127 const platform = yield* HostProcess.Platform;
128 const environment = yield* HostProcess.Environment;
133129 const service = yield* BootService.BootService;
134130 const plan = yield* planUninstall({ baseDir: input.baseDir });
135131
136132 if (!plan.service && plan.launcher === undefined && plan.runtimeDir === undefined) {
137133 yield* Console.log(`Nothing to remove: t3 is not installed for ${input.baseDir}.`);
138 if (!(yield* HostProcessIsExecutable)) {
134 if (!(yield* HostProcess.IsExecutable)) {
139135 yield* Console.log(
140136 " This t3 runs from a Node script, so it was installed by npm or built from source. Remove it the same way (`npm uninstall -g t3`, or delete the checkout).",
141137 );
apps/server/src/cli/update.test.ts+13-18
......@@ -4,12 +4,7 @@ import * as Effect from "effect/Effect";
44import * as FileSystem from "effect/FileSystem";
55import * as Option from "effect/Option";
66import * as Path from "effect/Path";
7import {
8 HostProcessEnvironment,
9 HostProcessInvokedAs,
10 HostProcessPlatform,
11 HostProcessWorkingDirectory,
12} from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
138
149import { repointLauncher, resolveLauncherPath } from "./update.ts";
1510
......@@ -37,7 +32,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {
3732
3833 assert.deepStrictEqual(Option.getOrUndefined(repointed), launcher);
3934 assert.equal(yield* fs.readLink(launcher), newExe);
40 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),
35 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
4136 );
4237
4338 it.effect("leaves a plain copy or a foreign symlink alone", () =>
......@@ -71,7 +66,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {
7166 }
7267 assert.equal(yield* fs.readLink(foreign), elsewhere);
7368 assert.equal(yield* fs.readLink(otherLauncher), otherHome);
74 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),
69 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
7570 );
7671
7772 it.effect("finds the launcher a bare command name resolved to on PATH", () =>
......@@ -84,26 +79,26 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {
8479 yield* fs.writeFileString(launcher, "");
8580
8681 const bare = yield* resolveLauncherPath.pipe(
87 Effect.provideService(HostProcessInvokedAs, "t3"),
88 Effect.provideService(HostProcessEnvironment, {
82 Effect.provideService(HostProcess.InvokedAs, "t3"),
83 Effect.provideService(HostProcess.Environment, {
8984 PATH: `${path.join(root, "missing")}:${path.join(root, "bin")}`,
9085 }),
91 Effect.provideService(HostProcessWorkingDirectory, root),
86 Effect.provideService(HostProcess.WorkingDirectory, root),
9287 );
9388 const relative = yield* resolveLauncherPath.pipe(
94 Effect.provideService(HostProcessInvokedAs, "./bin/t3"),
95 Effect.provideService(HostProcessEnvironment, { PATH: "" }),
96 Effect.provideService(HostProcessWorkingDirectory, root),
89 Effect.provideService(HostProcess.InvokedAs, "./bin/t3"),
90 Effect.provideService(HostProcess.Environment, { PATH: "" }),
91 Effect.provideService(HostProcess.WorkingDirectory, root),
9792 );
9893 const absent = yield* resolveLauncherPath.pipe(
99 Effect.provideService(HostProcessInvokedAs, "t3"),
100 Effect.provideService(HostProcessEnvironment, { PATH: path.join(root, "missing") }),
101 Effect.provideService(HostProcessWorkingDirectory, root),
94 Effect.provideService(HostProcess.InvokedAs, "t3"),
95 Effect.provideService(HostProcess.Environment, { PATH: path.join(root, "missing") }),
96 Effect.provideService(HostProcess.WorkingDirectory, root),
10297 );
10398
10499 assert.equal(bare, launcher);
105100 assert.equal(relative, launcher);
106101 assert.equal(absent, undefined);
107 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),
102 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
108103 );
109104});
apps/server/src/cli/update.ts+12-19
......@@ -1,11 +1,4 @@
1import {
2 HostProcessArchitecture,
3 HostProcessEnvironment,
4 HostProcessInvokedAs,
5 HostProcessIsExecutable,
6 HostProcessPlatform,
7 HostProcessWorkingDirectory,
8} from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
92import {
103 CLI_RELEASE_BASE_URL_ENV,
114 CLI_RELEASE_CHANNELS,
......@@ -121,7 +114,7 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function
121114}) {
122115 const fs = yield* FileSystem.FileSystem;
123116 const path = yield* Path.Path;
124 const platform = yield* HostProcessPlatform;
117 const platform = yield* HostProcess.Platform;
125118 if (input.launchedAs === undefined) return Option.none<string>();
126119 const ownsTarget = (candidate: string) =>
127120 launcherOwnsVersionsDir(path, input.versionsDir, candidate);
......@@ -170,10 +163,10 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function
170163export const resolveLauncherPath = Effect.gen(function* () {
171164 const path = yield* Path.Path;
172165 const fs = yield* FileSystem.FileSystem;
173 const invokedAs = yield* HostProcessInvokedAs;
174 const cwd = yield* HostProcessWorkingDirectory;
175 const environment = yield* HostProcessEnvironment;
176 const platform = yield* HostProcessPlatform;
166 const invokedAs = yield* HostProcess.InvokedAs;
167 const cwd = yield* HostProcess.WorkingDirectory;
168 const environment = yield* HostProcess.Environment;
169 const platform = yield* HostProcess.Platform;
177170 if (invokedAs.includes("/") || invokedAs.includes("\\")) {
178171 return path.resolve(cwd, invokedAs);
179172 }
......@@ -198,7 +191,7 @@ export const findWindowsShim = Effect.fn("cli.update.find_windows_shim")(functio
198191) {
199192 const fs = yield* FileSystem.FileSystem;
200193 const path = yield* Path.Path;
201 const environment = yield* HostProcessEnvironment;
194 const environment = yield* HostProcess.Environment;
202195 const candidates = [
203196 ...(environment["T3CODE_INSTALL_BIN_DIR"] ? [environment["T3CODE_INSTALL_BIN_DIR"]] : []),
204197 ...(environment["PATH"] ?? environment["Path"] ?? "").split(";"),
......@@ -299,7 +292,7 @@ const findForegroundServer = Effect.fn("cli.update.find_foreground_server")(func
299292const belongsToBootService = Effect.fn("cli.update.belongs_to_boot_service")(function* (
300293 pid: number,
301294) {
302 const platform = yield* HostProcessPlatform;
295 const platform = yield* HostProcess.Platform;
303296 const fs = yield* FileSystem.FileSystem;
304297 const runner = yield* ProcessRunner.ProcessRunner;
305298 if (platform === "linux") {
......@@ -340,9 +333,9 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: {
340333 const fs = yield* FileSystem.FileSystem;
341334 const path = yield* Path.Path;
342335 const runner = yield* ProcessRunner.ProcessRunner;
343 const platform = yield* HostProcessPlatform;
344 const arch = yield* HostProcessArchitecture;
345 const environment = yield* HostProcessEnvironment;
336 const platform = yield* HostProcess.Platform;
337 const arch = yield* HostProcess.Architecture;
338 const environment = yield* HostProcess.Environment;
346339 const httpClient = yield* HttpClient.HttpClient;
347340 const service = yield* BootService.BootService;
348341
......@@ -531,7 +524,7 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: {
531524 ),
532525 );
533526
534 const launchedAs = (yield* HostProcessIsExecutable) ? yield* resolveLauncherPath : undefined;
527 const launchedAs = (yield* HostProcess.IsExecutable) ? yield* resolveLauncherPath : undefined;
535528 const repointed = yield* repointLauncher({
536529 launchedAs,
537530 versionsDir: path.dirname(runtime.versionDir),
apps/server/src/cloud/bootService.test.ts+4-8
......@@ -1,10 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { expect, it } from "@effect/vitest";
3import {
4 HostProcessExecutablePath,
5 HostProcessPlatform,
6 HostProcessUserId,
7} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
84import * as ConfigProvider from "effect/ConfigProvider";
95import * as Duration from "effect/Duration";
106import * as Effect from "effect/Effect";
......@@ -226,9 +222,9 @@ const makeHarness = Effect.fn("test.make_boot_service_harness")(function* (
226222 Effect.provideService(ProcessRunner.ProcessRunner, runner),
227223 Effect.provide(
228224 Layer.mergeAll(
229 Layer.succeed(HostProcessPlatform, platform),
230 Layer.succeed(HostProcessUserId, 501),
231 Layer.succeed(HostProcessExecutablePath, "/usr/bin/t3"),
225 Layer.succeed(HostProcess.Platform, platform),
226 Layer.succeed(HostProcess.UserId, 501),
227 Layer.succeed(HostProcess.ExecutablePath, "/usr/bin/t3"),
232228 Layer.succeed(
233229 HttpClient.HttpClient,
234230 HttpClient.make(() => Effect.die("no release download expected")),
apps/server/src/cloud/bootService.ts+5-10
......@@ -1,9 +1,4 @@
1import {
2 HostProcessArchitecture,
3 HostProcessExecutablePath,
4 HostProcessPlatform,
5 HostProcessUserId,
6} from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
72import * as Config from "effect/Config";
83import * as Context from "effect/Context";
94import * as DateTime from "effect/DateTime";
......@@ -558,10 +553,10 @@ export const make = Effect.fn("cloud.boot_service.make")(function* (input: {
558553 readonly cliVersion: string;
559554 readonly host?: BootServiceHost;
560555}) {
561 const hostExecPath = yield* HostProcessExecutablePath;
562 const platform = yield* HostProcessPlatform;
563 const arch = yield* HostProcessArchitecture;
564 const uid = yield* HostProcessUserId;
556 const hostExecPath = yield* HostProcess.ExecutablePath;
557 const platform = yield* HostProcess.Platform;
558 const arch = yield* HostProcess.Architecture;
559 const uid = yield* HostProcess.UserId;
565560 const httpClient = yield* HttpClient.HttpClient;
566561 const releaseBaseUrl = Option.getOrUndefined(
567562 yield* Config.String(CLI_RELEASE_BASE_URL_ENV).pipe(Config.option),
apps/server/src/cloud/selfUpdate.test.ts+3-3
......@@ -1,7 +1,7 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { expect, it } from "@effect/vitest";
33import { ServerSelfUpdateError, ThreadId } from "@t3tools/contracts";
4import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55import * as Cause from "effect/Cause";
66import * as Deferred from "effect/Deferred";
77import * as Effect from "effect/Effect";
......@@ -120,8 +120,8 @@ const makeHarness = Effect.fn("test.make_self_update_harness")(function* (
120120 },
121121 ),
122122 Effect.provideService(HttpClient.HttpClient, releaseHttpClient(order)),
123 Effect.provideService(HostProcessPlatform, "linux"),
124 Effect.provideService(HostProcessArchitecture, "x64"),
123 Effect.provideService(HostProcess.Platform, "linux"),
124 Effect.provideService(HostProcess.Architecture, "x64"),
125125 Effect.provide(ServerConfig.layer({ ...config, mode: options.mode ?? "web" })),
126126 );
127127 return { selfUpdate, order };
apps/server/src/cloud/selfUpdate.ts+3-3
......@@ -6,7 +6,7 @@ import {
66 type ServerSelfUpdateResult,
77 type ThreadId,
88} from "@t3tools/contracts";
9import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1010import * as Cause from "effect/Cause";
1111import * as Config from "effect/Config";
1212import * as Context from "effect/Context";
......@@ -176,8 +176,8 @@ export const make = Effect.fn("cloud.server_self_update.make")(function* () {
176176 const runner = yield* ProcessRunner.ProcessRunner;
177177 const fs = yield* FileSystem.FileSystem;
178178 const path = yield* Path.Path;
179 const platform = yield* HostProcessPlatform;
180 const arch = yield* HostProcessArchitecture;
179 const platform = yield* HostProcess.Platform;
180 const arch = yield* HostProcess.Architecture;
181181 // Archive-distributed targets download from GitHub Releases. The client is
182182 // optional so callers without one (tests, npm-only hosts) still construct.
183183 const httpClient = yield* HttpClient.HttpClient;
apps/server/src/cloud/serviceLauncherClient.test.ts+2-2
......@@ -1,5 +1,5 @@
11import { expect, it } from "@effect/vitest";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Effect from "effect/Effect";
44import * as Fiber from "effect/Fiber";
55
......@@ -45,7 +45,7 @@ class FakeLauncherProcess {
4545const makeClient = (host: FakeLauncherProcess, currentVersion: string) =>
4646 ServiceLauncherClient.make({ currentVersion }).pipe(
4747 Effect.provideService(ServiceLauncherClient.ServiceLauncherHostProcess, host),
48 Effect.provideService(HostProcessEnvironment, host.env),
48 Effect.provideService(HostProcess.Environment, host.env),
4949 );
5050
5151it.effect("waits for the launcher to durably commit the trial update ID", () =>
apps/server/src/cloud/serviceLauncherClient.ts+2-2
......@@ -1,5 +1,5 @@
11import type { ServerSelfUpdateOutcome } from "@t3tools/contracts";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Context from "effect/Context";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
......@@ -114,7 +114,7 @@ export class ServiceLauncherClient extends Context.Service<
114114const resolveStartup = Effect.fn("cloud.service_launcher_client.resolve_startup")(
115115 function* (options?: { readonly currentVersion?: string }) {
116116 const host = yield* ServiceLauncherHostProcess;
117 const environment = yield* HostProcessEnvironment;
117 const environment = yield* HostProcess.Environment;
118118 const currentVersion = options?.currentVersion ?? packageJson.version;
119119 const rawContext = environment[SERVICE_LAUNCHER_CONTEXT_ENV];
120120 const context = rawContext === undefined ? undefined : decodeServiceLauncherContext(rawContext);
apps/server/src/device/AgentDeviceShim.ts+2-2
......@@ -5,7 +5,7 @@
55 * types `agent-device …` and gets the version the injected instructions were
66 * written for, regardless of what is or is not globally installed.
77 */
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99import { resolveNodeExecutable } from "@t3tools/shared/nodeRuntime";
1010import * as Effect from "effect/Effect";
1111import * as FileSystem from "effect/FileSystem";
......@@ -20,7 +20,7 @@ export const ensureAgentDeviceShim = Effect.fn("AgentDeviceShim.ensure")(functio
2020 const { entryPath } = input;
2121 const fs = yield* FileSystem.FileSystem;
2222 const path = yield* Path.Path;
23 const platform = yield* HostProcessPlatform;
23 const platform = yield* HostProcess.Platform;
2424 const node = yield* resolveNodeExecutable("Device automation");
2525 const shimDir = path.join(input.stateDir, SHIM_DIR);
2626 yield* fs.makeDirectory(shimDir, { recursive: true });
apps/server/src/device/AgentDeviceTarget.test.ts+4-8
......@@ -1,9 +1,5 @@
11// @effect-diagnostics nodeBuiltinImport:off - exercises concurrent real CLI subprocesses.
2import {
3 HostProcessExecutablePath,
4 HostProcessIsExecutable,
5 HostProcessPlatform,
6} from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
73import { describe, expect, it } from "@effect/vitest";
84import * as NodeChildProcess from "node:child_process";
95import * as NodeUtil from "node:util";
......@@ -26,7 +22,7 @@ describe("host-bound agent commands", () => {
2622 const fs = yield* FileSystem.FileSystem;
2723 const path = yield* Path.Path;
2824 const temp = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-target-" });
29 const platform = yield* HostProcessPlatform;
25 const platform = yield* HostProcess.Platform;
3026 const dir = path.join(
3127 temp,
3228 platform === "win32" ? "paths with spaces" : "quotes '\" $HOME `literal`",
......@@ -92,8 +88,8 @@ if (process.env.AGENT_DEVICE_DAEMON_BASE_URL) process.exit(2);`,
9288 }
9389 }).pipe(
9490 Effect.scoped,
95 Effect.provideService(HostProcessIsExecutable, true),
96 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),
91 Effect.provideService(HostProcess.IsExecutable, true),
92 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
9793 Effect.provide(NodeServices.layer),
9894 ),
9995 );
apps/server/src/device/LocalDeviceHost.test.ts+10-15
......@@ -1,11 +1,6 @@
11import { describe, expect, it } from "@effect/vitest";
22import * as NodePath from "@effect/platform-node/NodePath";
3import {
4 HostProcessEnvironment,
5 HostProcessPlatform,
6 HostProcessIsExecutable,
7 HostProcessUserId,
8} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
94import * as Effect from "effect/Effect";
105import * as Layer from "effect/Layer";
116import * as Option from "effect/Option";
......@@ -26,8 +21,8 @@ const diagnose = (
2621 platform: NodeJS.Platform = "darwin",
2722) =>
2823 LocalDeviceHost.__testing.platformReason("android").pipe(
29 Effect.provideService(HostProcessEnvironment, environment),
30 Effect.provideService(HostProcessPlatform, platform),
24 Effect.provideService(HostProcess.Environment, environment),
25 Effect.provideService(HostProcess.Platform, platform),
3126 Effect.provideService(
3227 FileSystem.FileSystem,
3328 FileSystem.makeNoop({
......@@ -155,8 +150,8 @@ it.effect(
155150 ] as const) {
156151 const environment = { PATH: "/usr/bin", XDG_RUNTIME_DIR: runtimeDir };
157152 const result = yield* LocalDeviceHost.__testing.hubEnvironment(environment).pipe(
158 Effect.provideService(HostProcessPlatform, platform),
159 Effect.provideService(HostProcessUserId, uid),
153 Effect.provideService(HostProcess.Platform, platform),
154 Effect.provideService(HostProcess.UserId, uid),
160155 Effect.provideService(
161156 FileSystem.FileSystem,
162157 FileSystem.makeNoop({
......@@ -176,8 +171,8 @@ it.effect(
176171 const missing = yield* LocalDeviceHost.__testing
177172 .hubEnvironment({})
178173 .pipe(
179 Effect.provideService(HostProcessPlatform, "linux"),
180 Effect.provideService(HostProcessUserId, 1000),
174 Effect.provideService(HostProcess.Platform, "linux"),
175 Effect.provideService(HostProcess.UserId, 1000),
181176 Effect.provideService(FileSystem.FileSystem, FileSystem.makeNoop({})),
182177 );
183178 expect(missing.XDG_RUNTIME_DIR).toBeUndefined();
......@@ -192,8 +187,8 @@ it.effect(
192187 const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-consent-" });
193188 const host = yield* LocalDeviceHost.make().pipe(
194189 Effect.provide(Layer.mergeAll(ServerConfig.layerTest(baseDir, baseDir), NetService.layer)),
195 Effect.provideService(HostProcessEnvironment, { HOME: baseDir, PATH: "" }),
196 Effect.provideService(HostProcessPlatform, "linux"),
190 Effect.provideService(HostProcess.Environment, { HOME: baseDir, PATH: "" }),
191 Effect.provideService(HostProcess.Platform, "linux"),
197192 Effect.provideService(
198193 ChildProcessSpawner.ChildProcessSpawner,
199194 ChildProcessSpawner.make(() =>
......@@ -213,7 +208,7 @@ it.effect(
213208 expect(yield* host.current).toBeNull();
214209 const error = yield* host
215210 .ensureReady(() => Effect.die("Must not install without Node"))
216 .pipe(Effect.flip, Effect.provideService(HostProcessIsExecutable, true));
211 .pipe(Effect.flip, Effect.provideService(HostProcess.IsExecutable, true));
217212 expect(error.message).toContain("Local device support requires Node.js");
218213 expect(error.message).toContain("Install Node.js");
219214 yield* host.stop;
apps/server/src/device/LocalDeviceHost.ts+10-14
......@@ -19,11 +19,7 @@ import {
1919 LOCAL_DEVICE_HOST_ID,
2020} from "@t3tools/contracts";
2121import { waitForHttpReady } from "@t3tools/shared/httpReadiness";
22import {
23 HostProcessEnvironment,
24 HostProcessPlatform,
25 HostProcessUserId,
26} from "@t3tools/shared/hostProcess";
22import * as HostProcess from "@t3tools/shared/HostProcess";
2723import {
2824 resolveNodeExecutable,
2925 type NodeRuntimeUnavailableError,
......@@ -107,7 +103,7 @@ interface RunningHost {
107103const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* (
108104 platform: DevicePlatform,
109105): Effect.fn.Return<string | null, never, FileSystem.FileSystem | Path.Path> {
110 const hostPlatform = yield* HostProcessPlatform;
106 const hostPlatform = yield* HostProcess.Platform;
111107 if (platform === "ios") {
112108 if (hostPlatform !== "darwin") return "iOS Simulators need macOS with Xcode.";
113109 if (!(yield* isCommandAvailable("xcrun"))) return "Xcode command line tools were not found.";
......@@ -132,8 +128,8 @@ const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* (
132128const androidSdk = Effect.gen(function* () {
133129 const fs = yield* FileSystem.FileSystem;
134130 const path = yield* Path.Path;
135 const environment = yield* HostProcessEnvironment;
136 const platform = yield* HostProcessPlatform;
131 const environment = yield* HostProcess.Environment;
132 const platform = yield* HostProcess.Platform;
137133 const home = environment.HOME ?? environment.USERPROFILE ?? "";
138134 const explicit = environment.ANDROID_HOME?.trim() || environment.ANDROID_SDK_ROOT?.trim();
139135 const candidates = explicit
......@@ -208,8 +204,8 @@ const hubEnvironment = Effect.fn("LocalDeviceHost.hubEnvironment")(function* (
208204 environment: NodeJS.ProcessEnv,
209205) {
210206 const env: NodeJS.ProcessEnv = { ...environment, FORCE_COLOR: "0", NO_COLOR: "1" };
211 const platform = yield* HostProcessPlatform;
212 const uid = yield* HostProcessUserId;
207 const platform = yield* HostProcess.Platform;
208 const uid = yield* HostProcess.UserId;
213209 if (platform === "linux" && env.XDG_RUNTIME_DIR === undefined && uid !== undefined) {
214210 // SSH sessions may omit the directory where the emulator publishes its gRPC token.
215211 const runtimeDir = `/run/user/${uid}`;
......@@ -234,8 +230,8 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
234230 const net = yield* NetService.NetService;
235231 const runner = yield* ProcessRunner.ProcessRunner;
236232 const httpClient = yield* HttpClient.HttpClient;
237 const environment = yield* HostProcessEnvironment;
238 const hostPlatform = yield* HostProcessPlatform;
233 const environment = yield* HostProcess.Environment;
234 const hostPlatform = yield* HostProcess.Platform;
239235 const sdk = yield* androidSdk;
240236 const hostEnvironment = deviceHostEnvironment(environment, sdk.root, hostPlatform, path);
241237 const startLock = yield* Semaphore.make(1);
......@@ -406,7 +402,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
406402 stderr: "pipe",
407403 env: yield* hubEnvironment(hostEnvironment).pipe(
408404 Effect.provideService(FileSystem.FileSystem, fs),
409 Effect.provideService(HostProcessPlatform, hostPlatform),
405 Effect.provideService(HostProcess.Platform, hostPlatform),
410406 ),
411407 },
412408 ),
......@@ -598,7 +594,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
598594 const nodePath = yield* resolveNodeExecutable("Local device support", hostEnvironment).pipe(
599595 Effect.provideService(FileSystem.FileSystem, fs),
600596 Effect.provideService(Path.Path, path),
601 Effect.provideService(HostProcessPlatform, hostPlatform),
597 Effect.provideService(HostProcess.Platform, hostPlatform),
602598 );
603599 const installed = yield* isDeviceHubInstalled(config.baseDir).pipe(
604600 Effect.provideService(FileSystem.FileSystem, fs),
apps/server/src/device/sshDeviceScript.test.ts+4-4
......@@ -1,6 +1,6 @@
11// @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - verifies generated remote scripts using real shell and Node processes.
22import * as Effect from "effect/Effect";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import { describe, expect, it } from "@effect/vitest";
55import * as NodeChildProcess from "node:child_process";
66import * as NodeFSP from "node:fs/promises";
......@@ -14,7 +14,7 @@ const exec = NodeUtil.promisify(NodeChildProcess.execFile);
1414
1515it.effect("finds Android Studio Java for a non-interactive SSH session", () =>
1616 Effect.gen(function* () {
17 if ((yield* HostProcessPlatform) === "win32") return;
17 if ((yield* HostProcess.Platform) === "win32") return;
1818 yield* Effect.promise(async () => {
1919 const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-ssh-java-"));
2020 try {
......@@ -38,7 +38,7 @@ it.effect("finds Android Studio Java for a non-interactive SSH session", () =>
3838
3939it.effect("preserves shell metacharacters and newlines in remote arguments", () =>
4040 Effect.gen(function* () {
41 if ((yield* HostProcessPlatform) === "win32") return;
41 if ((yield* HostProcess.Platform) === "win32") return;
4242 yield* Effect.promise(async () => {
4343 const value = "quotes ' \" ; $(echo expanded) $HOME\nnext line";
4444 const result = await exec("sh", ["-c", `printf %s ${quoteRemoteArg(value)}`]);
......@@ -50,7 +50,7 @@ it.effect("preserves shell metacharacters and newlines in remote arguments", ()
5050describe("remote helper lifecycle", () => {
5151 it.effect("reuses its own healthy helpers and stops only its own runtime", () =>
5252 Effect.gen(function* () {
53 if ((yield* HostProcessPlatform) === "win32") return;
53 if ((yield* HostProcess.Platform) === "win32") return;
5454 yield* Effect.promise(async () => {
5555 const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-remote-script-"));
5656 const bin = NodePath.join(home, "bin");
apps/server/src/environment/RemoteOpenTargets.test.ts+2-2
......@@ -1,5 +1,5 @@
11import { it } from "@effect/vitest";
2import { HostProcessHostname } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as NetService from "@t3tools/shared/Net";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
......@@ -54,7 +54,7 @@ const resolveTargets = (input: {
5454 readonly hostname: string;
5555}) =>
5656 Effect.flatMap(RemoteOpenTargets.RemoteOpenTargets, (service) => service.resolveTargets()).pipe(
57 Effect.provideService(HostProcessHostname, input.hostname),
57 Effect.provideService(HostProcess.Hostname, input.hostname),
5858 Effect.provide(
5959 RemoteOpenTargets.layer.pipe(
6060 Layer.provide(Layer.mergeAll(layerNet(input.sshd), layerSpawner(input.tailscale))),
apps/server/src/environment/RemoteOpenTargets.ts+2-2
......@@ -9,7 +9,7 @@
99 * on the tailnet; `<hostname>.local` only on the same LAN).
1010 */
1111import { type RemoteOpenTarget } from "@t3tools/contracts";
12import { HostProcessHostname } from "@t3tools/shared/hostProcess";
12import * as HostProcess from "@t3tools/shared/HostProcess";
1313import * as NetService from "@t3tools/shared/Net";
1414import { readTailscaleStatus } from "@t3tools/tailscale";
1515import * as Context from "effect/Context";
......@@ -58,7 +58,7 @@ export const make = Effect.gen(function* () {
5858
5959 // os.hostname() may already be an FQDN (macOS often reports
6060 // "Name.local"); mDNS names are always `<first-label>.local`.
61 const hostname = yield* HostProcessHostname;
61 const hostname = yield* HostProcess.Hostname;
6262 const shortHostname = hostname.split(".")[0]?.trim();
6363 if (shortHostname !== undefined && shortHostname.length > 0) {
6464 targets.push({ kind: "mdns", host: `${shortHostname}.local` });
apps/server/src/environment/ServerEnvironment.test.ts+5-10
......@@ -10,12 +10,7 @@ import * as PlatformError from "effect/PlatformError";
1010import * as Schema from "effect/Schema";
1111
1212import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability";
13import {
14 HostProcessArguments,
15 HostProcessEnvironment,
16 HostProcessIsExecutable,
17 HostProcessPlatform,
18} from "@t3tools/shared/hostProcess";
13import * as HostProcess from "@t3tools/shared/HostProcess";
1914import * as OtelEnvironment from "@t3tools/shared/otelEnvironment";
2015
2116import * as ServerSecretStore from "../auth/ServerSecretStore.ts";
......@@ -112,10 +107,10 @@ it.layer(NodeServices.layer)("ServerEnvironmentLive", (it) => {
112107 Layer.provide(ServerConfig.layer({ ...config, mode })),
113108 ),
114109 ),
115 Effect.provideService(HostProcessArguments, ["node", entry]),
116 Effect.provideService(HostProcessIsExecutable, false),
117 Effect.provideService(HostProcessPlatform, "linux"),
118 Effect.provideService(HostProcessEnvironment, {}),
110 Effect.provideService(HostProcess.Arguments, ["node", entry]),
111 Effect.provideService(HostProcess.IsExecutable, false),
112 Effect.provideService(HostProcess.Platform, "linux"),
113 Effect.provideService(HostProcess.Environment, {}),
119114 );
120115 expect(descriptor.capabilities.serverInstallation).toEqual(
121116 mode === "web" ? { kind: "npm-global", prefix } : undefined,
apps/server/src/environment/ServerEnvironment.ts+3-3
......@@ -4,7 +4,7 @@ import {
44 PROVIDER_SEND_TURN_MAX_FILE_BYTES,
55 type ExecutionEnvironmentDescriptor,
66} from "@t3tools/contracts";
7import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
88import * as Context from "effect/Context";
99import * as Crypto from "effect/Crypto";
1010import * as Effect from "effect/Effect";
......@@ -186,8 +186,8 @@ export const make = Effect.gen(function* () {
186186 const serverConfig = yield* ServerConfig.ServerConfig;
187187 const secrets = yield* ServerSecretStore.ServerSecretStore;
188188 const identity = yield* ServerEnvironmentIdentity;
189 const hostPlatform = yield* HostProcessPlatform;
190 const hostArchitecture = yield* HostProcessArchitecture;
189 const hostPlatform = yield* HostProcess.Platform;
190 const hostArchitecture = yield* HostProcess.Architecture;
191191 const environmentId = yield* identity.getEnvironmentId;
192192 const cwdBaseName = path.basename(serverConfig.cwd).trim();
193193 const label = yield* resolveServerEnvironmentLabel({ cwdBaseName });
apps/server/src/environment/ServerEnvironmentLabel.test.ts+3-3
......@@ -7,7 +7,7 @@ import * as PlatformError from "effect/PlatformError";
77import * as References from "effect/References";
88import * as Schema from "effect/Schema";
99import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
10import { HostProcessHostname, HostProcessPlatform } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111import { vi } from "vite-plus/test";
1212
1313import * as ProcessRunner from "../processRunner.ts";
......@@ -52,8 +52,8 @@ const withHostPlatform = <ROut, E, RIn>(
5252) =>
5353 Layer.mergeAll(
5454 layer,
55 Layer.succeed(HostProcessPlatform, platform),
56 Layer.succeed(HostProcessHostname, hostname),
55 Layer.succeed(HostProcess.Platform, platform),
56 Layer.succeed(HostProcess.Hostname, hostname),
5757 );
5858
5959afterEach(() => {
apps/server/src/environment/ServerEnvironmentLabel.ts+3-3
......@@ -1,4 +1,4 @@
1import { HostProcessHostname, HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as Effect from "effect/Effect";
33import * as FileSystem from "effect/FileSystem";
44import * as Option from "effect/Option";
......@@ -151,7 +151,7 @@ const runFriendlyLabelCommand = Effect.fn("runFriendlyLabelCommand")(function* (
151151});
152152
153153const resolveFriendlyHostLabel = Effect.fn("resolveFriendlyHostLabel")(function* () {
154 const platform = yield* HostProcessPlatform;
154 const platform = yield* HostProcess.Platform;
155155 if (platform === "darwin") {
156156 return yield* runFriendlyLabelCommand({
157157 probe: "macos-computer-name",
......@@ -187,7 +187,7 @@ export const resolveServerEnvironmentLabel = Effect.fn("resolveServerEnvironment
187187 return friendlyHostLabel;
188188 }
189189
190 const hostname = normalizeLabel(yield* HostProcessHostname);
190 const hostname = normalizeLabel(yield* HostProcess.Hostname);
191191 if (hostname) {
192192 return hostname;
193193 }
apps/server/src/environment/ServerEnvironmentMachine.test.ts+2-2
......@@ -4,7 +4,7 @@ import * as FileSystem from "effect/FileSystem";
44import * as Layer from "effect/Layer";
55import * as PlatformError from "effect/PlatformError";
66import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
7import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
88import { vi } from "vite-plus/test";
99
1010import * as ProcessRunner from "../processRunner.ts";
......@@ -52,7 +52,7 @@ const layerDmiFileSystem = (files: Readonly<Record<string, string>>) =>
5252 });
5353
5454const withPlatform = (platform: NodeJS.Platform, fileSystem = FileSystem.layerNoop({})) =>
55 Layer.mergeAll(layerProcessRunnerTest, fileSystem, Layer.succeed(HostProcessPlatform, platform));
55 Layer.mergeAll(layerProcessRunnerTest, fileSystem, Layer.succeed(HostProcess.Platform, platform));
5656
5757afterEach(() => {
5858 runMock.mockReset();
apps/server/src/environment/ServerEnvironmentMachine.ts+2-2
......@@ -1,5 +1,5 @@
11import type { EnvironmentMachineKind } from "@t3tools/contracts";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Effect from "effect/Effect";
44import * as FileSystem from "effect/FileSystem";
55
......@@ -161,7 +161,7 @@ const detectLinuxMachineKind = Effect.fn("detectLinuxMachineKind")(function* ()
161161
162162export const detectServerEnvironmentMachineKind = Effect.fn("detectServerEnvironmentMachineKind")(
163163 function* () {
164 const platform = yield* HostProcessPlatform;
164 const platform = yield* HostProcess.Platform;
165165 switch (platform) {
166166 case "darwin":
167167 return yield* detectDarwinMachineKind();
apps/server/src/htmlRender/HtmlRender.test.ts+5-5
......@@ -2,7 +2,7 @@
22import * as NodeServices from "@effect/platform-node/NodeServices";
33import { describe, expect, it } from "@effect/vitest";
44import { ThreadId } from "@t3tools/contracts";
5import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66import {
77 HTML_RENDER_MEASURE_FONTS,
88 HTML_RENDER_MEASURE_WIDTHS,
......@@ -238,7 +238,7 @@ describe("HtmlRender", () => {
238238 "screenshots the page in headless Chrome with the requested theme and every console level",
239239 (ctx) =>
240240 Effect.gen(function* () {
241 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];
241 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
242242 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
243243 yield* Effect.gen(function* () {
244244 const htmlRender = yield* HtmlRender.HtmlRender;
......@@ -292,7 +292,7 @@ describe("HtmlRender", () => {
292292 "keeps every local file but the page itself out of the browser",
293293 (ctx) =>
294294 Effect.gen(function* () {
295 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];
295 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
296296 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
297297 yield* Effect.gen(function* () {
298298 const fileSystem = yield* FileSystem.FileSystem;
......@@ -323,7 +323,7 @@ describe("HtmlRender", () => {
323323 "keeps the page off this machine's local network",
324324 (ctx) =>
325325 Effect.gen(function* () {
326 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];
326 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
327327 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
328328 // The page's connections go through a proxy that only reaches public
329329 // addresses, and WebRTC is gone. Each line below is a way out that
......@@ -381,7 +381,7 @@ describe("HtmlRender", () => {
381381 "measures a published page at every client width with a fresh load each",
382382 (ctx) =>
383383 Effect.gen(function* () {
384 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];
384 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
385385 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
386386 yield* Effect.gen(function* () {
387387 const htmlRender = yield* HtmlRender.HtmlRender;
apps/server/src/htmlRender/HtmlRender.ts+2-2
......@@ -1,5 +1,5 @@
11import type { ThreadId } from "@t3tools/contracts";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import {
44 clampHtmlRenderHeight,
55 HTML_RENDER_COLUMN_WIDTH,
......@@ -341,7 +341,7 @@ const make = Effect.gen(function* () {
341341 const browsers = yield* Semaphore.make(MAX_CONCURRENT_BROWSERS);
342342 // Chrome's sandbox stays on unless the operator explicitly turns it off.
343343 // Chrome also refuses it as root, where that opt-out is the only way to run.
344 const noSandbox = PreviewBrowserHost.sandboxDisabled(yield* HostProcessEnvironment);
344 const noSandbox = PreviewBrowserHost.sandboxDisabled(yield* HostProcess.Environment);
345345 const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND);
346346
347347 /** Runs one browser launch; a host that cannot start it gets setup steps instead. */
apps/server/src/keybindings.test.ts+2-2
......@@ -12,7 +12,7 @@ import * as Schema from "effect/Schema";
1212import * as ServerConfig from "./config.ts";
1313import * as Keybindings from "./keybindings.ts";
1414import { KeybindingsConfigError, MAX_KEYBINDINGS_COUNT } from "@t3tools/contracts";
15import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
1616
1717const KeybindingsConfigJson = Schema.fromJsonString(KeybindingsConfig);
1818const encodeKeybindingsConfigJson = Schema.encodeEffect(KeybindingsConfigJson);
......@@ -564,7 +564,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => {
564564 );
565565
566566 // chmod cannot make a directory unwritable on Windows, so the write succeeds.
567 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
567 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
568568 "fails when config directory is not writable",
569569 () =>
570570 Effect.gen(function* () {
apps/server/src/mcp/toolkits/device/handlers.ts+2-2
......@@ -9,7 +9,7 @@ import {
99} from "@t3tools/contracts";
1010import * as Effect from "effect/Effect";
1111import * as Path from "effect/Path";
12import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
12import * as HostProcess from "@t3tools/shared/HostProcess";
1313import * as ServerConfig from "../../../config.ts";
1414import { ensureAgentDeviceShim } from "../../../device/AgentDeviceShim.ts";
1515import { nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";
......@@ -179,7 +179,7 @@ const handlers = {
179179 const targetArgs = [...agentDeviceTargetArgs(device), ...agentArgs];
180180 const config = yield* ServerConfig.ServerConfig;
181181 const path = yield* Path.Path;
182 const platform = yield* HostProcessPlatform;
182 const platform = yield* HostProcess.Platform;
183183 const shimDir = yield* ensureAgentDeviceShim({
184184 entryPath: yield* devices.agentCli,
185185 stateDir: config.stateDir,
apps/server/src/observability/HeapSnapshot.ts+2-2
......@@ -2,7 +2,7 @@
22import * as NodePath from "node:path";
33import * as NodeV8 from "node:v8";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66import * as DateTime from "effect/DateTime";
77import * as Effect from "effect/Effect";
88import * as FileSystem from "effect/FileSystem";
......@@ -40,7 +40,7 @@ export const writeHeapSnapshot = Effect.fn("server.heapSnapshot", { root: true }
4040 */
4141export const layer = Layer.effectDiscard(
4242 Effect.gen(function* () {
43 if ((yield* HostProcessPlatform) === "win32") return;
43 if ((yield* HostProcess.Platform) === "win32") return;
4444 const { logsDir } = yield* ServerConfig.ServerConfig;
4545 const runFork = Effect.runForkWith(yield* Effect.context<FileSystem.FileSystem>());
4646 const onSignal = () => void runFork(writeHeapSnapshot(logsDir));
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts+9-9
......@@ -27,7 +27,7 @@ import {
2727 type OrchestrationV2ProviderThread,
2828} from "@t3tools/contracts";
2929import { GrokSettings } from "@t3tools/provider-grok/settings";
30import { HostProcessIsExecutable, HostProcessPlatform } from "@t3tools/shared/hostProcess";
30import * as HostProcess from "@t3tools/shared/HostProcess";
3131import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
3232import * as DateTime from "effect/DateTime";
3333import * as Deferred from "effect/Deferred";
......@@ -705,7 +705,7 @@ describe("AcpAdapterV2", () => {
705705 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
706706 const path = yield* Path.Path;
707707 const selfInvocation = yield* resolveSelfInvocation().pipe(
708 Effect.provideService(HostProcessIsExecutable, true),
708 Effect.provideService(HostProcess.IsExecutable, true),
709709 );
710710 const mockAgentPath = yield* path.fromFileUrl(
711711 new URL("../../../scripts/acp-mock-agent.ts", import.meta.url),
......@@ -1833,7 +1833,7 @@ describe("AcpAdapterV2", () => {
18331833
18341834 it.live("cleans detached fixtures when an assertion aborts the test scope", () =>
18351835 Effect.gen(function* () {
1836 if ((yield* HostProcessPlatform) !== "linux") return;
1836 if ((yield* HostProcess.Platform) !== "linux") return;
18371837 const fileSystem = yield* FileSystem.FileSystem;
18381838 let published: ReadonlyArray<number> = [];
18391839 const failed = yield* Effect.scoped(
......@@ -1947,7 +1947,7 @@ describe("AcpAdapterV2", () => {
19471947
19481948 it.live("reaps detached native work when the provider exits before explicit teardown", () =>
19491949 Effect.gen(function* () {
1950 if ((yield* HostProcessPlatform) !== "linux") return;
1950 if ((yield* HostProcess.Platform) !== "linux") return;
19511951 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
19521952 const fileSystem = yield* FileSystem.FileSystem;
19531953 const path = yield* Path.Path;
......@@ -2026,7 +2026,7 @@ describe("AcpAdapterV2", () => {
20262026
20272027 it.live("surfaces reduced guarantee when delegated cgroup containment is unavailable", () =>
20282028 Effect.gen(function* () {
2029 if ((yield* HostProcessPlatform) !== "linux") return;
2029 if ((yield* HostProcess.Platform) !== "linux") return;
20302030 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
20312031 const path = yield* Path.Path;
20322032 const selfInvocation = yield* resolveSelfInvocation();
......@@ -3100,7 +3100,7 @@ describe("AcpAdapterV2", () => {
31003100 instanceId,
31013101 settings: DEFAULT_GROK_SETTINGS,
31023102 environment: {},
3103 hostPlatform: yield* HostProcessPlatform,
3103 hostPlatform: yield* HostProcess.Platform,
31043104 selfInvocation: yield* resolveSelfInvocation(),
31053105 // Production Grok runtimes are wrapped by the x.ai prompt runtime.
31063106 makeRuntime: (input) =>
......@@ -3147,7 +3147,7 @@ describe("AcpAdapterV2", () => {
31473147 instanceId,
31483148 settings: DEFAULT_GROK_SETTINGS,
31493149 environment: {},
3150 hostPlatform: yield* HostProcessPlatform,
3150 hostPlatform: yield* HostProcess.Platform,
31513151 selfInvocation: yield* resolveSelfInvocation(),
31523152 // Production Grok runtimes are wrapped by the x.ai prompt runtime.
31533153 makeRuntime: (input) =>
......@@ -13147,7 +13147,7 @@ describe("AcpAdapterV2", () => {
1314713147
1314813148 it.live("direct Stop skips uninterruptible ACP cancel and recovers after native teardown", () =>
1314913149 Effect.gen(function* () {
13150 if ((yield* HostProcessPlatform) !== "linux") return;
13150 if ((yield* HostProcess.Platform) !== "linux") return;
1315113151 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
1315213152 const fileSystem = yield* FileSystem.FileSystem;
1315313153 const idAllocator = yield* IdAllocator.IdAllocatorV2;
......@@ -13567,7 +13567,7 @@ describe("AcpAdapterV2", () => {
1356713567
1356813568 it.live("restart_active terminates native work and reloads a clean runtime", () =>
1356913569 Effect.gen(function* () {
13570 if ((yield* HostProcessPlatform) !== "linux") return;
13570 if ((yield* HostProcess.Platform) !== "linux") return;
1357113571 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
1357213572 const fileSystem = yield* FileSystem.FileSystem;
1357313573 const idAllocator = yield* IdAllocator.IdAllocatorV2;
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts+2-2
......@@ -47,7 +47,7 @@ import * as Stream from "effect/Stream";
4747import * as TestClock from "effect/testing/TestClock";
4848import { Tool } from "effect/ai";
4949import { formatClaudeResumeCompactionQuestion } from "@t3tools/shared/claudeCompaction";
50import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
50import * as HostProcess from "@t3tools/shared/HostProcess";
5151import { SpawnExecutableResolution } from "@t3tools/shared/shell";
5252
5353import { attachmentRelativePath } from "../../attachmentStore.ts";
......@@ -1171,7 +1171,7 @@ describe("ClaudeAdapterV2 executable path", () => {
11711171 const npmDir = "C:\\Users\\dev\\AppData\\Roaming\\npm";
11721172 const packageExe = `${npmDir}\\node_modules\\@anthropic-ai\\claude-code\\bin\\claude.exe`;
11731173 const executablePaths = yield* captureSdkExecutablePaths("claude").pipe(
1174 Effect.provideService(HostProcessPlatform, "win32"),
1174 Effect.provideService(HostProcess.Platform, "win32"),
11751175 Effect.provideService(SpawnExecutableResolution, () => `${npmDir}\\claude.cmd`),
11761176 Effect.provideService(ClaudeExecutableFileCheck, (filePath) => filePath === packageExe),
11771177 );
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts+2-2
......@@ -8,7 +8,7 @@ import {
88 type SDKUserMessage,
99} from "@anthropic-ai/claude-agent-sdk";
1010import * as NodeServices from "@effect/platform-node/NodeServices";
11import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
11import * as HostProcess from "@t3tools/shared/HostProcess";
1212import { SpawnExecutableResolution } from "@t3tools/shared/shell";
1313import {
1414 ProviderReplayEntry,
......@@ -1440,7 +1440,7 @@ async function recordMessagesUntilToolUse(input: {
14401440const resolveClaudeRecordingExecutablePath = Effect.fn("resolveClaudeRecordingExecutablePath")(
14411441 function* (environment: NodeJS.ProcessEnv) {
14421442 const resolveExecutable = yield* SpawnExecutableResolution;
1443 const platform = yield* HostProcessPlatform;
1443 const platform = yield* HostProcess.Platform;
14441444 const resolved = resolveExecutable("claude", platform, environment);
14451445 if (resolved === undefined) {
14461446 return undefined;
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts+4-4
......@@ -31,7 +31,7 @@ import type {
3131 WebSearchOutput,
3232} from "@anthropic-ai/claude-agent-sdk/sdk-tools";
3333import { parseCliArgs } from "@t3tools/shared/cliArgs";
34import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
34import * as HostProcess from "@t3tools/shared/HostProcess";
3535import { applyClaudePromptEffortPrefix } from "@t3tools/shared/model";
3636import {
3737 CLAUDE_RESUME_COMPACTION_NEVER_ANSWER,
......@@ -8176,7 +8176,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")(
81768176 ) {
81778177 const { instanceId, environment, enabled, config } = input;
81788178 const fileSystem = yield* FileSystem.FileSystem;
8179 const hostEnvironment = yield* HostProcessEnvironment;
8179 const hostEnvironment = yield* HostProcess.Environment;
81808180 const idAllocator = yield* IdAllocator.IdAllocatorV2;
81818181 const queryRunner = yield* ClaudeAgentSdkQueryRunner;
81828182 const serverConfig = yield* ServerConfig.ServerConfig;
......@@ -8186,7 +8186,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")(
81868186 const path = yield* Path.Path;
81878187 const crypto = yield* Crypto.Crypto;
81888188 const binaryPath = yield* resolveClaudeSdkExecutablePath(
8189 expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),
8189 expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
81908190 claudeEnvironment,
81918191 );
81928192 return yield* makeClaudeAdapterV2({
......@@ -8231,7 +8231,7 @@ const makeDefaultClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2.layer")(function*
82318231 const fileSystem = yield* FileSystem.FileSystem;
82328232 const path = yield* Path.Path;
82338233 const crypto = yield* Crypto.Crypto;
8234 const hostEnvironment = yield* HostProcessEnvironment;
8234 const hostEnvironment = yield* HostProcess.Environment;
82358235 const idAllocator = yield* IdAllocator.IdAllocatorV2;
82368236 const queryRunner = yield* ClaudeAgentSdkQueryRunner;
82378237 const serverConfig = yield* ServerConfig.ServerConfig;
apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts+6-6
......@@ -29,7 +29,7 @@ import {
2929 TurnItemId,
3030} from "@t3tools/contracts";
3131import { assert, describe, it } from "@effect/vitest";
32import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
32import * as HostProcess from "@t3tools/shared/HostProcess";
3333import { SpawnExecutableResolution } from "@t3tools/shared/shell";
3434import * as CodexClient from "effect-codex-app-server/client";
3535import * as CodexError from "effect-codex-app-server/errors";
......@@ -698,8 +698,8 @@ describe("CodexAdapterV2 process spawning", () => {
698698 assert.deepEqual(command.options.env, { CUSTOM: "1" });
699699 assert.equal(command.options.extendEnv, true);
700700 }).pipe(
701 Effect.provideService(HostProcessPlatform, "win32"),
702 Effect.provideService(HostProcessEnvironment, {
701 Effect.provideService(HostProcess.Platform, "win32"),
702 Effect.provideService(HostProcess.Environment, {
703703 PATH: "C:\\Windows\\System32",
704704 HOST_ONLY: "1",
705705 }),
......@@ -726,7 +726,7 @@ describe("CodexAdapterV2 process spawning", () => {
726726 assert.deepEqual(command.args, ["app-server"]);
727727 assert.equal(command.options.shell, false);
728728 }).pipe(
729 Effect.provideService(HostProcessPlatform, "win32"),
729 Effect.provideService(HostProcess.Platform, "win32"),
730730 Effect.provideService(SpawnExecutableResolution, () => "C:\\bin\\codex.exe"),
731731 ),
732732 );
......@@ -774,7 +774,7 @@ describe("CodexAdapterV2 process spawning", () => {
774774 ["app-server", "--strict-config", "-c", "model_reasoning_summary=detailed"],
775775 ["app-server", "--enable", "env-feature"],
776776 ]);
777 }).pipe(Effect.provideService(HostProcessPlatform, "linux")),
777 }).pipe(Effect.provideService(HostProcess.Platform, "linux")),
778778 );
779779
780780 it.effect("expands ~ in the configured binary path before spawning", () =>
......@@ -821,7 +821,7 @@ describe("CodexAdapterV2 process spawning", () => {
821821 Effect.provide(
822822 Layer.mergeAll(IdAllocator.layer, McpProviderSessions.layer, NodeServices.layer),
823823 ),
824 Effect.provideService(HostProcessPlatform, "linux"),
824 Effect.provideService(HostProcess.Platform, "linux"),
825825 ),
826826 );
827827});
apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts+4-4
......@@ -30,7 +30,7 @@ import {
3030 type ProviderSetupError,
3131} from "@t3tools/contracts";
3232import { SKILL_MENTION_PATTERN } from "@t3tools/shared/composerInlineTokens";
33import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
33import * as HostProcess from "@t3tools/shared/HostProcess";
3434import { dynamicToolTitle } from "@t3tools/shared/toolActivity";
3535import { getModelSelectionStringOptionValue, modelSelectionsEqual } from "@t3tools/shared/model";
3636import { resolveSpawnCommand } from "@t3tools/shared/shell";
......@@ -1562,7 +1562,7 @@ export const createCodexAdapterV2 = (
15621562 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
15631563 const crypto = yield* Crypto.Crypto;
15641564 const fileSystem = yield* FileSystem.FileSystem;
1565 const hostEnvironment = yield* HostProcessEnvironment;
1565 const hostEnvironment = yield* HostProcess.Environment;
15661566 const idAllocator = yield* IdAllocator.IdAllocatorV2;
15671567 const serverConfig = yield* ServerConfig;
15681568 const homeLayout = yield* resolveCodexHomeLayout(config);
......@@ -1582,7 +1582,7 @@ export const createCodexAdapterV2 = (
15821582 const settings = {
15831583 ...config,
15841584 enabled,
1585 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),
1585 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
15861586 homePath: homeLayout.effectiveHomePath ?? "",
15871587 } satisfies CodexSettings;
15881588
......@@ -1623,7 +1623,7 @@ const layer: Layer.Layer<
16231623 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
16241624 const crypto = yield* Crypto.Crypto;
16251625 const fileSystem = yield* FileSystem.FileSystem;
1626 const hostEnvironment = yield* HostProcessEnvironment;
1626 const hostEnvironment = yield* HostProcess.Environment;
16271627 const idAllocator = yield* IdAllocator.IdAllocatorV2;
16281628 const serverConfig = yield* ServerConfig;
16291629
apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.testkit.ts+2-2
......@@ -1,4 +1,4 @@
1import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import type { InteractionUpdate, RunResult } from "@cursor/sdk";
33import * as NodeServices from "@effect/platform-node/NodeServices";
44import {
......@@ -519,7 +519,7 @@ export function layer(
519519 // Skill discovery also scans user roots under HOME; an empty HOME keeps
520520 // replays from picking up the host's own skills.
521521 const layerHostEnvironment = Layer.effect(
522 HostProcessEnvironment,
522 HostProcess.Environment,
523523 Effect.gen(function* () {
524524 const fs = yield* FileSystem.FileSystem;
525525 const home = yield* fs.makeTempDirectoryScoped({ prefix: "t3-cursor-replay-home-" });
apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.test.ts+2-2
......@@ -7,7 +7,7 @@ import {
77 ThreadId,
88} from "@t3tools/contracts";
99import { GrokSettings } from "@t3tools/provider-grok/settings";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
1212import * as EffectAcpErrors from "effect-acp/errors";
1313import { xAiRateLimitedErrorCode } from "@t3tools/provider-grok/testing";
......@@ -364,7 +364,7 @@ describe("Grok launch permission mode", () => {
364364 return launches;
365365 }).pipe(
366366 // Keep the launch argv unwrapped by the Linux cgroup shim.
367 Effect.provideService(HostProcessPlatform, "darwin"),
367 Effect.provideService(HostProcess.Platform, "darwin"),
368368 Effect.provide(layerTest),
369369 );
370370
apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.testkit.ts+2-2
......@@ -6,7 +6,7 @@ import * as Layer from "effect/Layer";
66import * as Path from "effect/Path";
77import * as Schema from "effect/Schema";
88import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
9import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1010import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
1111
1212import * as TestProviderHost from "@t3tools/provider-testing/TestProviderHost";
......@@ -43,7 +43,7 @@ function layerGrokProviderAdapterRegistryReplay(
4343 const fileSystem = yield* FileSystem.FileSystem;
4444 const path = yield* Path.Path;
4545 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
46 const hostPlatform = yield* HostProcessPlatform;
46 const hostPlatform = yield* HostProcess.Platform;
4747 // Same queue the continuation worker drains when the fixture runs it.
4848 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
4949 const replayGate = options.replayGate;
apps/server/src/orchestration-v2/workflowScriptQuery.ts+2-2
......@@ -18,7 +18,7 @@ import * as NodePath from "node:path";
1818
1919import { OrchestrationGetWorkflowScriptError } from "@t3tools/contracts";
2020import * as Effect from "effect/Effect";
21import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
21import * as HostProcess from "@t3tools/shared/HostProcess";
2222
2323const SCRIPT_BYTE_CAP = 256 * 1024;
2424
......@@ -38,7 +38,7 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")(
3838 });
3939 }
4040
41 const home = yield* HostProcessHomeDirectory;
41 const home = yield* HostProcess.HomeDirectory;
4242 const root = yield* Effect.tryPromise({
4343 try: () => NodeFSP.realpath(scriptsRoot(home)),
4444 catch: (cause) =>
apps/server/src/os-jank.ts+5-9
......@@ -1,8 +1,4 @@
1import {
2 HostProcessEnvironment,
3 HostProcessHomeDirectory,
4 HostProcessPlatform,
5} from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
62import {
73 listLoginShellCandidates,
84 mergePathEntries,
......@@ -57,8 +53,8 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return<
5753 never,
5854 FileSystem.FileSystem | Path.Path
5955> {
60 const platform = yield* HostProcessPlatform;
61 const env = yield* HostProcessEnvironment;
56 const platform = yield* HostProcess.Platform;
57 const env = yield* HostProcess.Environment;
6258
6359 if (platform === "win32") {
6460 const repairedEnvironment = yield* resolveWindowsEnvironment(env).pipe(
......@@ -97,7 +93,7 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return<
9793
9894export const expandHomePath = Effect.fn(function* (input: string) {
9995 const { join } = yield* Path.Path;
100 const home = yield* HostProcessHomeDirectory;
96 const home = yield* HostProcess.HomeDirectory;
10197 if (input === "~") {
10298 return home;
10399 }
......@@ -110,7 +106,7 @@ export const expandHomePath = Effect.fn(function* (input: string) {
110106export const resolveBaseDir = Effect.fn(function* (raw: string | undefined) {
111107 const { join, resolve } = yield* Path.Path;
112108 if (!raw || raw.trim().length === 0) {
113 return join(yield* HostProcessHomeDirectory, ".t3");
109 return join(yield* HostProcess.HomeDirectory, ".t3");
114110 }
115111 return resolve(yield* expandHomePath(raw.trim()));
116112});
apps/server/src/preview/PortScanner.test.ts+4-4
......@@ -6,7 +6,7 @@ import {
66 PREVIEW_URL_MAX_LENGTH,
77 type DiscoveredLocalServer,
88} from "@t3tools/contracts";
9import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1010import * as Net from "@t3tools/shared/Net";
1111import * as Cause from "effect/Cause";
1212import * as Clock from "effect/Clock";
......@@ -74,7 +74,7 @@ const layerProbeFailure = (
7474 reserveLoopbackPort: () => Effect.succeed(40_000),
7575 findAvailablePort: (preferred) => Effect.succeed(preferred),
7676 }),
77 Layer.succeed(HostProcessPlatform, "linux"),
77 Layer.succeed(HostProcess.Platform, "linux"),
7878 FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetch))),
7979 ),
8080 ),
......@@ -86,7 +86,7 @@ const layerTestPortDiscovery = PortScanner.layer.pipe(
8686 layerNoProc,
8787 layerTestProcessRunner,
8888 layerTestIntegrationNet,
89 Layer.succeed(HostProcessPlatform, "win32"),
89 Layer.succeed(HostProcess.Platform, "win32"),
9090 FetchHttpClient.layer,
9191 ),
9292 ),
......@@ -122,7 +122,7 @@ const layerLsofScanner = (input: {
122122 reserveLoopbackPort: () => Effect.succeed(40_000),
123123 findAvailablePort: (preferred) => Effect.succeed(preferred),
124124 }),
125 Layer.succeed(HostProcessPlatform, "linux"),
125 Layer.succeed(HostProcess.Platform, "linux"),
126126 FetchHttpClient.layer.pipe(
127127 Layer.provide(Layer.succeed(FetchHttpClient.Fetch, input.fetch)),
128128 ),
apps/server/src/preview/PortScanner.ts+2-2
......@@ -25,7 +25,7 @@ import {
2525 ThreadId,
2626 type DiscoveredLocalServer,
2727} from "@t3tools/contracts";
28import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
28import * as HostProcess from "@t3tools/shared/HostProcess";
2929import * as Net from "@t3tools/shared/Net";
3030import { isLoopbackHost, LSOF_LOCAL_HOST_TOKENS } from "@t3tools/shared/preview";
3131import * as Cause from "effect/Cause";
......@@ -342,7 +342,7 @@ export const make = Effect.gen(function* PortDiscoveryMake() {
342342 const net = yield* Net.NetService;
343343 const processRunner = yield* ProcessRunner.ProcessRunner;
344344 const fileSystem = yield* FileSystem.FileSystem;
345 const hostPlatform = yield* HostProcessPlatform;
345 const hostPlatform = yield* HostProcess.Platform;
346346 const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.withScope);
347347 const stateRef = yield* Ref.make<ScannerState>({
348348 listeners: new Map(),
apps/server/src/preview/PreviewBrowser.test.ts+4-4
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { expect, it } from "@effect/vitest";
3import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Deferred from "effect/Deferred";
55import * as Crypto from "effect/Crypto";
66import type * as Duration from "effect/Duration";
......@@ -20,7 +20,7 @@ import * as PreviewBrowser from "./PreviewBrowser.ts";
2020
2121// POSIX modes cannot be checked on NTFS, so follow the host like the Antigravity suite.
2222const hostPlatform: NodeJS.Platform =
23 HostProcessPlatform.defaultValue() === "win32" ? "win32" : "linux";
23 HostProcess.Platform.defaultValue() === "win32" ? "win32" : "linux";
2424const executableName =
2525 hostPlatform === "win32" ? "chrome-headless-shell.exe" : "chrome-headless-shell";
2626const ROOT = "chrome-headless-shell-fixture/";
......@@ -105,8 +105,8 @@ const makeHarness = Effect.fn("test.makePreviewBrowser")(function* (
105105 },
106106 ...(options.wait === undefined ? {} : { wait: options.wait }),
107107 }).pipe(
108 Effect.provideService(HostProcessPlatform, hostPlatform),
109 Effect.provideService(HostProcessArchitecture, "x64"),
108 Effect.provideService(HostProcess.Platform, hostPlatform),
109 Effect.provideService(HostProcess.Architecture, "x64"),
110110 Effect.provideService(
111111 HttpClient.HttpClient,
112112 HttpClient.make((request) =>
apps/server/src/preview/PreviewBrowser.ts+3-3
......@@ -1,6 +1,6 @@
11// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest.
22import * as EffectNodeStream from "@effect/platform-node/NodeStream";
3import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Cause from "effect/Cause";
55import * as Clock from "effect/Clock";
66import * as Context from "effect/Context";
......@@ -175,8 +175,8 @@ export const makePreviewBrowser = Effect.fn("PreviewBrowser.make")(function* (
175175 const http = yield* HttpClient.HttpClient;
176176 // Installs belong to the service, so they finish even when no caller is still waiting.
177177 const serviceScope = yield* Effect.scope;
178 const platform = yield* HostProcessPlatform;
179 const arch = yield* HostProcessArchitecture;
178 const platform = yield* HostProcess.Platform;
179 const arch = yield* HostProcess.Architecture;
180180 const release =
181181 options.release === undefined ? previewBrowserRelease(platform, arch) : options.release;
182182 const wait = options.wait ?? "45 seconds";
apps/server/src/preview/PreviewBrowserHost.test.ts+2-2
......@@ -1,5 +1,5 @@
11import { describe, expect, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Effect from "effect/Effect";
44import * as Sink from "effect/Sink";
55import * as Stream from "effect/Stream";
......@@ -67,7 +67,7 @@ const diagnose = (input: {
6767 setupCommand: "sudo t3 browser setup",
6868 }).pipe(
6969 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
70 Effect.provideService(HostProcessPlatform, input.platform),
70 Effect.provideService(HostProcess.Platform, input.platform),
7171 Effect.map((error) => ({ error, commands })),
7272 );
7373};
apps/server/src/preview/PreviewBrowserHost.ts+3-3
......@@ -7,7 +7,7 @@
77 * gets the command instead, and only the operator's explicit
88 * `T3CODE_SERVER_BROWSER_SANDBOX=0` launches without it.
99 */
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111import * as Effect from "effect/Effect";
1212import * as FileSystem from "effect/FileSystem";
1313import * as Schema from "effect/Schema";
......@@ -108,7 +108,7 @@ export const diagnoseLaunchFailure = Effect.fn("PreviewBrowserHost.diagnoseLaunc
108108 if (input.output.includes(NO_SANDBOX_SIGNATURE)) {
109109 return new PreviewBrowserSandboxError({ setupCommand });
110110 }
111 if ((yield* HostProcessPlatform) !== "linux") return undefined;
111 if ((yield* HostProcess.Platform) !== "linux") return undefined;
112112 const libraries = yield* missingLibraries(input.executable);
113113 return libraries.length === 0
114114 ? undefined
......@@ -147,7 +147,7 @@ export const missingLibraries = Effect.fn("PreviewBrowserHost.missingLibraries")
147147 * root, so the server checks it at startup.
148148 */
149149export const sandboxBlocked = Effect.gen(function* () {
150 if ((yield* HostProcessPlatform) !== "linux") return false;
150 if ((yield* HostProcess.Platform) !== "linux") return false;
151151 const fs = yield* FileSystem.FileSystem;
152152 const restricted = yield* fs.readFileString(USERNS_RESTRICTION).pipe(
153153 Effect.map((value) => value.trim() === "1"),
apps/server/src/preview/ServerBrowser.ts+3-7
......@@ -42,11 +42,7 @@ import {
4242 SERVER_BROWSER_AUTOMATION_CLIENT_ID,
4343 type PreviewAppearancePreference,
4444} from "@t3tools/contracts";
45import {
46 HostProcessArchitecture,
47 HostProcessEnvironment,
48 HostProcessPlatform,
49} from "@t3tools/shared/hostProcess";
45import * as HostProcess from "@t3tools/shared/HostProcess";
5046import { normalizePreviewUrl } from "@t3tools/shared/preview";
5147import { resolvePreviewViewport } from "@t3tools/shared/previewViewport";
5248import * as NodeCrypto from "node:crypto";
......@@ -476,7 +472,7 @@ const CLIPBOARD_SCRIPT = `(() => {
476472
477473const make = Effect.gen(function* () {
478474 const config = yield* ServerConfig.ServerConfig;
479 const host = { platform: yield* HostProcessPlatform, arch: yield* HostProcessArchitecture };
475 const host = { platform: yield* HostProcess.Platform, arch: yield* HostProcess.Architecture };
480476 const manager = yield* PreviewManager.PreviewManager;
481477 const broker = yield* PreviewAutomationBroker.PreviewAutomationBroker;
482478 const environment = yield* ServerEnvironment.ServerEnvironment;
......@@ -2367,7 +2363,7 @@ const make = Effect.gen(function* () {
23672363 yield* manager.events.pipe(Stream.runForEach(mirrorManagerEvent), Effect.forkScoped);
23682364 // Whoever runs the server learns the fix before anyone opens a tab.
23692365 if (
2370 !PreviewBrowserHost.sandboxDisabled(yield* HostProcessEnvironment) &&
2366 !PreviewBrowserHost.sandboxDisabled(yield* HostProcess.Environment) &&
23712367 (yield* PreviewBrowserHost.sandboxBlocked)
23722368 ) {
23732369 yield* Effect.logWarning(
apps/server/src/process/externalLauncher.test.ts+5-5
......@@ -17,7 +17,7 @@ import * as Stream from "effect/Stream";
1717import * as TestClock from "effect/testing/TestClock";
1818import { ChildProcess, ChildProcessSpawner } from "effect/process";
1919
20import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
20import * as HostProcess from "@t3tools/shared/HostProcess";
2121import { SpawnExecutableResolution } from "@t3tools/shared/shell";
2222import * as ExternalLauncher from "./externalLauncher.ts";
2323
......@@ -25,7 +25,7 @@ import * as ExternalLauncher from "./externalLauncher.ts";
2525// directory to a posix-mocked resolver as PATH. On a Windows host the temp
2626// path carries a drive letter, so the posix `:` split shatters it; there is
2727// no posix executable to find there anyway.
28const windowsHost = HostProcessPlatform.defaultValue() === "win32";
28const windowsHost = HostProcess.Platform.defaultValue() === "win32";
2929
3030interface MockSpawnResult {
3131 readonly exitCode?: number;
......@@ -85,7 +85,7 @@ const layerTest = (input: {
8585
8686 return Layer.mergeAll(
8787 ExternalLauncher.layer.pipe(Layer.provide(Layer.merge(NodeServices.layer, layerSpawner))),
88 Layer.succeed(HostProcessPlatform, input.platform),
88 Layer.succeed(HostProcess.Platform, input.platform),
8989 Layer.succeed(
9090 SpawnExecutableResolution,
9191 (command) => input.resolveExecutable?.(command) ?? command,
......@@ -1302,7 +1302,7 @@ it.effect("memoizes editor discovery and refreshes after the cache window", () =
13021302 Effect.provide(
13031303 Layer.mergeAll(
13041304 layerLauncher,
1305 Layer.succeed(HostProcessPlatform, "win32"),
1305 Layer.succeed(HostProcess.Platform, "win32"),
13061306 ConfigProvider.layer(
13071307 ConfigProvider.fromEnv({
13081308 env: {
......@@ -1367,7 +1367,7 @@ it.effect("keeps scanning after the caller is interrupted and shares that scan",
13671367 Effect.provide(
13681368 Layer.mergeAll(
13691369 layerLauncher,
1370 Layer.succeed(HostProcessPlatform, "win32"),
1370 Layer.succeed(HostProcess.Platform, "win32"),
13711371 ConfigProvider.layer(
13721372 ConfigProvider.fromEnv({
13731373 env: {
apps/server/src/process/externalLauncher.ts+5-5
......@@ -19,7 +19,7 @@ import {
1919 type LaunchEditorInput,
2020} from "@t3tools/contracts";
2121import { resolveEditorCommand } from "@t3tools/shared/editor";
22import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
22import * as HostProcess from "@t3tools/shared/HostProcess";
2323import {
2424 isCommandAvailable,
2525 resolveSpawnCommand,
......@@ -441,20 +441,20 @@ const buildAvailableEditors = Effect.fn("externalLauncher.buildAvailableEditors"
441441const resolveBrowserLaunch = Effect.fn("externalLauncher.resolveBrowserLaunch")(function* (
442442 target: string,
443443) {
444 const platform = yield* HostProcessPlatform;
444 const platform = yield* HostProcess.Platform;
445445 const env = yield* readBrowserLaunchEnv;
446446 return buildBrowserLaunch(target, platform, env);
447447});
448448
449449const resolveAvailableEditors = Effect.fn("externalLauncher.resolveAvailableEditors")(function* () {
450 const platform = yield* HostProcessPlatform;
450 const platform = yield* HostProcess.Platform;
451451 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };
452452 return yield* buildAvailableEditors(platform, env).pipe(withPathDirectoryListings);
453453});
454454
455455const resolveFileManagerRevealKind = Effect.fn("externalLauncher.resolveFileManagerRevealKind")(
456456 function* () {
457 const platform = yield* HostProcessPlatform;
457 const platform = yield* HostProcess.Platform;
458458 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };
459459 return yield* fileManagerRevealKindForPlatform(platform, env);
460460 },
......@@ -519,7 +519,7 @@ const resolveEditorLaunch = Effect.fn("resolveEditorLaunch")(function* (
519519 ExternalLauncherError,
520520 FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner
521521> {
522 const platform = yield* HostProcessPlatform;
522 const platform = yield* HostProcess.Platform;
523523 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };
524524 yield* Effect.annotateCurrentSpan({
525525 "externalLauncher.editor": input.editor,
apps/server/src/processRunner.test.ts+4-4
......@@ -9,7 +9,7 @@ import * as Sink from "effect/Sink";
99import * as Stream from "effect/Stream";
1010import { TestClock } from "effect/testing";
1111import { ChildProcessSpawner } from "effect/process";
12import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
12import * as HostProcess from "@t3tools/shared/HostProcess";
1313import { SpawnExecutableResolution } from "@t3tools/shared/shell";
1414
1515import * as ProcessRunner from "./processRunner.ts";
......@@ -145,8 +145,8 @@ describe("runProcess", () => {
145145 args: ["repos", "pr", "list", "--source-branch", "feature & release"],
146146 env: { AZURE_CONFIG_DIR: "C:\\Users\\tester\\.azure" },
147147 }).pipe(
148 Effect.provideService(HostProcessPlatform, "win32"),
149 Effect.provideService(HostProcessEnvironment, {
148 Effect.provideService(HostProcess.Platform, "win32"),
149 Effect.provideService(HostProcess.Environment, {
150150 PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm",
151151 PATHEXT: ".COM;.EXE;.BAT;.CMD",
152152 }),
......@@ -407,7 +407,7 @@ describe("isWindowsCommandNotFound", () => {
407407 const isCommandNotFound = yield* ProcessRunner.isWindowsCommandNotFound(
408408 1,
409409 "wird nicht als interner oder externer Befehl, betriebsfahiges Programm oder Batch-Datei erkannt",
410 ).pipe(Effect.provideService(HostProcessPlatform, "win32"));
410 ).pipe(Effect.provideService(HostProcess.Platform, "win32"));
411411 expect(isCommandNotFound).toBe(true);
412412 }),
413413 );
apps/server/src/project/AgentSessionScanner.ts+4-8
......@@ -44,11 +44,7 @@ import {
4444 parseGitHubRepositoryNameWithOwnerFromRemoteUrl,
4545 parseOriginUrlFromGitConfig,
4646} from "@t3tools/shared/git";
47import {
48 HostProcessEnvironment,
49 HostProcessHomeDirectory,
50 HostProcessPlatform,
51} from "@t3tools/shared/hostProcess";
47import * as HostProcess from "@t3tools/shared/HostProcess";
5248import { normalizeProjectPathForComparison } from "@t3tools/shared/path";
5349
5450import * as ServerConfig from "../config.ts";
......@@ -633,9 +629,9 @@ export const make = Effect.gen(function* () {
633629 const worktreesDir = path.resolve(serverConfig.worktreesDir);
634630 // Windows filesystems are case-insensitive, so path prefix checks there
635631 // must case fold.
636 const foldWorktreeCase = (yield* HostProcessPlatform) === "win32";
637 const hostEnvironment = yield* HostProcessEnvironment;
638 const homeDir = yield* HostProcessHomeDirectory;
632 const foldWorktreeCase = (yield* HostProcess.Platform) === "win32";
633 const hostEnvironment = yield* HostProcess.Environment;
634 const homeDir = yield* HostProcess.HomeDirectory;
639635 // `/private/tmp` is what macOS reports for sessions started in `/tmp`.
640636 const excludedProjectRoots = new Set(
641637 [homeDir, NodeOS.tmpdir(), "/tmp", "/private/tmp"].map((directory) =>
apps/server/src/project/ProjectSetupScriptRunner.ts+3-3
......@@ -1,5 +1,5 @@
11import { ProjectId, type ProjectScript } from "@t3tools/contracts";
2import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import {
44 projectScriptRuntimeEnv,
55 resolveProjectScripts,
......@@ -206,8 +206,8 @@ export const make = Effect.gen(function* () {
206206 const serverSettings = yield* ServerSettings.ServerSettingsService;
207207 const crypto = yield* Crypto.Crypto;
208208 const completionShell = resolveCompletionShell(
209 yield* HostProcessPlatform,
210 yield* HostProcessEnvironment,
209 yield* HostProcess.Platform,
210 yield* HostProcess.Environment,
211211 );
212212
213213 /**
apps/server/src/provider/AntigravityInstallation.test.ts+7-12
......@@ -1,11 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { expect, it } from "@effect/vitest";
3import {
4 HostProcessArchitecture,
5 HostProcessEnvironment,
6 HostProcessIsExecutable,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
94import * as Crypto from "effect/Crypto";
105import * as Deferred from "effect/Deferred";
116import * as Effect from "effect/Effect";
......@@ -62,7 +57,7 @@ const zipFixtures = {
6257// the host and let the fixture names follow; the suite is about install
6358// mechanics, which are the same on every platform.
6459const hostPlatform: NodeJS.Platform =
65 HostProcessPlatform.defaultValue() === "win32" ? "win32" : "linux";
60 HostProcess.Platform.defaultValue() === "win32" ? "win32" : "linux";
6661const completeArchive = Buffer.from(
6762 hostPlatform === "win32" ? zipFixtures.windows : zipFixtures.complete,
6863 "base64",
......@@ -189,9 +184,9 @@ const makeHarness = Effect.fn("test.makeAntigravityInstallation")(function* (
189184 }),
190185 }).pipe(
191186 Effect.provideService(FileSystem.FileSystem, trackedFs),
192 Effect.provideService(HostProcessPlatform, platform),
193 Effect.provideService(HostProcessArchitecture, "x64"),
194 Effect.provideService(HostProcessEnvironment, { PATH: options.path ?? "" }),
187 Effect.provideService(HostProcess.Platform, platform),
188 Effect.provideService(HostProcess.Architecture, "x64"),
189 Effect.provideService(HostProcess.Environment, { PATH: options.path ?? "" }),
195190 Effect.provideService(
196191 HttpClient.HttpClient,
197192 HttpClient.make((request) =>
......@@ -259,7 +254,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => {
259254 });
260255 expect(requests).toEqual([]);
261256 expect(validations).toEqual([]);
262 }).pipe(Effect.provideService(HostProcessIsExecutable, true)),
257 }).pipe(Effect.provideService(HostProcess.IsExecutable, true)),
263258 );
264259
265260 it.effect("verifies both files before activating a streamed download", () =>
......@@ -734,7 +729,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => {
734729
735730 // Real posix executables in a real temp dir, resolved by a linux-mocked
736731 // PATH walk; a Windows temp path cannot be split on `:`.
737 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
732 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
738733 "honors explicit paths and reports invalid overrides without falling back",
739734 () =>
740735 Effect.gen(function* () {
apps/server/src/provider/AntigravityInstallation.ts+5-9
......@@ -1,11 +1,7 @@
11// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest or free-space query.
22import * as EffectNodeStream from "@effect/platform-node/NodeStream";
33import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts";
4import {
5 HostProcessArchitecture,
6 HostProcessEnvironment,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
95import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";
106import * as Clock from "effect/Clock";
117import * as Cause from "effect/Cause";
......@@ -156,9 +152,9 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma
156152 const http = yield* HttpClient.HttpClient;
157153 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
158154 const serviceScope = yield* Effect.scope;
159 const platform = yield* HostProcessPlatform;
160 const arch = yield* HostProcessArchitecture;
161 const environment = yield* HostProcessEnvironment;
155 const platform = yield* HostProcess.Platform;
156 const arch = yield* HostProcess.Architecture;
157 const environment = yield* HostProcess.Environment;
162158 const releaseAsset =
163159 options.releaseAsset === undefined
164160 ? resolveAntigravityReleaseAsset(platform, arch)
......@@ -410,7 +406,7 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma
410406 yield* resolveNodeExecutable("Antigravity", environment).pipe(
411407 Effect.provideService(FileSystem.FileSystem, fs),
412408 Effect.provideService(Path.Path, path),
413 Effect.provideService(HostProcessPlatform, platform),
409 Effect.provideService(HostProcess.Platform, platform),
414410 Effect.mapError((cause) =>
415411 installationError("verify", nodeRuntimeUnavailableMessage("Antigravity"), cause),
416412 ),
apps/server/src/provider/CodexInstallation.test.ts+4-8
......@@ -1,11 +1,7 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import * as ModelManifest from "./ModelManifest.ts";
33import { expect, it } from "@effect/vitest";
4import {
5 HostProcessArchitecture,
6 HostProcessEnvironment,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
95import * as Crypto from "effect/Crypto";
106import * as Deferred from "effect/Deferred";
117import * as Effect from "effect/Effect";
......@@ -66,9 +62,9 @@ const makeHarness = Effect.fn("test.makeCodexInstallation")(function* (
6662 forceRefresh: Effect.succeed(ModelManifest.BUNDLED_MODEL_MANIFEST),
6763 refreshInBackground: Effect.void,
6864 }),
69 Effect.provideService(HostProcessPlatform, "darwin"),
70 Effect.provideService(HostProcessArchitecture, "arm64"),
71 Effect.provideService(HostProcessEnvironment, { PATH: input.local ? localDirectory : "" }),
65 Effect.provideService(HostProcess.Platform, "darwin"),
66 Effect.provideService(HostProcess.Architecture, "arm64"),
67 Effect.provideService(HostProcess.Environment, { PATH: input.local ? localDirectory : "" }),
7268 Effect.provideService(
7369 HttpClient.HttpClient,
7470 HttpClient.make((request) =>
apps/server/src/provider/CodexInstallation.ts+6-10
......@@ -1,10 +1,6 @@
11// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest.
22import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts";
3import {
4 HostProcessArchitecture,
5 HostProcessEnvironment,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
84import { resolveCommandPath, resolveSpawnCommand } from "@t3tools/shared/shell";
95import * as Clock from "effect/Clock";
106import * as Cause from "effect/Cause";
......@@ -169,9 +165,9 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function
169165 const http = yield* HttpClient.HttpClient;
170166 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
171167 const serviceScope = yield* Effect.scope;
172 const platform = yield* HostProcessPlatform;
173 const environment = yield* HostProcessEnvironment;
174 const arch = yield* HostProcessArchitecture;
168 const platform = yield* HostProcess.Platform;
169 const environment = yield* HostProcess.Environment;
170 const arch = yield* HostProcess.Architecture;
175171 const asset =
176172 options.releaseAsset === undefined
177173 ? resolveCodexReleaseAsset(platform, arch)
......@@ -311,7 +307,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function
311307 args: ReadonlyArray<string>,
312308 ) {
313309 const resolved = yield* resolveSpawnCommand(command, args).pipe(
314 Effect.provideService(HostProcessPlatform, platform),
310 Effect.provideService(HostProcess.Platform, platform),
315311 );
316312 const child = yield* spawner.spawn(
317313 ChildProcess.make(resolved.command, resolved.args, { shell: resolved.shell }),
......@@ -335,7 +331,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function
335331 const resolveLocal = Effect.fn("CodexInstallation.resolveLocal")(
336332 function* () {
337333 const executablePath = yield* resolveCommandPath("codex", { env: environment }).pipe(
338 Effect.provideService(HostProcessPlatform, platform),
334 Effect.provideService(HostProcess.Platform, platform),
339335 Effect.provideService(FileSystem.FileSystem, fs),
340336 Effect.provideService(Path.Path, path),
341337 );
apps/server/src/provider/CodexProvider.ts+2-2
......@@ -47,7 +47,7 @@ import {
4747 type CodexRateLimitSnapshot,
4848 type CodexResetCreditsSummary,
4949} from "./codexUsageLimits.ts";
50import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
50import * as HostProcess from "@t3tools/shared/HostProcess";
5151import packageJson from "../../package.json" with { type: "json" };
5252const isCodexAppServerSpawnError = Schema.is(CodexErrors.CodexAppServerSpawnError);
5353const RATE_LIMITS_PROBE_TIMEOUT_MS = 3_000;
......@@ -376,7 +376,7 @@ export const withCodexAppServerClient = Effect.fn("withCodexAppServerClient")(fu
376376 // "CODEX_HOME points to '~/.codex_work', but that path does not exist".
377377 // Expand here for parity with `CodexTextGeneration`.
378378 const resolvedHomePath = input.homePath
379 ? expandHomePath(input.homePath, yield* HostProcessHomeDirectory)
379 ? expandHomePath(input.homePath, yield* HostProcess.HomeDirectory)
380380 : undefined;
381381 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
382382 const environment = {
apps/server/src/provider/Drivers/AntigravityDriver.test.ts+6-11
......@@ -5,12 +5,7 @@ import {
55 ProviderInstanceId,
66 type AntigravitySettings,
77} from "@t3tools/contracts";
8import {
9 HostProcessEnvironment,
10 HostProcessExecutablePath,
11 HostProcessIsExecutable,
12 HostProcessPlatform,
13} from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
149import * as Effect from "effect/Effect";
1510import * as Deferred from "effect/Deferred";
1611import * as Fiber from "effect/Fiber";
......@@ -37,7 +32,7 @@ import { AntigravityDriver } from "./AntigravityDriver.ts";
3732import * as ProviderHostLive from "../ProviderHostLive.ts";
3833import * as ServerSecretStore from "../../auth/ServerSecretStore.ts";
3934
40const hostPlatform = HostProcessPlatform.defaultValue();
35const hostPlatform = HostProcess.Platform.defaultValue();
4136const windowsHost = hostPlatform === "win32";
4237const decodeRequest = Schema.decodeEffect(
4338 Schema.fromJsonString(
......@@ -65,8 +60,8 @@ const makeHarness = Effect.fn("makeAntigravityDriverHarness")(function* (
6560 const path = yield* Path.Path;
6661 const config = yield* ServerConfig.ServerConfig;
6762 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
68 const nodePath = yield* HostProcessExecutablePath;
69 const baseEnv = yield* HostProcessEnvironment;
63 const nodePath = yield* HostProcess.ExecutablePath;
64 const baseEnv = yield* HostProcess.Environment;
7065 const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-antigravity-driver-" });
7166 const instanceId = ProviderInstanceId.make(path.basename(root));
7267 const mockAgentPath = yield* path.fromFileUrl(
......@@ -283,8 +278,8 @@ it.layer(layerTest)("AntigravityDriver", (it) => {
283278 expect(h.launches).toEqual([]);
284279 }).pipe(
285280 Effect.scoped,
286 Effect.provideService(HostProcessIsExecutable, true),
287 Effect.provideService(HostProcessEnvironment, { PATH: "" }),
281 Effect.provideService(HostProcess.IsExecutable, true),
282 Effect.provideService(HostProcess.Environment, { PATH: "" }),
288283 ),
289284 );
290285
apps/server/src/provider/Drivers/AntigravityDriver.ts+3-3
......@@ -1,7 +1,7 @@
11import { withAgentDeviceEnvironment } from "@t3tools/provider-core/server/mcpSession";
22import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions";
33import { AntigravitySettings, ProviderDriverKind, ProviderSetupError } from "@t3tools/contracts";
4import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
66import {
77 NodeRuntimeUnavailableError,
......@@ -115,9 +115,9 @@ export const AntigravityDriver: ProviderDriver<
115115 const authConfigIssue = antigravityAuthConfigIssue(auth);
116116 const processEnvironment = yield* mergeProviderInstanceEnvironment(environment);
117117 const userHome = resolveAntigravityUserHome(
118 yield* HostProcessPlatform,
118 yield* HostProcess.Platform,
119119 processEnvironment,
120 yield* HostProcessHomeDirectory,
120 yield* HostProcess.HomeDirectory,
121121 );
122122 const directories = yield* resolveAntigravityInstanceDirectories(
123123 host.paths.stateDir,
apps/server/src/provider/Drivers/AntigravityUsage.ts+3-3
......@@ -17,7 +17,7 @@ import type {
1717 ProviderUsageReader,
1818 ProviderUsageScan,
1919} from "@t3tools/provider-core/server/usage";
20import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
20import * as HostProcess from "@t3tools/shared/HostProcess";
2121import * as Context from "effect/Context";
2222import * as Crypto from "effect/Crypto";
2323import * as Effect from "effect/Effect";
......@@ -44,12 +44,12 @@ const make = Effect.gen(function* () {
4444 const fileSystem = yield* FileSystem.FileSystem;
4545 const path = yield* Path.Path;
4646 const host = yield* ProviderHost.ProviderHost;
47 const hostEnvironment = yield* HostProcessEnvironment;
47 const hostEnvironment = yield* HostProcess.Environment;
4848 const cache = makeAntigravityUsageCache();
4949
5050 /** `ANTIGRAVITY_DATA_DIR` (comma-separated) or the defaults, canonicalized. */
5151 const dataRoots = Effect.gen(function* () {
52 const home = yield* HostProcessHomeDirectory;
52 const home = yield* HostProcess.HomeDirectory;
5353 const configured = hostEnvironment["ANTIGRAVITY_DATA_DIR"]
5454 ?.split(",")
5555 .map((value) => value.trim())
apps/server/src/provider/Drivers/ClaudeDriver.ts+2-2
......@@ -71,7 +71,7 @@ import {
7171 makeClaudeContinuationGroupKey,
7272 resolveClaudeHomePath,
7373} from "./ClaudeHome.ts";
74import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
74import * as HostProcess from "@t3tools/shared/HostProcess";
7575const decodeClaudeSettings = Schema.decodeSync(ClaudeSettings);
7676
7777const DRIVER_KIND = ProviderDriverKind.make("claudeAgent");
......@@ -139,7 +139,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv, Path.
139139 const effectiveConfig = {
140140 ...config,
141141 enabled,
142 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),
142 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
143143 } satisfies ClaudeSettings;
144144 const resolveMaintenance = yield* makeCachedProviderMaintenanceResolution(
145145 resolveProviderMaintenanceCapabilitiesEffect(UPDATE, {
apps/server/src/provider/Drivers/ClaudeExecutable.test.ts+3-3
......@@ -1,5 +1,5 @@
11import { describe, expect, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import { SpawnExecutableResolution } from "@t3tools/shared/shell";
44import * as Effect from "effect/Effect";
55
......@@ -17,7 +17,7 @@ function withWindowsResolution(input: {
1717 const existing = new Set(input.existingFiles ?? []);
1818 return <A, E, R>(effect: Effect.Effect<A, E, R>) =>
1919 effect.pipe(
20 Effect.provideService(HostProcessPlatform, "win32"),
20 Effect.provideService(HostProcess.Platform, "win32"),
2121 Effect.provideService(SpawnExecutableResolution, () => input.resolvedCommand),
2222 Effect.provideService(ClaudeExecutableFileCheck, (filePath) => existing.has(filePath)),
2323 );
......@@ -28,7 +28,7 @@ describe("resolveClaudeSdkExecutablePath", () => {
2828 Effect.gen(function* () {
2929 expect(
3030 yield* resolveClaudeSdkExecutablePath("claude", {}).pipe(
31 Effect.provideService(HostProcessPlatform, "darwin"),
31 Effect.provideService(HostProcess.Platform, "darwin"),
3232 Effect.provideService(SpawnExecutableResolution, () => {
3333 throw new Error("must not resolve on non-Windows platforms");
3434 }),
apps/server/src/provider/Drivers/ClaudeExecutable.ts+2-2
......@@ -2,7 +2,7 @@
22import * as NodeFS from "node:fs";
33import * as NodePath from "node:path";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66import { SpawnExecutableResolution } from "@t3tools/shared/shell";
77import * as Context from "effect/Context";
88import * as Effect from "effect/Effect";
......@@ -67,7 +67,7 @@ export const ClaudeExecutableFileCheck = Context.Reference<ExecutableFileCheck>(
6767 */
6868export const resolveClaudeSdkExecutablePath = Effect.fn("resolveClaudeSdkExecutablePath")(
6969 function* (binaryPath: string, environment: NodeJS.ProcessEnv): Effect.fn.Return<string> {
70 const platform = yield* HostProcessPlatform;
70 const platform = yield* HostProcess.Platform;
7171 if (platform !== "win32") {
7272 return binaryPath;
7373 }
apps/server/src/provider/Drivers/ClaudeHome.ts+2-2
......@@ -4,7 +4,7 @@ import * as Path from "effect/Path";
44import * as Schema from "effect/Schema";
55
66import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";
7import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
88
99const quotePath = Schema.encodeSync(Schema.fromJsonString(Schema.String));
1010
......@@ -20,7 +20,7 @@ export const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function
2020 environment?: NodeJS.ProcessEnv,
2121): Effect.fn.Return<string, never, Path.Path> {
2222 const path = yield* Path.Path;
23 const home = yield* HostProcessHomeDirectory;
23 const home = yield* HostProcess.HomeDirectory;
2424 const homePath = config.homePath.trim();
2525 if (homePath.length > 0) {
2626 return path.resolve(expandHomePath(homePath, home));
apps/server/src/provider/Drivers/ClaudeSkills.ts+3-3
......@@ -19,7 +19,7 @@ import * as Effect from "effect/Effect";
1919import * as FileSystem from "effect/FileSystem";
2020import * as Path from "effect/Path";
2121import * as Schema from "effect/Schema";
22import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
22import * as HostProcess from "@t3tools/shared/HostProcess";
2323import { fromLenientJson } from "@t3tools/shared/schemaJson";
2424import { parse as parseYamlDocument } from "yaml";
2525
......@@ -242,7 +242,7 @@ const readSkillOverrides = Effect.fn("readSkillOverrides")(function* (
242242): Effect.fn.Return<ReadonlyMap<string, SkillOverride>, never, FileSystem.FileSystem | Path.Path> {
243243 const fileSystem = yield* FileSystem.FileSystem;
244244 const path = yield* Path.Path;
245 const platform = yield* HostProcessPlatform;
245 const platform = yield* HostProcess.Platform;
246246 const overridesByName = new Map<string, SkillOverride>();
247247 const repositoryRoot = cwd === undefined ? undefined : yield* findRepositoryRoot(cwd);
248248
......@@ -295,7 +295,7 @@ const resolveClaudeConfigDirPath = Effect.fn("resolveClaudeConfigDirPath")(funct
295295 cwd?: string,
296296): Effect.fn.Return<string, never, Path.Path> {
297297 const path = yield* Path.Path;
298 const home = yield* HostProcessHomeDirectory;
298 const home = yield* HostProcess.HomeDirectory;
299299 const homePath = config.homePath.trim();
300300 if (homePath.length > 0) {
301301 return path.resolve(expandHomePath(homePath, home));
apps/server/src/provider/Drivers/CodexDriver.test.ts+2-2
......@@ -7,7 +7,7 @@ import * as NodeOS from "node:os";
77import * as NodePath from "node:path";
88import { expect, it } from "@effect/vitest";
99import { EnvironmentId, ProviderInstanceId, ProviderSessionId, ThreadId } from "@t3tools/contracts";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111import * as Effect from "effect/Effect";
1212import * as Deferred from "effect/Deferred";
1313import * as Fiber from "effect/Fiber";
......@@ -88,7 +88,7 @@ const layerDeps = ServerConfig.layerTest(process.cwd(), {
8888const layerTest = ProviderHostLive.layer.pipe(Layer.provideMerge(layerDeps));
8989
9090// The `#!/bin/sh` stub below cannot be resolved as an executable on Windows.
91const windowsHost = HostProcessPlatform.defaultValue() === "win32";
91const windowsHost = HostProcess.Platform.defaultValue() === "win32";
9292
9393const noSpawn = ChildProcessSpawner.make(() =>
9494 Effect.die("Disabled Codex must not spawn a process"),
apps/server/src/provider/Drivers/CodexDriver.ts+2-2
......@@ -77,7 +77,7 @@ import { codexUsageReader } from "./codexUsage.ts";
7777import * as CodexInstallation from "../CodexInstallation.ts";
7878import * as ServerSecretStore from "../../auth/ServerSecretStore.ts";
7979import * as ServerEnvironment from "../../environment/ServerEnvironment.ts";
80import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
80import * as HostProcess from "@t3tools/shared/HostProcess";
8181const decodeCodexSettings = Schema.decodeSync(CodexSettings);
8282
8383const DRIVER_KIND = ProviderDriverKind.make("codex");
......@@ -179,7 +179,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv, Path.Pat
179179 const effectiveConfig = {
180180 ...config,
181181 enabled,
182 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),
182 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
183183 homePath: homeLayout.effectiveHomePath ?? "",
184184 } satisfies CodexSettings;
185185 const resolveMaintenance = yield* makeCachedProviderMaintenanceResolution(
apps/server/src/provider/Drivers/CodexHomeLayout.ts+2-2
......@@ -6,7 +6,7 @@ import * as Schema from "effect/Schema";
66import * as PlatformError from "effect/PlatformError";
77
88import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";
9import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1010
1111export interface CodexHomeLayout {
1212 readonly mode: "direct" | "authOverlay";
......@@ -42,7 +42,7 @@ export const resolveCodexHomeLayout = Effect.fn("resolveCodexHomeLayout")(functi
4242 config: CodexSettings,
4343): Effect.fn.Return<CodexHomeLayout, never, Path.Path> {
4444 const path = yield* Path.Path;
45 const home = yield* HostProcessHomeDirectory;
45 const home = yield* HostProcess.HomeDirectory;
4646 const sharedHomePath = resolveHomePath(path, home, config.homePath);
4747 const shadowHomePath = config.shadowHomePath.trim();
4848 if (shadowHomePath.length === 0) {
apps/server/src/provider/Drivers/claudeUsage.ts+2-2
......@@ -17,7 +17,7 @@ import {
1717 type TranscriptUsageFormat,
1818 type UsageRecord,
1919} from "@t3tools/provider-core/server/usage";
20import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
20import * as HostProcess from "@t3tools/shared/HostProcess";
2121
2222/**
2323 * Parses one line of a Claude Code transcript.
......@@ -111,7 +111,7 @@ export const claudeUsageReader: ProviderUsageReader<ClaudeSettings, Path.Path> =
111111 // An undecodable config has no trustworthy home to read.
112112 if (config === undefined) return [];
113113 const path = yield* Path.Path;
114 const homeDirectory = yield* HostProcessHomeDirectory;
114 const homeDirectory = yield* HostProcess.HomeDirectory;
115115 const configured = config.homePath.trim();
116116 const home = configured
117117 ? expandHomePath(configured, homeDirectory)
apps/server/src/provider/ProviderInstanceRegistry.test.ts+5-9
......@@ -39,11 +39,7 @@ import * as ProviderLatestVersions from "@t3tools/provider-core/server/ProviderL
3939import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions";
4040import type { GrokSettings } from "@t3tools/provider-grok/settings";
4141import type { CursorSettings } from "@t3tools/provider-cursor/settings";
42import {
43 HostProcessHomeDirectory,
44 HostProcessPlatform,
45 isHostWindows,
46} from "@t3tools/shared/hostProcess";
42import * as HostProcess from "@t3tools/shared/HostProcess";
4743import * as DateTime from "effect/DateTime";
4844import * as Effect from "effect/Effect";
4945import * as FileSystem from "effect/FileSystem";
......@@ -156,7 +152,7 @@ const makeTildeProviderFixtures = Effect.fn(
156152)(function* () {
157153 const fileSystem = yield* FileSystem.FileSystem;
158154 const path = yield* Path.Path;
159 const homePath = yield* HostProcessHomeDirectory;
155 const homePath = yield* HostProcess.HomeDirectory;
160156 const fixtureDir = yield* fileSystem.makeTempDirectoryScoped({
161157 directory: homePath,
162158 prefix: ".t3-provider-path-test-",
......@@ -349,7 +345,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {
349345
350346 it.live("reports Codex's answer when a redemption changed nothing", () =>
351347 Effect.gen(function* () {
352 if (yield* isHostWindows) return;
348 if (yield* HostProcess.isWindows) return;
353349 const fileSystem = yield* FileSystem.FileSystem;
354350 const fixtures = yield* makeTildeProviderFixtures();
355351 yield* fileSystem.writeFileString(
......@@ -386,7 +382,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {
386382
387383 it.live("runs Codex and Claude readiness probes from configured tilde paths", () =>
388384 Effect.gen(function* () {
389 if (yield* isHostWindows) return;
385 if (yield* HostProcess.isWindows) return;
390386
391387 const fixtures = yield* makeTildeProviderFixtures();
392388
......@@ -503,7 +499,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {
503499 return { outcome, after: yield* instance!.snapshot.getSnapshot };
504500 }).pipe(
505501 // macOS logins live in the Keychain, where resets are never read.
506 Effect.provideService(HostProcessPlatform, "linux"),
502 Effect.provideService(HostProcess.Platform, "linux"),
507503 Effect.provide(layerTest),
508504 );
509505
apps/server/src/provider/acp/AcpSessionRuntime.processTree.test.ts+5-5
......@@ -5,7 +5,7 @@ import * as NodePath from "node:path";
55import * as NodeURL from "node:url";
66
77import { describe, expect, it, vi } from "@effect/vitest";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99import * as Clock from "effect/Clock";
1010import * as Effect from "effect/Effect";
1111import * as Exit from "effect/Exit";
......@@ -155,7 +155,7 @@ describe("terminatePosixOwnedProcessTree", () => {
155155
156156 it.live("preserves exact argv and strips wrapper-only environment before exec", () =>
157157 Effect.gen(function* () {
158 if ((yield* HostProcessPlatform) !== "linux") return;
158 if ((yield* HostProcess.Platform) !== "linux") return;
159159 const lease = AcpSessionRuntime.makeLinuxCgroupController().create();
160160 if (lease === undefined) return;
161161 const scratchRoot = NodePath.join(process.cwd(), "tmp");
......@@ -235,7 +235,7 @@ describe("terminatePosixOwnedProcessTree", () => {
235235 );
236236
237237 it("contains a packaged-runtime command without requiring cgroup delegation", () => {
238 if (HostProcessPlatform.defaultValue() !== "linux") return;
238 if (HostProcess.Platform.defaultValue() !== "linux") return;
239239 const scratchRoot = NodePath.join(process.cwd(), "tmp");
240240 NodeFS.mkdirSync(scratchRoot, { recursive: true });
241241 const scratch = NodeFS.mkdtempSync(NodePath.join(scratchRoot, "acp-cgroup-wrapper-fake-"));
......@@ -316,7 +316,7 @@ describe("terminatePosixOwnedProcessTree", () => {
316316
317317 it.live("kills a post-TERM detached double fork without touching an unrelated sentinel", () =>
318318 Effect.gen(function* () {
319 if ((yield* HostProcessPlatform) !== "linux") return;
319 if ((yield* HostProcess.Platform) !== "linux") return;
320320 const controller = AcpSessionRuntime.makeLinuxCgroupController();
321321 const lease = controller.create();
322322 if (lease === undefined) return;
......@@ -531,7 +531,7 @@ describe("terminatePosixOwnedProcessTree", () => {
531531
532532 it.live("finds a child forked by a non-leader pthread", () =>
533533 Effect.gen(function* () {
534 if ((yield* HostProcessPlatform) !== "linux") return;
534 if ((yield* HostProcess.Platform) !== "linux") return;
535535 const scratchRoot = NodePath.join(process.cwd(), "tmp");
536536 NodeFS.mkdirSync(scratchRoot, { recursive: true });
537537 const scratch = NodeFS.mkdtempSync(NodePath.join(scratchRoot, "acp-pthread-spawn-"));
apps/server/src/provider/antigravityAuthSupport.test.ts+5-9
......@@ -5,11 +5,7 @@ import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
55import * as NodePath from "@effect/platform-node/NodePath";
66import * as NodeServices from "@effect/platform-node/NodeServices";
77import { ProviderInstanceId } from "@t3tools/contracts";
8import {
9 HostProcessExecutablePath,
10 HostProcessIsExecutable,
11 HostProcessPlatform,
12} from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
139import { describe, expect, it } from "@effect/vitest";
1410import * as Effect from "effect/Effect";
1511import * as FileSystem from "effect/FileSystem";
......@@ -574,8 +570,8 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {
574570 expect(profile.browserCommand).not.toContain("/packaged/t3");
575571 expect(yield* fs.exists(profile.acpDirectory)).toBe(true);
576572 }).pipe(
577 Effect.provideService(HostProcessIsExecutable, true),
578 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),
573 Effect.provideService(HostProcess.IsExecutable, true),
574 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
579575 ),
580576 );
581577
......@@ -601,7 +597,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {
601597 });
602598 }
603599 expect(yield* fs.exists(profileDirectory)).toBe(false);
604 }).pipe(Effect.provideService(HostProcessIsExecutable, true)),
600 }).pipe(Effect.provideService(HostProcess.IsExecutable, true)),
605601 );
606602
607603 it.effect("preflights the no-browser helper and creates private directories only", () =>
......@@ -616,7 +612,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {
616612 expect(profile.geminiHome).toBe(path.join(temporaryDirectory, "profile"));
617613 expect(yield* fs.exists(profile.acpDirectory)).toBe(true);
618614 expect(yield* fs.exists(profile.tokenPath)).toBe(false);
619 if ((yield* HostProcessPlatform) !== "win32") {
615 if ((yield* HostProcess.Platform) !== "win32") {
620616 expect((yield* fs.stat(profile.geminiHome)).mode & 0o777).toBe(0o700);
621617 expect((yield* fs.stat(profile.acpDirectory)).mode & 0o777).toBe(0o700);
622618 }
apps/server/src/provider/antigravityAuthSupport.ts+3-3
......@@ -2,7 +2,7 @@
22import * as NodeFSP from "node:fs/promises";
33
44import type { AntigravityAuthMethod, ProviderInstanceId } from "@t3tools/contracts";
5import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";
77import * as Crypto from "effect/Crypto";
88import * as Effect from "effect/Effect";
......@@ -315,13 +315,13 @@ export const prepareAntigravityProfile = Effect.fn("prepareAntigravityProfile")(
315315 const fs = yield* FileSystem.FileSystem;
316316 const path = yield* Path.Path;
317317 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
318 const platform = input.platform ?? (yield* HostProcessPlatform);
318 const platform = input.platform ?? (yield* HostProcess.Platform);
319319 const userHome =
320320 input.userHome ??
321321 resolveAntigravityUserHome(
322322 platform,
323323 input.baseEnv ?? process.env,
324 yield* HostProcessHomeDirectory,
324 yield* HostProcess.HomeDirectory,
325325 );
326326 const runtimeExecutablePath =
327327 input.runtimeExecutablePath ??
apps/server/src/provider/claudeResetCredits.test.ts+6-6
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { it as effectIt } from "@effect/vitest";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Deferred from "effect/Deferred";
55import * as Effect from "effect/Effect";
66import * as FileSystem from "effect/FileSystem";
......@@ -111,7 +111,7 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => {
111111 );
112112 });
113113 const credits = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(
114 Effect.provideService(HostProcessPlatform, "linux"),
114 Effect.provideService(HostProcess.Platform, "linux"),
115115 Effect.provideService(HttpClient.HttpClient, client),
116116 );
117117 expect(credits).toEqual({ availableCount: 1, nextCreditId: "grant_a" });
......@@ -122,11 +122,11 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => {
122122 Effect.gen(function* () {
123123 const { configDir } = yield* writeLogin;
124124 const darwin = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(
125 Effect.provideService(HostProcessPlatform, "darwin"),
125 Effect.provideService(HostProcess.Platform, "darwin"),
126126 Effect.provideService(HttpClient.HttpClient, refuseRequests),
127127 );
128128 const limited = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(
129 Effect.provideService(HostProcessPlatform, "linux"),
129 Effect.provideService(HostProcess.Platform, "linux"),
130130 Effect.provideService(HttpClient.HttpClient, respond(429, {})),
131131 );
132132 expect([darwin, limited]).toEqual([undefined, undefined]);
......@@ -147,7 +147,7 @@ const consume = (client: HttpClient.HttpClient, ids = { grantId: "grant_a", requ
147147 version: "2.1.0",
148148 ...ids,
149149 }).pipe(
150 Effect.provideService(HostProcessPlatform, "linux"),
150 Effect.provideService(HostProcess.Platform, "linux"),
151151 Effect.provideService(HttpClient.HttpClient, client),
152152 Effect.result,
153153 );
......@@ -228,7 +228,7 @@ effectIt.layer(NodeServices.layer)("consumeClaudeResetCredit", (it) => {
228228 grantId: "grant_a",
229229 requestId: "r-1",
230230 }).pipe(
231 Effect.provideService(HostProcessPlatform, "linux"),
231 Effect.provideService(HostProcess.Platform, "linux"),
232232 Effect.provideService(HttpClient.HttpClient, client),
233233 Effect.result,
234234 Effect.forkChild,
apps/server/src/provider/claudeResetCredits.ts+3-3
......@@ -11,7 +11,7 @@ import type {
1111 ProviderConsumeResetCreditOutcome,
1212 ServerProviderResetCredits,
1313} from "@t3tools/contracts";
14import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515import * as DateTime from "effect/DateTime";
1616import * as Effect from "effect/Effect";
1717import * as FileSystem from "effect/FileSystem";
......@@ -149,7 +149,7 @@ const readJson = <S extends Schema.Top>(schema: S, file: string) =>
149149
150150const readAccessToken = (configDir: string) =>
151151 Effect.gen(function* () {
152 if ((yield* HostProcessPlatform) === "darwin") return undefined;
152 if ((yield* HostProcess.Platform) === "darwin") return undefined;
153153 const path = yield* Path.Path;
154154 const credentials = yield* readJson(Credentials, path.join(configDir, ".credentials.json"));
155155 return credentials.claudeAiOauth?.accessToken?.trim() || undefined;
......@@ -195,7 +195,7 @@ export const claudeAccountConfigPath = Effect.fn("claudeAccountConfigPath")(func
195195 const path = yield* Path.Path;
196196 return configDir
197197 ? path.join(configDir, ".claude.json")
198 : path.join(yield* HostProcessHomeDirectory, ".claude.json");
198 : path.join(yield* HostProcess.HomeDirectory, ".claude.json");
199199});
200200
201201const CLAIM_OUTCOMES = {
apps/server/src/provider/providerInstallation.test.ts+2-2
......@@ -5,7 +5,7 @@ import {
55 ProviderInstanceId,
66 type ProviderInstallState,
77} from "@t3tools/contracts";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99import * as Effect from "effect/Effect";
1010import * as FileSystem from "effect/FileSystem";
1111import * as Layer from "effect/Layer";
......@@ -215,7 +215,7 @@ describe("provider installation routing", () => {
215215 Effect.gen(function* () {
216216 const fs = yield* FileSystem.FileSystem;
217217 const path = yield* Path.Path;
218 const platform = yield* HostProcessPlatform;
218 const platform = yield* HostProcess.Platform;
219219 const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-provider-install-route-" });
220220 const binary = platform === "win32" ? "agy-test.exe" : "agy-test";
221221 const executable = path.join(directory, binary);
apps/server/src/provider/providerMaintenanceRunner.test.ts+4-4
......@@ -20,7 +20,7 @@ import * as Stream from "effect/Stream";
2020import * as TestClock from "effect/testing/TestClock";
2121import { HttpClient, HttpClientResponse } from "effect/http";
2222import { ChildProcessSpawner } from "effect/process";
23import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
23import * as HostProcess from "@t3tools/shared/HostProcess";
2424import { SpawnExecutableResolution } from "@t3tools/shared/shell";
2525
2626import * as ProviderRegistry from "./ProviderRegistry.ts";
......@@ -45,7 +45,7 @@ const encoder = new TextEncoder();
4545// `{ command, args }` assertions below hold deterministically on any host
4646// (including Windows). Windows-specific resolution is covered by the dedicated
4747// win32 case at the end of this suite.
48const layerNonWindowsPlatform = Layer.succeed(HostProcessPlatform, "linux");
48const layerNonWindowsPlatform = Layer.succeed(HostProcess.Platform, "linux");
4949
5050function lifecycleFor(provider: ProviderDriverKind): ProviderMaintenanceCapabilities {
5151 if (provider === NATIVE_CLI_DRIVER) {
......@@ -962,8 +962,8 @@ describe("providerMaintenanceRunner", () => {
962962 }).pipe(
963963 Effect.provide(
964964 Layer.mergeAll(
965 Layer.succeed(HostProcessPlatform, "win32"),
966 Layer.succeed(HostProcessEnvironment, {
965 Layer.succeed(HostProcess.Platform, "win32"),
966 Layer.succeed(HostProcess.Environment, {
967967 PATH: "C:\\fake\\npm",
968968 PATHEXT: ".COM;.EXE;.BAT;.CMD",
969969 }),
apps/server/src/resourceTelemetry/HostResources.ts+2-2
......@@ -1,6 +1,6 @@
11import * as NodeOS from "node:os";
22import type { HostResourcesSnapshot } from "@t3tools/contracts";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Cache from "effect/Cache";
55import * as Context from "effect/Context";
66import * as DateTime from "effect/DateTime";
......@@ -40,7 +40,7 @@ function darwinAvailableMemory(output: string): number | null {
4040
4141const make = Effect.fn("makeHostResources")(function* () {
4242 const fs = yield* FileSystem.FileSystem;
43 const platform = yield* HostProcessPlatform;
43 const platform = yield* HostProcess.Platform;
4444 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
4545
4646 const sample = Effect.fn("HostResources.sample")(function* () {
apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts+20-24
......@@ -1,9 +1,5 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
2import {
3 HostProcessArchitecture,
4 HostProcessEnvironment,
5 HostProcessPlatform,
6} from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
73import { afterEach, assert, describe, expect, it, vi } from "@effect/vitest";
84import * as Effect from "effect/Effect";
95import * as FileSystem from "effect/FileSystem";
......@@ -13,7 +9,7 @@ import * as ResourceMonitorBinary from "./ResourceMonitorBinary.ts";
139
1410// The override checks POSIX exec bits on a real file under a linux platform
1511// mock; NTFS never reports those bits, so the check cannot be satisfied there.
16const windowsHost = HostProcessPlatform.defaultValue() === "win32";
12const windowsHost = HostProcess.Platform.defaultValue() === "win32";
1713
1814describe("ResourceMonitorBinary", () => {
1915 afterEach(() => {
......@@ -34,9 +30,9 @@ describe("ResourceMonitorBinary", () => {
3430
3531 const service = yield* ResourceMonitorBinary.make().pipe(
3632 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
37 Effect.provideService(HostProcessPlatform, "win32"),
38 Effect.provideService(HostProcessArchitecture, "arm64"),
39 Effect.provideService(HostProcessEnvironment, {
33 Effect.provideService(HostProcess.Platform, "win32"),
34 Effect.provideService(HostProcess.Architecture, "arm64"),
35 Effect.provideService(HostProcess.Environment, {
4036 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
4137 }),
4238 );
......@@ -58,10 +54,10 @@ describe("ResourceMonitorBinary", () => {
5854
5955 const service = yield* ResourceMonitorBinary.make().pipe(
6056 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
61 Effect.provideService(HostProcessPlatform, "linux"),
62 Effect.provideService(HostProcessArchitecture, "x64"),
57 Effect.provideService(HostProcess.Platform, "linux"),
58 Effect.provideService(HostProcess.Architecture, "x64"),
6359 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"),
64 Effect.provideService(HostProcessEnvironment, {
60 Effect.provideService(HostProcess.Environment, {
6561 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
6662 }),
6763 );
......@@ -82,9 +78,9 @@ describe("ResourceMonitorBinary", () => {
8278
8379 const service = yield* ResourceMonitorBinary.make().pipe(
8480 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
85 Effect.provideService(HostProcessPlatform, "freebsd"),
86 Effect.provideService(HostProcessArchitecture, "ia32"),
87 Effect.provideService(HostProcessEnvironment, {
81 Effect.provideService(HostProcess.Platform, "freebsd"),
82 Effect.provideService(HostProcess.Architecture, "ia32"),
83 Effect.provideService(HostProcess.Environment, {
8884 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
8985 }),
9086 );
......@@ -105,10 +101,10 @@ describe("ResourceMonitorBinary", () => {
105101
106102 const service = yield* ResourceMonitorBinary.make().pipe(
107103 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
108 Effect.provideService(HostProcessPlatform, "linux"),
109 Effect.provideService(HostProcessArchitecture, "x64"),
104 Effect.provideService(HostProcess.Platform, "linux"),
105 Effect.provideService(HostProcess.Architecture, "x64"),
110106 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "gnu"),
111 Effect.provideService(HostProcessEnvironment, {
107 Effect.provideService(HostProcess.Environment, {
112108 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
113109 }),
114110 );
......@@ -127,9 +123,9 @@ describe("ResourceMonitorBinary", () => {
127123 });
128124 const service = yield* ResourceMonitorBinary.make().pipe(
129125 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
130 Effect.provideService(HostProcessPlatform, "freebsd"),
131 Effect.provideService(HostProcessArchitecture, "ia32"),
132 Effect.provideService(HostProcessEnvironment, {}),
126 Effect.provideService(HostProcess.Platform, "freebsd"),
127 Effect.provideService(HostProcess.Architecture, "ia32"),
128 Effect.provideService(HostProcess.Environment, {}),
133129 );
134130 const error = yield* Effect.flip(service.resolve);
135131
......@@ -145,10 +141,10 @@ describe("ResourceMonitorBinary", () => {
145141 });
146142 const service = yield* ResourceMonitorBinary.make().pipe(
147143 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
148 Effect.provideService(HostProcessPlatform, "linux"),
149 Effect.provideService(HostProcessArchitecture, "x64"),
144 Effect.provideService(HostProcess.Platform, "linux"),
145 Effect.provideService(HostProcess.Architecture, "x64"),
150146 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"),
151 Effect.provideService(HostProcessEnvironment, {}),
147 Effect.provideService(HostProcess.Environment, {}),
152148 );
153149 const error = yield* Effect.flip(service.resolve);
154150
apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts+4-8
......@@ -1,8 +1,4 @@
1import {
2 HostProcessArchitecture,
3 HostProcessEnvironment,
4 HostProcessPlatform,
5} from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
62import * as Context from "effect/Context";
73import * as Effect from "effect/Effect";
84import * as FileSystem from "effect/FileSystem";
......@@ -139,9 +135,9 @@ export const make = Effect.fn("resourceTelemetry.resourceMonitorBinary.make")(fu
139135 const config = yield* ServerConfig.ServerConfig;
140136 const fileSystem = yield* FileSystem.FileSystem;
141137 const path = yield* Path.Path;
142 const platform = yield* HostProcessPlatform;
143 const architecture = yield* HostProcessArchitecture;
144 const environment = yield* HostProcessEnvironment;
138 const platform = yield* HostProcess.Platform;
139 const architecture = yield* HostProcess.Architecture;
140 const environment = yield* HostProcess.Environment;
145141 const linuxLibc = platform === "linux" ? yield* ResourceMonitorHostLinuxLibc : undefined;
146142 const executableName = binaryName(platform);
147143 const platformKey = resourceMonitorPlatformKey(platform, architecture);
apps/server/src/review/ReviewService.ts+2-2
......@@ -20,7 +20,7 @@ import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";
2020import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts";
2121import * as ServerSettings from "../serverSettings.ts";
2222import { isFilesystemRoot, managedWorktreesDirectories } from "../worktreesDirectory.ts";
23import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
23import * as HostProcess from "@t3tools/shared/HostProcess";
2424
2525export class ReviewService extends Context.Service<
2626 ReviewService,
......@@ -74,7 +74,7 @@ export const make = Effect.gen(function* () {
7474 const worktreesDirectories = yield* settings.getSettings.pipe(
7575 Effect.orElseSucceed(() => ({ worktreesDirectory: "", previousWorktreesDirectories: [] })),
7676 );
77 const home = yield* HostProcessHomeDirectory;
77 const home = yield* HostProcess.HomeDirectory;
7878 const [candidate, workspaceRoot, worktreesRoots] = yield* Effect.all([
7979 canonicalizePath(cwd),
8080 canonicalizePath(config.cwd),
apps/server/src/sourceControl/SourceControlRepositoryService.ts+2-2
......@@ -29,7 +29,7 @@ import {
2929import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";
3030import * as BitbucketApi from "@t3tools/source-control-bitbucket/server/BitbucketApi";
3131import * as SourceControlProviderRegistry from "./SourceControlProviderRegistry.ts";
32import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
32import * as HostProcess from "@t3tools/shared/HostProcess";
3333const isSourceControlRepositoryError = Schema.is(SourceControlRepositoryError);
3434const isSourceControlProviderError = Schema.is(SourceControlProviderError);
3535const isBitbucketRepositoryLocatorError = Schema.is(BitbucketApi.BitbucketRepositoryLocatorError);
......@@ -214,7 +214,7 @@ export const make = Effect.gen(function* () {
214214 });
215215 }
216216
217 return path.resolve(expandHomePath(trimmed, yield* HostProcessHomeDirectory));
217 return path.resolve(expandHomePath(trimmed, yield* HostProcess.HomeDirectory));
218218 },
219219 );
220220
apps/server/src/storageCleanup.ts+2-2
......@@ -38,7 +38,7 @@ import * as TerminalManager from "./terminal/Manager.ts";
3838import { isFilesystemRoot, managedWorktreesDirectories } from "./worktreesDirectory.ts";
3939import * as GitVcsDriver from "./vcs/GitVcsDriver.ts";
4040import { withWorkspaceLease } from "./workspace/workspaceLease.ts";
41import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
41import * as HostProcess from "@t3tools/shared/HostProcess";
4242
4343const decodeCleanupThread = Schema.decodeUnknownEffect(
4444 Schema.fromJsonString(OrchestrationV2AppThreadJson),
......@@ -214,7 +214,7 @@ export const make = Effect.gen(function* () {
214214 serverSettings,
215215 config.worktreesDir,
216216 path,
217 yield* HostProcessHomeDirectory,
217 yield* HostProcess.HomeDirectory,
218218 )) {
219219 // An unmounted drive only skips its own worktrees.
220220 const root = yield* fs.exists(directory).pipe(
apps/server/src/telemetry/AnalyticsService.test.ts+7-7
......@@ -11,7 +11,7 @@ import * as HttpClientError from "effect/http/HttpClientError";
1111import * as HttpServer from "effect/http/HttpServer";
1212import * as HttpServerRequest from "effect/http/HttpServerRequest";
1313import * as HttpServerResponse from "effect/http/HttpServerResponse";
14import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515
1616import * as ServerConfig from "../config.ts";
1717import { getTelemetryIdentifier } from "./Identify.ts";
......@@ -105,8 +105,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {
105105 ),
106106 Layer.provide(
107107 Layer.mergeAll(
108 Layer.succeed(HostProcessPlatform, "win32"),
109 Layer.succeed(HostProcessArchitecture, "x64"),
108 Layer.succeed(HostProcess.Platform, "win32"),
109 Layer.succeed(HostProcess.Architecture, "x64"),
110110 layerAcceptThenFailClient(batches),
111111 ),
112112 ),
......@@ -167,8 +167,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {
167167 Layer.provide(layerConfig),
168168 Layer.provide(
169169 Layer.mergeAll(
170 Layer.succeed(HostProcessPlatform, "linux"),
171 Layer.succeed(HostProcessArchitecture, "arm64"),
170 Layer.succeed(HostProcess.Platform, "linux"),
171 Layer.succeed(HostProcess.Architecture, "arm64"),
172172 ),
173173 ),
174174 Layer.provideMerge(NodeHttpServer.layerTest),
......@@ -257,8 +257,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {
257257 Layer.provide(layerConfig),
258258 Layer.provide(
259259 Layer.mergeAll(
260 Layer.succeed(HostProcessPlatform, "linux"),
261 Layer.succeed(HostProcessArchitecture, "arm64"),
260 Layer.succeed(HostProcess.Platform, "linux"),
261 Layer.succeed(HostProcess.Architecture, "arm64"),
262262 ),
263263 ),
264264 Layer.provideMerge(NodeHttpServer.layerTest),
apps/server/src/telemetry/AnalyticsService.ts+3-3
......@@ -8,7 +8,7 @@
88 *
99 * @module AnalyticsService
1010 */
11import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
11import * as HostProcess from "@t3tools/shared/HostProcess";
1212import type { ClientOs } from "@t3tools/contracts";
1313import * as Clock from "effect/Clock";
1414import * as Config from "effect/Config";
......@@ -136,8 +136,8 @@ export const make = Effect.gen(function* () {
136136 // The background flush and the shutdown flush must not send the same batch at once.
137137 const flushLock = yield* Semaphore.make(1);
138138 const clientType = serverConfig.mode === "desktop" ? "desktop-app" : "cli-web-client";
139 const hostPlatform = yield* HostProcessPlatform;
140 const hostArchitecture = yield* HostProcessArchitecture;
139 const hostPlatform = yield* HostProcess.Platform;
140 const hostArchitecture = yield* HostProcess.Architecture;
141141
142142 const enqueueBufferedEvent = (
143143 uuid: string,
apps/server/src/telemetry/Identify.ts+2-2
......@@ -9,7 +9,7 @@ import * as Schema from "effect/Schema";
99
1010import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite";
1111import * as ServerConfig from "../config.ts";
12import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
12import * as HostProcess from "@t3tools/shared/HostProcess";
1313
1414/**
1515 * Codex writes `tokens` only for ChatGPT logins and omits the key for API-key,
......@@ -312,6 +312,6 @@ export const getTelemetryIdentifierForHome = Effect.fn("getTelemetryIdentifierFo
312312);
313313
314314export const getTelemetryIdentifier = Effect.flatMap(
315 HostProcessHomeDirectory,
315 HostProcess.HomeDirectory,
316316 getTelemetryIdentifierForHome,
317317);
apps/server/src/terminal/Manager.test.ts+6-6
......@@ -12,7 +12,7 @@ import {
1212 ServerSettingsError,
1313 TerminalProviderInstanceNotFoundError,
1414} from "@t3tools/contracts";
15import { HostProcessPlatform, HostProcessArchitecture } from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
1616import * as Data from "effect/Data";
1717import * as Clock from "effect/Clock";
1818import * as Deferred from "effect/Deferred";
......@@ -315,7 +315,7 @@ const createManager = (
315315 );
316316
317317const layerWithHostPlatform = (platform: NodeJS.Platform) =>
318 Layer.succeed(HostProcessPlatform, platform);
318 Layer.succeed(HostProcess.Platform, platform);
319319
320320// Apply the existing line policy, then find the longest code-point-aligned byte tail.
321321function retainedHistory(text: string, maxLines: number, maxBytes = Infinity): string {
......@@ -619,7 +619,7 @@ it.layer(
619619
620620 it.effect("preserves non-notFound cwd stat failures", () =>
621621 Effect.gen(function* () {
622 if ((yield* HostProcessPlatform) === "win32") return;
622 if ((yield* HostProcess.Platform) === "win32") return;
623623
624624 const path = yield* Path.Path;
625625
......@@ -1826,7 +1826,7 @@ it.layer(
18261826
18271827 it.effect("retries with fallback shells when preferred shell spawn fails", () =>
18281828 Effect.gen(function* () {
1829 const platform = yield* HostProcessPlatform;
1829 const platform = yield* HostProcess.Platform;
18301830 const missingShell =
18311831 platform === "win32" ? "C:\\definitely\\missing-shell.exe" : "/definitely/missing-shell -l";
18321832 const { manager, ptyAdapter } = yield* createManager(5, {
......@@ -1933,7 +1933,7 @@ it.layer(
19331933 Effect.provide(
19341934 Layer.merge(
19351935 layerWithHostPlatform("win32"),
1936 Layer.succeed(HostProcessArchitecture, "x64"),
1936 Layer.succeed(HostProcess.Architecture, "x64"),
19371937 ),
19381938 ),
19391939 );
......@@ -2513,7 +2513,7 @@ it.layer(
25132513
25142514 it.effect("starts zsh with prompt spacer disabled to avoid `%` end markers", () =>
25152515 Effect.gen(function* () {
2516 if ((yield* HostProcessPlatform) === "win32") return;
2516 if ((yield* HostProcess.Platform) === "win32") return;
25172517 const { manager, ptyAdapter } = yield* createManager(5, {
25182518 shellResolver: () => "/bin/zsh",
25192519 });
apps/server/src/terminal/Manager.ts+4-8
......@@ -42,11 +42,7 @@ import {
4242} from "@t3tools/contracts";
4343import { makeKeyedCoalescingWorker } from "@t3tools/shared/KeyedCoalescingWorker";
4444import * as KeyedLock from "@t3tools/shared/KeyedLock";
45import {
46 HostProcessArchitecture,
47 HostProcessHomeDirectory,
48 HostProcessPlatform,
49} from "@t3tools/shared/hostProcess";
45import * as HostProcess from "@t3tools/shared/HostProcess";
5046import { mergePathEntries } from "@t3tools/shared/shell";
5147
5248import { acpRegistryManagedBinaryDirectories } from "@t3tools/provider-acp-registry/server";
......@@ -1482,8 +1478,8 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func
14821478 const logsDir = options.logsDir;
14831479 const historyLineLimit = options.historyLineLimit ?? DEFAULT_HISTORY_LINE_LIMIT;
14841480 const historyByteLimit = options.historyByteLimit ?? DEFAULT_HISTORY_BYTE_LIMIT;
1485 const platform = yield* HostProcessPlatform;
1486 const architecture = yield* HostProcessArchitecture;
1481 const platform = yield* HostProcess.Platform;
1482 const architecture = yield* HostProcess.Architecture;
14871483 // Terminals must inherit the user's full environment (minus the blocklist
14881484 // applied in createTerminalSpawnEnv) — an allowlist here silently strips
14891485 // things like PSModulePath, DISPLAY, proxies, and toolchain variables.
......@@ -2253,7 +2249,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func
22532249 baseEnv,
22542250 session.runtimeEnv,
22552251 platform,
2256 yield* HostProcessHomeDirectory,
2252 yield* HostProcess.HomeDirectory,
22572253 );
22582254 // Append (never prepend) managed ACP agent install directories so
22592255 // `kimi login` and friends resolve by name without shadowing any
apps/server/src/terminal/NodePtyAdapter.test.ts+5-5
......@@ -3,7 +3,7 @@ import * as NodeNet from "node:net";
33
44import * as NodeServices from "@effect/platform-node/NodeServices";
55import { assert, it } from "@effect/vitest";
6import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
6import * as HostProcess from "@t3tools/shared/HostProcess";
77import * as Cause from "effect/Cause";
88import * as Effect from "effect/Effect";
99import * as Exit from "effect/Exit";
......@@ -66,8 +66,8 @@ const layerTestFor = (platform: NodeJS.Platform = "win32") =>
6666 Layer.provide(
6767 Layer.mergeAll(
6868 NodeServices.layer,
69 Layer.succeed(HostProcessPlatform, platform),
70 Layer.succeed(HostProcessArchitecture, "x64"),
69 Layer.succeed(HostProcess.Platform, platform),
70 Layer.succeed(HostProcess.Architecture, "x64"),
7171 Layer.succeed(NodePtyAdapter.NodePtyModuleLoaderRef, () => Promise.resolve(fakeNodePty)),
7272 ),
7373 ),
......@@ -272,8 +272,8 @@ it.effect("reports native module load failures as structured startup defects", (
272272 Effect.provide(
273273 Layer.mergeAll(
274274 NodeServices.layer,
275 Layer.succeed(HostProcessPlatform, "win32"),
276 Layer.succeed(HostProcessArchitecture, "x64"),
275 Layer.succeed(HostProcess.Platform, "win32"),
276 Layer.succeed(HostProcess.Architecture, "x64"),
277277 ),
278278 ),
279279 ),
apps/server/src/terminal/NodePtyAdapter.ts+8-8
......@@ -7,7 +7,7 @@ import * as FileSystem from "effect/FileSystem";
77import * as Layer from "effect/Layer";
88import * as Path from "effect/Path";
99import * as Schema from "effect/Schema";
10import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111
1212import * as PtyAdapter from "@t3tools/shared/PtyAdapter";
1313
......@@ -46,8 +46,8 @@ let didEnsureSpawnHelperExecutable = false;
4646const resolveNodePtySpawnHelperPath = Effect.gen(function* () {
4747 const path = yield* Path.Path;
4848 const fs = yield* FileSystem.FileSystem;
49 const platform = yield* HostProcessPlatform;
50 const architecture = yield* HostProcessArchitecture;
49 const platform = yield* HostProcess.Platform;
50 const architecture = yield* HostProcess.Architecture;
5151
5252 const packageJsonPath = requireForNodePty.resolve("node-pty/package.json");
5353 const packageDir = path.dirname(packageJsonPath);
......@@ -67,7 +67,7 @@ const resolveNodePtySpawnHelperPath = Effect.gen(function* () {
6767
6868const ensureNodePtySpawnHelperExecutable = Effect.fn(function* () {
6969 const fs = yield* FileSystem.FileSystem;
70 const platform = yield* HostProcessPlatform;
70 const platform = yield* HostProcess.Platform;
7171 if (platform === "win32") return;
7272 if (didEnsureSpawnHelperExecutable) return;
7373
......@@ -236,8 +236,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () {
236236 const loadNodePtyModule = yield* NodePtyModuleLoaderRef;
237237 const fs = yield* FileSystem.FileSystem;
238238 const path = yield* Path.Path;
239 const platform = yield* HostProcessPlatform;
240 const architecture = yield* HostProcessArchitecture;
239 const platform = yield* HostProcess.Platform;
240 const architecture = yield* HostProcess.Architecture;
241241
242242 const nodePty = yield* Effect.tryPromise({
243243 try: loadNodePtyModule,
......@@ -253,8 +253,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () {
253253 ensureNodePtySpawnHelperExecutable().pipe(
254254 Effect.provideService(FileSystem.FileSystem, fs),
255255 Effect.provideService(Path.Path, path),
256 Effect.provideService(HostProcessPlatform, platform),
257 Effect.provideService(HostProcessArchitecture, architecture),
256 Effect.provideService(HostProcess.Platform, platform),
257 Effect.provideService(HostProcess.Architecture, architecture),
258258 Effect.orElseSucceed(() => undefined),
259259 ),
260260 );
apps/server/src/textGeneration/ClaudeTextGeneration.test.ts+3-3
......@@ -1,7 +1,7 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { it } from "@effect/vitest";
33import { ClaudeSettings, ProviderInstanceId } from "@t3tools/contracts";
4import { HostProcessPlatform, isHostWindows } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55import { createModelSelection } from "@t3tools/shared/model";
66import * as Effect from "effect/Effect";
77import * as FileSystem from "effect/FileSystem";
......@@ -35,7 +35,7 @@ function makeFakeClaudeBinary(dir: string) {
3535 return Effect.gen(function* () {
3636 const path = yield* Path.Path;
3737 const fs = yield* FileSystem.FileSystem;
38 const platform = yield* HostProcessPlatform;
38 const platform = yield* HostProcess.Platform;
3939 const binDir = path.join(dir, "bin");
4040 const fixturePath = yield* path.fromFileUrl(
4141 new URL("./testing/ClaudeTextGeneration.fixture.mjs", import.meta.url),
......@@ -69,7 +69,7 @@ function withFakeClaudeEnv<A, E, R>(
6969 const fs = yield* FileSystem.FileSystem;
7070 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3code-claude-text-" });
7171 const binDir = yield* makeFakeClaudeBinary(tempDir);
72 const pathDelimiter = (yield* isHostWindows) ? ";" : ":";
72 const pathDelimiter = (yield* HostProcess.isWindows) ? ";" : ":";
7373 const previousPath = process.env.PATH;
7474 const previousOutput = process.env.T3_FAKE_CLAUDE_OUTPUT;
7575 const previousExitCode = process.env.T3_FAKE_CLAUDE_EXIT_CODE;
apps/server/src/textGeneration/CodexTextGeneration.ts+2-2
......@@ -26,7 +26,7 @@ import {
2626} from "@t3tools/provider-core/server/textGenerationUtils";
2727import { codexModelFamily, getModelSelectionStringOptionValue } from "@t3tools/shared/model";
2828import { getCodexServiceTierOptionValue } from "../codexModelOptions.ts";
29import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
29import * as HostProcess from "@t3tools/shared/HostProcess";
3030
3131const CODEX_TIMEOUT_MS = 180_000;
3232const encodeJsonString = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown));
......@@ -218,7 +218,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func
218218 ? {
219219 CODEX_HOME: expandHomePath(
220220 effectiveConfig.homePath,
221 yield* HostProcessHomeDirectory,
221 yield* HostProcess.HomeDirectory,
222222 ),
223223 }
224224 : {}),
apps/server/src/usage/UsageService.test.ts+5-5
......@@ -8,7 +8,7 @@ import * as NodeSqlite from "node:sqlite";
88
99import { assert, describe, it } from "@effect/vitest";
1010import * as NodeServices from "@effect/platform-node/NodeServices";
11import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
11import * as HostProcess from "@t3tools/shared/HostProcess";
1212import { mergeUsage } from "@t3tools/shared/usageMerge";
1313import {
1414 EnvironmentId,
......@@ -134,7 +134,7 @@ const layerService = (input: {
134134 Layer.provideMerge(Layer.mock(ServerSecretStore.ServerSecretStore)({})),
135135 Layer.provideMerge(ServerConfig.layerTest(process.cwd(), { prefix: input.prefix })),
136136 Layer.provideMerge(NodeServices.layer),
137 Layer.provideMerge(Layer.succeed(HostProcessPlatform, input.platform ?? "linux")),
137 Layer.provideMerge(Layer.succeed(HostProcess.Platform, input.platform ?? "linux")),
138138 Layer.provideMerge(ServerSettings.layerTest(input.settings)),
139139 Layer.provideMerge(
140140 Layer.succeed(
......@@ -150,7 +150,7 @@ const layerService = (input: {
150150 ),
151151 ),
152152 Layer.provideMerge(
153 Layer.succeed(HostProcessEnvironment, {
153 Layer.succeed(HostProcess.Environment, {
154154 HOME: input.home,
155155 GROK_HOME: NodePath.join(input.home, "grok"),
156156 OPENCODE_DATA_DIR: NodePath.join(input.home, "opencode"),
......@@ -1356,7 +1356,7 @@ describe("UsageService", () => {
13561356 }).pipe(Effect.scoped),
13571357 );
13581358
1359 it.live.skipIf(HostProcessPlatform.defaultValue() === "win32")(
1359 it.live.skipIf(HostProcess.Platform.defaultValue() === "win32")(
13601360 "keeps a newer cached read when a slower scan of another window finishes later",
13611361 () =>
13621362 Effect.gen(function* () {
......@@ -1387,7 +1387,7 @@ describe("UsageService", () => {
13871387 }).pipe(Effect.scoped),
13881388 );
13891389
1390 it.live.skipIf(HostProcessPlatform.defaultValue() === "win32")(
1390 it.live.skipIf(HostProcess.Platform.defaultValue() === "win32")(
13911391 "keeps the later read when a scan that read earlier finishes first",
13921392 () =>
13931393 Effect.gen(function* () {
apps/server/src/usage/UsageService.ts+2-2
......@@ -31,7 +31,7 @@ import {
3131 type UsageSummaryInput,
3232 UsageReadError,
3333} from "@t3tools/contracts";
34import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
34import * as HostProcess from "@t3tools/shared/HostProcess";
3535import * as Cause from "effect/Cause";
3636import * as Clock from "effect/Clock";
3737import * as Context from "effect/Context";
......@@ -227,7 +227,7 @@ export const make = Effect.gen(function* () {
227227 const config = yield* ServerConfig.ServerConfig;
228228 const settingsService = yield* ServerSettings.ServerSettingsService;
229229 const httpClient = yield* HttpClient.HttpClient;
230 const hostEnvironment = yield* HostProcessEnvironment;
230 const hostEnvironment = yield* HostProcess.Environment;
231231 // The readers yield their own services; scans run them against this context.
232232 const readerContext = yield* Effect.context<BuiltInUsageReadersEnv>();
233233
apps/server/src/vcs/GitVcsDriverCore.test.ts+5-5
......@@ -1,7 +1,7 @@
11// @effect-diagnostics nodeBuiltinImport:off - realpathSync.native resolves Windows 8.3 short names, which the Effect realPath does not.
22import * as NodeFS from "node:fs";
33import * as NodeServices from "@effect/platform-node/NodeServices";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55import { assert, it, describe } from "@effect/vitest";
66import * as Deferred from "effect/Deferred";
77import * as Effect from "effect/Effect";
......@@ -1864,7 +1864,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
18641864 yield* writeTextFile(cwd, " leading.txt", "whitespace path\n");
18651865 yield* writeTextFile(cwd, "l.txt", "other\n");
18661866 yield* writeTextFile(cwd, "binary.dat", "binary\0data");
1867 if ((yield* HostProcessPlatform) !== "win32") {
1867 if ((yield* HostProcess.Platform) !== "win32") {
18681868 yield* writeTextFile(cwd, "tab\tand\nnewline.txt", "unusual path\n");
18691869 }
18701870 yield* git(cwd, ["add", "."]);
......@@ -1906,7 +1906,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
19061906 additions: 0,
19071907 deletions: 0,
19081908 });
1909 if ((yield* HostProcessPlatform) !== "win32") {
1909 if ((yield* HostProcess.Platform) !== "win32") {
19101910 assert.deepInclude(branch.files ?? [], {
19111911 path: "tab\tand\nnewline.txt",
19121912 previousPath: null,
......@@ -2890,7 +2890,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
28902890 });
28912891
28922892 // NTFS rejects a newline in a file name, so there is nothing to preserve there.
2893 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
2893 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
28942894 "preserves newline characters in worktree paths when listing refs",
28952895 () =>
28962896 Effect.gen(function* () {
......@@ -3965,7 +3965,7 @@ describe("Windows long path configuration", () => {
39653965 const layer = GitVcsDriver.layer.pipe(
39663966 Layer.provide(layerServerConfig),
39673967 Layer.provideMerge(NodeServices.layer),
3968 Layer.provide(Layer.succeed(HostProcessPlatform, platform)),
3968 Layer.provide(Layer.succeed(HostProcess.Platform, platform)),
39693969 );
39703970 return yield* Effect.gen(function* () {
39713971 const driver = yield* GitVcsDriver.GitVcsDriver;
apps/server/src/vcs/GitVcsDriverCore.ts+4-4
......@@ -29,7 +29,7 @@ import {
2929 type VcsRef,
3030} from "@t3tools/contracts";
3131import { dedupeRemoteBranchesWithLocalMatches, normalizeGitRemoteUrl } from "@t3tools/shared/git";
32import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
32import * as HostProcess from "@t3tools/shared/HostProcess";
3333import { compactTraceAttributes } from "@t3tools/shared/observability";
3434import { decodeJsonResult } from "@t3tools/shared/schemaJson";
3535import { parseT3ProjectFile } from "@t3tools/shared/t3ProjectFile";
......@@ -944,7 +944,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
944944 const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
945945 const { worktreesDir } = yield* ServerConfig.ServerConfig;
946946 const crypto = yield* Crypto.Crypto;
947 const hostPlatform = yield* HostProcessPlatform;
947 const hostPlatform = yield* HostProcess.Platform;
948948
949949 const executeRaw: GitVcsDriver.GitVcsDriver["Service"]["execute"] = Effect.fnUntraced(
950950 function* (input) {
......@@ -2657,7 +2657,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
26572657 "hash-object",
26582658 "-t",
26592659 "tree",
2660 (yield* HostProcessPlatform) === "win32" ? "NUL" : "/dev/null",
2660 (yield* HostProcess.Platform) === "win32" ? "NUL" : "/dev/null",
26612661 ]);
26622662 return stdout.trim();
26632663 });
......@@ -3403,7 +3403,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
34033403 options?.worktreesDirectory ?? "",
34043404 worktreesDir,
34053405 path,
3406 yield* HostProcessHomeDirectory,
3406 yield* HostProcess.HomeDirectory,
34073407 );
34083408 if (parentDir === null) {
34093409 return yield* new GitCommandError({
apps/server/src/vcs/VcsProcess.test.ts+2-2
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, describe, expect, it } from "@effect/vitest";
3import { HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Duration from "effect/Duration";
55import * as Deferred from "effect/Deferred";
66import * as Effect from "effect/Effect";
......@@ -535,7 +535,7 @@ describe("VcsProcess.run", () => {
535535 operation: "test.output-limit",
536536 command: "node",
537537 args: ["-e", "process.stdout.write('x'.repeat(2048))"],
538 cwd: yield* HostProcessWorkingDirectory,
538 cwd: yield* HostProcess.WorkingDirectory,
539539 maxOutputBytes: 128,
540540 outputMode: "error",
541541 }).pipe(Effect.flip);
apps/server/src/workspace/WorkspaceEntries.test.ts+3-3
......@@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError";
1111import { vi } from "vite-plus/test";
1212
1313import * as ServerConfig from "../config.ts";
14import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515import * as VcsProcess from "../vcs/VcsProcess.ts";
1616import * as WorkspaceEntries from "./WorkspaceEntries.ts";
1717import * as WorkspacePaths from "./WorkspacePaths.ts";
......@@ -84,7 +84,7 @@ const searchWorkspaceEntries = (input: {
8484 });
8585
8686const appendSeparator = (input: string) =>
87 Effect.map(HostProcessPlatform, (platform) =>
87 Effect.map(HostProcess.Platform, (platform) =>
8888 input.endsWith("/") || input.endsWith("\\")
8989 ? input
9090 : `${input}${platform === "win32" ? "\\" : "/"}`,
......@@ -143,7 +143,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceEntries", (it) => {
143143 const fileSystem = yield* FileSystem.FileSystem;
144144 const path = yield* Path.Path;
145145 yield* writeTextFile(cwd, ".git/HEAD");
146 const platform = yield* HostProcessPlatform;
146 const platform = yield* HostProcess.Platform;
147147 if (platform !== "win32") yield* fileSystem.symlink(outside, path.join(cwd, "external"));
148148 const workspaceEntries = yield* WorkspaceEntries.WorkspaceEntries;
149149 for (const directoryPath of [
apps/server/src/workspace/WorkspaceEntries.ts+4-4
......@@ -19,7 +19,7 @@ import type {
1919 ProjectSearchEntriesInput,
2020 ProjectSearchEntriesResult,
2121} from "@t3tools/contracts";
22import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
22import * as HostProcess from "@t3tools/shared/HostProcess";
2323import { isExplicitRelativePath, isWindowsAbsolutePath } from "@t3tools/shared/path";
2424import { normalizeSearchQuery } from "@t3tools/shared/searchRanking";
2525
......@@ -110,7 +110,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
110110 input: FilesystemBrowseInput,
111111 path: Path.Path,
112112): Effect.fn.Return<string, WorkspaceEntriesBrowseError> {
113 const platform = yield* HostProcessPlatform;
113 const platform = yield* HostProcess.Platform;
114114 if (platform !== "win32" && isWindowsAbsolutePath(input.partialPath)) {
115115 return yield* new WorkspaceEntriesWindowsPathUnsupportedError({
116116 cwd: input.cwd,
......@@ -120,7 +120,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
120120 }
121121
122122 if (!isExplicitRelativePath(input.partialPath)) {
123 return path.resolve(expandHomePath(input.partialPath, yield* HostProcessHomeDirectory));
123 return path.resolve(expandHomePath(input.partialPath, yield* HostProcess.HomeDirectory));
124124 }
125125
126126 if (!input.cwd) {
......@@ -129,7 +129,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
129129 });
130130 }
131131 return path.resolve(
132 expandHomePath(input.cwd, yield* HostProcessHomeDirectory),
132 expandHomePath(input.cwd, yield* HostProcess.HomeDirectory),
133133 input.partialPath,
134134 );
135135});
apps/server/src/workspace/WorkspaceFileSystem.test.ts+2-2
......@@ -14,7 +14,7 @@ import * as VcsProcess from "../vcs/VcsProcess.ts";
1414import * as WorkspaceEntries from "./WorkspaceEntries.ts";
1515import * as WorkspaceFileSystem from "./WorkspaceFileSystem.ts";
1616import * as WorkspacePaths from "./WorkspacePaths.ts";
17import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
17import * as HostProcess from "@t3tools/shared/HostProcess";
1818import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
1919
2020const layerProject = WorkspaceFileSystem.layer.pipe(
......@@ -102,7 +102,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceFileSystemLive", (i
102102 );
103103
104104 // Needs mkfifo; Windows has no FIFOs to reject.
105 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
105 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
106106 "rejects a FIFO without blocking on open",
107107 () =>
108108 Effect.gen(function* () {
apps/server/src/workspace/WorkspacePaths.ts+2-2
......@@ -15,7 +15,7 @@ import * as Path from "effect/Path";
1515import * as Schema from "effect/Schema";
1616
1717import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";
18import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
18import * as HostProcess from "@t3tools/shared/HostProcess";
1919
2020export class WorkspaceRootNotExistsError extends Schema.TaggedError<WorkspaceRootNotExistsError>()(
2121 "WorkspaceRootNotExistsError",
......@@ -154,7 +154,7 @@ export const make = Effect.gen(function* () {
154154 "WorkspacePaths.normalizeWorkspaceRoot",
155155 )(function* (workspaceRoot, options) {
156156 const normalizedWorkspaceRoot = path.resolve(
157 expandHomePath(workspaceRoot.trim(), yield* HostProcessHomeDirectory),
157 expandHomePath(workspaceRoot.trim(), yield* HostProcess.HomeDirectory),
158158 );
159159 let workspaceStat = yield* statWorkspaceRoot(
160160 workspaceRoot,
apps/server/src/ws.test.ts+2-2
......@@ -4,7 +4,7 @@ import {
44 type ServerConfig,
55 type ServerConfigStreamEvent,
66} from "@t3tools/contracts";
7import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
88import * as ConfigProvider from "effect/ConfigProvider";
99import * as Deferred from "effect/Deferred";
1010import * as Duration from "effect/Duration";
......@@ -164,7 +164,7 @@ const makeParkedWindowsLauncher = Effect.gen(function* () {
164164 );
165165 const onWindows = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
166166 effect.pipe(
167 Effect.provideService(HostProcessPlatform, "win32"),
167 Effect.provideService(HostProcess.Platform, "win32"),
168168 Effect.provide(
169169 ConfigProvider.layer(
170170 ConfigProvider.fromEnv({
oxlint-plugin-t3code/rules/no-global-process-runtime.test.ts+6-6
......@@ -8,10 +8,10 @@ describe("t3code/no-global-process-runtime", () => {
88 rule.valid(
99 "allows injected host process references",
1010 `
11 import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
11 import * as HostProcess from "@t3tools/shared/HostProcess";
1212 import * as Effect from "effect/Effect";
1313
14 export const isWindows = Effect.map(HostProcessPlatform, (platform) => platform === "win32");
14 export const isWindows = Effect.map(HostProcess.Platform, (platform) => platform === "win32");
1515 `,
1616 );
1717
......@@ -38,7 +38,7 @@ describe("t3code/no-global-process-runtime", () => {
3838 export const isWindows = process.platform === "win32";
3939 `,
4040 (output) => {
41 assert.match(output, /Use HostProcessPlatform/);
41 assert.match(output, /Use HostProcess\.Platform/);
4242 },
4343 );
4444
......@@ -48,7 +48,7 @@ describe("t3code/no-global-process-runtime", () => {
4848 export const isArm = process.arch === "arm64";
4949 `,
5050 (output) => {
51 assert.match(output, /Use HostProcessArchitecture/);
51 assert.match(output, /Use HostProcess\.Architecture/);
5252 },
5353 );
5454
......@@ -67,7 +67,7 @@ describe("t3code/no-global-process-runtime", () => {
6767 export const isWindows = NodeOS.platform() === "win32";
6868 `,
6969 (output) => {
70 assert.match(output, /Use HostProcessPlatform/);
70 assert.match(output, /Use HostProcess\.Platform/);
7171 },
7272 );
7373
......@@ -79,7 +79,7 @@ describe("t3code/no-global-process-runtime", () => {
7979 export const isArm = hostArch() === "arm64";
8080 `,
8181 (output) => {
82 assert.match(output, /Use HostProcessArchitecture/);
82 assert.match(output, /Use HostProcess\.Architecture/);
8383 },
8484 );
8585
oxlint-plugin-t3code/rules/no-global-process-runtime.ts+1-1
......@@ -19,7 +19,7 @@ const isGlobalProcessObject = (node: unknown): boolean => {
1919};
2020
2121const message = (property: string) =>
22 `Use HostProcess${property === "arch" ? "Architecture" : "Platform"} instead of process.${property}; inject the runtime reference in Effect code and provide it explicitly in tests.`;
22 `Use HostProcess.${property === "arch" ? "Architecture" : "Platform"} instead of process.${property}; inject the runtime reference in Effect code and provide it explicitly in tests.`;
2323
2424const getLiteralStringValue = (node: unknown): Option.Option<string> => {
2525 if (typeof node !== "object" || node === null) return Option.none();
packages/provider-acp-registry/src/server/AcpRegistrySupport.test.ts+14-18
......@@ -6,11 +6,7 @@ import {
66 ProviderInstanceId,
77} from "@t3tools/contracts";
88import { AcpRegistrySettings } from "../settings.ts";
9import {
10 HostProcessArchitecture,
11 HostProcessEnvironment,
12 HostProcessPlatform,
13} from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1410import { SpawnExecutableResolution } from "@t3tools/shared/shell";
1511import * as Deferred from "effect/Deferred";
1612import * as Effect from "effect/Effect";
......@@ -63,9 +59,9 @@ function layerResolver(
6359 return Layer.mergeAll(
6460 NodeServices.layer,
6561 TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)),
66 Layer.succeed(HostProcessPlatform, "linux"),
67 Layer.succeed(HostProcessArchitecture, "x64"),
68 Layer.succeed(HostProcessEnvironment, environment),
62 Layer.succeed(HostProcess.Platform, "linux"),
63 Layer.succeed(HostProcess.Architecture, "x64"),
64 Layer.succeed(HostProcess.Environment, environment),
6965 Layer.succeed(HttpClient.HttpClient, HttpClient.make(execute)),
7066 );
7167}
......@@ -229,7 +225,7 @@ describe("AcpRegistrySupport", () => {
229225 cacheDir,
230226 toolsDir: `${cacheDir}/tools`,
231227 registryUrl,
232 }).pipe(Effect.provideService(HostProcessEnvironment, hostEnvironment));
228 }).pipe(Effect.provideService(HostProcess.Environment, hostEnvironment));
233229 const localSettings = decodeAcpRegistrySettings({
234230 source: "local",
235231 commandPath: "dsh",
......@@ -279,7 +275,7 @@ describe("AcpRegistrySupport", () => {
279275 cacheDir,
280276 toolsDir: `${cacheDir}/tools`,
281277 registryUrl,
282 }).pipe(Effect.provideService(HostProcessEnvironment, environment));
278 }).pipe(Effect.provideService(HostProcess.Environment, environment));
283279 const resolved = yield* resolver.resolve(
284280 decodeAcpRegistrySettings({ source: "local", commandPath }),
285281 "/workspace",
......@@ -300,7 +296,7 @@ describe("AcpRegistrySupport", () => {
300296 toolsDir: `${cacheDir}/tools`,
301297 registryUrl,
302298 }).pipe(
303 Effect.provideService(HostProcessPlatform, "win32"),
299 Effect.provideService(HostProcess.Platform, "win32"),
304300 Effect.provideService(SpawnExecutableResolution, () => `C:\\bin\\dsh${extension}`),
305301 );
306302 const localSettings = decodeAcpRegistrySettings({ source: "local", commandPath: "dsh" });
......@@ -432,7 +428,7 @@ describe("AcpRegistrySupport", () => {
432428 cacheDir,
433429 toolsDir: `${cacheDir}/tools`,
434430 registryUrl,
435 }).pipe(Effect.provideService(HostProcessEnvironment, toolchain.environment));
431 }).pipe(Effect.provideService(HostProcess.Environment, toolchain.environment));
436432
437433 const first = yield* resolver.resolve(settings(), "/workspace", toolchain.environment);
438434 const second = yield* resolver.resolve(settings(), "/workspace", toolchain.environment);
......@@ -478,7 +474,7 @@ describe("AcpRegistrySupport", () => {
478474 cacheDir,
479475 toolsDir: `${cacheDir}/tools`,
480476 registryUrl,
481 }).pipe(Effect.provideService(HostProcessEnvironment, environment));
477 }).pipe(Effect.provideService(HostProcess.Environment, environment));
482478
483479 const resolved = yield* resolver.resolve(settings(), "/workspace", environment);
484480 const userGlobalBin = toolchain.globalBin;
......@@ -559,7 +555,7 @@ describe("AcpRegistrySupport", () => {
559555 toolsDir: `${cacheDir}/tools`,
560556 registryUrl,
561557 }).pipe(
562 Effect.provideService(HostProcessPlatform, "win32"),
558 Effect.provideService(HostProcess.Platform, "win32"),
563559 Effect.provideService(SpawnExecutableResolution, (command) => {
564560 if (command === "uv") return toolchain.uvPath;
565561 if (command === "fast-agent") return toolchain.executablePath;
......@@ -677,7 +673,7 @@ describe("AcpRegistrySupport", () => {
677673 cacheDir,
678674 toolsDir: `${cacheDir}/tools`,
679675 registryUrl,
680 }).pipe(Effect.provideService(HostProcessEnvironment, environment));
676 }).pipe(Effect.provideService(HostProcess.Environment, environment));
681677 yield* resolver.search({ query: "example" });
682678 expect(yield* resolver.inspect(settings(), environment)).toMatchObject({
683679 status: "unprepared",
......@@ -781,8 +777,8 @@ describe("AcpRegistrySupport", () => {
781777 TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)),
782778 ),
783779 ),
784 Effect.provideService(HostProcessPlatform, "linux"),
785 Effect.provideService(HostProcessArchitecture, "x64"),
780 Effect.provideService(HostProcess.Platform, "linux"),
781 Effect.provideService(HostProcess.Architecture, "x64"),
786782 );
787783 });
788784
......@@ -1097,7 +1093,7 @@ describe("AcpRegistrySupport", () => {
10971093 cacheDir,
10981094 toolsDir: `${cacheDir}/tools`,
10991095 registryUrl,
1100 }).pipe(Effect.provideService(HostProcessEnvironment, toolchain.environment));
1096 }).pipe(Effect.provideService(HostProcess.Environment, toolchain.environment));
11011097 const prepared = yield* resolver.prepare({ agentId: agent.id });
11021098 expect(prepared).toEqual({
11031099 agentId: "example-agent",
packages/provider-acp-registry/src/server/AcpRegistrySupport.ts+4-8
......@@ -12,11 +12,7 @@ import {
1212} from "@t3tools/contracts";
1313import type { AcpRegistryDistributionPreference } from "../settings.ts";
1414import type { AcpRegistrySettings } from "../settings.ts";
15import {
16 HostProcessArchitecture,
17 HostProcessEnvironment,
18 HostProcessPlatform,
19} from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
2016import {
2117 mergePathEntries,
2218 resolveSpawnCommand,
......@@ -637,9 +633,9 @@ export const makeAcpRegistryCatalog = Effect.fn("AcpRegistryCatalog.make")(funct
637633 const httpClient = yield* HttpClient.HttpClient;
638634 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
639635 const { settings: hostSettings } = yield* ProviderHost.ProviderHost;
640 const platform = yield* HostProcessPlatform;
641 const architecture = yield* HostProcessArchitecture;
642 const hostEnvironment = yield* HostProcessEnvironment;
636 const platform = yield* HostProcess.Platform;
637 const architecture = yield* HostProcess.Architecture;
638 const hostEnvironment = yield* HostProcess.Environment;
643639 const resolveExecutable = yield* SpawnExecutableResolution;
644640 const platformTarget = resolveAcpRegistryPlatformTarget(platform, architecture);
645641 const registryUrl = input.registryUrl ?? ACP_REGISTRY_URL;
packages/provider-acp-registry/src/server/adapter.ts+2-2
......@@ -5,7 +5,7 @@ import {
55} from "./devinAcp.ts";
66import { defaultInstanceIdForDriver, ProviderDriverKind } from "@t3tools/contracts";
77import { AcpRegistrySettings } from "../settings.ts";
8import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime";
1010import * as Crypto from "effect/Crypto";
1111import * as Effect from "effect/Effect";
......@@ -271,7 +271,7 @@ export const AcpRegistryAdapterV2Driver: ProviderAdapterDriver<
271271 defaultConfig: (): AcpRegistrySettings => DEFAULT_ACP_REGISTRY_SETTINGS,
272272 create: Effect.fn("AcpRegistryAdapterV2Driver.create")(
273273 function* (input: ProviderAdapterDriverCreateInput<AcpRegistrySettings>) {
274 const hostEnvironment = yield* HostProcessEnvironment;
274 const hostEnvironment = yield* HostProcess.Environment;
275275 const selfInvocation = yield* resolveSelfInvocation();
276276 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
277277 const makeNativeLogger = yield* makeAcpNativeLoggerFactory();
packages/provider-acp-registry/src/server/driver.ts+2-2
......@@ -8,7 +8,7 @@ import {
88 type ServerProviderModel,
99} from "@t3tools/contracts";
1010import { AcpRegistrySettings } from "../settings.ts";
11import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
11import * as HostProcess from "@t3tools/shared/HostProcess";
1212import { createModelCapabilities } from "@t3tools/shared/model";
1313import * as Clock from "effect/Clock";
1414import * as Crypto from "effect/Crypto";
......@@ -484,7 +484,7 @@ export const AcpRegistryDriver: ProviderDriver<AcpRegistrySettings, AcpRegistryD
484484 }
485485 const crypto = yield* Crypto.Crypto;
486486 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
487 const hostEnvironment = yield* HostProcessEnvironment;
487 const hostEnvironment = yield* HostProcess.Environment;
488488 const host = yield* ProviderHost.ProviderHost;
489489 const continuationIdentity = defaultProviderContinuationIdentity({
490490 driverKind: DRIVER_KIND,
packages/provider-acp/src/server/AcpSessionRuntime.ts+3-3
......@@ -27,7 +27,7 @@ import * as EffectAcpErrors from "effect-acp/errors";
2727import type * as EffectAcpSchema from "effect-acp/compat";
2828import type * as EffectAcpProtocol from "effect-acp/protocol";
2929import { resolveSpawnCommand } from "@t3tools/shared/shell";
30import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
30import * as HostProcess from "@t3tools/shared/HostProcess";
3131
3232import { signalProcessGroup } from "@t3tools/provider-core/server/processGroup";
3333import { appendAcpStderrTail, sanitizeAcpStderrExcerpt } from "./stderr.ts";
......@@ -1408,7 +1408,7 @@ export const make = (
14081408 const stoppingRef = yield* Ref.make(false);
14091409 const stderrFailure = yield* Deferred.make<never, EffectAcpErrors.AcpError>();
14101410 const stderrTailRef = yield* Ref.make("");
1411 const homeDirectory = yield* HostProcessHomeDirectory;
1411 const homeDirectory = yield* HostProcess.HomeDirectory;
14121412 const stderrDrained = yield* Deferred.make<void>();
14131413 const runtimeClosed = yield* Deferred.make<void>();
14141414 const promptSerializationSemaphore = yield* Semaphore.make(1);
......@@ -1729,7 +1729,7 @@ export const make = (
17291729 Effect.uninterruptible(terminateOwnedProcessGroupImpl),
17301730 );
17311731 if (options.ownDetachedProcessGroup === true) {
1732 const hostPlatform = yield* HostProcessPlatform;
1732 const hostPlatform = yield* HostProcess.Platform;
17331733 const forceTerminateOwnedProcessGroup =
17341734 hostPlatform === "win32"
17351735 ? terminateWindowsProcessTreeWithTaskkill(Number(child.pid)).pipe(
packages/provider-core/src/server/instanceEnvironment.test.ts+2-2
......@@ -2,7 +2,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
22import { describe, expect, it } from "@effect/vitest";
33import * as Effect from "effect/Effect";
44import * as Path from "effect/Path";
5import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66
77import { mergeProviderInstanceEnvironment } from "./instanceEnvironment.ts";
88
......@@ -36,7 +36,7 @@ describe("mergeProviderInstanceEnvironment", () => {
3636 CLAUDE_CONFIG_DIR: "~/.inherited-claude",
3737 });
3838 }).pipe(
39 Effect.provideService(HostProcessHomeDirectory, "/home/ada"),
39 Effect.provideService(HostProcess.HomeDirectory, "/home/ada"),
4040 Effect.provide(NodeServices.layer),
4141 ),
4242 );
packages/provider-core/src/server/instanceEnvironment.ts+2-2
......@@ -1,5 +1,5 @@
11import type { ProviderInstanceEnvironment } from "@t3tools/contracts";
2import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Effect from "effect/Effect";
44
55import { expandHomePath } from "./pathExpansion.ts";
......@@ -12,7 +12,7 @@ export const mergeProviderInstanceEnvironment = Effect.fn(function* (
1212 return baseEnv;
1313 }
1414
15 const home = yield* HostProcessHomeDirectory;
15 const home = yield* HostProcess.HomeDirectory;
1616 const next: NodeJS.ProcessEnv = { ...baseEnv };
1717 for (const variable of environment) {
1818 // Child processes do not apply shell expansion to environment values.
packages/provider-core/src/server/maintenanceResolver.test.ts+10-10
......@@ -6,7 +6,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
66import * as NodeOS from "node:os";
77import * as NodePath from "node:path";
88import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3tools/contracts";
9import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1010import * as Crypto from "effect/Crypto";
1111import * as Deferred from "effect/Deferred";
1212import * as Effect from "effect/Effect";
......@@ -37,7 +37,7 @@ import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
3737const driver = (value: string) => ProviderDriverKind.make(value);
3838// These write `#!/bin/sh` stubs and evaluate them with darwin/linux path
3939// semantics; a Windows temp path cannot be split on `:`.
40const windowsHost = HostProcessPlatform.defaultValue() === "win32";
40const windowsHost = HostProcess.Platform.defaultValue() === "win32";
4141const makeTempDir = (name: string) =>
4242 Crypto.Crypto.pipe(
4343 Effect.flatMap((crypto) => crypto.randomUUIDv4),
......@@ -332,7 +332,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
332332 env: {},
333333 platform: "win32",
334334 },
335 ).pipe(Effect.provideService(HostProcessPlatform, "win32"));
335 ).pipe(Effect.provideService(HostProcess.Platform, "win32"));
336336
337337 expect(capabilities.update).toMatchObject({
338338 executable: visiblePath,
......@@ -360,7 +360,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
360360 binaryPath: shim,
361361 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
362362 }).pipe(
363 Effect.provideService(HostProcessPlatform, "win32"),
363 Effect.provideService(HostProcess.Platform, "win32"),
364364 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
365365 );
366366
......@@ -376,7 +376,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
376376 binaryPath: script,
377377 env: { PATH: "" },
378378 }).pipe(
379 Effect.provideService(HostProcessPlatform, "linux"),
379 Effect.provideService(HostProcess.Platform, "linux"),
380380 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
381381 );
382382 expect(posix.update).toBeNull();
......@@ -429,7 +429,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
429429 env: { PATH: bunBinDir },
430430 },
431431 ).pipe(
432 Effect.provideService(HostProcessPlatform, "darwin"),
432 Effect.provideService(HostProcess.Platform, "darwin"),
433433 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
434434 );
435435
......@@ -454,7 +454,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
454454 env: { PATH: nativeBinDir },
455455 },
456456 ).pipe(
457 Effect.provideService(HostProcessPlatform, "darwin"),
457 Effect.provideService(HostProcess.Platform, "darwin"),
458458 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
459459 );
460460
......@@ -659,7 +659,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
659659 env: { PATH: brewBinDir },
660660 },
661661 ).pipe(
662 Effect.provideService(HostProcessPlatform, "darwin"),
662 Effect.provideService(HostProcess.Platform, "darwin"),
663663 Effect.provideService(
664664 ChildProcessSpawner.ChildProcessSpawner,
665665 stdoutSpawner((command, args) => {
......@@ -725,7 +725,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
725725 env: { PATH: brewBinDir },
726726 },
727727 ).pipe(
728 Effect.provideService(HostProcessPlatform, "darwin"),
728 Effect.provideService(HostProcess.Platform, "darwin"),
729729 Effect.provideService(
730730 ChildProcessSpawner.ChildProcessSpawner,
731731 stdoutSpawner(() => "/opt/homebrew\n"),
......@@ -864,7 +864,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
864864 binaryPath: kegBinary,
865865 env: { PATH: "" },
866866 }).pipe(
867 Effect.provideService(HostProcessPlatform, "darwin"),
867 Effect.provideService(HostProcess.Platform, "darwin"),
868868 Effect.provideService(
869869 ChildProcessSpawner.ChildProcessSpawner,
870870 stdoutSpawner((_command, args) => (args[0] === "--prefix" ? `${tempDir}\n` : "{}")),
packages/provider-core/src/server/maintenanceResolver.ts+4-4
......@@ -12,7 +12,7 @@ import {
1212 type ServerProviderVersionAdvisory,
1313} from "@t3tools/contracts";
1414import { compareSemverVersions } from "@t3tools/shared/semver";
15import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
1616import { causeErrorTag } from "@t3tools/shared/observability";
1717import { resolveCommandPath } from "@t3tools/shared/shell";
1818import * as Cache from "effect/Cache";
......@@ -141,7 +141,7 @@ export function makeProviderMaintenanceCapabilities(input: {
141141 readonly env?: NodeJS.ProcessEnv;
142142 readonly latestVersion?: string | null;
143143}): ProviderMaintenanceCapabilities {
144 const platform = input.platform ?? HostProcessPlatform.defaultValue();
144 const platform = input.platform ?? HostProcess.Platform.defaultValue();
145145 const update =
146146 input.updateExecutable === null || input.updateLockKey === null
147147 ? null
......@@ -587,7 +587,7 @@ const resolveNpmGlobalPrefix = Effect.fn("resolveNpmGlobalPrefix")(function* (
587587 if (fromRealPath) {
588588 return fromRealPath;
589589 }
590 if ((yield* HostProcessPlatform) !== "win32") {
590 if ((yield* HostProcess.Platform) !== "win32") {
591591 return null;
592592 }
593593 const fileSystem = yield* FileSystem.FileSystem;
......@@ -667,7 +667,7 @@ export const resolveProviderMaintenanceCapabilitiesEffect = Effect.fn(
667667 resolvedCommandPath,
668668 realCommandPath,
669669 env,
670 platform: yield* HostProcessPlatform,
670 platform: yield* HostProcess.Platform,
671671 });
672672});
673673
packages/provider-core/src/server/pathExpansion.ts+1-1
......@@ -3,7 +3,7 @@ import * as NodePath from "node:path";
33
44/**
55 * Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to `home`,
6 * the current user's home directory (`HostProcessHomeDirectory`). Spawned
6 * the current user's home directory (`HostProcess.HomeDirectory`). Spawned
77 * processes don't get shell expansion, so env vars like
88 * `CODEX_HOME=~/.codex-work` would be passed verbatim and treated as relative
99 * paths by the receiver.
packages/provider-core/src/server/processGroup.test.ts+2-2
......@@ -2,7 +2,7 @@
22import * as NodeChildProcess from "node:child_process";
33
44import { describe, expect, it } from "@effect/vitest";
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66
77import { signalProcessGroup } from "./processGroup.ts";
88
......@@ -15,7 +15,7 @@ const errorCode = (run: () => void) => {
1515 }
1616};
1717
18describe.skipIf(HostProcessPlatform.defaultValue() === "win32")("signalProcessGroup", () => {
18describe.skipIf(HostProcess.Platform.defaultValue() === "win32")("signalProcessGroup", () => {
1919 // Signal 0 only probes, so this is safe to run unguarded: `kill(-1, 0)` and
2020 // `kill(0, 0)` succeed, which is how a fake spawner's pid 1 became
2121 // `kill(-1, SIGKILL)` and took down every process the user owned.
packages/provider-core/src/server/snapshotProbe.test.ts+2-2
......@@ -1,6 +1,6 @@
11import { describe, expect, it } from "@effect/vitest";
22import type { ModelCapabilities } from "@t3tools/contracts";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import { createModelCapabilities } from "@t3tools/shared/model";
55import * as Effect from "effect/Effect";
66import * as Layer from "effect/Layer";
......@@ -158,7 +158,7 @@ describe("ProviderCommandNotFoundError", () => {
158158 ChildProcess.make("codex", ["--version"]),
159159 ).pipe(
160160 Effect.provide(Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner)),
161 Effect.provideService(HostProcessPlatform, "win32"),
161 Effect.provideService(HostProcess.Platform, "win32"),
162162 Effect.flip,
163163 );
164164
packages/provider-core/src/server/snapshotProbe.ts+2-2
......@@ -19,7 +19,7 @@ import * as Stream from "effect/Stream";
1919import * as ChildProcess from "effect/process/ChildProcess";
2020import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
2121import { readCustomModelEntries } from "@t3tools/shared/model";
22import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
22import * as HostProcess from "@t3tools/shared/HostProcess";
2323import { createProviderVersionAdvisory } from "./maintenanceResolver.ts";
2424import { collectUint8StreamText } from "./collectStreamText.ts";
2525
......@@ -38,7 +38,7 @@ export const isWindowsCommandNotFound = Effect.fn("isWindowsCommandNotFound")(fu
3838 code: number | null,
3939 stderr: string,
4040) {
41 const platform = yield* HostProcessPlatform;
41 const platform = yield* HostProcess.Platform;
4242 if (platform !== "win32") return false;
4343 if (code === 9009) return true;
4444 return WINDOWS_COMMAND_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(stderr));
packages/provider-cursor/src/server/CursorUsageAccounts.ts+4-8
......@@ -14,11 +14,7 @@
1414import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost";
1515import type { ProviderUsageScan } from "@t3tools/provider-core/server/usage";
1616import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite";
17import {
18 HostProcessEnvironment,
19 HostProcessHomeDirectory,
20 HostProcessPlatform,
21} from "@t3tools/shared/hostProcess";
17import * as HostProcess from "@t3tools/shared/HostProcess";
2218import * as Clock from "effect/Clock";
2319import * as Context from "effect/Context";
2420import * as Deferred from "effect/Deferred";
......@@ -71,8 +67,8 @@ const make = Effect.gen(function* () {
7167 const path = yield* Path.Path;
7268 const host = yield* ProviderHost.ProviderHost;
7369 const accountReader = yield* CursorAccountReader.CursorAccountReader;
74 const hostEnvironment = yield* HostProcessEnvironment;
75 const platform = yield* HostProcessPlatform;
70 const hostEnvironment = yield* HostProcess.Environment;
71 const platform = yield* HostProcess.Platform;
7672
7773 const cachePath = path.join(host.paths.stateDir, CURSOR_ACCOUNT_CACHE_FILE_NAME);
7874 /** Account caches by credential source. */
......@@ -286,7 +282,7 @@ const make = Effect.gen(function* () {
286282
287283 const scan: CursorUsageAccounts["Service"]["scan"] = Effect.fn("CursorUsageAccounts.scan")(
288284 function* ({ keychainUsageEnabled, windowStartMs, retentionCutoffMs, awaitRefresh }) {
289 const home = yield* HostProcessHomeDirectory;
285 const home = yield* HostProcess.HomeDirectory;
290286 const userHome =
291287 (platform === "win32" ? hostEnvironment["USERPROFILE"] : hostEnvironment["HOME"]) || home;
292288 const configHome = hostEnvironment["XDG_CONFIG_HOME"]?.trim();
packages/provider-cursor/src/server/adapter.ts+2-2
......@@ -9,7 +9,7 @@ import type {
99 ToolCall,
1010} from "@cursor/sdk";
1111import { formatReadToolLabel, formatSearchToolLabel } from "@t3tools/shared/toolActivity";
12import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
12import * as HostProcess from "@t3tools/shared/HostProcess";
1313import {
1414 isOrchestrationV2WorkActive,
1515 defaultInstanceIdForDriver,
......@@ -2620,7 +2620,7 @@ export const CursorAdapterV2Driver: ProviderAdapterDriver<
26202620 defaultConfig: (): CursorSettings => DEFAULT_CURSOR_SETTINGS,
26212621 create: Effect.fn("CursorAdapterV2Driver.create")(
26222622 function* (input: ProviderAdapterDriverCreateInput<CursorSettings>) {
2623 const hostEnvironment = yield* HostProcessEnvironment;
2623 const hostEnvironment = yield* HostProcess.Environment;
26242624 return yield* makeCursorAdapterV2({
26252625 instanceId: input.instanceId,
26262626 settings: {
packages/provider-cursor/src/server/skills.ts+2-2
......@@ -17,7 +17,7 @@ import * as Path from "effect/Path";
1717import * as PlatformError from "effect/PlatformError";
1818import * as Schema from "effect/Schema";
1919import { parse as parseYamlDocument } from "yaml";
20import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
20import * as HostProcess from "@t3tools/shared/HostProcess";
2121
2222const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
2323const SKILL_MENTION_PATTERN =
......@@ -224,7 +224,7 @@ const inspectCursorSkills = Effect.fn("inspectCursorSkills")(function* (
224224 const userHome =
225225 environment.HOME?.trim() ||
226226 environment.USERPROFILE?.trim() ||
227 (yield* HostProcessHomeDirectory);
227 (yield* HostProcess.HomeDirectory);
228228 const rootsBelow = (base: string, scope: "user" | "project") => [
229229 { directory: path.join(base, ".cursor", "skills"), scope },
230230 { directory: path.join(base, ".agents", "skills"), scope },
packages/provider-cursor/src/server/textGeneration.ts+2-2
......@@ -12,7 +12,7 @@ import * as TextGenerationOperations from "@t3tools/provider-core/server/textGen
1212import { cursorSdkModelSelection } from "./sdkModel.ts";
1313import type { CursorAuth } from "./auth.ts";
1414import * as CursorSdk from "./CursorSdk.ts";
15import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
1616
1717const CURSOR_TIMEOUT_MS = 180_000;
1818
......@@ -90,7 +90,7 @@ export const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(fu
9090 const apiKey = yield* resolveCursorApiKey(operation);
9191 // The SDK loads sandbox.json independently of settingSources and lets it
9292 // expand the writable paths. Its public API cannot override that policy.
93 if (yield* fs.exists(`${yield* HostProcessHomeDirectory}/.cursor/sandbox.json`)) {
93 if (yield* fs.exists(`${yield* HostProcess.HomeDirectory}/.cursor/sandbox.json`)) {
9494 return yield* new TextGenerationError({
9595 operation,
9696 detail:
packages/provider-cursor/src/server/usageLimits.test.ts+6-6
......@@ -1,6 +1,6 @@
11import { describe, expect, it } from "@effect/vitest";
22import { NodeServices } from "@effect/platform-node";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Effect from "effect/Effect";
55import * as FileSystem from "effect/FileSystem";
66import * as Path from "effect/Path";
......@@ -106,7 +106,7 @@ describe("Cursor usage limits", () => {
106106 { apiEndpoint: "https://cursor.example/" },
107107 { XDG_CONFIG_HOME: directory, HOME: directory, AGENT_CLI_CREDENTIAL_STORE: "file" },
108108 ).pipe(
109 Effect.provideService(HostProcessPlatform, platform),
109 Effect.provideService(HostProcess.Platform, platform),
110110 Effect.provideService(HttpClient.HttpClient, client),
111111 );
112112 expect(limits.windows[0]?.usedPercent).toBe(42);
......@@ -131,7 +131,7 @@ describe("Cursor usage limits", () => {
131131 },
132132 false,
133133 ).pipe(
134 Effect.provideService(HostProcessPlatform, platform),
134 Effect.provideService(HostProcess.Platform, platform),
135135 Effect.provideService(
136136 FileSystem.FileSystem,
137137 FileSystem.makeNoop({
......@@ -202,7 +202,7 @@ describe("Cursor usage limits", () => {
202202 Effect.gen(function* () {
203203 const limits = yield* withNodeServices(
204204 readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe(
205 Effect.provideService(HostProcessPlatform, "darwin"),
205 Effect.provideService(HostProcess.Platform, "darwin"),
206206 Effect.provideService(
207207 FileSystem.FileSystem,
208208 FileSystem.makeNoop({
......@@ -232,7 +232,7 @@ describe("Cursor usage limits", () => {
232232 Effect.gen(function* () {
233233 const limits = yield* withNodeServices(
234234 readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe(
235 Effect.provideService(HostProcessPlatform, "darwin"),
235 Effect.provideService(HostProcess.Platform, "darwin"),
236236 Effect.provideService(
237237 HttpClient.HttpClient,
238238 HttpClient.make(() => Effect.die("must not request limits without a login")),
......@@ -258,7 +258,7 @@ describe("Cursor usage limits", () => {
258258 ] as const) {
259259 const limits = yield* withNodeServices(
260260 readCursorUsageLimits({ apiEndpoint }, environment, true).pipe(
261 Effect.provideService(HostProcessPlatform, "darwin"),
261 Effect.provideService(HostProcess.Platform, "darwin"),
262262 Effect.provideService(
263263 HttpClient.HttpClient,
264264 HttpClient.make(() => Effect.die("must not send a Keychain credential to a proxy")),
packages/provider-cursor/src/server/usageLimits.ts+3-3
......@@ -1,6 +1,6 @@
11import type { ServerProviderUsageWindow } from "@t3tools/contracts";
22import type { CursorSettings } from "../settings.ts";
3import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import { CURSOR_USAGE_WINDOWS } from "@t3tools/shared/usageLimits";
55import * as DateTime from "effect/DateTime";
66import * as Effect from "effect/Effect";
......@@ -70,7 +70,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function
7070 return yield* Effect.gen(function* () {
7171 const fs = yield* FileSystem.FileSystem;
7272 const path = yield* Path.Path;
73 const platform = yield* HostProcessPlatform;
73 const platform = yield* HostProcess.Platform;
7474 const endpoint = (
7575 settings.apiEndpoint?.trim() ||
7676 environment.CURSOR_API_ENDPOINT?.trim() ||
......@@ -109,7 +109,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function
109109 } else if (!token) {
110110 const home =
111111 (platform === "win32" ? environment.USERPROFILE : environment.HOME) ||
112 (yield* HostProcessHomeDirectory);
112 (yield* HostProcess.HomeDirectory);
113113 const directory =
114114 platform === "win32"
115115 ? path.join(environment.APPDATA || path.join(home, "AppData", "Roaming"), "Cursor")
packages/provider-grok/src/server/acpSupport.ts+2-2
......@@ -12,7 +12,7 @@ import * as Layer from "effect/Layer";
1212import * as Scope from "effect/Scope";
1313import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
1414import * as EffectAcpErrors from "effect-acp/errors";
15import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
15import * as HostProcess from "@t3tools/shared/HostProcess";
1616import { normalizeModelSlug } from "@t3tools/shared/model";
1717
1818import * as AcpSessionRuntime from "@t3tools/provider-acp/server/AcpSessionRuntime";
......@@ -159,7 +159,7 @@ export const makeGrokAcpRuntime = (
159159 ChildProcessSpawner.ChildProcessSpawner | Crypto.Crypto | Scope.Scope
160160> =>
161161 Effect.gen(function* () {
162 const processGroupPlatform = yield* HostProcessPlatform.pipe(
162 const processGroupPlatform = yield* HostProcess.Platform.pipe(
163163 Effect.provide(NodeServices.layer),
164164 );
165165 const acpContext = yield* Layer.build(
packages/provider-grok/src/server/adapter.ts+6-10
......@@ -4,11 +4,7 @@ import {
44 isXAiTaskCompletedWakeNotification,
55 xAiRateLimitedErrorCode,
66} from "./xaiAcpExtension.ts";
7import {
8 HostProcessEnvironment,
9 HostProcessHomeDirectory,
10 HostProcessPlatform,
11} from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
128import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime";
139import {
1410 defaultInstanceIdForDriver,
......@@ -339,7 +335,7 @@ export const makeGrokAdapterV2 = Effect.fn("makeGrokAdapterV2")(function* (
339335) {
340336 return yield* makeAcpAdapterV2({
341337 instanceId: options.instanceId,
342 flavor: makeGrokAcpAdapterFlavor(options, yield* HostProcessHomeDirectory),
338 flavor: makeGrokAcpAdapterFlavor(options, yield* HostProcess.HomeDirectory),
343339 selfInvocation: options.selfInvocation,
344340 ...(options.nativeLogging === undefined ? {} : { nativeLogging: options.nativeLogging }),
345341 ...(options.continuationRequests === undefined
......@@ -365,8 +361,8 @@ export const GrokAdapterV2Driver: ProviderAdapterDriver<GrokSettings, GrokAdapte
365361 defaultConfig: (): GrokSettings => DEFAULT_GROK_SETTINGS,
366362 create: Effect.fn("GrokAdapterV2Driver.create")(
367363 function* (input: ProviderAdapterDriverCreateInput<GrokSettings>) {
368 const hostEnvironment = yield* HostProcessEnvironment;
369 const hostPlatform = yield* HostProcessPlatform;
364 const hostEnvironment = yield* HostProcess.Environment;
365 const hostPlatform = yield* HostProcess.Platform;
370366 const selfInvocation = yield* resolveSelfInvocation();
371367 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
372368 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
......@@ -415,8 +411,8 @@ const layer: Layer.Layer<
415411> = Layer.effect(
416412 ProviderAdapter.ProviderAdapterV2,
417413 Effect.gen(function* () {
418 const hostEnvironment = yield* HostProcessEnvironment;
419 const hostPlatform = yield* HostProcessPlatform;
414 const hostEnvironment = yield* HostProcess.Environment;
415 const hostPlatform = yield* HostProcess.Platform;
420416 const selfInvocation = yield* resolveSelfInvocation();
421417 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
422418 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
packages/provider-grok/src/server/driver.test.ts+2-2
......@@ -1,7 +1,7 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { expect, it } from "@effect/vitest";
33import { ProviderInstanceId } from "@t3tools/contracts";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55import * as Effect from "effect/Effect";
66import * as FileSystem from "effect/FileSystem";
77import * as Layer from "effect/Layer";
......@@ -41,7 +41,7 @@ const noSpawner = ChildProcessSpawner.make(() =>
4141);
4242
4343// The `#!/bin/sh` stub below cannot be resolved as an executable on Windows.
44const windowsHost = HostProcessPlatform.defaultValue() === "win32";
44const windowsHost = HostProcess.Platform.defaultValue() === "win32";
4545
4646it.layer(layerTest)("GrokDriver", (it) => {
4747 it.effect.skipIf(windowsHost)("updates through the configured executable's own updater", () =>
packages/provider-grok/src/server/usage.ts+2-2
......@@ -19,7 +19,7 @@ import {
1919} from "@t3tools/provider-core/server/usage";
2020
2121import type { GrokSettings } from "../settings.ts";
22import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
22import * as HostProcess from "@t3tools/shared/HostProcess";
2323
2424/**
2525 * Grok reports cost in integer ticks where `1 USD = 10^10` ticks. See Grok
......@@ -229,7 +229,7 @@ export const grokUsageReader: ProviderUsageReader<GrokSettings, Path.Path> = {
229229 format: grokUsageFormat,
230230 directories: Effect.fn("grokUsageReader.directories")(function* ({ environment }) {
231231 const path = yield* Path.Path;
232 const homeDirectory = yield* HostProcessHomeDirectory;
232 const homeDirectory = yield* HostProcess.HomeDirectory;
233233 const home = expandHomePath(
234234 environment.GROK_HOME?.trim() || path.join(homeDirectory, ".grok"),
235235 homeDirectory,
packages/provider-grok/src/server/usageLimits.ts+2-2
......@@ -13,7 +13,7 @@ import {
1313 makeUnavailableUsageLimits,
1414 makeUsageLimits,
1515} from "@t3tools/provider-core/server/usageLimits";
16import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
16import * as HostProcess from "@t3tools/shared/HostProcess";
1717
1818const GrokCredentials = Schema.Record(
1919 Schema.String,
......@@ -101,7 +101,7 @@ const readGrokCredential = Effect.fn("readGrokCredential")(function* (
101101 const home =
102102 environment.GROK_HOME?.trim() ||
103103 path.join(
104 environment.HOME || environment.USERPROFILE || (yield* HostProcessHomeDirectory),
104 environment.HOME || environment.USERPROFILE || (yield* HostProcess.HomeDirectory),
105105 ".grok",
106106 );
107107 for (const configPath of [
packages/provider-muse/src/server/driver.ts+3-3
......@@ -1,6 +1,6 @@
11import { ProviderDriverKind } from "@t3tools/contracts";
22import { MuseSettings } from "../settings.ts";
3import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Effect from "effect/Effect";
55import * as FileSystem from "effect/FileSystem";
66import * as Path from "effect/Path";
......@@ -69,7 +69,7 @@ export const MuseDriver: ProviderDriver<MuseSettings, MuseDriverEnv> = {
6969 const eventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
7070 const { cwd } = host.paths;
7171 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
72 const hostEnvironment = yield* HostProcessEnvironment;
72 const hostEnvironment = yield* HostProcess.Environment;
7373 // Drop an inherited META_API_KEY so Muse uses its login; an instance value still wins.
7474 const processEnvironment = yield* mergeProviderInstanceEnvironment(
7575 environment,
......@@ -78,7 +78,7 @@ export const MuseDriver: ProviderDriver<MuseSettings, MuseDriverEnv> = {
7878 const effectiveConfig = {
7979 ...config,
8080 enabled,
81 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),
81 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
8282 } satisfies MuseSettings;
8383 const continuationIdentity = defaultProviderContinuationIdentity({
8484 driverKind: DRIVER_KIND,
packages/provider-opencode/src/server/OpenCodeRuntime.environment.test.ts+4-8
......@@ -1,11 +1,7 @@
11import type { OpencodeClient } from "@opencode-ai/sdk/v2";
22import * as NodeServices from "@effect/platform-node/NodeServices";
33import { it as effectIt } from "@effect/vitest";
4import {
5 HostProcessEnvironment,
6 HostProcessExecutablePath,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
95import * as Effect from "effect/Effect";
106import * as Fiber from "effect/Fiber";
117import * as FileSystem from "effect/FileSystem";
......@@ -168,9 +164,9 @@ describe("OpenCode server output", () => {
168164 Effect.gen(function* () {
169165 const fs = yield* FileSystem.FileSystem;
170166 const path = yield* Path.Path;
171 const environment = yield* HostProcessEnvironment;
172 const executablePath = yield* HostProcessExecutablePath;
173 const platform = yield* HostProcessPlatform;
167 const environment = yield* HostProcess.Environment;
168 const executablePath = yield* HostProcess.ExecutablePath;
169 const platform = yield* HostProcess.Platform;
174170 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-output-" });
175171 const isWindows = platform === "win32";
176172 const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode");
packages/provider-opencode/src/server/OpenCodeRuntime.inventory.test.ts+5-9
......@@ -9,11 +9,7 @@ import * as FileSystem from "effect/FileSystem";
99import * as Layer from "effect/Layer";
1010import * as Path from "effect/Path";
1111import * as Queue from "effect/Queue";
12import {
13 HostProcessEnvironment,
14 HostProcessExecutablePath,
15 HostProcessPlatform,
16} from "@t3tools/shared/hostProcess";
12import * as HostProcess from "@t3tools/shared/HostProcess";
1713
1814import * as OpenCodeRuntime from "./OpenCodeRuntime.ts";
1915import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts";
......@@ -217,9 +213,9 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => {
217213 Effect.gen(function* () {
218214 const fs = yield* FileSystem.FileSystem;
219215 const path = yield* Path.Path;
220 const hostEnvironment = yield* HostProcessEnvironment;
221 const executablePath = yield* HostProcessExecutablePath;
222 const hostPlatform = yield* HostProcessPlatform;
216 const hostEnvironment = yield* HostProcess.Environment;
217 const executablePath = yield* HostProcess.ExecutablePath;
218 const hostPlatform = yield* HostProcess.Platform;
223219 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-inventory-" });
224220 const isWindows = hostPlatform === "win32";
225221 const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode");
......@@ -271,7 +267,7 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => {
271267 it.effect("caps and drains command stdout and stderr when requested", () =>
272268 Effect.gen(function* () {
273269 const runtime = yield* OpenCodeRuntime.OpenCodeRuntime;
274 const executablePath = yield* HostProcessExecutablePath;
270 const executablePath = yield* HostProcess.ExecutablePath;
275271 const outputBytes = 2 * 1024 * 1024;
276272 const result = yield* runtime.runOpenCodeCommand({
277273 binaryPath: executablePath,
packages/provider-opencode/src/server/OpenCodeRuntime.ts+2-2
......@@ -36,7 +36,7 @@ import { isWindowsCommandNotFound } from "@t3tools/provider-core/server/snapshot
3636import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts";
3737import { collectStreamAsString } from "@t3tools/provider-core/server/snapshotProbe";
3838import * as NetService from "@t3tools/shared/Net";
39import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
39import * as HostProcess from "@t3tools/shared/HostProcess";
4040import { compareSemverVersions, parseSemver } from "@t3tools/shared/semver";
4141import { resolveSpawnCommand } from "@t3tools/shared/shell";
4242const encodeUnknownJsonStringExit = Schema.encodeUnknownExit(Schema.fromJsonString(Schema.Unknown));
......@@ -595,7 +595,7 @@ function ensureRuntimeError(
595595const makeOpenCodeRuntime = Effect.gen(function* () {
596596 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
597597 const netService = yield* NetService.NetService;
598 const hostPlatform = yield* HostProcessPlatform;
598 const hostPlatform = yield* HostProcess.Platform;
599599 const serverLedger = yield* OpenCodeServerLedger.OpenCodeServerLedger;
600600 const resolveCommand = (command: string, args: ReadonlyArray<string>, env?: NodeJS.ProcessEnv) =>
601601 resolveSpawnCommand(command, args, env ? { env } : {});
packages/provider-opencode/src/server/OpenCodeServerLedger.test.ts+3-3
......@@ -3,7 +3,7 @@ import * as NodeChildProcess from "node:child_process";
33
44import * as NodeServices from "@effect/platform-node/NodeServices";
55import { describe, expect, it } from "@effect/vitest";
6import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
6import * as HostProcess from "@t3tools/shared/HostProcess";
77import * as Deferred from "effect/Deferred";
88import * as Effect from "effect/Effect";
99import * as Exit from "effect/Exit";
......@@ -67,7 +67,7 @@ const recordFromDeadServer = (stateDir: string, server: { readonly pid: number }
6767 yield* previousServer.exited;
6868 });
6969
70const hostPlatform = HostProcessPlatform.defaultValue();
70const hostPlatform = HostProcess.Platform.defaultValue();
7171// procps accepts the same `ps` flags as macOS, so Linux also covers the macOS path.
7272const observedPlatforms: ReadonlyArray<NodeJS.Platform> =
7373 hostPlatform === "linux" ? ["linux", "darwin"] : hostPlatform === "darwin" ? ["darwin"] : [];
......@@ -75,7 +75,7 @@ const observedPlatforms: ReadonlyArray<NodeJS.Platform> =
7575describe.each(observedPlatforms)("OpenCodeServerLedger observing as %s", (platform) => {
7676 const provideHost = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
7777 effect.pipe(
78 Effect.provideService(HostProcessPlatform, platform),
78 Effect.provideService(HostProcess.Platform, platform),
7979 Effect.provide(NodeServices.layer),
8080 );
8181
packages/provider-opencode/src/server/OpenCodeServerLedger.ts+2-2
......@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as Context from "effect/Context";
33import * as Effect from "effect/Effect";
44import * as FileSystem from "effect/FileSystem";
......@@ -119,7 +119,7 @@ export const make = Effect.fn("OpenCodeServerLedger.make")(function* (input: {
119119 const fs = yield* FileSystem.FileSystem;
120120 const path = yield* Path.Path;
121121 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
122 const platform = yield* HostProcessPlatform;
122 const platform = yield* HostProcess.Platform;
123123 const directory = path.join(input.stateDir, ENTRY_DIRECTORY);
124124 // Windows servers are not detached and are never recorded.
125125 const recordable = platform === "linux" || platform === "darwin";
packages/provider-opencode/src/server/adapter.ts+3-3
......@@ -9,7 +9,7 @@ import type {
99 Todo as OpenCodeTodo,
1010 ToolPart,
1111} from "@opencode-ai/sdk/v2";
12import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
12import * as HostProcess from "@t3tools/shared/HostProcess";
1313import { getModelSelectionStringOptionValue } from "@t3tools/shared/model";
1414import { causeErrorTag } from "@t3tools/shared/observability";
1515import {
......@@ -3739,7 +3739,7 @@ export const OpenCodeAdapterV2Driver: ProviderAdapterDriver<
37393739 defaultConfig: (): OpenCodeSettings => DEFAULT_OPENCODE_SETTINGS,
37403740 create: Effect.fn("OpenCodeAdapterV2Driver.create")(
37413741 function* (input: ProviderAdapterDriverCreateInput<OpenCodeSettings>) {
3742 const hostEnvironment = yield* HostProcessEnvironment;
3742 const hostEnvironment = yield* HostProcess.Environment;
37433743 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
37443744 return yield* makeOpenCodeAdapterV2({
37453745 instanceId: input.instanceId,
......@@ -3769,7 +3769,7 @@ const layer: Layer.Layer<ProviderAdapter.ProviderAdapterV2, never, OpenCodeAdapt
37693769 Layer.effect(
37703770 ProviderAdapter.ProviderAdapterV2,
37713771 Effect.gen(function* () {
3772 const hostEnvironment = yield* HostProcessEnvironment;
3772 const hostEnvironment = yield* HostProcess.Environment;
37733773 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
37743774 return yield* makeOpenCodeAdapterV2({
37753775 instanceId: OPENCODE_DEFAULT_INSTANCE_ID,
packages/provider-opencode/src/server/driver.test.ts+3-3
......@@ -7,7 +7,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
77import { assert, it } from "@effect/vitest";
88import { ProviderInstanceId } from "@t3tools/contracts";
99import type { OpenCodeSettings } from "../settings.ts";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
10import * as HostProcess from "@t3tools/shared/HostProcess";
1111import * as Effect from "effect/Effect";
1212import * as Fiber from "effect/Fiber";
1313import * as Layer from "effect/Layer";
......@@ -156,7 +156,7 @@ const resolveUpdate = (generation: "v1" | "v2", binaryPath: string) =>
156156 Effect.provide(NodeServices.layer),
157157 );
158158
159it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
159it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
160160 "updates an npm-global OpenCode 2 install as @opencode/cli and a 1.x one as opencode-ai",
161161 () =>
162162 Effect.gen(function* () {
......@@ -243,7 +243,7 @@ it.layer(layerUpdate)("OpenCodeDriver updates", (it) => {
243243 }).pipe(Effect.scoped),
244244 );
245245
246 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
246 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
247247 "offers no package update for an unknown version and follows a changed one on a fresh read",
248248 () =>
249249 Effect.gen(function* () {
packages/provider-opencode/src/server/usage.ts+3-3
......@@ -11,7 +11,7 @@ import {
1111 type ProviderUsageReader,
1212 type UsageRecord,
1313} from "@t3tools/provider-core/server/usage";
14import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
1616import * as Effect from "effect/Effect";
1717import * as Exit from "effect/Exit";
......@@ -257,8 +257,8 @@ export const readOpenCodeUsage = Effect.fn("readOpenCodeUsage")(function* (
257257const resolveOpenCodeDataDirs = Effect.fn("resolveOpenCodeDataDirs")(function* () {
258258 const fileSystem = yield* FileSystem.FileSystem;
259259 const path = yield* Path.Path;
260 const environment = yield* HostProcessEnvironment;
261 const homeDirectory = yield* HostProcessHomeDirectory;
260 const environment = yield* HostProcess.Environment;
261 const homeDirectory = yield* HostProcess.HomeDirectory;
262262 const roots = environment["OPENCODE_DATA_DIR"]
263263 ?.split(",")
264264 .map((value) => value.trim())
packages/provider-opencode/src/server/usageLimits.ts+2-2
......@@ -16,7 +16,7 @@ import {
1616 makeUnavailableUsageLimits,
1717 makeUsageLimits,
1818} from "@t3tools/provider-core/server/usageLimits";
19import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
19import * as HostProcess from "@t3tools/shared/HostProcess";
2020
2121const AuthFile = Schema.Struct({ "opencode-go": Schema.optionalKey(Schema.Unknown) });
2222const ApiAuth = Schema.Struct({ type: Schema.Literal("api"), key: Schema.String });
......@@ -47,7 +47,7 @@ export const readOpenCodeGoUsageLimits = Effect.fn("readOpenCodeGoUsageLimits")(
4747 const dataHome =
4848 env.XDG_DATA_HOME ||
4949 path.join(
50 env.HOME || env.USERPROFILE || (yield* HostProcessHomeDirectory),
50 env.HOME || env.USERPROFILE || (yield* HostProcess.HomeDirectory),
5151 ".local",
5252 "share",
5353 );
packages/provider-opencode/src/server/v2/OpenCode2Server.test.ts+5-9
......@@ -1,10 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, it } from "@effect/vitest";
3import {
4 HostProcessEnvironment,
5 HostProcessExecutablePath,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
84import * as Effect from "effect/Effect";
95import * as Fiber from "effect/Fiber";
106import * as FileSystem from "effect/FileSystem";
......@@ -221,7 +217,7 @@ describe("OpenCode2Server spawned server", () => {
221217 Effect.gen(function* () {
222218 const fs = yield* FileSystem.FileSystem;
223219 const path = yield* Path.Path;
224 const platform = yield* HostProcessPlatform;
220 const platform = yield* HostProcess.Platform;
225221 const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode2-fake-" });
226222 const isWindows = platform === "win32";
227223 const binaryPath = path.join(directory, isWindows ? "opencode.cmd" : "opencode");
......@@ -230,8 +226,8 @@ describe("OpenCode2Server spawned server", () => {
230226 yield* fs.writeFileString(
231227 binaryPath,
232228 isWindows
233 ? `@echo off\r\n"${yield* HostProcessExecutablePath}" "${scriptPath}" %*\r\n`
234 : `#!/bin/sh\nexec "${yield* HostProcessExecutablePath}" "${scriptPath}" "$@"\n`,
229 ? `@echo off\r\n"${yield* HostProcess.ExecutablePath}" "${scriptPath}" %*\r\n`
230 : `#!/bin/sh\nexec "${yield* HostProcess.ExecutablePath}" "${scriptPath}" "$@"\n`,
235231 );
236232 if (!isWindows) yield* fs.chmod(binaryPath, 0o755);
237233
......@@ -240,7 +236,7 @@ describe("OpenCode2Server spawned server", () => {
240236 serverUrl: "",
241237 serverPassword: "",
242238 directory,
243 environment: { ...(yield* HostProcessEnvironment), OPENCODE_SERVER_PASSWORD: "ambient" },
239 environment: { ...(yield* HostProcess.Environment), OPENCODE_SERVER_PASSWORD: "ambient" },
244240 });
245241 const first = yield* server.withConnection((connection) => Effect.succeed(connection));
246242 const second = yield* server.withConnection((connection) => Effect.succeed(connection));
packages/provider-pi/src/server/adapter.test.ts+2-2
......@@ -38,7 +38,7 @@ import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderS
3838import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator";
3939import * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";
4040import { handoffBudget } from "@t3tools/provider-core/server/handoffBudget";
41import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
41import * as HostProcess from "@t3tools/shared/HostProcess";
4242import {
4343 makePiAdapterV2,
4444 PiAdapterV2Driver,
......@@ -336,7 +336,7 @@ const makeAdapter = Effect.fnUntraced(function* (
336336 config: { enabled: true, binaryPath: "pi", launchArgs, customModels: [] },
337337 }).pipe(
338338 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
339 Effect.provideService(HostProcessEnvironment, {}),
339 Effect.provideService(HostProcess.Environment, {}),
340340 Effect.provideService(ProviderContinuationRequests.ProviderContinuationRequests, {
341341 ...continuationRequests,
342342 take: Effect.never,
packages/provider-pi/src/server/adapter.ts+3-3
......@@ -23,7 +23,7 @@
2323 * Terminal-only decoration such as status, widget, title, and editor-text
2424 * updates has no matching T3 surface and is ignored.
2525 */
26import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
26import * as HostProcess from "@t3tools/shared/HostProcess";
2727import { getModelSelectionStringOptionValue } from "@t3tools/shared/model";
2828import {
2929 defaultInstanceIdForDriver,
......@@ -3271,7 +3271,7 @@ export const PiAdapterV2Driver: ProviderAdapterDriver<PiSettings, PiAdapterV2Dri
32713271 defaultConfig: (): PiSettings => DEFAULT_PI_SETTINGS,
32723272 create: Effect.fn("PiAdapterV2Driver.create")(
32733273 function* (input: ProviderAdapterDriverCreateInput<PiSettings>) {
3274 const hostEnvironment = yield* HostProcessEnvironment;
3274 const hostEnvironment = yield* HostProcess.Environment;
32753275 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
32763276 return yield* makePiAdapterV2({
32773277 instanceId: input.instanceId,
......@@ -3299,7 +3299,7 @@ const layer: Layer.Layer<ProviderAdapter.ProviderAdapterV2, never, PiAdapterV2Dr
32993299 Layer.effect(
33003300 ProviderAdapter.ProviderAdapterV2,
33013301 Effect.gen(function* () {
3302 const hostEnvironment = yield* HostProcessEnvironment;
3302 const hostEnvironment = yield* HostProcess.Environment;
33033303 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
33043304 return yield* makePiAdapterV2({
33053305 instanceId: PI_DEFAULT_INSTANCE_ID,
packages/provider-pi/src/server/rpc.ts+2-2
......@@ -28,7 +28,7 @@ import * as Schema from "effect/Schema";
2828import * as Stream from "effect/Stream";
2929import * as ChildProcess from "effect/process/ChildProcess";
3030import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
31import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
31import * as HostProcess from "@t3tools/shared/HostProcess";
3232import { resolveSpawnCommand } from "@t3tools/shared/shell";
3333
3434import { signalProcessGroup } from "@t3tools/provider-core/server/processGroup";
......@@ -215,7 +215,7 @@ const terminatePiProcess = (kill: (signal: NodeJS.Signals) => boolean, hasExited
215215
216216export const makePiRpcConnection = Effect.fnUntraced(function* (options: PiRpcSpawnOptions) {
217217 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
218 const platform = yield* HostProcessPlatform;
218 const platform = yield* HostProcess.Platform;
219219 const scope = yield* Effect.scope;
220220
221221 const spawnCommand = yield* resolveSpawnCommand(options.command, [...options.args], {
packages/provider-testing/src/fakeCli.ts+3-3
......@@ -2,7 +2,7 @@
22import * as NodeFS from "node:fs";
33import * as NodePath from "node:path";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66
77export interface FakeCliOptions {
88 /** Directory the launcher and its stub are written into. */
......@@ -15,7 +15,7 @@ export interface FakeCliOptions {
1515 readonly env?: Readonly<Record<string, string>>;
1616 /**
1717 * Platform the launcher is shaped for. Effect callers should pass the value
18 * they read from `HostProcessPlatform` so an injected override is honoured;
18 * they read from `HostProcess.Platform` so an injected override is honoured;
1919 * defaults to the real host for plain tests.
2020 */
2121 readonly platform?: NodeJS.Platform;
......@@ -45,7 +45,7 @@ export function writeFakeCli(options: FakeCliOptions): string {
4545 "utf8",
4646 );
4747
48 if ((options.platform ?? HostProcessPlatform.defaultValue()) === "win32") {
48 if ((options.platform ?? HostProcess.Platform.defaultValue()) === "win32") {
4949 const launcherPath = NodePath.join(options.directory, `${options.name}.cmd`);
5050 NodeFS.writeFileSync(
5151 launcherPath,
packages/shared/package.json+3-3
......@@ -311,9 +311,9 @@
311311 "types": "./src/nodeRuntime.ts",
312312 "import": "./src/nodeRuntime.ts"
313313 },
314 "./hostProcess": {
315 "types": "./src/hostProcess.ts",
316 "import": "./src/hostProcess.ts"
314 "./HostProcess": {
315 "types": "./src/HostProcess.ts",
316 "import": "./src/HostProcess.ts"
317317 },
318318 "./testing/longTempDir": {
319319 "types": "./src/testing/longTempDir.ts",
packages/shared/src/HostProcess.ts created+110
......@@ -0,0 +1,110 @@
1import * as Context from "effect/Context";
2import * as Effect from "effect/Effect";
3import * as NodeDns from "node:dns";
4import * as NodeOS from "node:os";
5import * as NodeSea from "node:sea";
6
7export const Platform = Context.Reference<NodeJS.Platform>("@t3tools/shared/HostProcess/Platform", {
8 defaultValue: () => process.platform,
9});
10
11export const Architecture = Context.Reference<NodeJS.Architecture>(
12 "@t3tools/shared/HostProcess/Architecture",
13 {
14 defaultValue: () => process.arch,
15 },
16);
17
18export const Hostname = Context.Reference<string>("@t3tools/shared/HostProcess/Hostname", {
19 defaultValue: () => NodeOS.hostname(),
20});
21
22export const HomeDirectory = Context.Reference<string>(
23 "@t3tools/shared/HostProcess/HomeDirectory",
24 {
25 defaultValue: () => NodeOS.homedir(),
26 },
27);
28
29export const Environment = Context.Reference<NodeJS.ProcessEnv>(
30 "@t3tools/shared/HostProcess/Environment",
31 {
32 defaultValue: () => process.env,
33 },
34);
35
36export const WorkingDirectory = Context.Reference<string>(
37 "@t3tools/shared/HostProcess/WorkingDirectory",
38 {
39 defaultValue: () => process.cwd(),
40 },
41);
42
43export const ExecutablePath = Context.Reference<string>(
44 "@t3tools/shared/HostProcess/ExecutablePath",
45 {
46 defaultValue: () => process.execPath,
47 },
48);
49
50export const Arguments = Context.Reference<ReadonlyArray<string>>(
51 "@t3tools/shared/HostProcess/Arguments",
52 {
53 defaultValue: () => process.argv,
54 },
55);
56
57/**
58 * The command the shell was given, before Node resolved it to the binary:
59 * `t3` for a PATH lookup, `./t3` or the launcher symlink for an explicit
60 * path. `process.argv[0]` and `execPath` are always the resolved binary.
61 */
62export const InvokedAs = Context.Reference<string>("@t3tools/shared/HostProcess/InvokedAs", {
63 defaultValue: () => process.argv0,
64});
65
66/**
67 * Whether this process is a Node single-executable rather than a script run
68 * by a Node on the machine. Code that needs a sibling file or a Node to run
69 * one branches on this: an executable hosts such things as hidden
70 * subcommands of itself.
71 */
72export const IsExecutable = Context.Reference<boolean>("@t3tools/shared/HostProcess/IsExecutable", {
73 defaultValue: () => NodeSea.isSea(),
74});
75
76/**
77 * Every IP address this machine answers to: the interface addresses, plus
78 * whatever the resolver returns for the machine's own hostname. The latter
79 * matters because a hostname can map to an address no interface carries —
80 * Debian-style hosts put `127.0.1.1` in `/etc/hosts` — and a program that
81 * records "its" address by resolving its hostname (Firefox's profile lock
82 * does) will write that one. "Is this address ours" has to accept both.
83 *
84 * Best effort: a failed lookup just leaves the interface set.
85 */
86export const Addresses = Context.Reference<Effect.Effect<ReadonlySet<string>>>(
87 "@t3tools/shared/HostProcess/Addresses",
88 {
89 defaultValue: () =>
90 Effect.gen(function* () {
91 const interfaces = Object.values(NodeOS.networkInterfaces())
92 .flat()
93 .flatMap((entry) => (entry ? [entry.address] : []));
94 const resolved = yield* Effect.tryPromise(() =>
95 NodeDns.promises.lookup(NodeOS.hostname(), { all: true }),
96 ).pipe(
97 Effect.map((entries) => entries.map((entry) => entry.address)),
98 Effect.orElseSucceed(() => [] as ReadonlyArray<string>),
99 );
100 return new Set([...interfaces, ...resolved]);
101 }),
102 },
103);
104
105/** Undefined on platforms without POSIX uids (Windows). */
106export const UserId = Context.Reference<number | undefined>("@t3tools/shared/HostProcess/UserId", {
107 defaultValue: () => process.getuid?.(),
108});
109
110export const isWindows = Effect.map(Platform, (platform) => platform === "win32");
packages/shared/src/editor.ts+2-2
......@@ -4,7 +4,7 @@ import * as FileSystem from "effect/FileSystem";
44import * as Option from "effect/Option";
55import * as Path from "effect/Path";
66
7import * as HostProcess from "./hostProcess.ts";
7import * as HostProcess from "./HostProcess.ts";
88import { isCommandAvailable } from "./shell.ts";
99
1010type Editor = (typeof EDITORS)[number];
......@@ -37,7 +37,7 @@ export const resolveEditorCommand = Effect.fn("editor.resolveEditorCommand")(fun
3737 if (yield* isCommandAvailable(command, { env })) return Option.some({ command, baseArgs });
3838 }
3939
40 const platform = yield* HostProcess.HostProcessPlatform;
40 const platform = yield* HostProcess.Platform;
4141 const path = yield* Path.Path;
4242 const fs = yield* FileSystem.FileSystem;
4343 const home = env.HOME;
packages/shared/src/hostProcess.ts deleted-125
......@@ -1,125 +0,0 @@
1import * as Context from "effect/Context";
2import * as Effect from "effect/Effect";
3import * as NodeDns from "node:dns";
4import * as NodeOS from "node:os";
5import * as NodeSea from "node:sea";
6
7export const HostProcessPlatform = Context.Reference<NodeJS.Platform>(
8 "@t3tools/shared/hostProcess/HostProcessPlatform",
9 {
10 defaultValue: () => process.platform,
11 },
12);
13
14export const HostProcessArchitecture = Context.Reference<NodeJS.Architecture>(
15 "@t3tools/shared/hostProcess/HostProcessArchitecture",
16 {
17 defaultValue: () => process.arch,
18 },
19);
20
21export const HostProcessHostname = Context.Reference<string>(
22 "@t3tools/shared/hostProcess/HostProcessHostname",
23 {
24 defaultValue: () => NodeOS.hostname(),
25 },
26);
27
28export const HostProcessHomeDirectory = Context.Reference<string>(
29 "@t3tools/shared/hostProcess/HostProcessHomeDirectory",
30 {
31 defaultValue: () => NodeOS.homedir(),
32 },
33);
34
35export const HostProcessEnvironment = Context.Reference<NodeJS.ProcessEnv>(
36 "@t3tools/shared/hostProcess/HostProcessEnvironment",
37 {
38 defaultValue: () => process.env,
39 },
40);
41
42export const HostProcessWorkingDirectory = Context.Reference<string>(
43 "@t3tools/shared/hostProcess/HostProcessWorkingDirectory",
44 {
45 defaultValue: () => process.cwd(),
46 },
47);
48
49export const HostProcessExecutablePath = Context.Reference<string>(
50 "@t3tools/shared/hostProcess/HostProcessExecutablePath",
51 {
52 defaultValue: () => process.execPath,
53 },
54);
55
56export const HostProcessArguments = Context.Reference<ReadonlyArray<string>>(
57 "@t3tools/shared/hostProcess/HostProcessArguments",
58 {
59 defaultValue: () => process.argv,
60 },
61);
62
63/**
64 * The command the shell was given, before Node resolved it to the binary:
65 * `t3` for a PATH lookup, `./t3` or the launcher symlink for an explicit
66 * path. `process.argv[0]` and `execPath` are always the resolved binary.
67 */
68export const HostProcessInvokedAs = Context.Reference<string>(
69 "@t3tools/shared/hostProcess/HostProcessInvokedAs",
70 {
71 defaultValue: () => process.argv0,
72 },
73);
74
75/**
76 * Whether this process is a Node single-executable rather than a script run
77 * by a Node on the machine. Code that needs a sibling file or a Node to run
78 * one branches on this: an executable hosts such things as hidden
79 * subcommands of itself.
80 */
81export const HostProcessIsExecutable = Context.Reference<boolean>(
82 "@t3tools/shared/hostProcess/HostProcessIsExecutable",
83 {
84 defaultValue: () => NodeSea.isSea(),
85 },
86);
87
88/**
89 * Every IP address this machine answers to: the interface addresses, plus
90 * whatever the resolver returns for the machine's own hostname. The latter
91 * matters because a hostname can map to an address no interface carries —
92 * Debian-style hosts put `127.0.1.1` in `/etc/hosts` — and a program that
93 * records "its" address by resolving its hostname (Firefox's profile lock
94 * does) will write that one. "Is this address ours" has to accept both.
95 *
96 * Best effort: a failed lookup just leaves the interface set.
97 */
98export const HostProcessAddresses = Context.Reference<Effect.Effect<ReadonlySet<string>>>(
99 "@t3tools/shared/hostProcess/HostProcessAddresses",
100 {
101 defaultValue: () =>
102 Effect.gen(function* () {
103 const interfaces = Object.values(NodeOS.networkInterfaces())
104 .flat()
105 .flatMap((entry) => (entry ? [entry.address] : []));
106 const resolved = yield* Effect.tryPromise(() =>
107 NodeDns.promises.lookup(NodeOS.hostname(), { all: true }),
108 ).pipe(
109 Effect.map((entries) => entries.map((entry) => entry.address)),
110 Effect.orElseSucceed(() => [] as ReadonlyArray<string>),
111 );
112 return new Set([...interfaces, ...resolved]);
113 }),
114 },
115);
116
117/** Undefined on platforms without POSIX uids (Windows). */
118export const HostProcessUserId = Context.Reference<number | undefined>(
119 "@t3tools/shared/hostProcess/HostProcessUserId",
120 {
121 defaultValue: () => process.getuid?.(),
122 },
123);
124
125export const isHostWindows = Effect.map(HostProcessPlatform, (platform) => platform === "win32");
packages/shared/src/logging.test.ts+2-2
......@@ -3,7 +3,7 @@ import * as NodeFS from "node:fs";
33import * as NodeOS from "node:os";
44import * as NodePath from "node:path";
55import { afterEach, describe, expect, it } from "vite-plus/test";
6import { HostProcessPlatform } from "./hostProcess.ts";
6import * as HostProcess from "./HostProcess.ts";
77
88import {
99 RotatingFileSink,
......@@ -11,7 +11,7 @@ import {
1111 RotatingFileSinkError,
1212} from "./logging.ts";
1313
14const windowsHost = HostProcessPlatform.defaultValue() === "win32";
14const windowsHost = HostProcess.Platform.defaultValue() === "win32";
1515const tempDirectories: string[] = [];
1616
1717const makeTempDirectory = (): string => {
packages/shared/src/nodeRuntime.test.ts+28-33
......@@ -5,12 +5,7 @@ import * as FileSystem from "effect/FileSystem";
55import * as Path from "effect/Path";
66import * as Result from "effect/Result";
77
8import {
9 HostProcessArguments,
10 HostProcessExecutablePath,
11 HostProcessIsExecutable,
12 HostProcessPlatform,
13} from "./hostProcess.ts";
8import * as HostProcess from "./HostProcess.ts";
149import { resolveNodeExecutable, resolveSelfInvocation, selfInvocationArgs } from "./nodeRuntime.ts";
1510import { symlinksSupported } from "./testing/symlinks.ts";
1611
......@@ -19,9 +14,9 @@ describe("Self invocation", () => {
1914 Effect.gen(function* () {
2015 const path = yield* Path.Path;
2116 const invocation = yield* resolveSelfInvocation().pipe(
22 Effect.provideService(HostProcessExecutablePath, "/runtime/node"),
23 Effect.provideService(HostProcessIsExecutable, false),
24 Effect.provideService(HostProcessArguments, ["/runtime/node", "dist/bin.mjs", "serve"]),
17 Effect.provideService(HostProcess.ExecutablePath, "/runtime/node"),
18 Effect.provideService(HostProcess.IsExecutable, false),
19 Effect.provideService(HostProcess.Arguments, ["/runtime/node", "dist/bin.mjs", "serve"]),
2520 );
2621 expect(invocation.command).toBe("/runtime/node");
2722 expect(invocation.entrypoint).toBe(path.resolve("dist/bin.mjs"));
......@@ -36,9 +31,9 @@ describe("Self invocation", () => {
3631 Effect.gen(function* () {
3732 // Node repeats the binary at argv[1] for a single-executable; it is not a script.
3833 const invocation = yield* resolveSelfInvocation().pipe(
39 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),
40 Effect.provideService(HostProcessIsExecutable, true),
41 Effect.provideService(HostProcessArguments, ["/packaged/t3", "/packaged/t3", "serve"]),
34 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
35 Effect.provideService(HostProcess.IsExecutable, true),
36 Effect.provideService(HostProcess.Arguments, ["/packaged/t3", "/packaged/t3", "serve"]),
4237 );
4338 expect(invocation).toEqual({ command: "/packaged/t3", entrypoint: undefined });
4439 expect(selfInvocationArgs(invocation, ["acp-mcp-bridge"])).toEqual(["acp-mcp-bridge"]);
......@@ -52,8 +47,8 @@ describe("Node runtime selection", () => {
5247 for (const executable of ["/runtime/node", "/Applications/T3 Code.app/Electron"]) {
5348 expect(
5449 yield* resolveNodeExecutable("Local device support", { PATH: "" }).pipe(
55 Effect.provideService(HostProcessExecutablePath, executable),
56 Effect.provideService(HostProcessIsExecutable, false),
50 Effect.provideService(HostProcess.ExecutablePath, executable),
51 Effect.provideService(HostProcess.IsExecutable, false),
5752 ),
5853 ).toBe(executable);
5954 }
......@@ -69,8 +64,8 @@ describe("Node runtime selection", () => {
6964 }),
7065 ).toBe(process.execPath);
7166 }).pipe(
72 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),
73 Effect.provideService(HostProcessIsExecutable, true),
67 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
68 Effect.provideService(HostProcess.IsExecutable, true),
7469 Effect.provide(NodeServices.layer),
7570 ),
7671 );
......@@ -84,7 +79,7 @@ describe("Node runtime selection", () => {
8479 expect(error.message).toContain("Local device support requires Node.js");
8580 expect(error.message).toContain("Install Node.js");
8681 }).pipe(
87 Effect.provideService(HostProcessIsExecutable, true),
82 Effect.provideService(HostProcess.IsExecutable, true),
8883 Effect.provide(NodeServices.layer),
8984 ),
9085 );
......@@ -94,7 +89,7 @@ describe("Node runtime selection", () => {
9489 const fs = yield* FileSystem.FileSystem;
9590 const path = yield* Path.Path;
9691 const directory = yield* fs.makeTempDirectoryScoped();
97 const platform = yield* HostProcessPlatform;
92 const platform = yield* HostProcess.Platform;
9893 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
9994 const env = { PATH: directory };
10095 expect(
......@@ -107,8 +102,8 @@ describe("Node runtime selection", () => {
107102 expect(yield* resolveNodeExecutable("Local device support", env)).toBe(node);
108103 }).pipe(
109104 Effect.scoped,
110 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),
111 Effect.provideService(HostProcessIsExecutable, true),
105 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
106 Effect.provideService(HostProcess.IsExecutable, true),
112107 Effect.provide(NodeServices.layer),
113108 ),
114109 );
......@@ -134,9 +129,9 @@ describe("Node runtime selection", () => {
134129 ).toBe(node);
135130 }).pipe(
136131 Effect.scoped,
137 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),
138 Effect.provideService(HostProcessIsExecutable, true),
139 Effect.provideService(HostProcessPlatform, "win32"),
132 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
133 Effect.provideService(HostProcess.IsExecutable, true),
134 Effect.provideService(HostProcess.Platform, "win32"),
140135 Effect.provide(NodeServices.layer),
141136 ),
142137 );
......@@ -156,8 +151,8 @@ describe("Node runtime selection", () => {
156151 expect(error.message).toContain("Install Node.js");
157152 }).pipe(
158153 Effect.scoped,
159 Effect.provideService(HostProcessIsExecutable, true),
160 Effect.provideService(HostProcessPlatform, "win32"),
154 Effect.provideService(HostProcess.IsExecutable, true),
155 Effect.provideService(HostProcess.Platform, "win32"),
161156 Effect.provide(NodeServices.layer),
162157 ),
163158 );
......@@ -167,21 +162,21 @@ describe("Node runtime selection", () => {
167162 const fs = yield* FileSystem.FileSystem;
168163 const path = yield* Path.Path;
169164 const directory = yield* fs.makeTempDirectoryScoped();
170 const platform = yield* HostProcessPlatform;
165 const platform = yield* HostProcess.Platform;
171166 const executable = path.join(directory, platform === "win32" ? "t3.exe" : "t3");
172167 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
173168 yield* fs.writeFileString(executable, "standalone executable fixture");
174169 yield* fs.chmod(executable, 0o755);
175170 yield* fs.link(executable, node);
176171 const error = yield* resolveNodeExecutable("Local device support", { PATH: directory }).pipe(
177 Effect.provideService(HostProcessExecutablePath, executable),
172 Effect.provideService(HostProcess.ExecutablePath, executable),
178173 Effect.flip,
179174 );
180175 expect(error._tag).toBe("NodeRuntimeUnavailableError");
181176 expect(error.message).toContain("Install Node.js");
182177 }).pipe(
183178 Effect.scoped,
184 Effect.provideService(HostProcessIsExecutable, true),
179 Effect.provideService(HostProcess.IsExecutable, true),
185180 Effect.provide(NodeServices.layer),
186181 ),
187182 );
......@@ -191,14 +186,14 @@ describe("Node runtime selection", () => {
191186 const fs = yield* FileSystem.FileSystem;
192187 const path = yield* Path.Path;
193188 const directory = yield* fs.makeTempDirectoryScoped();
194 const platform = yield* HostProcessPlatform;
189 const platform = yield* HostProcess.Platform;
195190 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
196191 yield* fs.symlink(process.execPath, node);
197192 expect(yield* resolveNodeExecutable("Local device support", { PATH: directory })).toBe(node);
198193 }).pipe(
199194 Effect.scoped,
200 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),
201 Effect.provideService(HostProcessIsExecutable, true),
195 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
196 Effect.provideService(HostProcess.IsExecutable, true),
202197 Effect.provide(NodeServices.layer),
203198 ),
204199 );
......@@ -210,7 +205,7 @@ describe("Node runtime selection", () => {
210205 const fs = yield* FileSystem.FileSystem;
211206 const path = yield* Path.Path;
212207 const directory = yield* fs.makeTempDirectoryScoped();
213 const platform = yield* HostProcessPlatform;
208 const platform = yield* HostProcess.Platform;
214209 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
215210 yield* fs.symlink(process.execPath, node);
216211 const error = yield* resolveNodeExecutable("Local device support", {
......@@ -219,7 +214,7 @@ describe("Node runtime selection", () => {
219214 expect(error.message).toContain("Install Node.js");
220215 }).pipe(
221216 Effect.scoped,
222 Effect.provideService(HostProcessIsExecutable, true),
217 Effect.provideService(HostProcess.IsExecutable, true),
223218 Effect.provide(NodeServices.layer),
224219 ),
225220 );
packages/shared/src/nodeRuntime.ts+8-14
......@@ -4,13 +4,7 @@ import * as Path from "effect/Path";
44import * as Option from "effect/Option";
55import * as Schema from "effect/Schema";
66
7import {
8 HostProcessArguments,
9 HostProcessEnvironment,
10 HostProcessExecutablePath,
11 HostProcessIsExecutable,
12 HostProcessPlatform,
13} from "./hostProcess.ts";
7import * as HostProcess from "./HostProcess.ts";
148import { CommandResolutionCache, resolveCommandPath } from "./shell.ts";
159
1610const NodeRuntimeFeature = Schema.Literals([
......@@ -51,11 +45,11 @@ export interface SelfInvocation {
5145 * assemble the pair themselves.
5246 */
5347export const resolveSelfInvocation = Effect.fn("nodeRuntime.resolveSelfInvocation")(function* () {
54 const command = yield* HostProcessExecutablePath;
55 if (yield* HostProcessIsExecutable)
48 const command = yield* HostProcess.ExecutablePath;
49 if (yield* HostProcess.IsExecutable)
5650 return { command, entrypoint: undefined } satisfies SelfInvocation;
5751 const path = yield* Path.Path;
58 const entry = (yield* HostProcessArguments)[1];
52 const entry = (yield* HostProcess.Arguments)[1];
5953 // Children spawn from their own working directory, so the script path must be absolute.
6054 return {
6155 command,
......@@ -75,13 +69,13 @@ export const resolveNodeExecutable = Effect.fn("nodeRuntime.resolveNodeExecutabl
7569 feature: typeof NodeRuntimeFeature.Type,
7670 environment?: NodeJS.ProcessEnv,
7771) {
78 const executablePath = yield* HostProcessExecutablePath;
79 if (!(yield* HostProcessIsExecutable)) return executablePath;
72 const executablePath = yield* HostProcess.ExecutablePath;
73 if (!(yield* HostProcess.IsExecutable)) return executablePath;
8074
8175 const fs = yield* FileSystem.FileSystem;
8276 const path = yield* Path.Path;
83 const platform = yield* HostProcessPlatform;
84 const env = environment ?? (yield* HostProcessEnvironment);
77 const platform = yield* HostProcess.Platform;
78 const env = environment ?? (yield* HostProcess.Environment);
8579 const nodePath = yield* resolveCommandPath(platform === "win32" ? "node.exe" : "node", {
8680 // Batch wrappers require a shell; helper callers launch the runtime directly.
8781 env: platform === "win32" ? { ...env, PATHEXT: ".EXE" } : env,
packages/shared/src/relayClient.test.ts+4-4
......@@ -14,18 +14,18 @@ import * as Stream from "effect/Stream";
1414import * as TestClock from "effect/testing/TestClock";
1515import { HttpClient, HttpClientResponse } from "effect/http";
1616import { ChildProcess, ChildProcessSpawner } from "effect/process";
17import { HostProcessArchitecture, HostProcessPlatform } from "./hostProcess.ts";
17import * as HostProcess from "./HostProcess.ts";
1818
1919import * as RelayClient from "./relayClient.ts";
2020
2121// The suite runs the linux code path against the real filesystem, checking
2222// POSIX exec bits that NTFS never reports; the win32 branch skips that check.
23const windowsHost = HostProcessPlatform.defaultValue() === "win32";
23const windowsHost = HostProcess.Platform.defaultValue() === "win32";
2424
2525const layerHostRuntime = (env: Record<string, string> = {}, platform: NodeJS.Platform = "linux") =>
2626 Layer.mergeAll(
27 Layer.succeed(HostProcessPlatform, platform),
28 Layer.succeed(HostProcessArchitecture, "x64"),
27 Layer.succeed(HostProcess.Platform, platform),
28 Layer.succeed(HostProcess.Architecture, "x64"),
2929 ConfigProvider.layer(ConfigProvider.fromEnv({ env })),
3030 );
3131
packages/shared/src/relayClient.ts+3-3
......@@ -21,7 +21,7 @@ import * as Schedule from "effect/Schedule";
2121import * as Semaphore from "effect/Semaphore";
2222import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http";
2323import { ChildProcess, ChildProcessSpawner } from "effect/process";
24import { HostProcessArchitecture, HostProcessPlatform } from "./hostProcess.ts";
24import * as HostProcess from "./HostProcess.ts";
2525
2626export const CLOUDFLARED_VERSION = "2026.10.0";
2727// The oldest release that accepts every flag the connector is started with
......@@ -257,8 +257,8 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function
257257 const path = yield* Path.Path;
258258 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
259259 const installSemaphore = yield* Semaphore.make(1);
260 const platform = yield* HostProcessPlatform;
261 const arch = yield* HostProcessArchitecture;
260 const platform = yield* HostProcess.Platform;
261 const arch = yield* HostProcess.Architecture;
262262 const releaseAsset = options.releaseAsset ?? resolveReleaseAsset(platform, arch);
263263 const loadCloudflaredConfig = Effect.suspend(() => CloudflaredConfig).pipe(Effect.orDie);
264264 const managedRoot = path.join(options.baseDir, "tools", "cloudflared");
packages/shared/src/shell.test.ts+13-13
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { it as effectIt } from "@effect/vitest";
3import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Effect from "effect/Effect";
55import * as FileSystem from "effect/FileSystem";
66import * as Path from "effect/Path";
......@@ -342,7 +342,7 @@ effectIt.layer(NodeServices.layer)("isCommandAvailable", (it) => {
342342 expect(
343343 yield* isCommandAvailable("definitely-not-installed", {
344344 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
345 }).pipe(Effect.provideService(HostProcessPlatform, "win32")),
345 }).pipe(Effect.provideService(HostProcess.Platform, "win32")),
346346 ).toBe(false);
347347 }),
348348 );
......@@ -353,7 +353,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
353353 Effect.gen(function* () {
354354 const result = yield* resolveCommandPath("definitely-not-installed", {
355355 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
356 }).pipe(Effect.provideService(HostProcessPlatform, "win32"), Effect.result);
356 }).pipe(Effect.provideService(HostProcess.Platform, "win32"), Effect.result);
357357
358358 expect(result._tag).toBe("Failure");
359359 }),
......@@ -367,7 +367,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
367367 Effect.gen(function* () {
368368 const probed: Array<string> = [];
369369 const result = yield* resolveCommandPath("definitely-not-installed", { env }).pipe(
370 Effect.provideService(HostProcessPlatform, "win32"),
370 Effect.provideService(HostProcess.Platform, "win32"),
371371 Effect.provideService(CommandResolutionCache, new Map()),
372372 Effect.provide(
373373 FileSystem.layerNoop({
......@@ -425,7 +425,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
425425 const resolved = yield* resolveCommandPath(command, {
426426 env: { PATH: cwd, PATHEXT: ".CMD" },
427427 }).pipe(
428 Effect.provideService(HostProcessPlatform, "win32"),
428 Effect.provideService(HostProcess.Platform, "win32"),
429429 Effect.provideService(CommandResolutionCache, new Map()),
430430 Effect.provideService(FileSystem.FileSystem, {
431431 ...fs,
......@@ -458,7 +458,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
458458 yield* TestClock.adjust("30 seconds");
459459 expect(yield* resolveCommandPath("appeared", options)).toBe(executable);
460460 }).pipe(
461 Effect.provideService(HostProcessPlatform, "win32"),
461 Effect.provideService(HostProcess.Platform, "win32"),
462462 Effect.provideService(CommandResolutionCache, new Map()),
463463 ),
464464 );
......@@ -505,7 +505,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
505505 );
506506 expect(probed).toEqual([path.join(first, "cursor.CMD"), path.join(second, "late.EXE")]);
507507 }).pipe(
508 Effect.provideService(HostProcessPlatform, "win32"),
508 Effect.provideService(HostProcess.Platform, "win32"),
509509 Effect.provideService(CommandResolutionCache, new Map()),
510510 ),
511511 );
......@@ -517,7 +517,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
517517 const command = yield* resolveSpawnCommand("node.exe", ["script.js", "hello & goodbye"], {
518518 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
519519 }).pipe(
520 Effect.provideService(HostProcessPlatform, "win32"),
520 Effect.provideService(HostProcess.Platform, "win32"),
521521 Effect.provideService(CommandResolutionCache, new Map()),
522522 );
523523
......@@ -536,7 +536,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
536536 ["run", "value & calc", "%PATH%", 'quote"value'],
537537 { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" } },
538538 ).pipe(
539 Effect.provideService(HostProcessPlatform, "win32"),
539 Effect.provideService(HostProcess.Platform, "win32"),
540540 Effect.provideService(CommandResolutionCache, new Map()),
541541 Effect.provideService(
542542 SpawnExecutableResolution,
......@@ -563,9 +563,9 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
563563 env: { CODEX_HOME: "C:\\Users\\tester\\.codex" },
564564 extendEnv: true,
565565 }).pipe(
566 Effect.provideService(HostProcessPlatform, "win32"),
566 Effect.provideService(HostProcess.Platform, "win32"),
567567 Effect.provideService(CommandResolutionCache, new Map()),
568 Effect.provideService(HostProcessEnvironment, {
568 Effect.provideService(HostProcess.Environment, {
569569 PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm",
570570 PATHEXT: ".COM;.EXE;.BAT;.CMD",
571571 }),
......@@ -592,7 +592,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
592592 };
593593 const resolve = (command: string, path: string, resolver = scan) =>
594594 resolveSpawnCommand(command, [], { env: { PATH: path, PATHEXT: ".EXE" } }).pipe(
595 Effect.provideService(HostProcessPlatform, "win32"),
595 Effect.provideService(HostProcess.Platform, "win32"),
596596 Effect.provideService(SpawnExecutableResolution, resolver),
597597 );
598598
......@@ -632,7 +632,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
632632 const command = yield* resolveSpawnCommand("missing & calc", ["unsafe & value"], {
633633 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
634634 }).pipe(
635 Effect.provideService(HostProcessPlatform, "win32"),
635 Effect.provideService(HostProcess.Platform, "win32"),
636636 Effect.provideService(CommandResolutionCache, new Map()),
637637 );
638638
packages/shared/src/shell.ts+6-6
......@@ -11,7 +11,7 @@ import * as FileSystem from "effect/FileSystem";
1111import * as Option from "effect/Option";
1212import * as Path from "effect/Path";
1313
14import { HostProcessEnvironment, HostProcessPlatform } from "./hostProcess.ts";
14import * as HostProcess from "./HostProcess.ts";
1515import * as Context from "effect/Context";
1616const SHELL_ENV_NAME_PATTERN = /^[A-Z0-9_]+$/;
1717const WINDOWS_PATH_DELIMITER = ";";
......@@ -503,7 +503,7 @@ interface CommandResolutionCacheEntry {
503503 readonly expiresAtNanos: bigint;
504504}
505505
506// The cache lives in the Effect environment (like HostProcessPlatform above)
506// The cache lives in the Effect environment (like HostProcess.Platform above)
507507// so tests and embedders can provide an isolated instance; the default is a
508508// single process-wide map shared by all consumers.
509509export const CommandResolutionCache = Context.Reference<Map<string, CommandResolutionCacheEntry>>(
......@@ -688,8 +688,8 @@ export const resolveCommandPath = Effect.fn("shell.resolveCommandPath")(function
688688 options: CommandAvailabilityOptions = {},
689689) {
690690 return yield* resolveCommandPathForPlatform(command, {
691 env: options.env ?? (yield* HostProcessEnvironment),
692 platform: yield* HostProcessPlatform,
691 env: options.env ?? (yield* HostProcess.Environment),
692 platform: yield* HostProcess.Platform,
693693 });
694694});
695695
......@@ -699,12 +699,12 @@ export const resolveSpawnCommand = Effect.fnUntraced(function* (
699699 args: ReadonlyArray<string>,
700700 options: CommandAvailabilityOptions = {},
701701): Effect.fn.Return<ResolvedSpawnCommand> {
702 const platform = yield* HostProcessPlatform;
702 const platform = yield* HostProcess.Platform;
703703 if (platform !== "win32") {
704704 return { command, args: [...args], shell: false };
705705 }
706706
707 const hostEnvironment = yield* HostProcessEnvironment;
707 const hostEnvironment = yield* HostProcess.Environment;
708708 const env =
709709 options.env === undefined
710710 ? hostEnvironment
packages/shared/src/testing/longTempDir.ts+2-2
......@@ -1,14 +1,14 @@
11// @effect-diagnostics nodeBuiltinImport:off - runs once at test setup, outside any Effect runtime.
22import * as NodeFS from "node:fs";
33import * as NodeOS from "node:os";
4import { HostProcessPlatform } from "../hostProcess.ts";
4import * as HostProcess from "../HostProcess.ts";
55
66// GitHub's Windows runners hand out the temp directory by its 8.3 short name
77// (C:\Users\RUNNER~1\...). Anything that canonicalises a path, such as git or
88// realpath, reports the long form, so equality checks between a temp path and
99// its canonical form fail. Node reads TEMP/TMP on every os.tmpdir() call, so
1010// pointing them at the long form fixes every temp directory the suite makes.
11if (HostProcessPlatform.defaultValue() === "win32") {
11if (HostProcess.Platform.defaultValue() === "win32") {
1212 try {
1313 const longForm = NodeFS.realpathSync.native(NodeOS.tmpdir());
1414 process.env.TEMP = longForm;
packages/source-control-forgejo/src/server/ForgejoCli.ts+3-3
......@@ -11,7 +11,7 @@ import * as NodePath from "node:path";
1111import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http";
1212import { ChildProcessSpawner } from "effect/process";
1313import { decodeJsonResult } from "@t3tools/shared/schemaJson";
14import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost";
1616import { collectUint8StreamText } from "@t3tools/provider-core/server/collectStreamText";
1717import type { SourceControlProviderContext } from "@t3tools/source-control-core/server/SourceControlProvider";
......@@ -248,8 +248,8 @@ export const make = Effect.gen(function* () {
248248
249249 const readKeys = Effect.fn("ForgejoCli.readKeys")(function* (cwd: string) {
250250 for (const path of forgejoKeysPaths({
251 platform: yield* HostProcessPlatform,
252 home: yield* HostProcessHomeDirectory,
251 platform: yield* HostProcess.Platform,
252 home: yield* HostProcess.HomeDirectory,
253253 ...(globalThis.process.env.XDG_DATA_HOME
254254 ? { dataHome: globalThis.process.env.XDG_DATA_HOME }
255255 : {}),
packages/source-control-github/src/server/GitHubCredentials.ts+3-3
......@@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError";
1111import * as Redacted from "effect/Redacted";
1212import * as Schema from "effect/Schema";
1313
14import { HostProcessEnvironment, HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess";
14import * as HostProcess from "@t3tools/shared/HostProcess";
1515
1616import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost";
1717
......@@ -130,8 +130,8 @@ export const make = Effect.gen(function* () {
130130 const sourceControlHost = yield* SourceControlHost.SourceControlHost;
131131 const process = sourceControlHost.process;
132132 const crypto = yield* Crypto.Crypto;
133 const environment = yield* HostProcessEnvironment;
134 const workingDirectory = yield* HostProcessWorkingDirectory;
133 const environment = yield* HostProcess.Environment;
134 const workingDirectory = yield* HostProcess.WorkingDirectory;
135135
136136 /** `host:sha256(token)`, safe for cache keys and rate-limit scopes. */
137137 const fingerprintOf = (host: string, token: string) =>
packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts+3-3
......@@ -1,4 +1,4 @@
1import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import { assert, describe, it } from "@effect/vitest";
33import * as NodeServices from "@effect/platform-node/NodeServices";
44import * as Effect from "effect/Effect";
......@@ -1075,7 +1075,7 @@ it.live.each([
10751075 remoteName: "enterprise",
10761076 remoteBranch: "feature",
10771077 });
1078 }).pipe(Effect.provide(layer), Effect.provideService(HostProcessEnvironment, {}), Effect.scoped);
1078 }).pipe(Effect.provide(layer), Effect.provideService(HostProcess.Environment, {}), Effect.scoped);
10791079});
10801080
10811081it.effect.each([
......@@ -1162,7 +1162,7 @@ it.effect.each([
11621162 ]);
11631163 }).pipe(
11641164 Effect.provide(layer),
1165 Effect.provideService(HostProcessEnvironment, { GH_REPO: envRepository }),
1165 Effect.provideService(HostProcess.Environment, { GH_REPO: envRepository }),
11661166 Effect.scoped,
11671167 );
11681168 },
packages/source-control-github/src/server/GitHubSourceControlProvider.ts+3-3
......@@ -18,7 +18,7 @@ import {
1818 type SourceControlRepositoryCloneUrls,
1919} from "@t3tools/contracts";
2020import { normalizeGitRemoteUrl } from "@t3tools/shared/git";
21import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
21import * as HostProcess from "@t3tools/shared/HostProcess";
2222import { decodeJsonResult } from "@t3tools/shared/schemaJson";
2323import { isSshRemoteUrl } from "@t3tools/shared/sourceControl";
2424
......@@ -193,7 +193,7 @@ export const makeDiscovery = Effect.gen(function* () {
193193 const api = yield* GitHubApi.GitHubApi;
194194 const sourceControlHost = yield* SourceControlHost.SourceControlHost;
195195 const process = sourceControlHost.process;
196 const environment = yield* HostProcessEnvironment;
196 const environment = yield* HostProcess.Environment;
197197
198198 return {
199199 type: "managed-cli",
......@@ -478,7 +478,7 @@ export const make = Effect.gen(function* () {
478478 const api = yield* GitHubApi.GitHubApi;
479479 const sourceControlHost = yield* SourceControlHost.SourceControlHost;
480480 const process = sourceControlHost.process;
481 const environment = yield* HostProcessEnvironment;
481 const environment = yield* HostProcess.Environment;
482482 const git = sourceControlHost.git;
483483 const fileSystem = yield* FileSystem.FileSystem;
484484
packages/ssh/src/auth.test.ts+3-3
......@@ -5,7 +5,7 @@ import * as Effect from "effect/Effect";
55import * as FileSystem from "effect/FileSystem";
66import * as Layer from "effect/Layer";
77import * as Path from "effect/Path";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
8import * as HostProcess from "@t3tools/shared/HostProcess";
99
1010import {
1111 buildSshAskpassHelperDescriptor,
......@@ -50,7 +50,7 @@ describe("ssh auth", () => {
5050 assert.equal(yield* fs.exists(askpassPath), true);
5151 assert.include(yield* fs.readFileString(askpassPath), 'printf "%s\\n" "$T3_SSH_AUTH_SECRET"');
5252 }).pipe(
53 Effect.provide(Layer.merge(NodeServices.layer, Layer.succeed(HostProcessPlatform, "linux"))),
53 Effect.provide(Layer.merge(NodeServices.layer, Layer.succeed(HostProcess.Platform, "linux"))),
5454 Effect.scoped,
5555 ),
5656 );
......@@ -61,7 +61,7 @@ describe("ssh auth", () => {
6161 directory: "C:\\temp\\t3code-ssh-askpass",
6262 }).pipe(
6363 Effect.provide(
64 Layer.merge(NodeServices.layer, Layer.succeed(HostProcessPlatform, "win32")),
64 Layer.merge(NodeServices.layer, Layer.succeed(HostProcess.Platform, "win32")),
6565 ),
6666 );
6767
packages/ssh/src/auth.ts+4-4
......@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as Config from "effect/Config";
33import * as Context from "effect/Context";
44import * as Effect from "effect/Effect";
......@@ -113,7 +113,7 @@ export const buildSshAskpassHelperDescriptor = Effect.fn(
113113)(function* (input: {
114114 readonly directory: string;
115115}): Effect.fn.Return<SshAskpassHelperDescriptor, never, Path.Path> {
116 const platform = yield* HostProcessPlatform;
116 const platform = yield* HostProcess.Platform;
117117 const path = yield* Path.Path;
118118 const directory = input.directory;
119119
......@@ -152,7 +152,7 @@ const ensureSshAskpassHelpers = Effect.fn("ssh/auth.ensureSshAskpassHelpers")(fu
152152 const fs = yield* FileSystem.FileSystem;
153153 const path = yield* Path.Path;
154154 const descriptor = yield* buildSshAskpassHelperDescriptor(input);
155 const platform = yield* HostProcessPlatform;
155 const platform = yield* HostProcess.Platform;
156156
157157 yield* fs.makeDirectory(path.dirname(descriptor.launcherPath), { recursive: true });
158158
......@@ -182,7 +182,7 @@ export const buildSshChildEnvironment = Effect.fn("ssh/auth.buildSshChildEnviron
182182 return baseEnv;
183183 }
184184
185 const platform = yield* HostProcessPlatform;
185 const platform = yield* HostProcess.Platform;
186186 const hostDisplay = input.baseEnv
187187 ? input.baseEnv.DISPLAY
188188 : yield* Config.String("DISPLAY").pipe(
packages/ssh/src/command.ts+2-2
......@@ -1,5 +1,5 @@
11import type { DesktopSshEnvironmentTarget } from "@t3tools/contracts";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as Crypto from "effect/Crypto";
44import * as Duration from "effect/Duration";
55import * as Effect from "effect/Effect";
......@@ -25,7 +25,7 @@ const MAX_SSH_ERROR_OUTPUT_LENGTH = 4_000;
2525const sshCommandForPlatform = (platform: NodeJS.Platform): string =>
2626 platform === "win32" ? "ssh.exe" : "ssh";
2727
28export const resolveSshCommand = Effect.map(HostProcessPlatform, sshCommandForPlatform);
28export const resolveSshCommand = Effect.map(HostProcess.Platform, sshCommandForPlatform);
2929
3030const encoder = new TextEncoder();
3131
packages/ssh/src/runnerProcess.test.ts+3-3
......@@ -1,6 +1,6 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
22import { assert, describe, it } from "@effect/vitest";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
44import * as Deferred from "effect/Deferred";
55import * as Effect from "effect/Effect";
66import * as Fiber from "effect/Fiber";
......@@ -21,7 +21,7 @@ const Started = Schema.Struct({
2121});
2222const decodeStarted = Schema.decodeUnknownSync(Schema.fromJsonString(Started));
2323
24describe.skipIf(HostProcessPlatform.defaultValue() === "win32")(
24describe.skipIf(HostProcess.Platform.defaultValue() === "win32")(
2525 "remote runner process ownership",
2626 () => {
2727 it.live("keeps the server PID and graceful shutdown through the node-script runner", () =>
......@@ -130,7 +130,7 @@ server.listen(Number(process.env.T3_TEST_PORT ?? 0), "127.0.0.1", () => {
130130 },
131131);
132132
133describe.skipIf(HostProcessPlatform.defaultValue() === "win32")(
133describe.skipIf(HostProcess.Platform.defaultValue() === "win32")(
134134 "remote stop process ownership",
135135 () => {
136136 it.live.each(["graceful", "timeout", "external"] as const)(
packages/ssh/src/tunnel.test.ts+3-3
......@@ -1,7 +1,7 @@
11import { assert, describe, it } from "@effect/vitest";
22import * as NodeServices from "@effect/platform-node/NodeServices";
33import * as NetService from "@t3tools/shared/Net";
4import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
4import * as HostProcess from "@t3tools/shared/HostProcess";
55import * as Deferred from "effect/Deferred";
66import * as Duration from "effect/Duration";
77import * as Effect from "effect/Effect";
......@@ -691,8 +691,8 @@ describe("ssh tunnel scripts", () => {
691691// lock excludes concurrent installers. Run the real script against a tiny
692692// fake archive served from a file:// mirror.
693693describe("archive runner script", () => {
694 const hostPlatform = HostProcessPlatform.defaultValue();
695 const hostArch = HostProcessArchitecture.defaultValue();
694 const hostPlatform = HostProcess.Platform.defaultValue();
695 const hostArch = HostProcess.Architecture.defaultValue();
696696 const windowsHost = hostPlatform === "win32";
697697 const archiveVersion = "1.2.3-preview.20260911.4";
698698
packages/tailscale/src/tailscale.test.ts+2-2
......@@ -8,7 +8,7 @@ import * as Sink from "effect/Sink";
88import * as Stream from "effect/Stream";
99import * as TestClock from "effect/testing/TestClock";
1010import { ChildProcessSpawner } from "effect/process";
11import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
11import * as HostProcess from "@t3tools/shared/HostProcess";
1212
1313import {
1414 buildTailscaleHttpsBaseUrl,
......@@ -104,7 +104,7 @@ function neverFinishingMockHandle() {
104104function layerSpawner(spawner: ChildProcessSpawner.ChildProcessSpawner["Service"]) {
105105 return Layer.merge(
106106 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner),
107 Layer.succeed(HostProcessPlatform, "linux"),
107 Layer.succeed(HostProcess.Platform, "linux"),
108108 );
109109}
110110
packages/tailscale/src/tailscale.ts+3-3
......@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as Duration from "effect/Duration";
33import * as Effect from "effect/Effect";
44import * as Option from "effect/Option";
......@@ -217,7 +217,7 @@ export const parseTailscaleStatus = (
217217export const readTailscaleStatus = Effect.gen(function* () {
218218 const args = ["status", "--json"];
219219 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
220 const hostPlatform = yield* HostProcessPlatform;
220 const hostPlatform = yield* HostProcess.Platform;
221221 const executable = tailscaleCommandForPlatform(hostPlatform);
222222 const commandContext = {
223223 executable,
......@@ -291,7 +291,7 @@ const runTailscaleCommand = (
291291): Effect.Effect<void, TailscaleCommandError, ChildProcessSpawner.ChildProcessSpawner> =>
292292 Effect.gen(function* () {
293293 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
294 const hostPlatform = yield* HostProcessPlatform;
294 const hostPlatform = yield* HostProcess.Platform;
295295 const executable = tailscaleCommandForPlatform(hostPlatform);
296296 const commandContext = {
297297 executable,
scripts/build-cli-archive.ts+3-3
......@@ -28,7 +28,7 @@ import * as Schema from "effect/Schema";
2828import { Command, Flag } from "effect/cli";
2929import { ChildProcess, ChildProcessSpawner } from "effect/process";
3030
31import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
31import * as HostProcess from "@t3tools/shared/HostProcess";
3232import { fromYaml } from "@t3tools/shared/schemaYaml";
3333import { resolveSpawnCommand } from "@t3tools/shared/shell";
3434import rootPackageJson from "../package.json" with { type: "json" };
......@@ -478,8 +478,8 @@ const buildCliArchive = Effect.fn("buildCliArchive")(function* (input: {
478478 );
479479 // The unsuffixed host build is only a valid stand-in when it was built for
480480 // this platform and architecture; otherwise a missing target must fail.
481 const hostPlatform = yield* HostProcessPlatform;
482 const hostKey = `${hostPlatform === "win32" ? "win" : hostPlatform}-${yield* HostProcessArchitecture}`;
481 const hostPlatform = yield* HostProcess.Platform;
482 const hostKey = `${hostPlatform === "win32" ? "win" : hostPlatform}-${yield* HostProcess.Architecture}`;
483483 const builtExecutable = (yield* fs.exists(targetExecutable))
484484 ? targetExecutable
485485 : targetKey === hostKey
scripts/build-desktop-artifact.test.ts+17-17
......@@ -93,7 +93,7 @@ import {
9393 wslRuntimeArchiveStem,
9494} from "./build-desktop-artifact.ts";
9595import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts";
96import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
96import * as HostProcess from "@t3tools/shared/HostProcess";
9797import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
9898
9999// Keeps pnpm from auto-installing TypeScript, a types-only peer, into the app.
......@@ -1263,7 +1263,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
12631263 assert.isBelow(result.fileCount, WINDOWS_PACKAGED_PAYLOAD_FILE_LIMIT);
12641264 assert.deepStrictEqual(secondAsar, firstAsar);
12651265 }),
1266 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),
1266 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
12671267 );
12681268
12691269 it.effect("accepts an embedded Linux CLI release archive with a matching digest", () =>
......@@ -1283,7 +1283,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
12831283
12841284 assert.equal(result.packagedAppDir, fixture.packagedAppDir);
12851285 }),
1286 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),
1286 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
12871287 );
12881288
12891289 it.effect.each(["x64", "arm64"] as const)(
......@@ -1307,7 +1307,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
13071307
13081308 assert.equal(result.packagedAppDir, fixture.packagedAppDir);
13091309 }),
1310 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),
1310 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
13111311 );
13121312
13131313 it.effect.each(["x64", "arm64"] as const)(
......@@ -1498,8 +1498,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
14981498 Effect.provide(
14991499 Layer.mergeAll(
15001500 spawnerLayer,
1501 Layer.succeed(HostProcessPlatform, "win32"),
1502 Layer.succeed(HostProcessArchitecture, "x64"),
1501 Layer.succeed(HostProcess.Platform, "win32"),
1502 Layer.succeed(HostProcess.Architecture, "x64"),
15031503 ),
15041504 ),
15051505 );
......@@ -1541,8 +1541,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
15411541 Effect.provide(
15421542 Layer.mergeAll(
15431543 spawnerLayer,
1544 Layer.succeed(HostProcessPlatform, "linux"),
1545 Layer.succeed(HostProcessArchitecture, "x64"),
1544 Layer.succeed(HostProcess.Platform, "linux"),
1545 Layer.succeed(HostProcess.Architecture, "x64"),
15461546 ),
15471547 ),
15481548 );
......@@ -1577,8 +1577,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
15771577 Effect.provide(
15781578 Layer.mergeAll(
15791579 spawnerLayer,
1580 Layer.succeed(HostProcessPlatform, "darwin"),
1581 Layer.succeed(HostProcessArchitecture, "arm64"),
1580 Layer.succeed(HostProcess.Platform, "darwin"),
1581 Layer.succeed(HostProcess.Architecture, "arm64"),
15821582 ),
15831583 ),
15841584 );
......@@ -1623,8 +1623,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
16231623 Effect.provide(
16241624 Layer.mergeAll(
16251625 spawnerLayer,
1626 Layer.succeed(HostProcessPlatform, "win32"),
1627 Layer.succeed(HostProcessArchitecture, "x64"),
1626 Layer.succeed(HostProcess.Platform, "win32"),
1627 Layer.succeed(HostProcess.Architecture, "x64"),
16281628 ),
16291629 ),
16301630 );
......@@ -1652,8 +1652,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
16521652 ).pipe(
16531653 Effect.provide(
16541654 Layer.mergeAll(
1655 Layer.succeed(HostProcessPlatform, "win32"),
1656 Layer.succeed(HostProcessArchitecture, "x64"),
1655 Layer.succeed(HostProcess.Platform, "win32"),
1656 Layer.succeed(HostProcess.Architecture, "x64"),
16571657 ),
16581658 ),
16591659 ),
......@@ -1764,7 +1764,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
17641764 assert.instanceOf(error, BundleNotSelfContainedError);
17651765 assert.include(error.output, "t3code-deliberately-missing-package");
17661766 }),
1767 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),
1767 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
17681768 );
17691769
17701770 it.effect("preserves both Linux icon resize failures with structural context", () => {
......@@ -2333,8 +2333,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
23332333 }).pipe(
23342334 Effect.provide(
23352335 Layer.mergeAll(
2336 Layer.succeed(HostProcessPlatform, "win32"),
2337 Layer.succeed(HostProcessArchitecture, "x64"),
2336 Layer.succeed(HostProcess.Platform, "win32"),
2337 Layer.succeed(HostProcess.Architecture, "x64"),
23382338 ConfigProvider.layer(
23392339 ConfigProvider.fromEnv({
23402340 env: {
scripts/build-desktop-artifact.ts+7-7
......@@ -16,7 +16,7 @@ import {
1616} from "@electron/asar";
1717
1818import { fromYaml } from "@t3tools/shared/schemaYaml";
19import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
19import * as HostProcess from "@t3tools/shared/HostProcess";
2020import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";
2121import { resolveSpawnCommand } from "@t3tools/shared/shell";
2222import rootPackageJson from "../package.json" with { type: "json" };
......@@ -869,7 +869,7 @@ const resolveGitCommitHash = Effect.fn("resolveGitCommitHash")(function* (repoRo
869869const resolvePythonForNodeGyp = Effect.fn("resolvePythonForNodeGyp")(function* () {
870870 const fs = yield* FileSystem.FileSystem;
871871 const path = yield* Path.Path;
872 const hostPlatform = yield* HostProcessPlatform;
872 const hostPlatform = yield* HostProcess.Platform;
873873 const env = yield* Config.all({
874874 configuredPython: Config.String("npm_config_python").pipe(
875875 Config.orElse(() => Config.String("PYTHON")),
......@@ -1716,7 +1716,7 @@ export const resolveBuildOptions = Effect.fn("resolveBuildOptions")(function* (
17161716 const path = yield* Path.Path;
17171717 const repoRoot = yield* RepoRoot;
17181718 const env = yield* BuildEnvConfig;
1719 const hostPlatform = yield* HostProcessPlatform;
1719 const hostPlatform = yield* HostProcess.Platform;
17201720
17211721 const platform = mergeOptions(
17221722 input.platform,
......@@ -2404,7 +2404,7 @@ export const stageBrowserSecret = Effect.fn("stageBrowserSecret")(function* (inp
24042404 // silently. `universal` is a mac-only arch the option type still admits;
24052405 // the helper script rejects it, so it maps to the concrete x64 the Linux
24062406 // resource monitor uses for the same request.
2407 const hostPlatform = yield* HostProcessPlatform;
2407 const hostPlatform = yield* HostProcess.Platform;
24082408 if (hostPlatform !== "linux") {
24092409 return yield* new LinuxBrowserSecretHostError({ hostPlatform });
24102410 }
......@@ -3165,8 +3165,8 @@ export const verifyWindowsPrimaryFffNativeLoad = Effect.fn(
31653165 readonly targetArch: typeof BuildArch.Type;
31663166 readonly verbose: boolean;
31673167}) {
3168 const hostPlatform = yield* HostProcessPlatform;
3169 const hostArchitecture = yield* HostProcessArchitecture;
3168 const hostPlatform = yield* HostProcess.Platform;
3169 const hostArchitecture = yield* HostProcess.Architecture;
31703170 const fs = yield* FileSystem.FileSystem;
31713171 const path = yield* Path.Path;
31723172 const executablePath = path.join(input.packagedAppDir, input.appExecutableName);
......@@ -3485,7 +3485,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* (
34853485 const repoRoot = yield* RepoRoot;
34863486 const path = yield* Path.Path;
34873487 const fs = yield* FileSystem.FileSystem;
3488 const hostPlatform = yield* HostProcessPlatform;
3488 const hostPlatform = yield* HostProcess.Platform;
34893489 if (hostPlatform === "linux" && options.platform === "linux") {
34903490 yield* preflightLinuxDesktopBuild(options.arch);
34913491 }
scripts/build-npm-platform-packages.test.ts+3-3
......@@ -1,4 +1,4 @@
1import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as NodeServices from "@effect/platform-node/NodeServices";
33import { assert, it } from "@effect/vitest";
44import * as Effect from "effect/Effect";
......@@ -203,8 +203,8 @@ it.layer(NodeServices.layer)("build-npm-platform-packages", (it) => {
203203
204204 // NODE_PATH stands in for node_modules: require.resolve finds the
205205 // platform package there exactly as it would after `npm install`.
206 const hostPlatform = yield* HostProcessPlatform;
207 const hostArch = yield* HostProcessArchitecture;
206 const hostPlatform = yield* HostProcess.Platform;
207 const hostArch = yield* HostProcess.Architecture;
208208 const env = { ...process.env, NODE_PATH: fixture.outputDir } as Record<string, string>;
209209 if (KEYS.some((key) => key === `${hostPlatform}-${hostArch}`)) {
210210 const passthrough = yield* run(process.execPath, ["bin/t3.js", "serve", "--port", "1234"], {
scripts/build-npm-platform-packages.ts+3-3
......@@ -36,7 +36,7 @@ import {
3636 cliArchiveFileName,
3737 type CliArchivePlatformKey,
3838} from "@t3tools/shared/cliRelease";
39import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
39import * as HostProcess from "@t3tools/shared/HostProcess";
4040import { fromJsonStringPretty } from "@t3tools/shared/schemaJson";
4141import { isCommandAvailable } from "@t3tools/shared/shell";
4242import serverPackageJson from "../apps/server/package.json" with { type: "json" };
......@@ -253,7 +253,7 @@ const runCommand = Effect.fn("runCommand")(function* (
253253const extractArchive = Effect.fn("extractArchive")(function* (archive: string, into: string) {
254254 const fs = yield* FileSystem.FileSystem;
255255 const path = yield* Path.Path;
256 const platform = yield* HostProcessPlatform;
256 const platform = yield* HostProcess.Platform;
257257 if (!archive.endsWith(".zip")) {
258258 yield* runCommand(ChildProcess.make("tar", ["-xf", archive, "-C", into]), "tar -xf");
259259 } else if (platform === "win32") {
......@@ -282,7 +282,7 @@ const extractArchive = Effect.fn("extractArchive")(function* (archive: string, i
282282});
283283
284284/** Tar to build npm tarballs with; see build-cli-archive.ts for why Windows names bsdtar by path. */
285const hostTar = Effect.map(HostProcessPlatform, (platform) =>
285const hostTar = Effect.map(HostProcess.Platform, (platform) =>
286286 platform === "win32" ? windowsSystemTar() : "tar",
287287);
288288
scripts/dev-runner.test.ts+16-20
......@@ -4,11 +4,7 @@ import * as NodeFS from "node:fs";
44import * as NodeOS from "node:os";
55import * as NodePath from "node:path";
66import * as NetService from "@t3tools/shared/Net";
7import {
8 HostProcessEnvironment,
9 HostProcessPlatform,
10 HostProcessWorkingDirectory,
11} from "@t3tools/shared/hostProcess";
7import * as HostProcess from "@t3tools/shared/HostProcess";
128import { assert, describe, it } from "@effect/vitest";
139import * as ConfigProvider from "effect/ConfigProvider";
1410import * as Effect from "effect/Effect";
......@@ -887,7 +883,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
887883 return Effect.gen(function* () {
888884 const error = yield* runDevRunnerWithInput(devServerInput).pipe(
889885 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
890 Effect.provideService(HostProcessPlatform, "linux"),
886 Effect.provideService(HostProcess.Platform, "linux"),
891887 Effect.flip,
892888 );
893889
......@@ -953,7 +949,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
953949 share: true,
954950 }).pipe(
955951 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
956 Effect.provideService(HostProcessPlatform, "linux"),
952 Effect.provideService(HostProcess.Platform, "linux"),
957953 );
958954
959955 assert.equal(spawnCount, 1);
......@@ -977,7 +973,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
977973 host: "192.168.1.10",
978974 }).pipe(
979975 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
980 Effect.provideService(HostProcessPlatform, "linux"),
976 Effect.provideService(HostProcess.Platform, "linux"),
981977 Effect.flip,
982978 );
983979
......@@ -1012,7 +1008,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
10121008 host: "0.0.0.0",
10131009 }).pipe(
10141010 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1015 Effect.provideService(HostProcessPlatform, "linux"),
1011 Effect.provideService(HostProcess.Platform, "linux"),
10161012 );
10171013
10181014 assert.equal(spawnCount, 1);
......@@ -1037,7 +1033,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
10371033 host: "192.168.1.10",
10381034 }).pipe(
10391035 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1040 Effect.provideService(HostProcessPlatform, "linux"),
1036 Effect.provideService(HostProcess.Platform, "linux"),
10411037 );
10421038
10431039 assert.equal(spawnCount, 1);
......@@ -1097,9 +1093,9 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
10971093 share: true,
10981094 }).pipe(
10991095 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1100 Effect.provideService(HostProcessPlatform, "linux"),
1096 Effect.provideService(HostProcess.Platform, "linux"),
11011097 Effect.provideService(
1102 HostProcessEnvironment,
1098 HostProcess.Environment,
11031099 input.ambientBundledDev === undefined
11041100 ? {}
11051101 : { T3CODE_BUNDLED_DEV: input.ambientBundledDev },
......@@ -1144,8 +1140,8 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
11441140 port: undefined,
11451141 }).pipe(
11461142 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1147 Effect.provideService(HostProcessPlatform, "linux"),
1148 Effect.provideService(HostProcessEnvironment, {}),
1143 Effect.provideService(HostProcess.Platform, "linux"),
1144 Effect.provideService(HostProcess.Environment, {}),
11491145 );
11501146
11511147 assert.equal(captured?.T3CODE_BUNDLED_DEV, undefined);
......@@ -1172,7 +1168,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
11721168 share: true,
11731169 }).pipe(
11741170 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1175 Effect.provideService(HostProcessPlatform, "linux"),
1171 Effect.provideService(HostProcess.Platform, "linux"),
11761172 );
11771173
11781174 assert.equal(spawnCount, 0);
......@@ -1188,7 +1184,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
11881184 return Effect.gen(function* () {
11891185 const error = yield* runDevRunnerWithInput(devServerInput).pipe(
11901186 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1191 Effect.provideService(HostProcessPlatform, "linux"),
1187 Effect.provideService(HostProcess.Platform, "linux"),
11921188 Effect.flip,
11931189 );
11941190
......@@ -1221,7 +1217,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
12211217 return Effect.gen(function* () {
12221218 const error = yield* runDevRunnerWithInput(devServerInput).pipe(
12231219 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1224 Effect.provideService(HostProcessPlatform, "linux"),
1220 Effect.provideService(HostProcess.Platform, "linux"),
12251221 Effect.flip,
12261222 );
12271223
......@@ -1274,10 +1270,10 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
12741270
12751271 yield* runDevRunnerWithInput({ ...devServerInput, t3Home: input.t3Home }).pipe(
12761272 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1277 Effect.provideService(HostProcessPlatform, "linux"),
1278 Effect.provideService(HostProcessWorkingDirectory, input.cwd),
1273 Effect.provideService(HostProcess.Platform, "linux"),
1274 Effect.provideService(HostProcess.WorkingDirectory, input.cwd),
12791275 Effect.provideService(
1280 HostProcessEnvironment,
1276 HostProcess.Environment,
12811277 input.ambientHome === undefined ? {} : { T3CODE_HOME: input.ambientHome },
12821278 ),
12831279 );
scripts/dev-runner.ts+4-4
......@@ -6,7 +6,7 @@ import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
66import * as NodeServices from "@effect/platform-node/NodeServices";
77import * as NetService from "@t3tools/shared/Net";
88import { resolveGitWorktreePath, resolveWorktreeT3Home } from "@t3tools/shared/devHome";
9import { HostProcessEnvironment, HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess";
9import * as HostProcess from "@t3tools/shared/HostProcess";
1010import { resolveSpawnCommand } from "@t3tools/shared/shell";
1111import * as Config from "effect/Config";
1212import * as Effect from "effect/Effect";
......@@ -645,7 +645,7 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) {
645645 return yield* new DevRunnerHostNotProxiableError({ mode: input.mode, host: input.host });
646646 }
647647
648 const worktreePath = yield* resolveGitWorktreePath(yield* HostProcessWorkingDirectory);
648 const worktreePath = yield* resolveGitWorktreePath(yield* HostProcess.WorkingDirectory);
649649
650650 const { offset, source } = yield* resolveOffset({
651651 portOffset,
......@@ -663,11 +663,11 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) {
663663 checkPortAvailability: makeDefaultCheckPortAvailability(input.host),
664664 });
665665
666 const hostEnvironment = yield* HostProcessEnvironment;
666 const hostEnvironment = yield* HostProcess.Environment;
667667 // A dev server started inside a worktree defaults to that worktree's own
668668 // (gitignored) `.t3` — see @t3tools/shared/devHome for why this must
669669 // outrank an ambient T3CODE_HOME. `--home-dir` still wins.
670 const worktreeHome = yield* resolveWorktreeT3Home(yield* HostProcessWorkingDirectory);
670 const worktreeHome = yield* resolveWorktreeT3Home(yield* HostProcess.WorkingDirectory);
671671 // Trim before choosing: `--home-dir ""` is not a selection, and treating it
672672 // as one would skip the worktree default and land on the shared home —
673673 // exactly the outcome this precedence exists to prevent.
scripts/export-brand-icons.ts+2-2
......@@ -2,7 +2,7 @@
22
33import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
44import * as NodeServices from "@effect/platform-node/NodeServices";
5import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66import * as Console from "effect/Console";
77import * as Effect from "effect/Effect";
88import * as FileSystem from "effect/FileSystem";
......@@ -408,7 +408,7 @@ const probeIconComposerTool = Effect.fn("iconExport.probeIconComposerTool")(func
408408
409409const resolveIconComposerTool = Effect.fn("iconExport.resolveIconComposerTool")(function* () {
410410 const path = yield* Path.Path;
411 const environment = yield* HostProcessEnvironment;
411 const environment = yield* HostProcess.Environment;
412412 const configuredTool = environment.ICON_COMPOSER_TOOL?.trim();
413413 if (configuredTool) {
414414 const tool = yield* probeIconComposerTool(configuredTool);
scripts/install.test.ts+3-3
......@@ -1,5 +1,5 @@
11// @effect-diagnostics nodeBuiltinImport:off - Drives the real shell installer through a PTY and a gated HTTP fixture.
2import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import * as NodeChildProcess from "node:child_process";
44import * as NodeCrypto from "node:crypto";
55import * as NodeFSP from "node:fs/promises";
......@@ -9,13 +9,13 @@ import * as NodePath from "node:path";
99import { describe, expect, it } from "vite-plus/test";
1010
1111// util-linux's script gives the real installer a terminal without a browser or extra packages.
12describe.skipIf(HostProcessPlatform.defaultValue() !== "linux")("installer terminal", () => {
12describe.skipIf(HostProcess.Platform.defaultValue() !== "linux")("installer terminal", () => {
1313 it.each([false, true])(
1414 "preserves download and install behavior (HTTP failure: %s)",
1515 async (fail) => {
1616 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-install-progress-"));
1717 const version = "1.2.3";
18 const stem = `t3-${version}-linux-${HostProcessArchitecture.defaultValue()}`;
18 const stem = `t3-${version}-linux-${HostProcess.Architecture.defaultValue()}`;
1919 const archiveName = `${stem}.tar.gz`;
2020 let resumeDownload: (() => void) | undefined;
2121 let sawPartialProgress = false;
scripts/lib/build-target-arch.test.ts+3-3
......@@ -2,7 +2,7 @@ import { assert, describe, it } from "@effect/vitest";
22import * as ConfigProvider from "effect/ConfigProvider";
33import * as Effect from "effect/Effect";
44import * as Layer from "effect/Layer";
5import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
5import * as HostProcess from "@t3tools/shared/HostProcess";
66
77import { getDefaultBuildArch } from "./build-target-arch.ts";
88
......@@ -18,8 +18,8 @@ const withHostRuntime = (
1818) =>
1919 Effect.provide(
2020 Layer.mergeAll(
21 Layer.succeed(HostProcessPlatform, platform),
22 Layer.succeed(HostProcessArchitecture, arch),
21 Layer.succeed(HostProcess.Platform, platform),
22 Layer.succeed(HostProcess.Architecture, arch),
2323 ConfigProvider.layer(ConfigProvider.fromEnv({ env: compactEnv(env) })),
2424 ),
2525 );
scripts/lib/build-target-arch.ts+3-3
......@@ -1,4 +1,4 @@
1import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
1import * as HostProcess from "@t3tools/shared/HostProcess";
22import * as Config from "effect/Config";
33import * as Effect from "effect/Effect";
44import * as Option from "effect/Option";
......@@ -27,8 +27,8 @@ const optionToUndefined = <A>(value: Option.Option<A>): A | undefined =>
2727 Option.getOrUndefined(value);
2828
2929const resolveHostProcessArch = Effect.fn("resolveHostProcessArch")(function* () {
30 const platform = yield* HostProcessPlatform;
31 const processArch = yield* HostProcessArchitecture;
30 const platform = yield* HostProcess.Platform;
31 const processArch = yield* HostProcess.Architecture;
3232 if (processArch === "arm64") return "arm64";
3333 if (processArch === "x64") {
3434 if (platform !== "win32") return "x64";
scripts/lib/cli-external-packages.test.ts+1-1
......@@ -34,7 +34,7 @@ const decodeManifest = Schema.decodeUnknownSync(Schema.fromJsonString(PackageMan
3434
3535describe("shouldBundleCliDependency", () => {
3636 it("bundles ordinary runtime dependencies", () => {
37 for (const id of ["effect", "@effect/platform", "hono", "@t3tools/shared/hostProcess"]) {
37 for (const id of ["effect", "@effect/platform", "hono", "@t3tools/shared/HostProcess"]) {
3838 assert.strictEqual(shouldBundleCliDependency(id), true, id);
3939 }
4040 });
scripts/mobile-native-client.ts+7-11
......@@ -1,10 +1,6 @@
11import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
22import * as NodeServices from "@effect/platform-node/NodeServices";
3import {
4 HostProcessEnvironment,
5 HostProcessExecutablePath,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
3import * as HostProcess from "@t3tools/shared/HostProcess";
84import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell";
95import * as Console from "effect/Console";
106import * as Crypto from "effect/Crypto";
......@@ -155,9 +151,9 @@ const collect = <E>(stream: Stream.Stream<Uint8Array, E>) =>
155151 );
156152export const resolveAdb = Effect.gen(function* () {
157153 if (yield* isCommandAvailable("adb")) return "adb";
158 const environment = yield* HostProcessEnvironment;
154 const environment = yield* HostProcess.Environment;
159155 const path = yield* Path.Path;
160 const executable = (yield* HostProcessPlatform) === "win32" ? "adb.exe" : "adb";
156 const executable = (yield* HostProcess.Platform) === "win32" ? "adb.exe" : "adb";
161157 for (const sdk of [environment.ANDROID_SDK_ROOT, environment.ANDROID_HOME]) {
162158 if (!sdk) continue;
163159 const candidate = path.join(sdk, "platform-tools", executable);
......@@ -176,7 +172,7 @@ const command = Effect.fn("nativeClient.command")(function* (
176172 cwd?: string,
177173) {
178174 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
179 const environment = yield* HostProcessEnvironment;
175 const environment = yield* HostProcess.Environment;
180176 const spawn = yield* resolveSpawnCommand(program === "adb" ? yield* resolveAdb : program, args);
181177 const child = yield* spawner.spawn(
182178 ChildProcess.make(spawn.command, spawn.args, {
......@@ -207,7 +203,7 @@ const command = Effect.fn("nativeClient.command")(function* (
207203}, Effect.scoped);
208204
209205const fingerprint = Effect.fn("nativeClient.fingerprint")(function* (platform: NativePlatform) {
210 const output = yield* command(yield* HostProcessExecutablePath, [
206 const output = yield* command(yield* HostProcess.ExecutablePath, [
211207 "--eval",
212208 `require('expo/fingerprint').createFingerprintAsync(process.cwd(), { platforms: [process.argv[1]], silent: true }).then(fp => console.log('T3_NATIVE_FINGERPRINT=' + fp.hash)).catch(e => { console.error(e); process.exitCode = 1; });`,
213209 platform,
......@@ -226,7 +222,7 @@ const validateDevice = Effect.fn("nativeClient.validateDevice")(function* (
226222 device: string,
227223) {
228224 if (platform === "ios") {
229 if ((yield* HostProcessPlatform) !== "darwin")
225 if ((yield* HostProcess.Platform) !== "darwin")
230226 return yield* new NativeClientError({
231227 message: "Run iOS check/ensure on the Mac that hosts the simulator.",
232228 });
......@@ -299,7 +295,7 @@ const main = Command.make(
299295 yield* validateDevice(platform, device);
300296 const fs = yield* FileSystem.FileSystem;
301297 const path = yield* Path.Path;
302 const environment = yield* HostProcessEnvironment;
298 const environment = yield* HostProcess.Environment;
303299 const home = environment.HOME ?? environment.USERPROFILE;
304300 if (!home)
305301 return yield* new NativeClientError({
scripts/mobile-native-static-check.test.ts+2-2
......@@ -1,5 +1,5 @@
11import * as NodeServices from "@effect/platform-node/NodeServices";
2import * as HostProcess from "@t3tools/shared/hostProcess";
2import * as HostProcess from "@t3tools/shared/HostProcess";
33import { assert, it } from "@effect/vitest";
44import * as Effect from "effect/Effect";
55import * as FileSystem from "effect/FileSystem";
......@@ -33,7 +33,7 @@ const provideSpawner = (spawn: ChildProcessSpawner.ChildProcessSpawner["Service"
3333 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, ChildProcessSpawner.make(spawn));
3434
3535const runSwiftLint = runCommand("swiftlint", ["lint", "--strict"], "/repo/apps/mobile").pipe(
36 Effect.provideService(HostProcess.HostProcessPlatform, "linux"),
36 Effect.provideService(HostProcess.Platform, "linux"),
3737);
3838
3939it.layer(NodeServices.layer)("mobile native source discovery", (it) => {
scripts/smoke-cli-archive.ts+2-2
......@@ -22,7 +22,7 @@ import { Command, Flag } from "effect/cli";
2222import { ChildProcess, ChildProcessSpawner } from "effect/process";
2323
2424import * as NetService from "@t3tools/shared/Net";
25import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
25import * as HostProcess from "@t3tools/shared/HostProcess";
2626import { windowsSystemTar } from "./build-cli-archive.ts";
2727import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http";
2828
......@@ -72,7 +72,7 @@ const smokeCliArchive = Effect.fn("smokeCliArchive")(function* (input: {
7272}) {
7373 const fs = yield* FileSystem.FileSystem;
7474 const path = yield* Path.Path;
75 const platform = yield* HostProcessPlatform;
75 const platform = yield* HostProcess.Platform;
7676 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
7777 const scratch = yield* fs.makeTempDirectory({ prefix: "t3-cli-smoke-" });
7878 // Windows can keep t3.exe locked (EBUSY) for a moment after the server
vite.config.ts+1-1
......@@ -219,7 +219,7 @@ export default defineConfig({
219219 },
220220 {
221221 // The one place that reads the host platform to seed the injected references.
222 files: ["packages/shared/src/hostProcess.ts"],
222 files: ["packages/shared/src/HostProcess.ts"],
223223 rules: { "t3code/no-global-process-runtime": "off" },
224224 },
225225 {