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";...@@ -35,7 +35,7 @@ import * as DesktopUpdates from "../updates/DesktopUpdates.ts";
35import * as DesktopSnapShot from "../snapShot/DesktopSnapShot.ts";35import * as DesktopSnapShot from "../snapShot/DesktopSnapShot.ts";
36import * as DesktopWslBackend from "../wsl/DesktopWslBackend.ts";36import * as DesktopWslBackend from "../wsl/DesktopWslBackend.ts";
37import * as DesktopRendererHistory from "../telemetry/DesktopRendererHistory.ts";37import * as DesktopRendererHistory from "../telemetry/DesktopRendererHistory.ts";
38import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";38import * as HostProcess from "@t3tools/shared/HostProcess";
3939
40const DEFAULT_DESKTOP_BACKEND_PORT = 3773;40const DEFAULT_DESKTOP_BACKEND_PORT = 3773;
41const MAX_TCP_PORT = 65_535;41const MAX_TCP_PORT = 65_535;
...@@ -286,7 +286,7 @@ const startup = Effect.gen(function* () {...@@ -286,7 +286,7 @@ const startup = Effect.gen(function* () {
286 const linuxElectronOptions =286 const linuxElectronOptions =
287 environment.platform === "linux" && !hasCommandLinePasswordStore287 environment.platform === "linux" && !hasCommandLinePasswordStore
288 ? DesktopPreReadyPlatform.resolveEarlyLinuxElectronOptionsFromProcess(288 ? DesktopPreReadyPlatform.resolveEarlyLinuxElectronOptionsFromProcess(
289 yield* HostProcessHomeDirectory,289 yield* HostProcess.HomeDirectory,
290 )290 )
291 : preReadyElectronOptions.linux;291 : preReadyElectronOptions.linux;
292 if (linuxElectronOptions !== null && !hasCommandLinePasswordStore) {292 if (linuxElectronOptions !== null && !hasCommandLinePasswordStore) {
apps/desktop/src/app/DesktopAppActivation.test.ts+9-9
...@@ -11,7 +11,7 @@ import {...@@ -11,7 +11,7 @@ import {
11 type DesktopAppActivationResponse,11 type DesktopAppActivationResponse,
12} from "@t3tools/contracts";12} from "@t3tools/contracts";
13import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";13import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
14import { HostProcessPlatform, HostProcessUserId } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
15import { it } from "@effect/vitest";15import { it } from "@effect/vitest";
16import * as Effect from "effect/Effect";16import * as Effect from "effect/Effect";
17import { afterEach, describe, expect } from "vite-plus/test";17import { afterEach, describe, expect } from "vite-plus/test";
...@@ -83,8 +83,8 @@ function exchange(address: string, payload: DesktopAppActivationRequest) {...@@ -83,8 +83,8 @@ function exchange(address: string, payload: DesktopAppActivationRequest) {
83describe("desktop app control server", () => {83describe("desktop app control server", () => {
84 it.effect("roundtrips a request and removes its socket on shutdown", () =>84 it.effect("roundtrips a request and removes its socket on shutdown", () =>
85 Effect.gen(function* () {85 Effect.gen(function* () {
86 const platform = yield* HostProcessPlatform;86 const platform = yield* HostProcess.Platform;
87 const userId = yield* HostProcessUserId;87 const userId = yield* HostProcess.UserId;
88 yield* Effect.promise(async () => {88 yield* Effect.promise(async () => {
89 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-control-test-"));89 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-control-test-"));
90 const target = makeTarget(NodePath.join(root, "userdata"), platform, userId);90 const target = makeTarget(NodePath.join(root, "userdata"), platform, userId);
...@@ -123,8 +123,8 @@ describe("desktop app control server", () => {...@@ -123,8 +123,8 @@ describe("desktop app control server", () => {
123123
124 it.effect("cancels a queued request when the client disconnects", () =>124 it.effect("cancels a queued request when the client disconnects", () =>
125 Effect.gen(function* () {125 Effect.gen(function* () {
126 const platform = yield* HostProcessPlatform;126 const platform = yield* HostProcess.Platform;
127 const userId = yield* HostProcessUserId;127 const userId = yield* HostProcess.UserId;
128 yield* Effect.promise(async () => {128 yield* Effect.promise(async () => {
129 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-cancel-test-"));129 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-cancel-test-"));
130 const target = makeTarget(NodePath.join(root, "userdata"), platform, userId);130 const target = makeTarget(NodePath.join(root, "userdata"), platform, userId);
...@@ -162,8 +162,8 @@ describe("desktop app control server", () => {...@@ -162,8 +162,8 @@ describe("desktop app control server", () => {
162 // Two desktop apps can share one state dir, such as nightly and a preview build.162 // Two desktop apps can share one state dir, such as nightly and a preview build.
163 it.effect("keeps a newer app's socket when an older app on the same state dir quits", () =>163 it.effect("keeps a newer app's socket when an older app on the same state dir quits", () =>
164 Effect.gen(function* () {164 Effect.gen(function* () {
165 const platform = yield* HostProcessPlatform;165 const platform = yield* HostProcess.Platform;
166 const userId = yield* HostProcessUserId;166 const userId = yield* HostProcess.UserId;
167 if (platform === "win32") return;167 if (platform === "win32") return;
168 yield* Effect.promise(async () => {168 yield* Effect.promise(async () => {
169 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-takeover-test-"));169 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-takeover-test-"));
...@@ -183,8 +183,8 @@ describe("desktop app control server", () => {...@@ -183,8 +183,8 @@ describe("desktop app control server", () => {
183183
184 it.effect("binds its address again after the socket file is removed", () =>184 it.effect("binds its address again after the socket file is removed", () =>
185 Effect.gen(function* () {185 Effect.gen(function* () {
186 const platform = yield* HostProcessPlatform;186 const platform = yield* HostProcess.Platform;
187 const userId = yield* HostProcessUserId;187 const userId = yield* HostProcess.UserId;
188 if (platform === "win32") return;188 if (platform === "win32") return;
189 yield* Effect.promise(async () => {189 yield* Effect.promise(async () => {
190 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-reclaim-test-"));190 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 {...@@ -12,7 +12,7 @@ import {
12 type DesktopAppActivationResponse,12 type DesktopAppActivationResponse,
13} from "@t3tools/contracts";13} from "@t3tools/contracts";
14import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";14import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
15import { HostProcessUserId } from "@t3tools/shared/hostProcess";15import * as HostProcess from "@t3tools/shared/HostProcess";
16import * as Context from "effect/Context";16import * as Context from "effect/Context";
17import * as Effect from "effect/Effect";17import * as Effect from "effect/Effect";
18import * as Layer from "effect/Layer";18import * as Layer from "effect/Layer";
...@@ -315,7 +315,7 @@ export const make = Effect.gen(function* () {...@@ -315,7 +315,7 @@ export const make = Effect.gen(function* () {
315 const desktopWindow = yield* DesktopWindow.DesktopWindow;315 const desktopWindow = yield* DesktopWindow.DesktopWindow;
316 const electronWindow = yield* ElectronWindow.ElectronWindow;316 const electronWindow = yield* ElectronWindow.ElectronWindow;
317 const path = yield* Path.Path;317 const path = yield* Path.Path;
318 const userId = yield* HostProcessUserId;318 const userId = yield* HostProcess.UserId;
319 const runPromise = Effect.runPromiseWith(yield* Effect.context<never>());319 const runPromise = Effect.runPromiseWith(yield* Effect.context<never>());
320 const address = resolveDesktopAppControlAddress({320 const address = resolveDesktopAppControlAddress({
321 stateDir: path.resolve(desktopEnvironment.stateDir),321 stateDir: path.resolve(desktopEnvironment.stateDir),
apps/desktop/src/app/DesktopClerk.test.ts+2-2
...@@ -3,7 +3,7 @@ import * as NodeHttp from "node:http";...@@ -3,7 +3,7 @@ import * as NodeHttp from "node:http";
3import * as NodePath from "@effect/platform-node/NodePath";3import * as NodePath from "@effect/platform-node/NodePath";
4import { codexAuthHandoffUrl, readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff";4import { codexAuthHandoffUrl, readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff";
5import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts";5import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts";
6import { HostProcessArguments } from "@t3tools/shared/hostProcess";6import * as HostProcess from "@t3tools/shared/HostProcess";
7import { assert, describe, it } from "@effect/vitest";7import { assert, describe, it } from "@effect/vitest";
8import * as Cause from "effect/Cause";8import * as Cause from "effect/Cause";
9import * as Effect from "effect/Effect";9import * as Effect from "effect/Effect";
...@@ -375,7 +375,7 @@ it.effect.each(["startup", "open-url"] as const)(...@@ -375,7 +375,7 @@ it.effect.each(["startup", "open-url"] as const)(
375 assert.strictEqual(delivery?.returnUrl, request.returnUrl);375 assert.strictEqual(delivery?.returnUrl, request.returnUrl);
376 }).pipe(376 }).pipe(
377 Effect.provide(layerDesktopClerk(true, [], "darwin", undefined, shell)),377 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"]),
379 Effect.provideService(ElectronApp.ElectronApp, electronApp),379 Effect.provideService(ElectronApp.ElectronApp, electronApp),
380 Effect.provideService(380 Effect.provideService(
381 ElectronWindow.ElectronWindow,381 ElectronWindow.ElectronWindow,
apps/desktop/src/app/DesktopClerk.ts+2-2
...@@ -11,7 +11,7 @@ import { codexAuthDeliveryUrl, readCodexAuthHandoff } from "@t3tools/shared/code...@@ -11,7 +11,7 @@ import { codexAuthDeliveryUrl, readCodexAuthHandoff } from "@t3tools/shared/code
11import { receiveCodexAuthCallback, CodexAuthCallbackError } from "./CodexAuthCallback.ts";11import { receiveCodexAuthCallback, CodexAuthCallbackError } from "./CodexAuthCallback.ts";
12import * as ElectronShell from "../electron/ElectronShell.ts";12import * as ElectronShell from "../electron/ElectronShell.ts";
13import { providerAuthReturnUrl } from "@t3tools/shared/providerAuthReturnUrl";13import { providerAuthReturnUrl } from "@t3tools/shared/providerAuthReturnUrl";
14import { HostProcessArguments } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
15import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";15import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";
16import * as ElectronApp from "../electron/ElectronApp.ts";16import * as ElectronApp from "../electron/ElectronApp.ts";
17import * as ElectronProtocol from "../electron/ElectronProtocol.ts";17import * as ElectronProtocol from "../electron/ElectronProtocol.ts";
...@@ -182,7 +182,7 @@ export const make = Effect.gen(function* () {...@@ -182,7 +182,7 @@ export const make = Effect.gen(function* () {
182 );182 );
183 return true;183 return true;
184 };184 };
185 const args = yield* HostProcessArguments;185 const args = yield* HostProcess.Arguments;
186 args.some((value) => startProviderAuthHandoff(value));186 args.some((value) => startProviderAuthHandoff(value));
187 yield* electronApp.on("open-url", (event: { preventDefault: () => void }, url: string) => {187 yield* electronApp.on("open-url", (event: { preventDefault: () => void }, url: string) => {
188 if (startProviderAuthHandoff(url) || resumeProviderAuth(url)) event.preventDefault();188 if (startProviderAuthHandoff(url) || resumeProviderAuth(url)) event.preventDefault();
apps/desktop/src/app/DesktopPreReadyFileSystem.test.ts+2-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, it } from "@effect/vitest";2import { assert, it } from "@effect/vitest";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Exit from "effect/Exit";5import * as Exit from "effect/Exit";
6import * as FileSystem from "effect/FileSystem";6import * as FileSystem from "effect/FileSystem";
...@@ -32,7 +32,7 @@ it.layer(NodeServices.layer)("DesktopPreReadyFileSystem", (it) => {...@@ -32,7 +32,7 @@ it.layer(NodeServices.layer)("DesktopPreReadyFileSystem", (it) => {
32 }),32 }),
33 );33 );
3434
35 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32" || process.getuid?.() === 0)(35 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32" || process.getuid?.() === 0)(
36 "fails instead of treating an unreadable profile as missing",36 "fails instead of treating an unreadable profile as missing",
37 () =>37 () =>
38 Effect.gen(function* () {38 Effect.gen(function* () {
apps/desktop/src/app/DesktopPreReadyPlatform.test.ts+6-6
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { assert, describe, it } from "@effect/vitest";1import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Context from "effect/Context";3import * as Context from "effect/Context";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
...@@ -75,7 +75,7 @@ describe("DesktopPreReadyPlatform", () => {...@@ -75,7 +75,7 @@ describe("DesktopPreReadyPlatform", () => {
75 }).pipe(75 }).pipe(
76 Effect.provide(76 Effect.provide(
77 DesktopPreReadyPlatform.layer.pipe(77 DesktopPreReadyPlatform.layer.pipe(
78 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),78 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
79 ),79 ),
80 ),80 ),
81 );81 );
...@@ -111,7 +111,7 @@ describe("DesktopPreReadyPlatform", () => {...@@ -111,7 +111,7 @@ describe("DesktopPreReadyPlatform", () => {
111 }));111 }));
112 yield* Layer.build(112 yield* Layer.build(
113 DesktopPreReadyPlatform.layer.pipe(113 DesktopPreReadyPlatform.layer.pipe(
114 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),114 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
115 ),115 ),
116 );116 );
117 const identity = yield* Effect.promise(() => portalIdentity);117 const identity = yield* Effect.promise(() => portalIdentity);
...@@ -135,7 +135,7 @@ describe("DesktopPreReadyPlatform", () => {...@@ -135,7 +135,7 @@ describe("DesktopPreReadyPlatform", () => {
135 });135 });
136136
137 return DesktopPreReadyPlatform.make.pipe(137 return DesktopPreReadyPlatform.make.pipe(
138 Effect.provideService(HostProcessPlatform, "linux"),138 Effect.provideService(HostProcess.Platform, "linux"),
139 Effect.asVoid,139 Effect.asVoid,
140 );140 );
141 });141 });
...@@ -151,7 +151,7 @@ describe("DesktopPreReadyPlatform", () => {...@@ -151,7 +151,7 @@ describe("DesktopPreReadyPlatform", () => {
151 assert.include(contents, "MimeType=x-scheme-handler/t3code;");151 assert.include(contents, "MimeType=x-scheme-handler/t3code;");
152 assert.include(contents, "Icon=");152 assert.include(contents, "Icon=");
153 assert.equal(setDesktopNameMock.mock.calls.length, 1);153 assert.equal(setDesktopNameMock.mock.calls.length, 1);
154 }).pipe(Effect.provideService(HostProcessPlatform, "linux"));154 }).pipe(Effect.provideService(HostProcess.Platform, "linux"));
155 });155 });
156156
157 it.effect(157 it.effect(
...@@ -168,7 +168,7 @@ describe("DesktopPreReadyPlatform", () => {...@@ -168,7 +168,7 @@ describe("DesktopPreReadyPlatform", () => {
168 });168 });
169169
170 const layerPreReady = DesktopPreReadyPlatform.layer.pipe(170 const layerPreReady = DesktopPreReadyPlatform.layer.pipe(
171 Layer.provide(Layer.succeed(HostProcessPlatform, "darwin")),171 Layer.provide(Layer.succeed(HostProcess.Platform, "darwin")),
172 );172 );
173173
174 const layerClerkShaped = Layer.effect(174 const layerClerkShaped = Layer.effect(
apps/desktop/src/app/DesktopPreReadyPlatform.ts+3-3
...@@ -6,7 +6,7 @@ import * as Effect from "effect/Effect";...@@ -6,7 +6,7 @@ import * as Effect from "effect/Effect";
6import * as Layer from "effect/Layer";6import * as Layer from "effect/Layer";
77
8import * as Electron from "electron";8import * as Electron from "electron";
9import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";9import * as HostProcess from "@t3tools/shared/HostProcess";
1010
11import * as DesktopEarlyElectronStartup from "./DesktopEarlyElectronStartup.ts";11import * as DesktopEarlyElectronStartup from "./DesktopEarlyElectronStartup.ts";
12import { resolveDesktopAppBranding } from "./DesktopEnvironment.ts";12import { resolveDesktopAppBranding } from "./DesktopEnvironment.ts";
...@@ -50,8 +50,8 @@ export class DesktopPreReadyElectronOptions extends Context.Service<...@@ -50,8 +50,8 @@ export class DesktopPreReadyElectronOptions extends Context.Service<
5050
51/** @public Service construction is part of the canonical Effect module API. */51/** @public Service construction is part of the canonical Effect module API. */
52export const make = Effect.gen(function* () {52export const make = Effect.gen(function* () {
53 const platform = yield* HostProcessPlatform;53 const platform = yield* HostProcess.Platform;
54 const homeDirectory = yield* HostProcessHomeDirectory;54 const homeDirectory = yield* HostProcess.HomeDirectory;
55 return yield* Effect.sync((): DesktopPreReadyElectronOptions["Service"] => {55 return yield* Effect.sync((): DesktopPreReadyElectronOptions["Service"] => {
56 const linuxPasswordStoreCommandLine =56 const linuxPasswordStoreCommandLine =
57 platform === "linux"57 platform === "linux"
apps/desktop/src/backend/DesktopNetworkInterfaces.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { assert, describe, it } from "@effect/vitest";1import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Cause from "effect/Cause";3import * as Cause from "effect/Cause";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
...@@ -16,7 +16,7 @@ vi.mock("node:os", () => ({...@@ -16,7 +16,7 @@ vi.mock("node:os", () => ({
16import * as DesktopNetworkInterfaces from "./DesktopNetworkInterfaces.ts";16import * as DesktopNetworkInterfaces from "./DesktopNetworkInterfaces.ts";
1717
18const layerTest = DesktopNetworkInterfaces.layer.pipe(18const layerTest = DesktopNetworkInterfaces.layer.pipe(
19 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),19 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
20);20);
2121
22describe("DesktopNetworkInterfaces", () => {22describe("DesktopNetworkInterfaces", () => {
apps/desktop/src/backend/DesktopNetworkInterfaces.ts+2-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeOS from "node:os";1import * as NodeOS from "node:os";
22
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Context from "effect/Context";4import * as Context from "effect/Context";
5import * as Effect from "effect/Effect";5import * as Effect from "effect/Effect";
6import * as Layer from "effect/Layer";6import * as Layer from "effect/Layer";
...@@ -41,7 +41,7 @@ export class DesktopNetworkInterfaces extends Context.Service<...@@ -41,7 +41,7 @@ export class DesktopNetworkInterfaces extends Context.Service<
4141
42/** @public Service construction is part of the canonical Effect module API. */42/** @public Service construction is part of the canonical Effect module API. */
43export const make = Effect.gen(function* () {43export const make = Effect.gen(function* () {
44 const platform = yield* HostProcessPlatform;44 const platform = yield* HostProcess.Platform;
45 return DesktopNetworkInterfaces.of({45 return DesktopNetworkInterfaces.of({
46 read: Effect.try({46 read: Effect.try({
47 try: () => NodeOS.networkInterfaces(),47 try: () => NodeOS.networkInterfaces(),
apps/desktop/src/electron/ElectronMenu.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { assert, describe, it } from "@effect/vitest";1import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Cause from "effect/Cause";3import * as Cause from "effect/Cause";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
...@@ -28,7 +28,7 @@ vi.mock("electron", () => ({...@@ -28,7 +28,7 @@ vi.mock("electron", () => ({
28import * as ElectronMenu from "./ElectronMenu.ts";28import * as ElectronMenu from "./ElectronMenu.ts";
2929
30const layerTest = ElectronMenu.layer.pipe(30const layerTest = ElectronMenu.layer.pipe(
31 Layer.provide(Layer.succeed(HostProcessPlatform, "linux")),31 Layer.provide(Layer.succeed(HostProcess.Platform, "linux")),
32);32);
3333
34const makeWindow = (zoomFactor = 1): Electron.BrowserWindow =>34const makeWindow = (zoomFactor = 1): Electron.BrowserWindow =>
apps/desktop/src/electron/ElectronMenu.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import type { ContextMenuItem } from "@t3tools/contracts";1import type { ContextMenuItem } from "@t3tools/contracts";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Context from "effect/Context";3import * as Context from "effect/Context";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
...@@ -114,7 +114,7 @@ const normalizePosition = (...@@ -114,7 +114,7 @@ const normalizePosition = (
114114
115/** @public Service construction is part of the canonical Effect module API. */115/** @public Service construction is part of the canonical Effect module API. */
116export const make = Effect.gen(function* () {116export const make = Effect.gen(function* () {
117 const platform = yield* HostProcessPlatform;117 const platform = yield* HostProcess.Platform;
118 let destructiveMenuIconCache: Option.Option<Electron.NativeImage> | undefined;118 let destructiveMenuIconCache: Option.Option<Electron.NativeImage> | undefined;
119119
120 const getDestructiveMenuIcon = (): Option.Option<Electron.NativeImage> => {120 const getDestructiveMenuIcon = (): Option.Option<Electron.NativeImage> => {
apps/desktop/src/electron/ElectronSafeStorage.ts+2-2
...@@ -5,7 +5,7 @@ import * as Option from "effect/Option";...@@ -5,7 +5,7 @@ import * as Option from "effect/Option";
5import * as Schema from "effect/Schema";5import * as Schema from "effect/Schema";
66
7import * as Electron from "electron";7import * as Electron from "electron";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
99
10const electronSafeStorageErrorFields = {10const electronSafeStorageErrorFields = {
11 cause: Schema.Defect(),11 cause: Schema.Defect(),
...@@ -67,7 +67,7 @@ export class ElectronSafeStorage extends Context.Service<...@@ -67,7 +67,7 @@ export class ElectronSafeStorage extends Context.Service<
6767
68/** @public Service construction is part of the canonical Effect module API. */68/** @public Service construction is part of the canonical Effect module API. */
69export const make = Effect.gen(function* () {69export const make = Effect.gen(function* () {
70 const platform = yield* HostProcessPlatform;70 const platform = yield* HostProcess.Platform;
7171
72 return ElectronSafeStorage.of({72 return ElectronSafeStorage.of({
73 isEncryptionAvailable: Effect.try({73 isEncryptionAvailable: Effect.try({
apps/desktop/src/electron/ElectronWindow.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { assert, describe, it } from "@effect/vitest";1import { assert, describe, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Cause from "effect/Cause";3import * as Cause from "effect/Cause";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Fiber from "effect/Fiber";5import * as Fiber from "effect/Fiber";
...@@ -58,7 +58,7 @@ vi.mock("electron", () => ({...@@ -58,7 +58,7 @@ vi.mock("electron", () => ({
58import * as ElectronWindow from "./ElectronWindow.ts";58import * as ElectronWindow from "./ElectronWindow.ts";
5959
60const layerTestFor = (platform: NodeJS.Platform) =>60const 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
63const layerTest = layerTestFor("linux");63const layerTest = layerTestFor("linux");
6464
apps/desktop/src/electron/ElectronWindow.ts+2-2
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
22
3import * as NodePath from "node:path";3import * as NodePath from "node:path";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
6import type * as Cause from "effect/Cause";6import type * as Cause from "effect/Cause";
7import * as Context from "effect/Context";7import * as Context from "effect/Context";
8import * as Effect from "effect/Effect";8import * as Effect from "effect/Effect";
...@@ -129,7 +129,7 @@ export class ElectronWindow extends Context.Service<...@@ -129,7 +129,7 @@ export class ElectronWindow extends Context.Service<
129129
130/** @public Service construction is part of the canonical Effect module API. */130/** @public Service construction is part of the canonical Effect module API. */
131export const make = Effect.gen(function* () {131export const make = Effect.gen(function* () {
132 const platform = yield* HostProcessPlatform;132 const platform = yield* HostProcess.Platform;
133 // The focus worker loads a native accessibility module. Start it on the first133 // The focus worker loads a native accessibility module. Start it on the first
134 // capture reveal so users who never capture pay nothing at launch.134 // capture reveal so users who never capture pay nothing at launch.
135 let windowsForegroundFocus: ReturnType<typeof startWindowsForegroundFocusThread> | undefined;135 let windowsForegroundFocus: ReturnType<typeof startWindowsForegroundFocusThread> | undefined;
apps/desktop/src/ipc/methods/notificationBadge.test.ts+2-2
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1import * as Effect from "effect/Effect";1import * as Effect from "effect/Effect";
2import { beforeEach, expect, vi } from "vite-plus/test";2import { beforeEach, expect, vi } from "vite-plus/test";
3import { it } from "@effect/vitest";3import { it } from "@effect/vitest";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
55
6const native = vi.hoisted(() => ({6const native = vi.hoisted(() => ({
7 setBadgeCount: vi.fn(),7 setBadgeCount: vi.fn(),
...@@ -122,7 +122,7 @@ it.effect("validates IPC and clears on native focus, quit, and disposal", () =>...@@ -122,7 +122,7 @@ it.effect("validates IPC and clears on native focus, quit, and disposal", () =>
122 expect(native.setBadgeCount).toHaveBeenLastCalledWith(0);122 expect(native.setBadgeCount).toHaveBeenLastCalledWith(0);
123 }),123 }),
124 ).pipe(124 ).pipe(
125 Effect.provideService(HostProcessPlatform, "linux"),125 Effect.provideService(HostProcess.Platform, "linux"),
126 Effect.provide([126 Effect.provide([
127 ElectronApp.layer,127 ElectronApp.layer,
128 DesktopIpc.layer({128 DesktopIpc.layer({
apps/desktop/src/ipc/methods/notificationBadge.ts+2-2
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1import * as Electron from "electron";1import * as Electron from "electron";
2import * as Effect from "effect/Effect";2import * as Effect from "effect/Effect";
3import * as Schema from "effect/Schema";3import * as Schema from "effect/Schema";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
55
6import * as ElectronApp from "../../electron/ElectronApp.ts";6import * as ElectronApp from "../../electron/ElectronApp.ts";
7import * as DesktopIpc from "../DesktopIpc.ts";7import * as DesktopIpc from "../DesktopIpc.ts";
...@@ -45,7 +45,7 @@ export const installNotificationBadge = Effect.fn("desktop.ipc.installNotificati...@@ -45,7 +45,7 @@ export const installNotificationBadge = Effect.fn("desktop.ipc.installNotificati
45 function* () {45 function* () {
46 const ipc = yield* DesktopIpc.DesktopIpc;46 const ipc = yield* DesktopIpc.DesktopIpc;
47 const app = yield* ElectronApp.ElectronApp;47 const app = yield* ElectronApp.ElectronApp;
48 const platform = yield* HostProcessPlatform;48 const platform = yield* HostProcess.Platform;
49 const clear = () => {49 const clear = () => {
50 applyNotificationBadge(platform, { count: 0, image: null });50 applyNotificationBadge(platform, { count: 0, image: null });
51 for (const window of Electron.BrowserWindow.getAllWindows()) {51 for (const window of Electron.BrowserWindow.getAllWindows()) {
apps/desktop/src/ipc/methods/window.test.ts+4-4
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import { assert, describe, it } from "@effect/vitest";1import { assert, describe, it } from "@effect/vitest";
2import * as NodeServices from "@effect/platform-node/NodeServices";2import * as NodeServices from "@effect/platform-node/NodeServices";
3import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as FileSystem from "effect/FileSystem";4import * as FileSystem from "effect/FileSystem";
5import * as Path from "effect/Path";5import * as Path from "effect/Path";
6import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
...@@ -314,7 +314,7 @@ describe("pickProjectFavicon", () => {...@@ -314,7 +314,7 @@ describe("pickProjectFavicon", () => {
314 );314 );
315});315});
316316
317it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(317it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
318 "finds remote editors installed without PATH launchers",318 "finds remote editors installed without PATH launchers",
319 () =>319 () =>
320 Effect.gen(function* () {320 Effect.gen(function* () {
...@@ -333,11 +333,11 @@ it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(...@@ -333,11 +333,11 @@ it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(
333 yield* fs.chmod(executable, 0o755);333 yield* fs.chmod(executable, 0o755);
334 }334 }
335 const editors = yield* probeRemoteEditors.handler(undefined).pipe(335 const editors = yield* probeRemoteEditors.handler(undefined).pipe(
336 Effect.provideService(HostProcessEnvironment, {336 Effect.provideService(HostProcess.Environment, {
337 HOME: home,337 HOME: home,
338 PATH: path.join(home, "empty"),338 PATH: path.join(home, "empty"),
339 }),339 }),
340 Effect.provideService(HostProcessPlatform, "darwin"),340 Effect.provideService(HostProcess.Platform, "darwin"),
341 );341 );
342 assert.include(editors, "cursor");342 assert.include(editors, "cursor");
343 assert.include(editors, "vscode");343 assert.include(editors, "vscode");
apps/desktop/src/ipc/methods/window.ts+3-4
...@@ -15,7 +15,7 @@ import {...@@ -15,7 +15,7 @@ import {
15} from "@t3tools/contracts";15} from "@t3tools/contracts";
16import { WORKSPACE_IMAGE_PREVIEW_EXTENSIONS } from "@t3tools/shared/filePreview";16import { WORKSPACE_IMAGE_PREVIEW_EXTENSIONS } from "@t3tools/shared/filePreview";
17import { resolveEditorCommand } from "@t3tools/shared/editor";17import { resolveEditorCommand } from "@t3tools/shared/editor";
18import * as HostProcess from "@t3tools/shared/hostProcess";18import * as HostProcess from "@t3tools/shared/HostProcess";
19import * as FileSystem from "effect/FileSystem";19import * as FileSystem from "effect/FileSystem";
20import * as Path from "effect/Path";20import * as Path from "effect/Path";
21import * as Effect from "effect/Effect";21import * as Effect from "effect/Effect";
...@@ -45,7 +45,6 @@ import {...@@ -45,7 +45,6 @@ import {
45 resolveWslPickFolderDefaultPath,45 resolveWslPickFolderDefaultPath,
46 wslUncPathToLinuxPath,46 wslUncPathToLinuxPath,
47} from "../../wsl/wslPathParsing.ts";47} from "../../wsl/wslPathParsing.ts";
48import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";
4948
50const ContextMenuPosition = Schema.Struct({49const ContextMenuPosition = Schema.Struct({
51 x: Schema.Number,50 x: Schema.Number,
...@@ -345,7 +344,7 @@ export const probeRemoteEditors = DesktopIpc.makeIpcMethod({...@@ -345,7 +344,7 @@ export const probeRemoteEditors = DesktopIpc.makeIpcMethod({
345 result: Schema.Array(EditorId),344 result: Schema.Array(EditorId),
346 handler: Effect.fn("desktop.ipc.window.probeRemoteEditors")(function* () {345 handler: Effect.fn("desktop.ipc.window.probeRemoteEditors")(function* () {
347 const available: Array<EditorId> = [];346 const available: Array<EditorId> = [];
348 const env = yield* HostProcess.HostProcessEnvironment;347 const env = yield* HostProcess.Environment;
349 for (const editorId of REMOTE_CAPABLE_EDITOR_IDS) {348 for (const editorId of REMOTE_CAPABLE_EDITOR_IDS) {
350 const editor = EDITORS.find((editor) => editor.id === editorId);349 const editor = EDITORS.find((editor) => editor.id === editorId);
351 if (editor && Option.isSome(yield* resolveEditorCommand(editor, env))) {350 if (editor && Option.isSome(yield* resolveEditorCommand(editor, env))) {
...@@ -398,7 +397,7 @@ export const pickThemeFiles = DesktopIpc.makeIpcMethod({...@@ -398,7 +397,7 @@ export const pickThemeFiles = DesktopIpc.makeIpcMethod({
398 // The VS Code extensions directory is the same dotfolder on Windows,397 // The VS Code extensions directory is the same dotfolder on Windows,
399 // macOS, and Linux; when it is missing the picker opens wherever the398 // macOS, and Linux; when it is missing the picker opens wherever the
400 // platform would by default.399 // platform would by default.
401 const extensionsDir = path.join(yield* HostProcessHomeDirectory, ".vscode", "extensions");400 const extensionsDir = path.join(yield* HostProcess.HomeDirectory, ".vscode", "extensions");
402 const defaultPath = yield* fileSystem401 const defaultPath = yield* fileSystem
403 .exists(extensionsDir)402 .exists(extensionsDir)
404 .pipe(Effect.orElseSucceed(() => false));403 .pipe(Effect.orElseSucceed(() => false));
apps/desktop/src/main.ts+3-3
...@@ -18,7 +18,7 @@ import * as Option from "effect/Option";...@@ -18,7 +18,7 @@ import * as Option from "effect/Option";
18import * as Electron from "electron";18import * as Electron from "electron";
1919
20import * as NetService from "@t3tools/shared/Net";20import * as NetService from "@t3tools/shared/Net";
21import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";21import * as HostProcess from "@t3tools/shared/HostProcess";
22import type { RemoteT3RunnerOptions } from "@t3tools/ssh/tunnel";22import type { RemoteT3RunnerOptions } from "@t3tools/ssh/tunnel";
23import serverPackageJson from "../../server/package.json" with { type: "json" };23import serverPackageJson from "../../server/package.json" with { type: "json" };
2424
...@@ -90,8 +90,8 @@ const layerDesktopEnvironment = Layer.unwrap(...@@ -90,8 +90,8 @@ const layerDesktopEnvironment = Layer.unwrap(
90 const metadata = yield* Effect.service(ElectronApp.ElectronApp).pipe(90 const metadata = yield* Effect.service(ElectronApp.ElectronApp).pipe(
91 Effect.flatMap((app) => app.metadata),91 Effect.flatMap((app) => app.metadata),
92 );92 );
93 const platform = yield* HostProcessPlatform;93 const platform = yield* HostProcess.Platform;
94 const processArch = yield* HostProcessArchitecture;94 const processArch = yield* HostProcess.Architecture;
95 return DesktopEnvironment.layer({95 return DesktopEnvironment.layer({
96 dirname: __dirname,96 dirname: __dirname,
97 homeDirectory: NodeOS.homedir(),97 homeDirectory: NodeOS.homedir(),
apps/desktop/src/preview/BrowserImport/BrowserImport.test.ts+6-10
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, describe, it } from "@effect/vitest";2import { assert, describe, it } from "@effect/vitest";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessEnvironment,
5 HostProcessExecutablePath,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
8import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
9import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
10import * as Fiber from "effect/Fiber";6import * as Fiber from "effect/Fiber";
...@@ -52,10 +48,10 @@ const layerRejectedBeforeSession = Layer.succeed(...@@ -52,10 +48,10 @@ const layerRejectedBeforeSession = Layer.succeed(
52const withImporter = Effect.fnUntraced(function* () {48const withImporter = Effect.fnUntraced(function* () {
53 const fileSystem = yield* FileSystem.FileSystem;49 const fileSystem = yield* FileSystem.FileSystem;
54 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-import-" });50 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 });
56 const context = yield* sourcePathContext.pipe(52 const context = yield* sourcePathContext.pipe(
57 Effect.provideService(HostProcessEnvironment, { HOME: home }),53 Effect.provideService(HostProcess.Environment, { HOME: home }),
58 Effect.provideService(HostProcessPlatform, "darwin"),54 Effect.provideService(HostProcess.Platform, "darwin"),
59 );55 );
60 const root = helium.userDataDirectory(context);56 const root = helium.userDataDirectory(context);
61 if (root === undefined) throw new Error("Helium has no macOS user-data directory");57 if (root === undefined) throw new Error("Helium has no macOS user-data directory");
...@@ -69,8 +65,8 @@ const withImporter = Effect.fnUntraced(function* () {...@@ -69,8 +65,8 @@ const withImporter = Effect.fnUntraced(function* () {
69 BrowserImport.layer.pipe(65 BrowserImport.layer.pipe(
70 Layer.provide(layerRejectedBeforeSession),66 Layer.provide(layerRejectedBeforeSession),
71 Layer.provide(layerEnvironment),67 Layer.provide(layerEnvironment),
72 Layer.provide(Layer.succeed(HostProcessPlatform, "darwin")),68 Layer.provide(Layer.succeed(HostProcess.Platform, "darwin")),
73 Layer.provide(Layer.succeed(HostProcessExecutablePath, "/Applications/T3 Code.app")),69 Layer.provide(Layer.succeed(HostProcess.ExecutablePath, "/Applications/T3 Code.app")),
74 Layer.provide(NodeServices.layer),70 Layer.provide(NodeServices.layer),
75 ),71 ),
76 ),72 ),
apps/desktop/src/preview/BrowserImport/BrowserImport.ts+3-3
...@@ -21,7 +21,7 @@ import * as Schema from "effect/Schema";...@@ -21,7 +21,7 @@ import * as Schema from "effect/Schema";
21import * as Scope from "effect/Scope";21import * as Scope from "effect/Scope";
22import { ChildProcessSpawner } from "effect/process";22import { ChildProcessSpawner } from "effect/process";
2323
24import { HostProcessExecutablePath, HostProcessPlatform } from "@t3tools/shared/hostProcess";24import * as HostProcess from "@t3tools/shared/HostProcess";
2525
26import * as BrowserSession from "../BrowserSession.ts";26import * as BrowserSession from "../BrowserSession.ts";
27import { ChromiumCookieReadError, readChromiumCookies } from "./ChromiumCookies.ts";27import { ChromiumCookieReadError, readChromiumCookies } from "./ChromiumCookies.ts";
...@@ -169,8 +169,8 @@ export const writeCookies = Effect.fn("BrowserImport.writeCookies")(function* (...@@ -169,8 +169,8 @@ export const writeCookies = Effect.fn("BrowserImport.writeCookies")(function* (
169/** @public Service construction is part of the canonical Effect module API. */169/** @public Service construction is part of the canonical Effect module API. */
170export const make = Effect.gen(function* BrowserImportMake() {170export const make = Effect.gen(function* BrowserImportMake() {
171 const browserSession = yield* BrowserSession.BrowserSession;171 const browserSession = yield* BrowserSession.BrowserSession;
172 const platform = yield* HostProcessPlatform;172 const platform = yield* HostProcess.Platform;
173 const executablePath = yield* HostProcessExecutablePath;173 const executablePath = yield* HostProcess.ExecutablePath;
174 // Captured here so the service's methods stay free of a requirements174 // Captured here so the service's methods stay free of a requirements
175 // channel: the layer is built where NodeServices is already in scope.175 // channel: the layer is built where NodeServices is already in scope.
176 const platformServices = yield* Effect.context<176 const platformServices = yield* Effect.context<
apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts+1-1
...@@ -315,7 +315,7 @@ export interface ChromiumCookieSource {...@@ -315,7 +315,7 @@ export interface ChromiumCookieSource {
315 readonly keychainAccount: string | undefined;315 readonly keychainAccount: string | undefined;
316 readonly linuxSecretApplication: string | undefined;316 readonly linuxSecretApplication: string | undefined;
317 readonly windowsLocalStatePath?: string;317 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. */
319 readonly platform: NodeJS.Platform;319 readonly platform: NodeJS.Platform;
320}320}
321321
apps/desktop/src/preview/BrowserImport/ChromiumKeys.test.ts+3-3
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { describe, expect, it } from "@effect/vitest";1import { describe, expect, it } from "@effect/vitest";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Deferred from "effect/Deferred";3import * as Deferred from "effect/Deferred";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
...@@ -232,7 +232,7 @@ describe("Linux Chromium secrets", () => {...@@ -232,7 +232,7 @@ describe("Linux Chromium secrets", () => {
232 capture: (value) => (captured = value),232 capture: (value) => (captured = value),
233 }),233 }),
234 ),234 ),
235 Effect.provideService(HostProcessEnvironment, {235 Effect.provideService(HostProcess.Environment, {
236 PATH: "/synthetic/bin",236 PATH: "/synthetic/bin",
237 SESSION_MARKER: "kept",237 SESSION_MARKER: "kept",
238 LC_ALL: "localized",238 LC_ALL: "localized",
...@@ -322,7 +322,7 @@ describe("Windows Chromium secrets", () => {...@@ -322,7 +322,7 @@ describe("Windows Chromium secrets", () => {
322 Effect.provide(322 Effect.provide(
323 layerHelper({ stdout: key.toString("base64"), capture: (value) => (captured = value) }),323 layerHelper({ stdout: key.toString("base64"), capture: (value) => (captured = value) }),
324 ),324 ),
325 Effect.provideService(HostProcessEnvironment, { SystemRoot: "C:\\Windows" }),325 Effect.provideService(HostProcess.Environment, { SystemRoot: "C:\\Windows" }),
326 );326 );
327 });327 });
328});328});
apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts+3-3
...@@ -19,7 +19,7 @@...@@ -19,7 +19,7 @@
19 */19 */
20import * as NodeCrypto from "node:crypto";20import * as NodeCrypto from "node:crypto";
2121
22import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";22import * as HostProcess from "@t3tools/shared/HostProcess";
2323
24import * as Effect from "effect/Effect";24import * as Effect from "effect/Effect";
25import * as Base64 from "effect/encoding/Base64";25import * as Base64 from "effect/encoding/Base64";
...@@ -138,7 +138,7 @@ export const readLinuxSecret = Effect.fn("ChromiumKeys.readLinuxSecret")(functio...@@ -138,7 +138,7 @@ export const readLinuxSecret = Effect.fn("ChromiumKeys.readLinuxSecret")(functio
138 return yield* Effect.scoped(138 return yield* Effect.scoped(
139 Effect.gen(function* () {139 Effect.gen(function* () {
140 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;140 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
141 const environment = yield* HostProcessEnvironment;141 const environment = yield* HostProcess.Environment;
142 const helper = yield* LinuxBrowserSecretPath;142 const helper = yield* LinuxBrowserSecretPath;
143 if (helper === undefined) {143 if (helper === undefined) {
144 return yield* new ChromiumKeyError({ reason: "keychainUnavailable" });144 return yield* new ChromiumKeyError({ reason: "keychainUnavailable" });
...@@ -219,7 +219,7 @@ export const decodeWindowsWrappedKey = Effect.fn("ChromiumKeys.decodeWindowsWrap...@@ -219,7 +219,7 @@ export const decodeWindowsWrappedKey = Effect.fn("ChromiumKeys.decodeWindowsWrap
219export const unwrapWindowsDpapiKey = Effect.fn("ChromiumKeys.unwrapWindowsDpapiKey")(function* (219export const unwrapWindowsDpapiKey = Effect.fn("ChromiumKeys.unwrapWindowsDpapiKey")(function* (
220 wrapped: Buffer,220 wrapped: Buffer,
221) {221) {
222 const environment = yield* HostProcessEnvironment;222 const environment = yield* HostProcess.Environment;
223 return yield* Effect.scoped(223 return yield* Effect.scoped(
224 Effect.gen(function* () {224 Effect.gen(function* () {
225 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;225 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
apps/desktop/src/preview/BrowserImport/SafariPermission.test.ts+5-5
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, it } from "@effect/vitest";2import { assert, it } from "@effect/vitest";
3import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
6import * as PlatformError from "effect/PlatformError";6import * as PlatformError from "effect/PlatformError";
...@@ -30,8 +30,8 @@ it.effect("detects Safari access becoming available without reading or importing...@@ -30,8 +30,8 @@ it.effect("detects Safari access becoming available without reading or importing
30 ),30 ),
31 });31 });
32 const check = yield* safariPermissionCheck.pipe(32 const check = yield* safariPermissionCheck.pipe(
33 Effect.provideService(HostProcessEnvironment, { HOME: home }),33 Effect.provideService(HostProcess.Environment, { HOME: home }),
34 Effect.provideService(HostProcessPlatform, "darwin"),34 Effect.provideService(HostProcess.Platform, "darwin"),
35 Effect.provideService(FileSystem.FileSystem, guardedFs),35 Effect.provideService(FileSystem.FileSystem, guardedFs),
36 );36 );
37 assert.isFalse(yield* Effect.promise(check));37 assert.isFalse(yield* Effect.promise(check));
...@@ -47,8 +47,8 @@ it.effect("recognizes access when cookies exist only in a named Safari profile",...@@ -47,8 +47,8 @@ it.effect("recognizes access when cookies exist only in a named Safari profile",
47 const fs = yield* FileSystem.FileSystem;47 const fs = yield* FileSystem.FileSystem;
48 const home = yield* fs.makeTempDirectoryScoped({ prefix: "t3-safari-named-access-" });48 const home = yield* fs.makeTempDirectoryScoped({ prefix: "t3-safari-named-access-" });
49 const check = yield* safariPermissionCheck.pipe(49 const check = yield* safariPermissionCheck.pipe(
50 Effect.provideService(HostProcessEnvironment, { HOME: home }),50 Effect.provideService(HostProcess.Environment, { HOME: home }),
51 Effect.provideService(HostProcessPlatform, "darwin"),51 Effect.provideService(HostProcess.Platform, "darwin"),
52 );52 );
53 assert.isFalse(yield* Effect.promise(check));53 assert.isFalse(yield* Effect.promise(check));
54 const directory = `${home}/Library/Containers/com.apple.Safari/Data/Library/WebKit/WebsiteDataStore/12345678-1234-1234-1234-123456789abc/Cookies`;54 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 @@...@@ -3,11 +3,7 @@
3import * as NodePath from "node:path";3import * as NodePath from "node:path";
4import * as NodeServices from "@effect/platform-node/NodeServices";4import * as NodeServices from "@effect/platform-node/NodeServices";
5import { assert, describe, it } from "@effect/vitest";5import { assert, describe, it } from "@effect/vitest";
6import {6import * as HostProcess from "@t3tools/shared/HostProcess";
7 HostProcessEnvironment,
8 HostProcessHostname,
9 HostProcessPlatform,
10} from "@t3tools/shared/hostProcess";
11import * as Effect from "effect/Effect";7import * as Effect from "effect/Effect";
12import * as FileSystem from "effect/FileSystem";8import * as FileSystem from "effect/FileSystem";
13import * as Path from "effect/Path";9import * as Path from "effect/Path";
...@@ -80,8 +76,8 @@ const withSourceHome = Effect.fnUntraced(function* () {...@@ -80,8 +76,8 @@ const withSourceHome = Effect.fnUntraced(function* () {
80 const fileSystem = yield* FileSystem.FileSystem;76 const fileSystem = yield* FileSystem.FileSystem;
81 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-sources-" });77 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-sources-" });
82 const context = yield* sourcePathContext.pipe(78 const context = yield* sourcePathContext.pipe(
83 Effect.provideService(HostProcessEnvironment, { HOME: home }),79 Effect.provideService(HostProcess.Environment, { HOME: home }),
84 Effect.provideService(HostProcessPlatform, "darwin"),80 Effect.provideService(HostProcess.Platform, "darwin"),
85 );81 );
86 yield* fileSystem.makeDirectory(userDataDirectory(context), { recursive: true });82 yield* fileSystem.makeDirectory(userDataDirectory(context), { recursive: true });
87 return context;83 return context;
...@@ -133,8 +129,8 @@ describe("Helium on Linux", () => {...@@ -133,8 +129,8 @@ describe("Helium on Linux", () => {
133 const fileSystem = yield* FileSystem.FileSystem;129 const fileSystem = yield* FileSystem.FileSystem;
134 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-helium-linux-" });130 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-helium-linux-" });
135 const context = yield* sourcePathContext.pipe(131 const context = yield* sourcePathContext.pipe(
136 Effect.provideService(HostProcessEnvironment, { HOME: home }),132 Effect.provideService(HostProcess.Environment, { HOME: home }),
137 Effect.provideService(HostProcessPlatform, "linux"),133 Effect.provideService(HostProcess.Platform, "linux"),
138 );134 );
139 const root = `${home}/.config/net.imput.helium`;135 const root = `${home}/.config/net.imput.helium`;
140 yield* fileSystem.makeDirectory(`${root}/Default`, { recursive: true });136 yield* fileSystem.makeDirectory(`${root}/Default`, { recursive: true });
...@@ -162,11 +158,11 @@ describe("Helium on Windows", () => {...@@ -162,11 +158,11 @@ describe("Helium on Windows", () => {
162 run(158 run(
163 Effect.gen(function* () {159 Effect.gen(function* () {
164 const context = yield* sourcePathContext.pipe(160 const context = yield* sourcePathContext.pipe(
165 Effect.provideService(HostProcessEnvironment, {161 Effect.provideService(HostProcess.Environment, {
166 USERPROFILE: "C:\\Users\\browser-user",162 USERPROFILE: "C:\\Users\\browser-user",
167 LOCALAPPDATA: "C:\\Users\\browser-user\\AppData\\Local",163 LOCALAPPDATA: "C:\\Users\\browser-user\\AppData\\Local",
168 }),164 }),
169 Effect.provideService(HostProcessPlatform, "win32"),165 Effect.provideService(HostProcess.Platform, "win32"),
170 );166 );
171167
172 assert.include(helium.platforms, "win32");168 assert.include(helium.platforms, "win32");
...@@ -198,11 +194,11 @@ describe("isSourceRunning", () => {...@@ -198,11 +194,11 @@ describe("isSourceRunning", () => {
198 prefix: "t3code-helium-windows-lock-",194 prefix: "t3code-helium-windows-lock-",
199 });195 });
200 const context = yield* sourcePathContext.pipe(196 const context = yield* sourcePathContext.pipe(
201 Effect.provideService(HostProcessEnvironment, {197 Effect.provideService(HostProcess.Environment, {
202 HOME: home,198 HOME: home,
203 LOCALAPPDATA: home,199 LOCALAPPDATA: home,
204 }),200 }),
205 Effect.provideService(HostProcessPlatform, "win32"),201 Effect.provideService(HostProcess.Platform, "win32"),
206 );202 );
207 const profile = context.path.join(helium.userDataDirectory(context)!, "Default");203 const profile = context.path.join(helium.userDataDirectory(context)!, "Default");
208 const database = context.path.join(profile, "Network", "Cookies");204 const database = context.path.join(profile, "Network", "Cookies");
...@@ -259,12 +255,12 @@ describe("isSourceRunning", () => {...@@ -259,12 +255,12 @@ describe("isSourceRunning", () => {
259255
260 assert.isTrue(256 assert.isTrue(
261 yield* isSourceRunning(helium, paths).pipe(257 yield* isSourceRunning(helium, paths).pipe(
262 Effect.provideService(HostProcessHostname, "another-host"),258 Effect.provideService(HostProcess.Hostname, "another-host"),
263 ),259 ),
264 );260 );
265 assert.isFalse(261 assert.isFalse(
266 yield* isSourceRunning(helium, paths).pipe(262 yield* isSourceRunning(helium, paths).pipe(
267 Effect.provideService(HostProcessHostname, "lock-owner"),263 Effect.provideService(HostProcess.Hostname, "lock-owner"),
268 ),264 ),
269 );265 );
270 }),266 }),
...@@ -656,8 +652,8 @@ describe("cookieDatabaseCandidatePaths", () => {...@@ -656,8 +652,8 @@ describe("cookieDatabaseCandidatePaths", () => {
656 Effect.gen(function* () {652 Effect.gen(function* () {
657 const path = yield* Path.Path;653 const path = yield* Path.Path;
658 const context = yield* sourcePathContext.pipe(654 const context = yield* sourcePathContext.pipe(
659 Effect.provideService(HostProcessEnvironment, { HOME: "/tmp/test" }),655 Effect.provideService(HostProcess.Environment, { HOME: "/tmp/test" }),
660 Effect.provideService(HostProcessPlatform, "darwin"),656 Effect.provideService(HostProcess.Platform, "darwin"),
661 );657 );
662 const candidates = cookieDatabaseCandidatePaths(firefox, context, "Profiles/abc.default");658 const candidates = cookieDatabaseCandidatePaths(firefox, context, "Profiles/abc.default");
663 assert.deepEqual(candidates, [659 assert.deepEqual(candidates, [
...@@ -684,8 +680,8 @@ describe("Firefox Snap profiles", () => {...@@ -684,8 +680,8 @@ describe("Firefox Snap profiles", () => {
684 prefix: "t3code-firefox-snap-",680 prefix: "t3code-firefox-snap-",
685 });681 });
686 const context = yield* sourcePathContext.pipe(682 const context = yield* sourcePathContext.pipe(
687 Effect.provideService(HostProcessEnvironment, { HOME: home }),683 Effect.provideService(HostProcess.Environment, { HOME: home }),
688 Effect.provideService(HostProcessPlatform, "linux"),684 Effect.provideService(HostProcess.Platform, "linux"),
689 );685 );
690 const root = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox");686 const root = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox");
691 const directory = context.path.join(root, "abcd.default");687 const directory = context.path.join(root, "abcd.default");
...@@ -724,8 +720,8 @@ describe("Firefox Snap profiles", () => {...@@ -724,8 +720,8 @@ describe("Firefox Snap profiles", () => {
724 const fileSystem = yield* FileSystem.FileSystem;720 const fileSystem = yield* FileSystem.FileSystem;
725 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-snap-" });721 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-snap-" });
726 const context = yield* sourcePathContext.pipe(722 const context = yield* sourcePathContext.pipe(
727 Effect.provideService(HostProcessEnvironment, { HOME: home }),723 Effect.provideService(HostProcess.Environment, { HOME: home }),
728 Effect.provideService(HostProcessPlatform, "linux"),724 Effect.provideService(HostProcess.Platform, "linux"),
729 );725 );
730 const native = context.path.join(home, ".mozilla", "firefox");726 const native = context.path.join(home, ".mozilla", "firefox");
731 const snap = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox");727 const snap = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox");
...@@ -775,11 +771,11 @@ describe("listSourceProfiles Firefox fallback", () => {...@@ -775,11 +771,11 @@ describe("listSourceProfiles Firefox fallback", () => {
775 });771 });
776 const appData = path.join(home, "AppData", "Roaming");772 const appData = path.join(home, "AppData", "Roaming");
777 const context = yield* sourcePathContext.pipe(773 const context = yield* sourcePathContext.pipe(
778 Effect.provideService(HostProcessEnvironment, {774 Effect.provideService(HostProcess.Environment, {
779 HOME: home,775 HOME: home,
780 APPDATA: appData,776 APPDATA: appData,
781 }),777 }),
782 Effect.provideService(HostProcessPlatform, platform),778 Effect.provideService(HostProcess.Platform, platform),
783 );779 );
784 const root = firefox.userDataDirectory(context)!;780 const root = firefox.userDataDirectory(context)!;
785 const scanRoot = platform === "linux" ? root : path.join(root, "Profiles");781 const scanRoot = platform === "linux" ? root : path.join(root, "Profiles");
...@@ -812,8 +808,8 @@ describe("listSourceProfiles Firefox fallback", () => {...@@ -812,8 +808,8 @@ describe("listSourceProfiles Firefox fallback", () => {
812 prefix: "t3code-firefox-stale-ini-",808 prefix: "t3code-firefox-stale-ini-",
813 });809 });
814 const context = yield* sourcePathContext.pipe(810 const context = yield* sourcePathContext.pipe(
815 Effect.provideService(HostProcessEnvironment, { HOME: home }),811 Effect.provideService(HostProcess.Environment, { HOME: home }),
816 Effect.provideService(HostProcessPlatform, "darwin"),812 Effect.provideService(HostProcess.Platform, "darwin"),
817 );813 );
818 const root = firefox.userDataDirectory(context)!;814 const root = firefox.userDataDirectory(context)!;
819 // `profiles.ini` names a profile that was never launched (no cookie815 // `profiles.ini` names a profile that was never launched (no cookie
...@@ -851,8 +847,8 @@ describe("listSourceProfiles Firefox fallback", () => {...@@ -851,8 +847,8 @@ describe("listSourceProfiles Firefox fallback", () => {
851 prefix: "t3code-firefox-counts-",847 prefix: "t3code-firefox-counts-",
852 });848 });
853 const context = yield* sourcePathContext.pipe(849 const context = yield* sourcePathContext.pipe(
854 Effect.provideService(HostProcessEnvironment, { HOME: home }),850 Effect.provideService(HostProcess.Environment, { HOME: home }),
855 Effect.provideService(HostProcessPlatform, "darwin"),851 Effect.provideService(HostProcess.Platform, "darwin"),
856 );852 );
857 const root = firefox.userDataDirectory(context)!;853 const root = firefox.userDataDirectory(context)!;
858 const declaredDirectory = path.join(root, "Profiles", "declared.default");854 const declaredDirectory = path.join(root, "Profiles", "declared.default");
...@@ -902,8 +898,8 @@ describe("isSourceRunning for Firefox", () => {...@@ -902,8 +898,8 @@ describe("isSourceRunning for Firefox", () => {
902 const fileSystem = yield* FileSystem.FileSystem;898 const fileSystem = yield* FileSystem.FileSystem;
903 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" });899 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" });
904 const context = yield* sourcePathContext.pipe(900 const context = yield* sourcePathContext.pipe(
905 Effect.provideService(HostProcessEnvironment, { HOME: home }),901 Effect.provideService(HostProcess.Environment, { HOME: home }),
906 Effect.provideService(HostProcessPlatform, "darwin"),902 Effect.provideService(HostProcess.Platform, "darwin"),
907 );903 );
908 const root = firefox.userDataDirectory(context)!;904 const root = firefox.userDataDirectory(context)!;
909 const profile = `${root}/Profiles/abcd.default-release`;905 const profile = `${root}/Profiles/abcd.default-release`;
...@@ -952,7 +948,7 @@ describe("isSourceRunning for Firefox", () => {...@@ -952,7 +948,7 @@ describe("isSourceRunning for Firefox", () => {
952 );948 );
953949
954 // Holds the lock with python3's fcntl, which does not exist on Windows.950 // 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")(
956 "detects a live fcntl lock on .parentlock, as macOS Firefox leaves it",952 "detects a live fcntl lock on .parentlock, as macOS Firefox leaves it",
957 () =>953 () =>
958 run(954 run(
...@@ -961,8 +957,8 @@ describe("isSourceRunning for Firefox", () => {...@@ -961,8 +957,8 @@ describe("isSourceRunning for Firefox", () => {
961 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;957 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
962 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" });958 const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" });
963 const context = yield* sourcePathContext.pipe(959 const context = yield* sourcePathContext.pipe(
964 Effect.provideService(HostProcessEnvironment, { HOME: home }),960 Effect.provideService(HostProcess.Environment, { HOME: home }),
965 Effect.provideService(HostProcessPlatform, "darwin"),961 Effect.provideService(HostProcess.Platform, "darwin"),
966 );962 );
967 const root = firefox.userDataDirectory(context)!;963 const root = firefox.userDataDirectory(context)!;
968 const profile = `${root}/Profiles/abcd.default-release`;964 const profile = `${root}/Profiles/abcd.default-release`;
...@@ -1033,11 +1029,11 @@ describe("isSourceRunning for Firefox", () => {...@@ -1033,11 +1029,11 @@ describe("isSourceRunning for Firefox", () => {
1033 const context = yield* sourcePathContext.pipe(1029 const context = yield* sourcePathContext.pipe(
1034 // Firefox's win32 root hangs off %APPDATA%; without it the root is1030 // Firefox's win32 root hangs off %APPDATA%; without it the root is
1035 // undefined and the fixture would escape the sandbox into the repo.1031 // undefined and the fixture would escape the sandbox into the repo.
1036 Effect.provideService(HostProcessEnvironment, {1032 Effect.provideService(HostProcess.Environment, {
1037 HOME: home,1033 HOME: home,
1038 APPDATA: `${home}/AppData/Roaming`,1034 APPDATA: `${home}/AppData/Roaming`,
1039 }),1035 }),
1040 Effect.provideService(HostProcessPlatform, "win32"),1036 Effect.provideService(HostProcess.Platform, "win32"),
1041 );1037 );
1042 const root = firefox.userDataDirectory(context)!;1038 const root = firefox.userDataDirectory(context)!;
1043 const profile = `${root}/Profiles/gx7x7fqx.default-release`;1039 const profile = `${root}/Profiles/gx7x7fqx.default-release`;
apps/desktop/src/preview/BrowserImport/Sources.ts+6-11
...@@ -17,12 +17,7 @@...@@ -17,12 +17,7 @@
17 */17 */
18import type { BrowserImportSourceId, BrowserImportSourceProfile } from "@t3tools/contracts";18import type { BrowserImportSourceId, BrowserImportSourceProfile } from "@t3tools/contracts";
19import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";19import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
20import {20import * as HostProcess from "@t3tools/shared/HostProcess";
21 HostProcessEnvironment,
22 HostProcessAddresses,
23 HostProcessHostname,
24 HostProcessPlatform,
25} from "@t3tools/shared/hostProcess";
26import * as Effect from "effect/Effect";21import * as Effect from "effect/Effect";
27import * as FileSystem from "effect/FileSystem";22import * as FileSystem from "effect/FileSystem";
28import * as Path from "effect/Path";23import * as Path from "effect/Path";
...@@ -335,8 +330,8 @@ export function parseFirefoxProfiles(...@@ -335,8 +330,8 @@ export function parseFirefoxProfiles(
335 */330 */
336export const sourcePathContext = Effect.gen(function* () {331export const sourcePathContext = Effect.gen(function* () {
337 const path = yield* Path.Path;332 const path = yield* Path.Path;
338 const platform = yield* HostProcessPlatform;333 const platform = yield* HostProcess.Platform;
339 const environment = yield* HostProcessEnvironment;334 const environment = yield* HostProcess.Environment;
340 return {335 return {
341 path,336 path,
342 platform,337 platform,
...@@ -782,7 +777,7 @@ export const posixLockIsHeld = Effect.fnUntraced(function* (...@@ -782,7 +777,7 @@ export const posixLockIsHeld = Effect.fnUntraced(function* (
782 interpreters: ReadonlyArray<string> = FCNTL_PROBE_INTERPRETERS,777 interpreters: ReadonlyArray<string> = FCNTL_PROBE_INTERPRETERS,
783) {778) {
784 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;779 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
785 const environment = yield* HostProcessEnvironment;780 const environment = yield* HostProcess.Environment;
786 for (const interpreter of interpreters) {781 for (const interpreter of interpreters) {
787 const verdict = yield* Effect.scoped(782 const verdict = yield* Effect.scoped(
788 Effect.gen(function* () {783 Effect.gen(function* () {
...@@ -872,7 +867,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning")...@@ -872,7 +867,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning")
872 if (context.platform === "win32") {867 if (context.platform === "win32") {
873 return yield* windowsChromiumCookiesAreHeld(definition, context);868 return yield* windowsChromiumCookiesAreHeld(definition, context);
874 }869 }
875 const currentHost = yield* HostProcessHostname;870 const currentHost = yield* HostProcess.Hostname;
876 const lock = context.path.join(root, "SingletonLock");871 const lock = context.path.join(root, "SingletonLock");
877 return yield* fileSystem.readLink(lock).pipe(872 return yield* fileSystem.readLink(lock).pipe(
878 Effect.flatMap((target) => chromiumSingletonLockIsHeld(target, currentHost, processIsAlive)),873 Effect.flatMap((target) => chromiumSingletonLockIsHeld(target, currentHost, processIsAlive)),
...@@ -883,7 +878,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning")...@@ -883,7 +878,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning")
883 const profiles = yield* listSourceProfiles(definition, context);878 const profiles = yield* listSourceProfiles(definition, context);
884 // Only the Linux `lock` symlink names an address, so Windows skips the lookup.879 // Only the Linux `lock` symlink names an address, so Windows skips the lookup.
885 const localAddresses: ReadonlySet<string> =880 const localAddresses: ReadonlySet<string> =
886 context.platform === "win32" ? new Set() : yield* yield* HostProcessAddresses;881 context.platform === "win32" ? new Set() : yield* yield* HostProcess.Addresses;
887 const found = yield* Effect.forEach(profiles, (profile) => {882 const found = yield* Effect.forEach(profiles, (profile) => {
888 const directory = context.path.isAbsolute(profile.directory)883 const directory = context.path.isAbsolute(profile.directory)
889 ? profile.directory884 ? profile.directory
apps/desktop/src/preview/Manager.test.ts+2-2
...@@ -5,7 +5,7 @@ import type {...@@ -5,7 +5,7 @@ import type {
5 DesktopPreviewRecordingFrame,5 DesktopPreviewRecordingFrame,
6 DesktopPreviewRecordingInputEvent,6 DesktopPreviewRecordingInputEvent,
7} from "@t3tools/contracts";7} from "@t3tools/contracts";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
9import { parseKeybindingShortcut } from "@t3tools/shared/keybindings";9import { parseKeybindingShortcut } from "@t3tools/shared/keybindings";
10import * as Cause from "effect/Cause";10import * as Cause from "effect/Cause";
11import * as Deferred from "effect/Deferred";11import * as Deferred from "effect/Deferred";
...@@ -313,7 +313,7 @@ const managerLayer = (platform: NodeJS.Platform = "darwin") =>...@@ -313,7 +313,7 @@ const managerLayer = (platform: NodeJS.Platform = "darwin") =>
313 Layer.provideMerge(layerFileSystem),313 Layer.provideMerge(layerFileSystem),
314 Layer.provideMerge(Path.layer),314 Layer.provideMerge(Path.layer),
315 Layer.provideMerge(NodeCrypto.layer),315 Layer.provideMerge(NodeCrypto.layer),
316 Layer.provideMerge(Layer.succeed(HostProcessPlatform, platform)),316 Layer.provideMerge(Layer.succeed(HostProcess.Platform, platform)),
317 );317 );
318318
319const withManager = <A>(319const withManager = <A>(
apps/desktop/src/preview/Manager.ts+2-2
...@@ -25,7 +25,7 @@ import type {...@@ -25,7 +25,7 @@ import type {
25 DesktopPreviewTabDefaults,25 DesktopPreviewTabDefaults,
26 PreviewForwardedShortcut,26 PreviewForwardedShortcut,
27} from "@t3tools/contracts";27} from "@t3tools/contracts";
28import { HostProcessPlatform } from "@t3tools/shared/hostProcess";28import * as HostProcess from "@t3tools/shared/HostProcess";
29import { matchesKeybindingShortcut } from "@t3tools/shared/keybindings";29import { matchesKeybindingShortcut } from "@t3tools/shared/keybindings";
30import { normalizePreviewUrl } from "@t3tools/shared/preview";30import { normalizePreviewUrl } from "@t3tools/shared/preview";
31import {31import {
...@@ -544,7 +544,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function...@@ -544,7 +544,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
544) {544) {
545 const fileSystem = yield* FileSystem.FileSystem;545 const fileSystem = yield* FileSystem.FileSystem;
546 const rendererHistory = yield* DesktopRendererHistory.DesktopRendererHistory;546 const rendererHistory = yield* DesktopRendererHistory.DesktopRendererHistory;
547 const hostPlatform = yield* HostProcessPlatform;547 const hostPlatform = yield* HostProcess.Platform;
548 const path = yield* Path.Path;548 const path = yield* Path.Path;
549 const crypto = yield* Crypto.Crypto;549 const crypto = yield* Crypto.Crypto;
550 const parentScope = yield* Scope.Scope;550 const parentScope = yield* Scope.Scope;
apps/desktop/src/snapShot/DesktopSnapShot.ts+2-2
...@@ -88,7 +88,7 @@ import {...@@ -88,7 +88,7 @@ import {
88 snapShotShortcutRegistrationFailureMessage,88 snapShotShortcutRegistrationFailureMessage,
89 snapShotShortcutSystemConflict,89 snapShotShortcutSystemConflict,
90} from "./snapShot.ts";90} from "./snapShot.ts";
91import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";91import * as HostProcess from "@t3tools/shared/HostProcess";
9292
93const MAX_CAPTURE_WIDTH = 2_560;93const MAX_CAPTURE_WIDTH = 2_560;
94const MAX_CAPTURE_HEIGHT = 1_600;94const MAX_CAPTURE_HEIGHT = 1_600;
...@@ -728,7 +728,7 @@ export const make = Effect.gen(function* () {...@@ -728,7 +728,7 @@ export const make = Effect.gen(function* () {
728 const runPromise = Effect.runPromiseWith(context);728 const runPromise = Effect.runPromiseWith(context);
729 const captureDirectory = path.join(environment.stateDir, "snap-shots");729 const captureDirectory = path.join(environment.stateDir, "snap-shots");
730 const linuxAppId = environment.linuxDesktopEntryName.replace(/\.desktop$/, "");730 const linuxAppId = environment.linuxDesktopEntryName.replace(/\.desktop$/, "");
731 const home = yield* HostProcessHomeDirectory;731 const home = yield* HostProcess.HomeDirectory;
732 let shortcutVerified = false;732 let shortcutVerified = false;
733 const gnomeSetupPaths = {733 const gnomeSetupPaths = {
734 bundle: environment.isPackaged734 bundle: environment.isPackaged
apps/desktop/src/snapShot/snapShot.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { it as effectIt } from "@effect/vitest";1import { it as effectIt } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import { describe, expect, it, vi } from "vite-plus/test";4import { describe, expect, it, vi } from "vite-plus/test";
55
...@@ -703,7 +703,7 @@ describe("isWaylandSession", () => {...@@ -703,7 +703,7 @@ describe("isWaylandSession", () => {
703 "falls back to a live runtime directory socket when session variables are stripped",703 "falls back to a live runtime directory socket when session variables are stripped",
704 () =>704 () =>
705 Effect.gen(function* () {705 Effect.gen(function* () {
706 if ((yield* HostProcessPlatform) !== "linux") return;706 if ((yield* HostProcess.Platform) !== "linux") return;
707 yield* Effect.promise(async () => {707 yield* Effect.promise(async () => {
708 const { mkdtemp, rm, writeFile } = await import("node:fs/promises");708 const { mkdtemp, rm, writeFile } = await import("node:fs/promises");
709 const { createServer } = await import("node:net");709 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";...@@ -5,7 +5,7 @@ import { revertCodexThread } from "../src/provider/CodexThreadRevert.ts";
5import { buildCodexInitializeParams } from "../src/provider/CodexProvider.ts";5import { buildCodexInitializeParams } from "../src/provider/CodexProvider.ts";
6import * as NodeRuntime from "@effect/platform-node/NodeRuntime";6import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
7import * as NodeServices from "@effect/platform-node/NodeServices";7import * as NodeServices from "@effect/platform-node/NodeServices";
8import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
9import { resolveSpawnCommand } from "@t3tools/shared/shell";9import { resolveSpawnCommand } from "@t3tools/shared/shell";
10import * as Console from "effect/Console";10import * as Console from "effect/Console";
11import * as Deferred from "effect/Deferred";11import * as Deferred from "effect/Deferred";
...@@ -1211,7 +1211,8 @@ function layerCodex({ recorder }: { readonly recorder: Recorder }) {...@@ -1211,7 +1211,8 @@ function layerCodex({ recorder }: { readonly recorder: Recorder }) {
1211 Effect.gen(function* () {1211 Effect.gen(function* () {
1212 // The vp node shim marks its children with VP_TOOL_RECURSION, which makes every1212 // The vp node shim marks its children with VP_TOOL_RECURSION, which makes every
1213 // `node` the agent runs through a shell fail. Codex must not inherit it.1213 // `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;
1215 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;1216 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
1216 const commandName = environment.T3_CODEX_BIN ?? environment.CODEX_BIN ?? "codex";1217 const commandName = environment.T3_CODEX_BIN ?? environment.CODEX_BIN ?? "codex";
1217 const spawnCommand = yield* resolveSpawnCommand(commandName, ["app-server"], {1218 const spawnCommand = yield* resolveSpawnCommand(commandName, ["app-server"], {
apps/server/scripts/record-grok-acp-replay-fixture.ts+3-3
...@@ -12,7 +12,7 @@...@@ -12,7 +12,7 @@
12import * as NodeServices from "@effect/platform-node/NodeServices";12import * as NodeServices from "@effect/platform-node/NodeServices";
13import { type ProviderReplayEntry } from "@t3tools/contracts";13import { type ProviderReplayEntry } from "@t3tools/contracts";
14import { GrokSettings } from "@t3tools/provider-grok/settings";14import { GrokSettings } from "@t3tools/provider-grok/settings";
15import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";15import * as HostProcess from "@t3tools/shared/HostProcess";
16import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";16import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
17import * as Clock from "effect/Clock";17import * as Clock from "effect/Clock";
18import * as Console from "effect/Console";18import * as Console from "effect/Console";
...@@ -442,12 +442,12 @@ const recordScenario = Effect.fn("recordGrokScenario")(function* (fixtureName: s...@@ -442,12 +442,12 @@ const recordScenario = Effect.fn("recordGrokScenario")(function* (fixtureName: s
442 const settings = { ...DEFAULT_GROK_SETTINGS, binaryPath: process.env.T3_GROK_BIN ?? "grok" };442 const settings = { ...DEFAULT_GROK_SETTINGS, binaryPath: process.env.T3_GROK_BIN ?? "grok" };
443 const layerRegistry = ProviderAdapterRegistry.layerFromAdaptersEffect(443 const layerRegistry = ProviderAdapterRegistry.layerFromAdaptersEffect(
444 Effect.gen(function* () {444 Effect.gen(function* () {
445 const environment = yield* HostProcessEnvironment;445 const environment = yield* HostProcess.Environment;
446 const adapter = yield* makeGrokAdapterV2({446 const adapter = yield* makeGrokAdapterV2({
447 instanceId: GROK_DEFAULT_INSTANCE_ID,447 instanceId: GROK_DEFAULT_INSTANCE_ID,
448 settings,448 settings,
449 environment,449 environment,
450 hostPlatform: yield* HostProcessPlatform,450 hostPlatform: yield* HostProcess.Platform,
451 selfInvocation: yield* resolveSelfInvocation(),451 selfInvocation: yield* resolveSelfInvocation(),
452 continuationRequests: yield* ProviderContinuationRequests.ProviderContinuationRequests,452 continuationRequests: yield* ProviderContinuationRequests.ProviderContinuationRequests,
453 // Production's runtime factory, with the protocol logger teeing raw lines.453 // 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";...@@ -7,7 +7,7 @@ import * as SqlClient from "effect/sql/SqlClient";
77
8import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";8import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
9import { runSqliteState } from "./t3-sqlite-state.ts";9import { runSqliteState } from "./t3-sqlite-state.ts";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
11import { symlinksSupported } from "@t3tools/shared/testing/symlinks";11import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
1212
13const createFixtureDatabase = Effect.fn("createSqliteStateFixtureDatabase")(function* (13const createFixtureDatabase = Effect.fn("createSqliteStateFixtureDatabase")(function* (
...@@ -90,7 +90,7 @@ it.layer(NodeServices.layer)("t3-sqlite-state", (it) => {...@@ -90,7 +90,7 @@ it.layer(NodeServices.layer)("t3-sqlite-state", (it) => {
90 sql: "INSERT INTO fixtures (id, label) VALUES (2, 'seeded')",90 sql: "INSERT INTO fixtures (id, label) VALUES (2, 'seeded')",
91 });91 });
92 assert.equal(mutation.operation, "exec");92 assert.equal(mutation.operation, "exec");
93 if (mutation.operation === "exec" && (yield* HostProcessPlatform) !== "win32") {93 if (mutation.operation === "exec" && (yield* HostProcess.Platform) !== "win32") {
94 // NTFS has no POSIX mode bits to report.94 // NTFS has no POSIX mode bits to report.
95 assert.equal((yield* fs.stat(mutation.backup)).mode & 0o777, 0o600);95 assert.equal((yield* fs.stat(mutation.backup)).mode & 0o777, 0o600);
96 }96 }
apps/server/src/assets/AssetAccess.test.ts+2-2
...@@ -36,7 +36,7 @@ import { openMediaFile } from "./MediaFile.ts";...@@ -36,7 +36,7 @@ import { openMediaFile } from "./MediaFile.ts";
36import { symlinksSupported } from "@t3tools/shared/testing/symlinks";36import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
37import * as GitHubCredentials from "@t3tools/source-control-github/server/GitHubCredentials";37import * as GitHubCredentials from "@t3tools/source-control-github/server/GitHubCredentials";
38import { githubMediaResponse } from "./GitHubMediaFetch.ts";38import { githubMediaResponse } from "./GitHubMediaFetch.ts";
39import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";39import * as HostProcess from "@t3tools/shared/HostProcess";
4040
41vi.mock("node:fs/promises", async (importOriginal) => {41vi.mock("node:fs/promises", async (importOriginal) => {
42 const actual = await importOriginal<typeof NodeFSP>();42 const actual = await importOriginal<typeof NodeFSP>();
...@@ -326,7 +326,7 @@ describe("AssetAccess", () => {...@@ -326,7 +326,7 @@ describe("AssetAccess", () => {
326 expect(yield* Effect.promise(() => response.text())).toBe("recording bytes");326 expect(yield* Effect.promise(() => response.text())).toBe("recording bytes");
327 }327 }
328 }328 }
329 }).pipe(Effect.provideService(HostProcessHomeDirectory, home));329 }).pipe(Effect.provideService(HostProcess.HomeDirectory, home));
330 }).pipe(Effect.provide(layerTest)),330 }).pipe(Effect.provide(layerTest)),
331 );331 );
332332
apps/server/src/assets/AssetAccess.ts+2-2
...@@ -58,7 +58,7 @@ import * as ProjectFaviconResolver from "../project/ProjectFaviconResolver.ts";...@@ -58,7 +58,7 @@ import * as ProjectFaviconResolver from "../project/ProjectFaviconResolver.ts";
58import * as WorkspacePaths from "../workspace/WorkspacePaths.ts";58import * as WorkspacePaths from "../workspace/WorkspacePaths.ts";
59import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";59import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";
60import { openMediaFile, readMediaFileHeader, type OpenMediaFile } from "./MediaFile.ts";60import { openMediaFile, readMediaFileHeader, type OpenMediaFile } from "./MediaFile.ts";
61import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";61import * as HostProcess from "@t3tools/shared/HostProcess";
6262
63export const ASSET_ROUTE_PREFIX = "/api/assets";63export const ASSET_ROUTE_PREFIX = "/api/assets";
6464
...@@ -470,7 +470,7 @@ export const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (i...@@ -470,7 +470,7 @@ export const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (i
470470
471 switch (input.resource._tag) {471 switch (input.resource._tag) {
472 case "media-file": {472 case "media-file": {
473 let requestedPath = expandHomePath(input.resource.path, yield* HostProcessHomeDirectory);473 let requestedPath = expandHomePath(input.resource.path, yield* HostProcess.HomeDirectory);
474 if (!path.isAbsolute(requestedPath)) {474 if (!path.isAbsolute(requestedPath)) {
475 if (!input.workspaceRoot) {475 if (!input.workspaceRoot) {
476 return yield* new AssetWorkspaceContextNotFoundError({ resource: input.resource });476 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";...@@ -5,7 +5,7 @@ import * as Layer from "effect/Layer";
5import * as Sink from "effect/Sink";5import * as Sink from "effect/Sink";
6import * as Stream from "effect/Stream";6import * as Stream from "effect/Stream";
7import { ChildProcessSpawner } from "effect/process";7import { ChildProcessSpawner } from "effect/process";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
99
10import * as ServerConfig from "../config.ts";10import * as ServerConfig from "../config.ts";
11import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";11import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";
...@@ -44,7 +44,7 @@ describe("resolveNativeAppIcon", () => {...@@ -44,7 +44,7 @@ describe("resolveNativeAppIcon", () => {
44 });44 });
45 const layerDependencies = Layer.mergeAll(45 const layerDependencies = Layer.mergeAll(
46 layerConfig,46 layerConfig,
47 Layer.succeed(HostProcessPlatform, "darwin"),47 Layer.succeed(HostProcess.Platform, "darwin"),
48 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner),48 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner),
49 ).pipe(Layer.provideMerge(NodeServices.layer));49 ).pipe(Layer.provideMerge(NodeServices.layer));
50 const layerTest = NativeAppIconResolver.layer.pipe(Layer.provide(layerDependencies));50 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";...@@ -15,7 +15,7 @@ import * as PlatformError from "effect/PlatformError";
15import * as Semaphore from "effect/Semaphore";15import * as Semaphore from "effect/Semaphore";
16import * as Hex from "effect/encoding/Hex";16import * as Hex from "effect/encoding/Hex";
17import { ChildProcess, ChildProcessSpawner } from "effect/process";17import { ChildProcess, ChildProcessSpawner } from "effect/process";
18import { HostProcessPlatform } from "@t3tools/shared/hostProcess";18import * as HostProcess from "@t3tools/shared/HostProcess";
1919
20import * as ServerConfig from "../config.ts";20import * as ServerConfig from "../config.ts";
2121
...@@ -214,7 +214,7 @@ const resolveNativeAppIconUncached = Effect.fn("NativeAppIconResolver.resolveUnc...@@ -214,7 +214,7 @@ const resolveNativeAppIconUncached = Effect.fn("NativeAppIconResolver.resolveUnc
214/** @public Service construction is part of the canonical Effect module API. */214/** @public Service construction is part of the canonical Effect module API. */
215export const make = Effect.gen(function* () {215export const make = Effect.gen(function* () {
216 const fileSystem = yield* FileSystem.FileSystem;216 const fileSystem = yield* FileSystem.FileSystem;
217 const hostPlatform = yield* HostProcessPlatform;217 const hostPlatform = yield* HostProcess.Platform;
218 const resolutionSemaphore = yield* Semaphore.make(2);218 const resolutionSemaphore = yield* Semaphore.make(2);
219 const resolutionCache: Cache.Cache<219 const resolutionCache: Cache.Cache<
220 string,220 string,
apps/server/src/bootstrap.test.ts+4-4
...@@ -11,7 +11,7 @@ import * as Effect from "effect/Effect";...@@ -11,7 +11,7 @@ import * as Effect from "effect/Effect";
11import * as Fiber from "effect/Fiber";11import * as Fiber from "effect/Fiber";
12import * as TestClock from "effect/testing/TestClock";12import * as TestClock from "effect/testing/TestClock";
13import { vi } from "vite-plus/test";13import { vi } from "vite-plus/test";
14import { HostProcessPlatform } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
1515
16import {16import {
17 BootstrapEnvelopeDecodeError,17 BootstrapEnvelopeDecodeError,
...@@ -55,7 +55,7 @@ vi.mock("node:fs", async (importOriginal) => {...@@ -55,7 +55,7 @@ vi.mock("node:fs", async (importOriginal) => {
55 };55 };
56});56});
5757
58const windowsHost = HostProcessPlatform.defaultValue() === "win32";58const windowsHost = HostProcess.Platform.defaultValue() === "win32";
59const nullDevice = windowsHost ? "\\\\.\\NUL" : "/dev/null";59const nullDevice = windowsHost ? "\\\\.\\NUL" : "/dev/null";
60const closeIfOpen = (fd: number) => {60const closeIfOpen = (fd: number) => {
61 try {61 try {
...@@ -116,7 +116,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {...@@ -116,7 +116,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
116 try {116 try {
117 const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {117 const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
118 timeoutMs: 100,118 timeoutMs: 100,
119 }).pipe(Effect.provideService(HostProcessPlatform, "linux"));119 }).pipe(Effect.provideService(HostProcess.Platform, "linux"));
120 assertSome(payload, {120 assertSome(payload, {
121 mode: "desktop",121 mode: "desktop",
122 });122 });
...@@ -141,7 +141,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {...@@ -141,7 +141,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
141 try {141 try {
142 const error = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {142 const error = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
143 timeoutMs: 100,143 timeoutMs: 100,
144 }).pipe(Effect.provideService(HostProcessPlatform, "linux"), Effect.flip);144 }).pipe(Effect.provideService(HostProcess.Platform, "linux"), Effect.flip);
145145
146 assert.instanceOf(error, BootstrapInputStreamOpenError);146 assert.instanceOf(error, BootstrapInputStreamOpenError);
147 assert.equal(error.fd, fd);147 assert.equal(error.fd, fd);
apps/server/src/bootstrap.ts+2-2
...@@ -10,7 +10,7 @@ import * as Predicate from "effect/Predicate";...@@ -10,7 +10,7 @@ import * as Predicate from "effect/Predicate";
10import * as Result from "effect/Result";10import * as Result from "effect/Result";
11import * as Schema from "effect/Schema";11import * as Schema from "effect/Schema";
12import { decodeJsonResult } from "@t3tools/shared/schemaJson";12import { decodeJsonResult } from "@t3tools/shared/schemaJson";
13import { HostProcessPlatform } from "@t3tools/shared/hostProcess";13import * as HostProcess from "@t3tools/shared/HostProcess";
1414
15export class BootstrapFdStatError extends Schema.TaggedError<BootstrapFdStatError>()(15export class BootstrapFdStatError extends Schema.TaggedError<BootstrapFdStatError>()(
16 "BootstrapFdStatError",16 "BootstrapFdStatError",
...@@ -168,7 +168,7 @@ const isFdReady = (fd: number) =>...@@ -168,7 +168,7 @@ const isFdReady = (fd: number) =>
168168
169const makeBootstrapInputStream = (fd: number) =>169const makeBootstrapInputStream = (fd: number) =>
170 Effect.gen(function* () {170 Effect.gen(function* () {
171 const platform = yield* HostProcessPlatform;171 const platform = yield* HostProcess.Platform;
172 const fdPath = resolveFdPath(fd, platform);172 const fdPath = resolveFdPath(fd, platform);
173 return yield* Effect.try<NodeStream.Readable, BootstrapInputStreamOpenError>({173 return yield* Effect.try<NodeStream.Readable, BootstrapInputStreamOpenError>({
174 try: () => {174 try: () => {
apps/server/src/checkpointing/CheckpointStore.test.ts+2-2
...@@ -4,7 +4,7 @@ import * as NodePath from "node:path";...@@ -4,7 +4,7 @@ import * as NodePath from "node:path";
4import * as NodeServices from "@effect/platform-node/NodeServices";4import * as NodeServices from "@effect/platform-node/NodeServices";
5import { it } from "@effect/vitest";5import { it } from "@effect/vitest";
6import { ThreadId, type VcsError } from "@t3tools/contracts";6import { ThreadId, type VcsError } from "@t3tools/contracts";
7import { HostProcessPlatform } from "@t3tools/shared/hostProcess";7import * as HostProcess from "@t3tools/shared/HostProcess";
8import * as Effect from "effect/Effect";8import * as Effect from "effect/Effect";
9import * as FileSystem from "effect/FileSystem";9import * as FileSystem from "effect/FileSystem";
10import * as Layer from "effect/Layer";10import * as Layer from "effect/Layer";
...@@ -329,7 +329,7 @@ it.layer(layerTest)("CheckpointStore.layer", (it) => {...@@ -329,7 +329,7 @@ it.layer(layerTest)("CheckpointStore.layer", (it) => {
329 const copiedText = Array.from({ length: 20 }, (_, index) => `copy line ${index}\n`).join(329 const copiedText = Array.from({ length: 20 }, (_, index) => `copy line ${index}\n`).join(
330 "",330 "",
331 );331 );
332 const platform = yield* HostProcessPlatform;332 const platform = yield* HostProcess.Platform;
333 const renamedPath = platform === "win32" ? "renamed café.txt" : "renamed\tcafé\nname.txt";333 const renamedPath = platform === "win32" ? "renamed café.txt" : "renamed\tcafé\nname.txt";
334 const addedPath = platform === "win32" ? "new café.txt" : "new\tfile\n名.txt";334 const addedPath = platform === "win32" ? "new café.txt" : "new\tfile\n名.txt";
335 for (const [path, contents] of Object.entries({335 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";...@@ -8,12 +8,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
8import { it } from "@effect/vitest";8import { it } from "@effect/vitest";
9import type { DesktopAppActivationRequest } from "@t3tools/contracts";9import type { DesktopAppActivationRequest } from "@t3tools/contracts";
10import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";10import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
11import {11import * as HostProcess from "@t3tools/shared/HostProcess";
12 HostProcessHomeDirectory,
13 HostProcessPlatform,
14 HostProcessUserId,
15 HostProcessWorkingDirectory,
16} from "@t3tools/shared/hostProcess";
17import * as NetService from "@t3tools/shared/Net";12import * as NetService from "@t3tools/shared/Net";
18import * as ConfigProvider from "effect/ConfigProvider";13import * as ConfigProvider from "effect/ConfigProvider";
19import * as Effect from "effect/Effect";14import * as Effect from "effect/Effect";
...@@ -110,8 +105,8 @@ async function startFakeDesktop(input: {...@@ -110,8 +105,8 @@ async function startFakeDesktop(input: {
110const fakeDesktop = Effect.fn(function* (105const fakeDesktop = Effect.fn(function* (
111 input: Omit<Parameters<typeof startFakeDesktop>[0], "platform" | "userId">,106 input: Omit<Parameters<typeof startFakeDesktop>[0], "platform" | "userId">,
112) {107) {
113 const platform = yield* HostProcessPlatform;108 const platform = yield* HostProcess.Platform;
114 const userId = yield* HostProcessUserId;109 const userId = yield* HostProcess.UserId;
115 return yield* Effect.acquireRelease(110 return yield* Effect.acquireRelease(
116 Effect.promise(() => startFakeDesktop({ ...input, platform, userId })),111 Effect.promise(() => startFakeDesktop({ ...input, platform, userId })),
117 (server) => Effect.promise(() => server.close()),112 (server) => Effect.promise(() => server.close()),
...@@ -142,7 +137,7 @@ describe("t3 server command safety", () => {...@@ -142,7 +137,7 @@ describe("t3 server command safety", () => {
142 "C:new-project",137 "C:new-project",
143 ]) {138 ]) {
144 const error = yield* runCli([word, "--base-dir", baseDir]).pipe(139 const error = yield* runCli([word, "--base-dir", baseDir]).pipe(
145 Effect.provideService(HostProcessPlatform, "linux"),140 Effect.provideService(HostProcess.Platform, "linux"),
146 Effect.flip,141 Effect.flip,
147 );142 );
148 expect(String(error)).toContain(`Unknown command "${word}"`);143 expect(String(error)).toContain(`Unknown command "${word}"`);
...@@ -181,7 +176,7 @@ describe("t3 server command safety", () => {...@@ -181,7 +176,7 @@ describe("t3 server command safety", () => {
181 yield* Effect.promise(() => NodeFSP.mkdir(stateDir, { recursive: true }));176 yield* Effect.promise(() => NodeFSP.mkdir(stateDir, { recursive: true }));
182 yield* Effect.promise(() => NodeFSP.writeFile(statePath, record));177 yield* Effect.promise(() => NodeFSP.writeFile(statePath, record));
183 const newDirectory = NodePath.join(root, "new-project");178 const newDirectory = NodePath.join(root, "new-project");
184 const platform = yield* HostProcessPlatform;179 const platform = yield* HostProcess.Platform;
185 for (const args of [180 for (const args of [
186 [],181 [],
187 ["start"],182 ["start"],
...@@ -193,7 +188,7 @@ describe("t3 server command safety", () => {...@@ -193,7 +188,7 @@ describe("t3 server command safety", () => {
193 ]) {188 ]) {
194 const error = yield* runCli(args, { T3CODE_HOME: baseDir }).pipe(189 const error = yield* runCli(args, { T3CODE_HOME: baseDir }).pipe(
195 Effect.provideService(190 Effect.provideService(
196 HostProcessPlatform,191 HostProcess.Platform,
197 args[0] === "C:new-project" ? "win32" : platform,192 args[0] === "C:new-project" ? "win32" : platform,
198 ),193 ),
199 Effect.flip,194 Effect.flip,
...@@ -234,7 +229,7 @@ describe("t3 app", () => {...@@ -234,7 +229,7 @@ describe("t3 app", () => {
234 Effect.gen(function* () {229 Effect.gen(function* () {
235 const baseDir = NodePath.join(root, "missing-t3-home");230 const baseDir = NodePath.join(root, "missing-t3-home");
236 const error = yield* runCli(["app", "--base-dir", baseDir]).pipe(231 const error = yield* runCli(["app", "--base-dir", baseDir]).pipe(
237 Effect.provideService(HostProcessPlatform, "freebsd"),232 Effect.provideService(HostProcess.Platform, "freebsd"),
238 Effect.flip,233 Effect.flip,
239 );234 );
240235
...@@ -257,7 +252,7 @@ describe("t3 app", () => {...@@ -257,7 +252,7 @@ describe("t3 app", () => {
257 expect(error).toMatchObject({252 expect(error).toMatchObject({
258 _tag: "DesktopAppUnreachableError",253 _tag: "DesktopAppUnreachableError",
259 candidateAddresses: [expect.any(String)],254 candidateAddresses: [expect.any(String)],
260 workspaceRoot: yield* HostProcessWorkingDirectory,255 workspaceRoot: yield* HostProcess.WorkingDirectory,
261 message: expect.stringContaining("Could not reach the T3 Code desktop app."),256 message: expect.stringContaining("Could not reach the T3 Code desktop app."),
262 cause: { code: "ENOENT" },257 cause: { code: "ENOENT" },
263 });258 });
...@@ -271,8 +266,8 @@ describe("t3 app", () => {...@@ -271,8 +266,8 @@ describe("t3 app", () => {
271 Effect.gen(function* () {266 Effect.gen(function* () {
272 const baseDir = NodePath.join(root, "t3-home");267 const baseDir = NodePath.join(root, "t3-home");
273 const explicitPath = NodePath.join(root, "project");268 const explicitPath = NodePath.join(root, "project");
274 const platform = yield* HostProcessPlatform;269 const platform = yield* HostProcess.Platform;
275 const workingDirectory = yield* HostProcessWorkingDirectory;270 const workingDirectory = yield* HostProcess.WorkingDirectory;
276 const desktop = yield* fakeDesktop({ baseDir });271 const desktop = yield* fakeDesktop({ baseDir });
277272
278 yield* runCli(["app"], { T3CODE_HOME: baseDir });273 yield* runCli(["app"], { T3CODE_HOME: baseDir });
...@@ -298,7 +293,7 @@ describe("t3 app", () => {...@@ -298,7 +293,7 @@ describe("t3 app", () => {
298293
299 expect(desktop.received).toHaveLength(1);294 expect(desktop.received).toHaveLength(1);
300 expect(development.received).toHaveLength(0);295 expect(development.received).toHaveLength(0);
301 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),296 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
302 ),297 ),
303 );298 );
304299
...@@ -313,7 +308,7 @@ describe("t3 app", () => {...@@ -313,7 +308,7 @@ describe("t3 app", () => {
313308
314 expect(development.received).toHaveLength(2);309 expect(development.received).toHaveLength(2);
315 expect(yield* pathExists(baseDir)).toBe(false);310 expect(yield* pathExists(baseDir)).toBe(false);
316 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),311 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
317 ),312 ),
318 );313 );
319314
...@@ -329,7 +324,7 @@ describe("t3 app", () => {...@@ -329,7 +324,7 @@ describe("t3 app", () => {
329 expect(flagError).toMatchObject({ _tag: "DesktopAppUnreachableError" });324 expect(flagError).toMatchObject({ _tag: "DesktopAppUnreachableError" });
330 expect(envError).toMatchObject({ _tag: "DesktopAppUnreachableError" });325 expect(envError).toMatchObject({ _tag: "DesktopAppUnreachableError" });
331 expect(development.received).toHaveLength(0);326 expect(development.received).toHaveLength(0);
332 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),327 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
333 ),328 ),
334 );329 );
335330
...@@ -363,7 +358,7 @@ describe("t3 app", () => {...@@ -363,7 +358,7 @@ describe("t3 app", () => {
363 _tag: "DesktopAppRequestFailedError",358 _tag: "DesktopAppRequestFailedError",
364 code: "project-create-failed",359 code: "project-create-failed",
365 requestId: desktop.received[0]?.requestId,360 requestId: desktop.received[0]?.requestId,
366 workspaceRoot: yield* HostProcessWorkingDirectory,361 workspaceRoot: yield* HostProcess.WorkingDirectory,
367 message: expect.stringContaining("project-create-failed"),362 message: expect.stringContaining("project-create-failed"),
368 cause: {363 cause: {
369 ok: false,364 ok: false,
...@@ -377,7 +372,7 @@ describe("t3 app", () => {...@@ -377,7 +372,7 @@ describe("t3 app", () => {
377 cause: { message: "The desktop app response is invalid." },372 cause: { message: "The desktop app response is invalid." },
378 });373 });
379 }374 }
380 }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped),375 }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped),
381 ),376 ),
382 );377 );
383});378});
apps/server/src/cli/app.ts+4-8
...@@ -10,11 +10,7 @@ import {...@@ -10,11 +10,7 @@ import {
10 type DesktopAppActivationRequest,10 type DesktopAppActivationRequest,
11} from "@t3tools/contracts";11} from "@t3tools/contracts";
12import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";12import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl";
13import {13import * as HostProcess from "@t3tools/shared/HostProcess";
14 HostProcessPlatform,
15 HostProcessUserId,
16 HostProcessWorkingDirectory,
17} from "@t3tools/shared/hostProcess";
18import * as Config from "effect/Config";14import * as Config from "effect/Config";
19import * as Console from "effect/Console";15import * as Console from "effect/Console";
20import * as Crypto from "effect/Crypto";16import * as Crypto from "effect/Crypto";
...@@ -188,7 +184,7 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: {...@@ -188,7 +184,7 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: {
188 readonly workspaceRoot: Option.Option<string>;184 readonly workspaceRoot: Option.Option<string>;
189}) {185}) {
190 const environment = yield* appEnvironment;186 const environment = yield* appEnvironment;
191 const hostPlatform = yield* HostProcessPlatform;187 const hostPlatform = yield* HostProcess.Platform;
192 if (Option.isSome(environment.sshConnection) || Option.isSome(environment.sshTty)) {188 if (Option.isSome(environment.sshConnection) || Option.isSome(environment.sshTty)) {
193 return yield* new DesktopAppSshUnsupportedError({});189 return yield* new DesktopAppSshUnsupportedError({});
194 }190 }
...@@ -201,9 +197,9 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: {...@@ -201,9 +197,9 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: {
201 const baseDir = yield* resolveBaseDir(configuredBaseDir);197 const baseDir = yield* resolveBaseDir(configuredBaseDir);
202 const allowDevFallback = Option.isNone(flags.baseDir) && !environment.t3Home?.trim();198 const allowDevFallback = Option.isNone(flags.baseDir) && !environment.t3Home?.trim();
203 const rawWorkspaceRoot =199 const rawWorkspaceRoot =
204 Option.getOrUndefined(flags.workspaceRoot) ?? (yield* HostProcessWorkingDirectory);200 Option.getOrUndefined(flags.workspaceRoot) ?? (yield* HostProcess.WorkingDirectory);
205 const workspaceRoot = path.resolve(yield* expandHomePath(rawWorkspaceRoot));201 const workspaceRoot = path.resolve(yield* expandHomePath(rawWorkspaceRoot));
206 const userId = yield* HostProcessUserId;202 const userId = yield* HostProcess.UserId;
207 const resolveAddress = (stateSubdirectory: "userdata" | "dev") =>203 const resolveAddress = (stateSubdirectory: "userdata" | "dev") =>
208 resolveDesktopAppControlAddress({204 resolveDesktopAppControlAddress({
209 stateDir: path.join(baseDir, stateSubdirectory),205 stateDir: path.join(baseDir, stateSubdirectory),
apps/server/src/cli/browser.ts+4-8
...@@ -10,11 +10,7 @@...@@ -10,11 +10,7 @@
10 * Both need root. Without it, the command prints what it would change and the10 * Both need root. Without it, the command prints what it would change and the
11 * `sudo` line to run. It is safe to run again; it skips what is already done.11 * `sudo` line to run. It is safe to run again; it skips what is already done.
12 */12 */
13import {13import * as HostProcess from "@t3tools/shared/HostProcess";
14 HostProcessEnvironment,
15 HostProcessPlatform,
16 HostProcessUserId,
17} from "@t3tools/shared/hostProcess";
18import * as Console from "effect/Console";14import * as Console from "effect/Console";
19import * as Effect from "effect/Effect";15import * as Effect from "effect/Effect";
20import * as FileSystem from "effect/FileSystem";16import * as FileSystem from "effect/FileSystem";
...@@ -61,7 +57,7 @@ const runStep = Effect.fn("browserSetup.runStep")(function* (...@@ -61,7 +57,7 @@ const runStep = Effect.fn("browserSetup.runStep")(function* (
61 * unspecified home falls back to the invoking user's `~/.t3`.57 * unspecified home falls back to the invoking user's `~/.t3`.
62 */58 */
63const setupBaseDir = Effect.fn("browserSetup.baseDir")(function* (explicit: Option.Option<string>) {59const setupBaseDir = Effect.fn("browserSetup.baseDir")(function* (explicit: Option.Option<string>) {
64 const env = yield* HostProcessEnvironment;60 const env = yield* HostProcess.Environment;
65 const raw = Option.getOrUndefined(explicit) ?? env.T3CODE_HOME;61 const raw = Option.getOrUndefined(explicit) ?? env.T3CODE_HOME;
66 if (raw !== undefined || env.SUDO_USER === undefined) return yield* resolveBaseDir(raw);62 if (raw !== undefined || env.SUDO_USER === undefined) return yield* resolveBaseDir(raw);
67 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;63 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
...@@ -109,11 +105,11 @@ const browserSetupCommand = Command.make("setup", { baseDir: baseDirFlag }).pipe...@@ -109,11 +105,11 @@ const browserSetupCommand = Command.make("setup", { baseDir: baseDirFlag }).pipe
109 ),105 ),
110 Command.withHandler(({ baseDir }) =>106 Command.withHandler(({ baseDir }) =>
111 Effect.gen(function* () {107 Effect.gen(function* () {
112 if ((yield* HostProcessPlatform) !== "linux") {108 if ((yield* HostProcess.Platform) !== "linux") {
113 return yield* Console.log("Nothing to set up: T3's browser runs as is on this system.");109 return yield* Console.log("Nothing to set up: T3's browser runs as is on this system.");
114 }110 }
115 const fs = yield* FileSystem.FileSystem;111 const fs = yield* FileSystem.FileSystem;
116 const isRoot = (yield* HostProcessUserId) === 0;112 const isRoot = (yield* HostProcess.UserId) === 0;
117 const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND);113 const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND);
118114
119 const needsProfile = yield* PreviewBrowserHost.sandboxBlocked;115 const needsProfile = yield* PreviewBrowserHost.sandboxBlocked;
apps/server/src/cli/connect.ts+2-2
...@@ -5,7 +5,7 @@ import {...@@ -5,7 +5,7 @@ import {
5 type RelayClientInstallProgressStage,5 type RelayClientInstallProgressStage,
6} from "@t3tools/contracts";6} from "@t3tools/contracts";
7import { RelayOkResponse } from "@t3tools/contracts/relay";7import { RelayOkResponse } from "@t3tools/contracts/relay";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
9import * as RelayClient from "@t3tools/shared/relayClient";9import * as RelayClient from "@t3tools/shared/relayClient";
10import { withRelayClientTracing } from "@t3tools/shared/relayTracing";10import { withRelayClientTracing } from "@t3tools/shared/relayTracing";
11import * as Cause from "effect/Cause";11import * as Cause from "effect/Cause";
...@@ -686,7 +686,7 @@ export const connectCommand = Command.make("connect", {...@@ -686,7 +686,7 @@ export const connectCommand = Command.make("connect", {
686 // show how to run the server manually.686 // show how to run the server manually.
687 const background = yield* recoverServiceOnboardingOffer(offerServiceDuringOnboarding);687 const background = yield* recoverServiceOnboardingOffer(offerServiceDuringOnboarding);
688 if (background) {688 if (background) {
689 const platform = yield* HostProcessPlatform;689 const platform = yield* HostProcess.Platform;
690 yield* Console.log(690 yield* Console.log(
691 platform === "darwin"691 platform === "darwin"
692 ? "\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."692 ? "\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 @@...@@ -1,12 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, expect, it } from "@effect/vitest";2import { assert, expect, it } from "@effect/vitest";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessArguments,
5 HostProcessEnvironment,
6 HostProcessExecutablePath,
7 HostProcessIsExecutable,
8 HostProcessPlatform,
9} from "@t3tools/shared/hostProcess";
10import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
11import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
12import * as Path from "effect/Path";6import * as Path from "effect/Path";
...@@ -113,11 +107,11 @@ it.layer(NodeServices.layer)("root CLI commands", (it) => {...@@ -113,11 +107,11 @@ it.layer(NodeServices.layer)("root CLI commands", (it) => {
113 readonly executable?: boolean;107 readonly executable?: boolean;
114 }) =>108 }) =>
115 resolveRootCliCommand("browser setup").pipe(109 resolveRootCliCommand("browser setup").pipe(
116 Effect.provideService(HostProcessExecutablePath, input.node),110 Effect.provideService(HostProcess.ExecutablePath, input.node),
117 Effect.provideService(HostProcessArguments, [input.node, input.entry]),111 Effect.provideService(HostProcess.Arguments, [input.node, input.entry]),
118 Effect.provideService(HostProcessIsExecutable, input.executable ?? false),112 Effect.provideService(HostProcess.IsExecutable, input.executable ?? false),
119 Effect.provideService(HostProcessPlatform, "linux"),113 Effect.provideService(HostProcess.Platform, "linux"),
120 Effect.provideService(HostProcessEnvironment, { PATH: input.path ?? "", ...input.env }),114 Effect.provideService(HostProcess.Environment, { PATH: input.path ?? "", ...input.env }),
121 );115 );
122116
123 /** A directory holding an executable `t3`, to stand in for one on PATH. */117 /** 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) => {...@@ -201,9 +195,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
201 yield* fs.makeDirectory(path.dirname(entry), { recursive: true });195 yield* fs.makeDirectory(path.dirname(entry), { recursive: true });
202 yield* fs.writeFileString(entry, "");196 yield* fs.writeFileString(entry, "");
203 const installation = yield* resolveServerInstallation.pipe(197 const installation = yield* resolveServerInstallation.pipe(
204 Effect.provideService(HostProcessArguments, ["node", entry]),198 Effect.provideService(HostProcess.Arguments, ["node", entry]),
205 Effect.provideService(HostProcessExecutablePath, entry),199 Effect.provideService(HostProcess.ExecutablePath, entry),
206 Effect.provideService(HostProcessIsExecutable, entry.endsWith("/t3")),200 Effect.provideService(HostProcess.IsExecutable, entry.endsWith("/t3")),
207 );201 );
208 expect(installation).toEqual({ kind });202 expect(installation).toEqual({ kind });
209 }203 }
...@@ -227,9 +221,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {...@@ -227,9 +221,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
227 '{"name":"t3","version":"0.0.45","bin":{"t3":"./dist/bin.mjs"}}',221 '{"name":"t3","version":"0.0.45","bin":{"t3":"./dist/bin.mjs"}}',
228 );222 );
229 const resolve = resolveServerInstallation.pipe(223 const resolve = resolveServerInstallation.pipe(
230 Effect.provideService(HostProcessArguments, ["node", entry]),224 Effect.provideService(HostProcess.Arguments, ["node", entry]),
231 Effect.provideService(HostProcessIsExecutable, false),225 Effect.provideService(HostProcess.IsExecutable, false),
232 Effect.provideService(HostProcessPlatform, "linux"),226 Effect.provideService(HostProcess.Platform, "linux"),
233 );227 );
234 expect(yield* resolve).toBeNull();228 expect(yield* resolve).toBeNull();
235 yield* fs.symlink(entry, globalBin);229 yield* fs.symlink(entry, globalBin);
...@@ -237,7 +231,7 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {...@@ -237,7 +231,7 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
237 yield* fs.remove(globalBin);231 yield* fs.remove(globalBin);
238 yield* fs.writeFileString(globalBin, "an unrelated t3 command");232 yield* fs.writeFileString(globalBin, "an unrelated t3 command");
239 expect(yield* resolve).toBeNull();233 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();
241 }),235 }),
242 );236 );
243237
...@@ -261,9 +255,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {...@@ -261,9 +255,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
261 );255 );
262 yield* fs.symlink(launcher, path.join(prefix, "bin/t3"));256 yield* fs.symlink(launcher, path.join(prefix, "bin/t3"));
263 const resolve = resolveServerInstallation.pipe(257 const resolve = resolveServerInstallation.pipe(
264 Effect.provideService(HostProcessExecutablePath, entry),258 Effect.provideService(HostProcess.ExecutablePath, entry),
265 Effect.provideService(HostProcessIsExecutable, true),259 Effect.provideService(HostProcess.IsExecutable, true),
266 Effect.provideService(HostProcessPlatform, "linux"),260 Effect.provideService(HostProcess.Platform, "linux"),
267 );261 );
268 for (const [version, expected] of [262 for (const [version, expected] of [
269 ["0.0.44", null],263 ["0.0.44", null],
...@@ -296,8 +290,8 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {...@@ -296,8 +290,8 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => {
296 }290 }
297 expect(291 expect(
298 yield* resolveServerInstallation.pipe(292 yield* resolveServerInstallation.pipe(
299 Effect.provideService(HostProcessArguments, ["node", entry]),293 Effect.provideService(HostProcess.Arguments, ["node", entry]),
300 Effect.provideService(HostProcessIsExecutable, false),294 Effect.provideService(HostProcess.IsExecutable, false),
301 ),295 ),
302 ).toBeNull();296 ).toBeNull();
303 }297 }
apps/server/src/cli/invocation.ts+10-16
...@@ -5,13 +5,7 @@ import * as Path from "effect/Path";...@@ -5,13 +5,7 @@ import * as Path from "effect/Path";
5import * as Schema from "effect/Schema";5import * as Schema from "effect/Schema";
66
7import type { ServerInstallation } from "@t3tools/contracts";7import type { ServerInstallation } from "@t3tools/contracts";
8import {8import * as HostProcess from "@t3tools/shared/HostProcess";
9 HostProcessArguments,
10 HostProcessEnvironment,
11 HostProcessExecutablePath,
12 HostProcessIsExecutable,
13 HostProcessPlatform,
14} from "@t3tools/shared/hostProcess";
15import { isCommandAvailable } from "@t3tools/shared/shell";9import { isCommandAvailable } from "@t3tools/shared/shell";
1610
17import packageJson from "../../package.json" with { type: "json" };11import packageJson from "../../package.json" with { type: "json" };
...@@ -60,10 +54,10 @@ const decodeInstallManifest = Schema.decodeUnknownEffect(Schema.fromJsonString(I...@@ -60,10 +54,10 @@ const decodeInstallManifest = Schema.decodeUnknownEffect(Schema.fromJsonString(I
60export const resolveServerInstallation = Effect.gen(function* () {54export const resolveServerInstallation = Effect.gen(function* () {
61 const fs = yield* FileSystem.FileSystem;55 const fs = yield* FileSystem.FileSystem;
62 const path = yield* Path.Path;56 const path = yield* Path.Path;
63 const args = yield* HostProcessArguments;57 const args = yield* HostProcess.Arguments;
64 const executable = yield* HostProcessIsExecutable;58 const executable = yield* HostProcess.IsExecutable;
65 const executablePath = yield* HostProcessExecutablePath;59 const executablePath = yield* HostProcess.ExecutablePath;
66 const platform = yield* HostProcessPlatform;60 const platform = yield* HostProcess.Platform;
67 const entry = yield* fs.realPath(executable ? executablePath : (args[1] ?? ""));61 const entry = yield* fs.realPath(executable ? executablePath : (args[1] ?? ""));
68 const match =62 const match =
69 /^(.*)\/lib\/node_modules\/t3\/(?:dist\/bin\.mjs|bin\/t3\.js|node_modules\/@t3code\/t3-[^/]+\/t3)$/.exec(63 /^(.*)\/lib\/node_modules\/t3\/(?:dist\/bin\.mjs|bin\/t3\.js|node_modules\/@t3code\/t3-[^/]+\/t3)$/.exec(
...@@ -141,7 +135,7 @@ export function formatCliCommand(input: {...@@ -141,7 +135,7 @@ export function formatCliCommand(input: {
141135
142/** `formatCliCommand` against this process's real entry path and version. */136/** `formatCliCommand` against this process's real entry path and version. */
143export const resolveCliCommand = (subcommand: string) =>137export const resolveCliCommand = (subcommand: string) =>
144 Effect.map(HostProcessArguments, (processArguments) =>138 Effect.map(HostProcess.Arguments, (processArguments) =>
145 formatCliCommand({139 formatCliCommand({
146 subcommand,140 subcommand,
147 entryPath: processArguments[1] ?? "",141 entryPath: processArguments[1] ?? "",
...@@ -161,12 +155,12 @@ const shellWord = (value: string) =>...@@ -161,12 +155,12 @@ const shellWord = (value: string) =>
161 */155 */
162const resolveInstallLauncher = Effect.gen(function* () {156const resolveInstallLauncher = Effect.gen(function* () {
163 const fs = yield* FileSystem.FileSystem;157 const fs = yield* FileSystem.FileSystem;
164 const shim = (yield* HostProcessEnvironment).T3CODE_CLI_PATH?.trim();158 const shim = (yield* HostProcess.Environment).T3CODE_CLI_PATH?.trim();
165 if (shim && (yield* fs.exists(shim).pipe(Effect.orElseSucceed(() => false)))) {159 if (shim && (yield* fs.exists(shim).pipe(Effect.orElseSucceed(() => false)))) {
166 return Option.some(shim);160 return Option.some(shim);
167 }161 }
168 return (yield* HostProcessIsExecutable)162 return (yield* HostProcess.IsExecutable)
169 ? Option.some(yield* HostProcessExecutablePath)163 ? Option.some(yield* HostProcess.ExecutablePath)
170 : Option.none<string>();164 : Option.none<string>();
171});165});
172166
...@@ -197,7 +191,7 @@ export const resolveRootCliCommand = (subcommand: string) =>...@@ -197,7 +191,7 @@ export const resolveRootCliCommand = (subcommand: string) =>
197 Effect.gen(function* () {191 Effect.gen(function* () {
198 const { command, launcher } = yield* resolveHostCliCommand(subcommand);192 const { command, launcher } = yield* resolveHostCliCommand(subcommand);
199 if (launcher) return `sudo ${command}`;193 if (launcher) return `sudo ${command}`;
200 const executablePath = yield* HostProcessExecutablePath;194 const executablePath = yield* HostProcess.ExecutablePath;
201 const systemNode = ROOT_PATH_DIRECTORIES.some((directory) =>195 const systemNode = ROOT_PATH_DIRECTORIES.some((directory) =>
202 executablePath.startsWith(`${directory}/`),196 executablePath.startsWith(`${directory}/`),
203 );197 );
apps/server/src/cli/pair.test.ts+2-2
...@@ -7,7 +7,7 @@ import * as NodePath from "node:path";...@@ -7,7 +7,7 @@ import * as NodePath from "node:path";
7import * as NodeServices from "@effect/platform-node/NodeServices";7import * as NodeServices from "@effect/platform-node/NodeServices";
8import { AuthStandardClientScopes } from "@t3tools/contracts";8import { AuthStandardClientScopes } from "@t3tools/contracts";
9import * as NetService from "@t3tools/shared/Net";9import * as NetService from "@t3tools/shared/Net";
10import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
11import { assert, describe, expect, it } from "@effect/vitest";11import { assert, describe, expect, it } from "@effect/vitest";
12import * as Effect from "effect/Effect";12import * as Effect from "effect/Effect";
13import * as Layer from "effect/Layer";13import * as Layer from "effect/Layer";
...@@ -184,7 +184,7 @@ describe("t3 pair", () => {...@@ -184,7 +184,7 @@ describe("t3 pair", () => {
184 }),184 }),
185 ).pipe(185 ).pipe(
186 Effect.provide(NodeServices.layer),186 Effect.provide(NodeServices.layer),
187 Effect.provideService(HostProcessEnvironment, {187 Effect.provideService(HostProcess.Environment, {
188 ...process.env,188 ...process.env,
189 [SERVICE_LAUNCHER_CONTEXT_ENV]: JSON.stringify({189 [SERVICE_LAUNCHER_CONTEXT_ENV]: JSON.stringify({
190 protocol: SERVICE_LAUNCHER_PROTOCOL,190 protocol: SERVICE_LAUNCHER_PROTOCOL,
apps/server/src/cli/server.ts+2-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as Effect from "effect/Effect";2import * as Effect from "effect/Effect";
3import * as FileSystem from "effect/FileSystem";3import * as FileSystem from "effect/FileSystem";
4import * as Option from "effect/Option";4import * as Option from "effect/Option";
...@@ -32,7 +32,7 @@ export const runDefaultServerCommand = (flags: CliServerFlags) =>...@@ -32,7 +32,7 @@ export const runDefaultServerCommand = (flags: CliServerFlags) =>
32 if (Option.isSome(flags.cwd)) {32 if (Option.isSome(flags.cwd)) {
33 const cwd = flags.cwd.value.trim();33 const cwd = flags.cwd.value.trim();
34 const fs = yield* FileSystem.FileSystem;34 const fs = yield* FileSystem.FileSystem;
35 const platform = yield* HostProcessPlatform;35 const platform = yield* HostProcess.Platform;
36 const explicitPath =36 const explicitPath =
37 cwd === "." ||37 cwd === "." ||
38 cwd === ".." ||38 cwd === ".." ||
apps/server/src/cli/service.test.ts+4-4
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, expect, it } from "@effect/vitest";2import { assert, expect, it } from "@effect/vitest";
3import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as NetService from "@t3tools/shared/Net";4import * as NetService from "@t3tools/shared/Net";
5import * as ConfigProvider from "effect/ConfigProvider";5import * as ConfigProvider from "effect/ConfigProvider";
6import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
...@@ -136,7 +136,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands...@@ -136,7 +136,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands
136 "--base-dir",136 "--base-dir",
137 baseDir,137 baseDir,
138 ]).pipe(138 ]).pipe(
139 Effect.provideService(HostProcessEnvironment, {}),139 Effect.provideService(HostProcess.Environment, {}),
140 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),140 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),
141 );141 );
142142
...@@ -161,7 +161,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands...@@ -161,7 +161,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands
161 "--base-dir",161 "--base-dir",
162 baseDir,162 baseDir,
163 ]).pipe(163 ]).pipe(
164 Effect.provideService(HostProcessEnvironment, {}),164 Effect.provideService(HostProcess.Environment, {}),
165 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),165 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),
166 Effect.flip,166 Effect.flip,
167 );167 );
...@@ -190,7 +190,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands...@@ -190,7 +190,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands
190 baseDir,190 baseDir,
191 "--allow-downgrade",191 "--allow-downgrade",
192 ]).pipe(192 ]).pipe(
193 Effect.provideService(HostProcessEnvironment, {}),193 Effect.provideService(HostProcess.Environment, {}),
194 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),194 Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),
195 );195 );
196196
apps/server/src/cli/service.ts+2-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as Console from "effect/Console";2import * as Console from "effect/Console";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";4import * as Layer from "effect/Layer";
...@@ -241,7 +241,7 @@ export const offerServiceDuringOnboarding = Effect.gen(function* () {...@@ -241,7 +241,7 @@ export const offerServiceDuringOnboarding = Effect.gen(function* () {
241 }241 }
242 // A LaunchAgent starts at login and dies at logout; there is no242 // A LaunchAgent starts at login and dies at logout; there is no
243 // enable-linger equivalent on macOS. Do not promise more than that.243 // enable-linger equivalent on macOS. Do not promise more than that.
244 const platform = yield* HostProcessPlatform;244 const platform = yield* HostProcess.Platform;
245 const wanted = yield* Prompt.run(245 const wanted = yield* Prompt.run(
246 Prompt.Confirm({246 Prompt.Confirm({
247 message: installed247 message: installed
apps/server/src/cli/theme.test.ts+2-2
...@@ -14,11 +14,11 @@ import { Command } from "effect/cli";...@@ -14,11 +14,11 @@ import { Command } from "effect/cli";
1414
15import { cli } from "../binCli.ts";15import { cli } from "../binCli.ts";
16import { symlinksSupported } from "@t3tools/shared/testing/symlinks";16import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
17import { HostProcessPlatform } from "@t3tools/shared/hostProcess";17import * as HostProcess from "@t3tools/shared/HostProcess";
1818
19// These force a failure with chmod, which Windows ignores for directories and19// These force a failure with chmod, which Windows ignores for directories and
20// cannot use to make a file unreadable, so the failure never happens there.20// 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
23const runCli = (args: ReadonlyArray<string>) =>23const runCli = (args: ReadonlyArray<string>) =>
24 Command.runWith(cli, { version: "0.0.0" })(args).pipe(24 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";...@@ -14,7 +14,7 @@ import * as NodeChildProcess from "node:child_process";
14import * as NodeOS from "node:os";14import * as NodeOS from "node:os";
15import * as NodeReadlinePromises from "node:readline/promises";15import * as NodeReadlinePromises from "node:readline/promises";
1616
17import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";17import * as HostProcess from "@t3tools/shared/HostProcess";
18import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell";18import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell";
19import * as Config from "effect/Config";19import * as Config from "effect/Config";
20import * as Console from "effect/Console";20import * as Console from "effect/Console";
...@@ -193,7 +193,7 @@ export const triageCommand = Command.make("triage", {...@@ -193,7 +193,7 @@ export const triageCommand = Command.make("triage", {
193 releaseTag: /^[^-+]+-(?:nightly|preview)\./.test(version)193 releaseTag: /^[^-+]+-(?:nightly|preview)\./.test(version)
194 ? `v${version} (prerelease build; if this tag does not exist, clone main)`194 ? `v${version} (prerelease build; if this tag does not exist, clone main)`
195 : `v${version}`,195 : `v${version}`,
196 os: `${yield* HostProcessPlatform} ${yield* HostProcessArchitecture} (${NodeOS.release()})`,196 os: `${yield* HostProcess.Platform} ${yield* HostProcess.Architecture} (${NodeOS.release()})`,
197 nodeVersion: process.version,197 nodeVersion: process.version,
198 launchedAs: yield* resolveCliCommand("triage"),198 launchedAs: yield* resolveCliCommand("triage"),
199 server: yield* describeServerProcess(paths.serverRuntimeStatePath),199 server: yield* describeServerProcess(paths.serverRuntimeStatePath),
apps/server/src/cli/uninstall.test.ts+2-2
...@@ -3,7 +3,7 @@ import { assert, it } from "@effect/vitest";...@@ -3,7 +3,7 @@ import { assert, it } from "@effect/vitest";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as FileSystem from "effect/FileSystem";4import * as FileSystem from "effect/FileSystem";
5import * as Path from "effect/Path";5import * as Path from "effect/Path";
6import { HostProcessPlatform } from "@t3tools/shared/hostProcess";6import * as HostProcess from "@t3tools/shared/HostProcess";
77
8import { findOwnedLauncher } from "./uninstall.ts";8import { findOwnedLauncher } from "./uninstall.ts";
99
...@@ -32,6 +32,6 @@ it.layer(NodeServices.layer)("t3 uninstall launcher", (it) => {...@@ -32,6 +32,6 @@ it.layer(NodeServices.layer)("t3 uninstall launcher", (it) => {
32 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: theirs, versionsDir }));32 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: theirs, versionsDir }));
33 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: copy, versionsDir }));33 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: copy, versionsDir }));
34 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: undefined, versionsDir }));34 assert.isUndefined(yield* findOwnedLauncher({ launchedAs: undefined, versionsDir }));
35 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),35 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
36 );36 );
37});37});
apps/server/src/cli/uninstall.ts+6-10
...@@ -4,11 +4,7 @@...@@ -4,11 +4,7 @@
4// cannot express: it kills the child when the scope closes.4// cannot express: it kills the child when the scope closes.
5import * as NodeChildProcess from "node:child_process";5import * as NodeChildProcess from "node:child_process";
66
7import {7import * as HostProcess from "@t3tools/shared/HostProcess";
8 HostProcessEnvironment,
9 HostProcessIsExecutable,
10 HostProcessPlatform,
11} from "@t3tools/shared/hostProcess";
12import * as Console from "effect/Console";8import * as Console from "effect/Console";
13import * as Effect from "effect/Effect";9import * as Effect from "effect/Effect";
14import * as FileSystem from "effect/FileSystem";10import * as FileSystem from "effect/FileSystem";
...@@ -58,7 +54,7 @@ export const findOwnedLauncher = Effect.fn("cli.uninstall.find_launcher")(functi...@@ -58,7 +54,7 @@ export const findOwnedLauncher = Effect.fn("cli.uninstall.find_launcher")(functi
58}) {54}) {
59 const fs = yield* FileSystem.FileSystem;55 const fs = yield* FileSystem.FileSystem;
60 const path = yield* Path.Path;56 const path = yield* Path.Path;
61 const platform = yield* HostProcessPlatform;57 const platform = yield* HostProcess.Platform;
62 if (input.launchedAs === undefined) return undefined;58 if (input.launchedAs === undefined) return undefined;
63 if (platform === "win32") {59 if (platform === "win32") {
64 const shimPath = yield* findWindowsShim(input.launchedAs);60 const shimPath = yield* findWindowsShim(input.launchedAs);
...@@ -87,7 +83,7 @@ const planUninstall = Effect.fn("cli.uninstall.plan")(function* (input: {...@@ -87,7 +83,7 @@ const planUninstall = Effect.fn("cli.uninstall.plan")(function* (input: {
87 path.resolve(status.installedBaseDir) === path.resolve(input.baseDir);83 path.resolve(status.installedBaseDir) === path.resolve(input.baseDir);
88 const versionsDir = pinnedRuntimeVersionsDir(path, input.baseDir);84 const versionsDir = pinnedRuntimeVersionsDir(path, input.baseDir);
89 const runtimeDir = path.dirname(versionsDir);85 const runtimeDir = path.dirname(versionsDir);
90 const launchedAs = (yield* HostProcessIsExecutable) ? yield* resolveLauncherPath : undefined;86 const launchedAs = (yield* HostProcess.IsExecutable) ? yield* resolveLauncherPath : undefined;
91 const plan: UninstallPlan = {87 const plan: UninstallPlan = {
92 service: status.supported && status.installed && servesThisHome,88 service: status.supported && status.installed && servesThisHome,
93 launcher: yield* findOwnedLauncher({ launchedAs, versionsDir }),89 launcher: yield* findOwnedLauncher({ launchedAs, versionsDir }),
...@@ -128,14 +124,14 @@ const runUninstall = Effect.fn("cli.uninstall.run")(function* (input: {...@@ -128,14 +124,14 @@ const runUninstall = Effect.fn("cli.uninstall.run")(function* (input: {
128 readonly assumeYes: boolean;124 readonly assumeYes: boolean;
129}) {125}) {
130 const fs = yield* FileSystem.FileSystem;126 const fs = yield* FileSystem.FileSystem;
131 const platform = yield* HostProcessPlatform;127 const platform = yield* HostProcess.Platform;
132 const environment = yield* HostProcessEnvironment;128 const environment = yield* HostProcess.Environment;
133 const service = yield* BootService.BootService;129 const service = yield* BootService.BootService;
134 const plan = yield* planUninstall({ baseDir: input.baseDir });130 const plan = yield* planUninstall({ baseDir: input.baseDir });
135131
136 if (!plan.service && plan.launcher === undefined && plan.runtimeDir === undefined) {132 if (!plan.service && plan.launcher === undefined && plan.runtimeDir === undefined) {
137 yield* Console.log(`Nothing to remove: t3 is not installed for ${input.baseDir}.`);133 yield* Console.log(`Nothing to remove: t3 is not installed for ${input.baseDir}.`);
138 if (!(yield* HostProcessIsExecutable)) {134 if (!(yield* HostProcess.IsExecutable)) {
139 yield* Console.log(135 yield* Console.log(
140 " 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).",136 " 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).",
141 );137 );
apps/server/src/cli/update.test.ts+13-18
...@@ -4,12 +4,7 @@ import * as Effect from "effect/Effect";...@@ -4,12 +4,7 @@ import * as Effect from "effect/Effect";
4import * as FileSystem from "effect/FileSystem";4import * as FileSystem from "effect/FileSystem";
5import * as Option from "effect/Option";5import * as Option from "effect/Option";
6import * as Path from "effect/Path";6import * as Path from "effect/Path";
7import {7import * as HostProcess from "@t3tools/shared/HostProcess";
8 HostProcessEnvironment,
9 HostProcessInvokedAs,
10 HostProcessPlatform,
11 HostProcessWorkingDirectory,
12} from "@t3tools/shared/hostProcess";
138
14import { repointLauncher, resolveLauncherPath } from "./update.ts";9import { repointLauncher, resolveLauncherPath } from "./update.ts";
1510
...@@ -37,7 +32,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {...@@ -37,7 +32,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {
3732
38 assert.deepStrictEqual(Option.getOrUndefined(repointed), launcher);33 assert.deepStrictEqual(Option.getOrUndefined(repointed), launcher);
39 assert.equal(yield* fs.readLink(launcher), newExe);34 assert.equal(yield* fs.readLink(launcher), newExe);
40 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),35 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
41 );36 );
4237
43 it.effect("leaves a plain copy or a foreign symlink alone", () =>38 it.effect("leaves a plain copy or a foreign symlink alone", () =>
...@@ -71,7 +66,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {...@@ -71,7 +66,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {
71 }66 }
72 assert.equal(yield* fs.readLink(foreign), elsewhere);67 assert.equal(yield* fs.readLink(foreign), elsewhere);
73 assert.equal(yield* fs.readLink(otherLauncher), otherHome);68 assert.equal(yield* fs.readLink(otherLauncher), otherHome);
74 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),69 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
75 );70 );
7671
77 it.effect("finds the launcher a bare command name resolved to on PATH", () =>72 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) => {...@@ -84,26 +79,26 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => {
84 yield* fs.writeFileString(launcher, "");79 yield* fs.writeFileString(launcher, "");
8580
86 const bare = yield* resolveLauncherPath.pipe(81 const bare = yield* resolveLauncherPath.pipe(
87 Effect.provideService(HostProcessInvokedAs, "t3"),82 Effect.provideService(HostProcess.InvokedAs, "t3"),
88 Effect.provideService(HostProcessEnvironment, {83 Effect.provideService(HostProcess.Environment, {
89 PATH: `${path.join(root, "missing")}:${path.join(root, "bin")}`,84 PATH: `${path.join(root, "missing")}:${path.join(root, "bin")}`,
90 }),85 }),
91 Effect.provideService(HostProcessWorkingDirectory, root),86 Effect.provideService(HostProcess.WorkingDirectory, root),
92 );87 );
93 const relative = yield* resolveLauncherPath.pipe(88 const relative = yield* resolveLauncherPath.pipe(
94 Effect.provideService(HostProcessInvokedAs, "./bin/t3"),89 Effect.provideService(HostProcess.InvokedAs, "./bin/t3"),
95 Effect.provideService(HostProcessEnvironment, { PATH: "" }),90 Effect.provideService(HostProcess.Environment, { PATH: "" }),
96 Effect.provideService(HostProcessWorkingDirectory, root),91 Effect.provideService(HostProcess.WorkingDirectory, root),
97 );92 );
98 const absent = yield* resolveLauncherPath.pipe(93 const absent = yield* resolveLauncherPath.pipe(
99 Effect.provideService(HostProcessInvokedAs, "t3"),94 Effect.provideService(HostProcess.InvokedAs, "t3"),
100 Effect.provideService(HostProcessEnvironment, { PATH: path.join(root, "missing") }),95 Effect.provideService(HostProcess.Environment, { PATH: path.join(root, "missing") }),
101 Effect.provideService(HostProcessWorkingDirectory, root),96 Effect.provideService(HostProcess.WorkingDirectory, root),
102 );97 );
10398
104 assert.equal(bare, launcher);99 assert.equal(bare, launcher);
105 assert.equal(relative, launcher);100 assert.equal(relative, launcher);
106 assert.equal(absent, undefined);101 assert.equal(absent, undefined);
107 }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")),102 }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")),
108 );103 );
109});104});
apps/server/src/cli/update.ts+12-19
...@@ -1,11 +1,4 @@...@@ -1,11 +1,4 @@
1import {1import * as HostProcess from "@t3tools/shared/HostProcess";
2 HostProcessArchitecture,
3 HostProcessEnvironment,
4 HostProcessInvokedAs,
5 HostProcessIsExecutable,
6 HostProcessPlatform,
7 HostProcessWorkingDirectory,
8} from "@t3tools/shared/hostProcess";
9import {2import {
10 CLI_RELEASE_BASE_URL_ENV,3 CLI_RELEASE_BASE_URL_ENV,
11 CLI_RELEASE_CHANNELS,4 CLI_RELEASE_CHANNELS,
...@@ -121,7 +114,7 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function...@@ -121,7 +114,7 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function
121}) {114}) {
122 const fs = yield* FileSystem.FileSystem;115 const fs = yield* FileSystem.FileSystem;
123 const path = yield* Path.Path;116 const path = yield* Path.Path;
124 const platform = yield* HostProcessPlatform;117 const platform = yield* HostProcess.Platform;
125 if (input.launchedAs === undefined) return Option.none<string>();118 if (input.launchedAs === undefined) return Option.none<string>();
126 const ownsTarget = (candidate: string) =>119 const ownsTarget = (candidate: string) =>
127 launcherOwnsVersionsDir(path, input.versionsDir, candidate);120 launcherOwnsVersionsDir(path, input.versionsDir, candidate);
...@@ -170,10 +163,10 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function...@@ -170,10 +163,10 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function
170export const resolveLauncherPath = Effect.gen(function* () {163export const resolveLauncherPath = Effect.gen(function* () {
171 const path = yield* Path.Path;164 const path = yield* Path.Path;
172 const fs = yield* FileSystem.FileSystem;165 const fs = yield* FileSystem.FileSystem;
173 const invokedAs = yield* HostProcessInvokedAs;166 const invokedAs = yield* HostProcess.InvokedAs;
174 const cwd = yield* HostProcessWorkingDirectory;167 const cwd = yield* HostProcess.WorkingDirectory;
175 const environment = yield* HostProcessEnvironment;168 const environment = yield* HostProcess.Environment;
176 const platform = yield* HostProcessPlatform;169 const platform = yield* HostProcess.Platform;
177 if (invokedAs.includes("/") || invokedAs.includes("\\")) {170 if (invokedAs.includes("/") || invokedAs.includes("\\")) {
178 return path.resolve(cwd, invokedAs);171 return path.resolve(cwd, invokedAs);
179 }172 }
...@@ -198,7 +191,7 @@ export const findWindowsShim = Effect.fn("cli.update.find_windows_shim")(functio...@@ -198,7 +191,7 @@ export const findWindowsShim = Effect.fn("cli.update.find_windows_shim")(functio
198) {191) {
199 const fs = yield* FileSystem.FileSystem;192 const fs = yield* FileSystem.FileSystem;
200 const path = yield* Path.Path;193 const path = yield* Path.Path;
201 const environment = yield* HostProcessEnvironment;194 const environment = yield* HostProcess.Environment;
202 const candidates = [195 const candidates = [
203 ...(environment["T3CODE_INSTALL_BIN_DIR"] ? [environment["T3CODE_INSTALL_BIN_DIR"]] : []),196 ...(environment["T3CODE_INSTALL_BIN_DIR"] ? [environment["T3CODE_INSTALL_BIN_DIR"]] : []),
204 ...(environment["PATH"] ?? environment["Path"] ?? "").split(";"),197 ...(environment["PATH"] ?? environment["Path"] ?? "").split(";"),
...@@ -299,7 +292,7 @@ const findForegroundServer = Effect.fn("cli.update.find_foreground_server")(func...@@ -299,7 +292,7 @@ const findForegroundServer = Effect.fn("cli.update.find_foreground_server")(func
299const belongsToBootService = Effect.fn("cli.update.belongs_to_boot_service")(function* (292const belongsToBootService = Effect.fn("cli.update.belongs_to_boot_service")(function* (
300 pid: number,293 pid: number,
301) {294) {
302 const platform = yield* HostProcessPlatform;295 const platform = yield* HostProcess.Platform;
303 const fs = yield* FileSystem.FileSystem;296 const fs = yield* FileSystem.FileSystem;
304 const runner = yield* ProcessRunner.ProcessRunner;297 const runner = yield* ProcessRunner.ProcessRunner;
305 if (platform === "linux") {298 if (platform === "linux") {
...@@ -340,9 +333,9 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: {...@@ -340,9 +333,9 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: {
340 const fs = yield* FileSystem.FileSystem;333 const fs = yield* FileSystem.FileSystem;
341 const path = yield* Path.Path;334 const path = yield* Path.Path;
342 const runner = yield* ProcessRunner.ProcessRunner;335 const runner = yield* ProcessRunner.ProcessRunner;
343 const platform = yield* HostProcessPlatform;336 const platform = yield* HostProcess.Platform;
344 const arch = yield* HostProcessArchitecture;337 const arch = yield* HostProcess.Architecture;
345 const environment = yield* HostProcessEnvironment;338 const environment = yield* HostProcess.Environment;
346 const httpClient = yield* HttpClient.HttpClient;339 const httpClient = yield* HttpClient.HttpClient;
347 const service = yield* BootService.BootService;340 const service = yield* BootService.BootService;
348341
...@@ -531,7 +524,7 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: {...@@ -531,7 +524,7 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: {
531 ),524 ),
532 );525 );
533526
534 const launchedAs = (yield* HostProcessIsExecutable) ? yield* resolveLauncherPath : undefined;527 const launchedAs = (yield* HostProcess.IsExecutable) ? yield* resolveLauncherPath : undefined;
535 const repointed = yield* repointLauncher({528 const repointed = yield* repointLauncher({
536 launchedAs,529 launchedAs,
537 versionsDir: path.dirname(runtime.versionDir),530 versionsDir: path.dirname(runtime.versionDir),
apps/server/src/cloud/bootService.test.ts+4-8
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { expect, it } from "@effect/vitest";2import { expect, it } from "@effect/vitest";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessExecutablePath,
5 HostProcessPlatform,
6 HostProcessUserId,
7} from "@t3tools/shared/hostProcess";
8import * as ConfigProvider from "effect/ConfigProvider";4import * as ConfigProvider from "effect/ConfigProvider";
9import * as Duration from "effect/Duration";5import * as Duration from "effect/Duration";
10import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
...@@ -226,9 +222,9 @@ const makeHarness = Effect.fn("test.make_boot_service_harness")(function* (...@@ -226,9 +222,9 @@ const makeHarness = Effect.fn("test.make_boot_service_harness")(function* (
226 Effect.provideService(ProcessRunner.ProcessRunner, runner),222 Effect.provideService(ProcessRunner.ProcessRunner, runner),
227 Effect.provide(223 Effect.provide(
228 Layer.mergeAll(224 Layer.mergeAll(
229 Layer.succeed(HostProcessPlatform, platform),225 Layer.succeed(HostProcess.Platform, platform),
230 Layer.succeed(HostProcessUserId, 501),226 Layer.succeed(HostProcess.UserId, 501),
231 Layer.succeed(HostProcessExecutablePath, "/usr/bin/t3"),227 Layer.succeed(HostProcess.ExecutablePath, "/usr/bin/t3"),
232 Layer.succeed(228 Layer.succeed(
233 HttpClient.HttpClient,229 HttpClient.HttpClient,
234 HttpClient.make(() => Effect.die("no release download expected")),230 HttpClient.make(() => Effect.die("no release download expected")),
apps/server/src/cloud/bootService.ts+5-10
...@@ -1,9 +1,4 @@...@@ -1,9 +1,4 @@
1import {1import * as HostProcess from "@t3tools/shared/HostProcess";
2 HostProcessArchitecture,
3 HostProcessExecutablePath,
4 HostProcessPlatform,
5 HostProcessUserId,
6} from "@t3tools/shared/hostProcess";
7import * as Config from "effect/Config";2import * as Config from "effect/Config";
8import * as Context from "effect/Context";3import * as Context from "effect/Context";
9import * as DateTime from "effect/DateTime";4import * as DateTime from "effect/DateTime";
...@@ -558,10 +553,10 @@ export const make = Effect.fn("cloud.boot_service.make")(function* (input: {...@@ -558,10 +553,10 @@ export const make = Effect.fn("cloud.boot_service.make")(function* (input: {
558 readonly cliVersion: string;553 readonly cliVersion: string;
559 readonly host?: BootServiceHost;554 readonly host?: BootServiceHost;
560}) {555}) {
561 const hostExecPath = yield* HostProcessExecutablePath;556 const hostExecPath = yield* HostProcess.ExecutablePath;
562 const platform = yield* HostProcessPlatform;557 const platform = yield* HostProcess.Platform;
563 const arch = yield* HostProcessArchitecture;558 const arch = yield* HostProcess.Architecture;
564 const uid = yield* HostProcessUserId;559 const uid = yield* HostProcess.UserId;
565 const httpClient = yield* HttpClient.HttpClient;560 const httpClient = yield* HttpClient.HttpClient;
566 const releaseBaseUrl = Option.getOrUndefined(561 const releaseBaseUrl = Option.getOrUndefined(
567 yield* Config.String(CLI_RELEASE_BASE_URL_ENV).pipe(Config.option),562 yield* Config.String(CLI_RELEASE_BASE_URL_ENV).pipe(Config.option),
apps/server/src/cloud/selfUpdate.test.ts+3-3
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { expect, it } from "@effect/vitest";2import { expect, it } from "@effect/vitest";
3import { ServerSelfUpdateError, ThreadId } from "@t3tools/contracts";3import { ServerSelfUpdateError, ThreadId } from "@t3tools/contracts";
4import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
5import * as Cause from "effect/Cause";5import * as Cause from "effect/Cause";
6import * as Deferred from "effect/Deferred";6import * as Deferred from "effect/Deferred";
7import * as Effect from "effect/Effect";7import * as Effect from "effect/Effect";
...@@ -120,8 +120,8 @@ const makeHarness = Effect.fn("test.make_self_update_harness")(function* (...@@ -120,8 +120,8 @@ const makeHarness = Effect.fn("test.make_self_update_harness")(function* (
120 },120 },
121 ),121 ),
122 Effect.provideService(HttpClient.HttpClient, releaseHttpClient(order)),122 Effect.provideService(HttpClient.HttpClient, releaseHttpClient(order)),
123 Effect.provideService(HostProcessPlatform, "linux"),123 Effect.provideService(HostProcess.Platform, "linux"),
124 Effect.provideService(HostProcessArchitecture, "x64"),124 Effect.provideService(HostProcess.Architecture, "x64"),
125 Effect.provide(ServerConfig.layer({ ...config, mode: options.mode ?? "web" })),125 Effect.provide(ServerConfig.layer({ ...config, mode: options.mode ?? "web" })),
126 );126 );
127 return { selfUpdate, order };127 return { selfUpdate, order };
apps/server/src/cloud/selfUpdate.ts+3-3
...@@ -6,7 +6,7 @@ import {...@@ -6,7 +6,7 @@ import {
6 type ServerSelfUpdateResult,6 type ServerSelfUpdateResult,
7 type ThreadId,7 type ThreadId,
8} from "@t3tools/contracts";8} from "@t3tools/contracts";
9import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";9import * as HostProcess from "@t3tools/shared/HostProcess";
10import * as Cause from "effect/Cause";10import * as Cause from "effect/Cause";
11import * as Config from "effect/Config";11import * as Config from "effect/Config";
12import * as Context from "effect/Context";12import * as Context from "effect/Context";
...@@ -176,8 +176,8 @@ export const make = Effect.fn("cloud.server_self_update.make")(function* () {...@@ -176,8 +176,8 @@ export const make = Effect.fn("cloud.server_self_update.make")(function* () {
176 const runner = yield* ProcessRunner.ProcessRunner;176 const runner = yield* ProcessRunner.ProcessRunner;
177 const fs = yield* FileSystem.FileSystem;177 const fs = yield* FileSystem.FileSystem;
178 const path = yield* Path.Path;178 const path = yield* Path.Path;
179 const platform = yield* HostProcessPlatform;179 const platform = yield* HostProcess.Platform;
180 const arch = yield* HostProcessArchitecture;180 const arch = yield* HostProcess.Architecture;
181 // Archive-distributed targets download from GitHub Releases. The client is181 // Archive-distributed targets download from GitHub Releases. The client is
182 // optional so callers without one (tests, npm-only hosts) still construct.182 // optional so callers without one (tests, npm-only hosts) still construct.
183 const httpClient = yield* HttpClient.HttpClient;183 const httpClient = yield* HttpClient.HttpClient;
apps/server/src/cloud/serviceLauncherClient.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { expect, it } from "@effect/vitest";1import { expect, it } from "@effect/vitest";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Fiber from "effect/Fiber";4import * as Fiber from "effect/Fiber";
55
...@@ -45,7 +45,7 @@ class FakeLauncherProcess {...@@ -45,7 +45,7 @@ class FakeLauncherProcess {
45const makeClient = (host: FakeLauncherProcess, currentVersion: string) =>45const makeClient = (host: FakeLauncherProcess, currentVersion: string) =>
46 ServiceLauncherClient.make({ currentVersion }).pipe(46 ServiceLauncherClient.make({ currentVersion }).pipe(
47 Effect.provideService(ServiceLauncherClient.ServiceLauncherHostProcess, host),47 Effect.provideService(ServiceLauncherClient.ServiceLauncherHostProcess, host),
48 Effect.provideService(HostProcessEnvironment, host.env),48 Effect.provideService(HostProcess.Environment, host.env),
49 );49 );
5050
51it.effect("waits for the launcher to durably commit the trial update ID", () =>51it.effect("waits for the launcher to durably commit the trial update ID", () =>
apps/server/src/cloud/serviceLauncherClient.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import type { ServerSelfUpdateOutcome } from "@t3tools/contracts";1import type { ServerSelfUpdateOutcome } from "@t3tools/contracts";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Context from "effect/Context";3import * as Context from "effect/Context";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
...@@ -114,7 +114,7 @@ export class ServiceLauncherClient extends Context.Service<...@@ -114,7 +114,7 @@ export class ServiceLauncherClient extends Context.Service<
114const resolveStartup = Effect.fn("cloud.service_launcher_client.resolve_startup")(114const resolveStartup = Effect.fn("cloud.service_launcher_client.resolve_startup")(
115 function* (options?: { readonly currentVersion?: string }) {115 function* (options?: { readonly currentVersion?: string }) {
116 const host = yield* ServiceLauncherHostProcess;116 const host = yield* ServiceLauncherHostProcess;
117 const environment = yield* HostProcessEnvironment;117 const environment = yield* HostProcess.Environment;
118 const currentVersion = options?.currentVersion ?? packageJson.version;118 const currentVersion = options?.currentVersion ?? packageJson.version;
119 const rawContext = environment[SERVICE_LAUNCHER_CONTEXT_ENV];119 const rawContext = environment[SERVICE_LAUNCHER_CONTEXT_ENV];
120 const context = rawContext === undefined ? undefined : decodeServiceLauncherContext(rawContext);120 const context = rawContext === undefined ? undefined : decodeServiceLauncherContext(rawContext);
apps/server/src/device/AgentDeviceShim.ts+2-2
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5 * types `agent-device …` and gets the version the injected instructions were5 * types `agent-device …` and gets the version the injected instructions were
6 * written for, regardless of what is or is not globally installed.6 * written for, regardless of what is or is not globally installed.
7 */7 */
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
9import { resolveNodeExecutable } from "@t3tools/shared/nodeRuntime";9import { resolveNodeExecutable } from "@t3tools/shared/nodeRuntime";
10import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
11import * as FileSystem from "effect/FileSystem";11import * as FileSystem from "effect/FileSystem";
...@@ -20,7 +20,7 @@ export const ensureAgentDeviceShim = Effect.fn("AgentDeviceShim.ensure")(functio...@@ -20,7 +20,7 @@ export const ensureAgentDeviceShim = Effect.fn("AgentDeviceShim.ensure")(functio
20 const { entryPath } = input;20 const { entryPath } = input;
21 const fs = yield* FileSystem.FileSystem;21 const fs = yield* FileSystem.FileSystem;
22 const path = yield* Path.Path;22 const path = yield* Path.Path;
23 const platform = yield* HostProcessPlatform;23 const platform = yield* HostProcess.Platform;
24 const node = yield* resolveNodeExecutable("Device automation");24 const node = yield* resolveNodeExecutable("Device automation");
25 const shimDir = path.join(input.stateDir, SHIM_DIR);25 const shimDir = path.join(input.stateDir, SHIM_DIR);
26 yield* fs.makeDirectory(shimDir, { recursive: true });26 yield* fs.makeDirectory(shimDir, { recursive: true });
apps/server/src/device/AgentDeviceTarget.test.ts+4-8
...@@ -1,9 +1,5 @@...@@ -1,9 +1,5 @@
1// @effect-diagnostics nodeBuiltinImport:off - exercises concurrent real CLI subprocesses.1// @effect-diagnostics nodeBuiltinImport:off - exercises concurrent real CLI subprocesses.
2import {2import * as HostProcess from "@t3tools/shared/HostProcess";
3 HostProcessExecutablePath,
4 HostProcessIsExecutable,
5 HostProcessPlatform,
6} from "@t3tools/shared/hostProcess";
7import { describe, expect, it } from "@effect/vitest";3import { describe, expect, it } from "@effect/vitest";
8import * as NodeChildProcess from "node:child_process";4import * as NodeChildProcess from "node:child_process";
9import * as NodeUtil from "node:util";5import * as NodeUtil from "node:util";
...@@ -26,7 +22,7 @@ describe("host-bound agent commands", () => {...@@ -26,7 +22,7 @@ describe("host-bound agent commands", () => {
26 const fs = yield* FileSystem.FileSystem;22 const fs = yield* FileSystem.FileSystem;
27 const path = yield* Path.Path;23 const path = yield* Path.Path;
28 const temp = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-target-" });24 const temp = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-target-" });
29 const platform = yield* HostProcessPlatform;25 const platform = yield* HostProcess.Platform;
30 const dir = path.join(26 const dir = path.join(
31 temp,27 temp,
32 platform === "win32" ? "paths with spaces" : "quotes '\" $HOME `literal`",28 platform === "win32" ? "paths with spaces" : "quotes '\" $HOME `literal`",
...@@ -92,8 +88,8 @@ if (process.env.AGENT_DEVICE_DAEMON_BASE_URL) process.exit(2);`,...@@ -92,8 +88,8 @@ if (process.env.AGENT_DEVICE_DAEMON_BASE_URL) process.exit(2);`,
92 }88 }
93 }).pipe(89 }).pipe(
94 Effect.scoped,90 Effect.scoped,
95 Effect.provideService(HostProcessIsExecutable, true),91 Effect.provideService(HostProcess.IsExecutable, true),
96 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),92 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
97 Effect.provide(NodeServices.layer),93 Effect.provide(NodeServices.layer),
98 ),94 ),
99 );95 );
apps/server/src/device/LocalDeviceHost.test.ts+10-15
...@@ -1,11 +1,6 @@...@@ -1,11 +1,6 @@
1import { describe, expect, it } from "@effect/vitest";1import { describe, expect, it } from "@effect/vitest";
2import * as NodePath from "@effect/platform-node/NodePath";2import * as NodePath from "@effect/platform-node/NodePath";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessEnvironment,
5 HostProcessPlatform,
6 HostProcessIsExecutable,
7 HostProcessUserId,
8} from "@t3tools/shared/hostProcess";
9import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
10import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
11import * as Option from "effect/Option";6import * as Option from "effect/Option";
...@@ -26,8 +21,8 @@ const diagnose = (...@@ -26,8 +21,8 @@ const diagnose = (
26 platform: NodeJS.Platform = "darwin",21 platform: NodeJS.Platform = "darwin",
27) =>22) =>
28 LocalDeviceHost.__testing.platformReason("android").pipe(23 LocalDeviceHost.__testing.platformReason("android").pipe(
29 Effect.provideService(HostProcessEnvironment, environment),24 Effect.provideService(HostProcess.Environment, environment),
30 Effect.provideService(HostProcessPlatform, platform),25 Effect.provideService(HostProcess.Platform, platform),
31 Effect.provideService(26 Effect.provideService(
32 FileSystem.FileSystem,27 FileSystem.FileSystem,
33 FileSystem.makeNoop({28 FileSystem.makeNoop({
...@@ -155,8 +150,8 @@ it.effect(...@@ -155,8 +150,8 @@ it.effect(
155 ] as const) {150 ] as const) {
156 const environment = { PATH: "/usr/bin", XDG_RUNTIME_DIR: runtimeDir };151 const environment = { PATH: "/usr/bin", XDG_RUNTIME_DIR: runtimeDir };
157 const result = yield* LocalDeviceHost.__testing.hubEnvironment(environment).pipe(152 const result = yield* LocalDeviceHost.__testing.hubEnvironment(environment).pipe(
158 Effect.provideService(HostProcessPlatform, platform),153 Effect.provideService(HostProcess.Platform, platform),
159 Effect.provideService(HostProcessUserId, uid),154 Effect.provideService(HostProcess.UserId, uid),
160 Effect.provideService(155 Effect.provideService(
161 FileSystem.FileSystem,156 FileSystem.FileSystem,
162 FileSystem.makeNoop({157 FileSystem.makeNoop({
...@@ -176,8 +171,8 @@ it.effect(...@@ -176,8 +171,8 @@ it.effect(
176 const missing = yield* LocalDeviceHost.__testing171 const missing = yield* LocalDeviceHost.__testing
177 .hubEnvironment({})172 .hubEnvironment({})
178 .pipe(173 .pipe(
179 Effect.provideService(HostProcessPlatform, "linux"),174 Effect.provideService(HostProcess.Platform, "linux"),
180 Effect.provideService(HostProcessUserId, 1000),175 Effect.provideService(HostProcess.UserId, 1000),
181 Effect.provideService(FileSystem.FileSystem, FileSystem.makeNoop({})),176 Effect.provideService(FileSystem.FileSystem, FileSystem.makeNoop({})),
182 );177 );
183 expect(missing.XDG_RUNTIME_DIR).toBeUndefined();178 expect(missing.XDG_RUNTIME_DIR).toBeUndefined();
...@@ -192,8 +187,8 @@ it.effect(...@@ -192,8 +187,8 @@ it.effect(
192 const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-consent-" });187 const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-consent-" });
193 const host = yield* LocalDeviceHost.make().pipe(188 const host = yield* LocalDeviceHost.make().pipe(
194 Effect.provide(Layer.mergeAll(ServerConfig.layerTest(baseDir, baseDir), NetService.layer)),189 Effect.provide(Layer.mergeAll(ServerConfig.layerTest(baseDir, baseDir), NetService.layer)),
195 Effect.provideService(HostProcessEnvironment, { HOME: baseDir, PATH: "" }),190 Effect.provideService(HostProcess.Environment, { HOME: baseDir, PATH: "" }),
196 Effect.provideService(HostProcessPlatform, "linux"),191 Effect.provideService(HostProcess.Platform, "linux"),
197 Effect.provideService(192 Effect.provideService(
198 ChildProcessSpawner.ChildProcessSpawner,193 ChildProcessSpawner.ChildProcessSpawner,
199 ChildProcessSpawner.make(() =>194 ChildProcessSpawner.make(() =>
...@@ -213,7 +208,7 @@ it.effect(...@@ -213,7 +208,7 @@ it.effect(
213 expect(yield* host.current).toBeNull();208 expect(yield* host.current).toBeNull();
214 const error = yield* host209 const error = yield* host
215 .ensureReady(() => Effect.die("Must not install without Node"))210 .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));
217 expect(error.message).toContain("Local device support requires Node.js");212 expect(error.message).toContain("Local device support requires Node.js");
218 expect(error.message).toContain("Install Node.js");213 expect(error.message).toContain("Install Node.js");
219 yield* host.stop;214 yield* host.stop;
apps/server/src/device/LocalDeviceHost.ts+10-14
...@@ -19,11 +19,7 @@ import {...@@ -19,11 +19,7 @@ import {
19 LOCAL_DEVICE_HOST_ID,19 LOCAL_DEVICE_HOST_ID,
20} from "@t3tools/contracts";20} from "@t3tools/contracts";
21import { waitForHttpReady } from "@t3tools/shared/httpReadiness";21import { waitForHttpReady } from "@t3tools/shared/httpReadiness";
22import {22import * as HostProcess from "@t3tools/shared/HostProcess";
23 HostProcessEnvironment,
24 HostProcessPlatform,
25 HostProcessUserId,
26} from "@t3tools/shared/hostProcess";
27import {23import {
28 resolveNodeExecutable,24 resolveNodeExecutable,
29 type NodeRuntimeUnavailableError,25 type NodeRuntimeUnavailableError,
...@@ -107,7 +103,7 @@ interface RunningHost {...@@ -107,7 +103,7 @@ interface RunningHost {
107const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* (103const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* (
108 platform: DevicePlatform,104 platform: DevicePlatform,
109): Effect.fn.Return<string | null, never, FileSystem.FileSystem | Path.Path> {105): Effect.fn.Return<string | null, never, FileSystem.FileSystem | Path.Path> {
110 const hostPlatform = yield* HostProcessPlatform;106 const hostPlatform = yield* HostProcess.Platform;
111 if (platform === "ios") {107 if (platform === "ios") {
112 if (hostPlatform !== "darwin") return "iOS Simulators need macOS with Xcode.";108 if (hostPlatform !== "darwin") return "iOS Simulators need macOS with Xcode.";
113 if (!(yield* isCommandAvailable("xcrun"))) return "Xcode command line tools were not found.";109 if (!(yield* isCommandAvailable("xcrun"))) return "Xcode command line tools were not found.";
...@@ -132,8 +128,8 @@ const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* (...@@ -132,8 +128,8 @@ const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* (
132const androidSdk = Effect.gen(function* () {128const androidSdk = Effect.gen(function* () {
133 const fs = yield* FileSystem.FileSystem;129 const fs = yield* FileSystem.FileSystem;
134 const path = yield* Path.Path;130 const path = yield* Path.Path;
135 const environment = yield* HostProcessEnvironment;131 const environment = yield* HostProcess.Environment;
136 const platform = yield* HostProcessPlatform;132 const platform = yield* HostProcess.Platform;
137 const home = environment.HOME ?? environment.USERPROFILE ?? "";133 const home = environment.HOME ?? environment.USERPROFILE ?? "";
138 const explicit = environment.ANDROID_HOME?.trim() || environment.ANDROID_SDK_ROOT?.trim();134 const explicit = environment.ANDROID_HOME?.trim() || environment.ANDROID_SDK_ROOT?.trim();
139 const candidates = explicit135 const candidates = explicit
...@@ -208,8 +204,8 @@ const hubEnvironment = Effect.fn("LocalDeviceHost.hubEnvironment")(function* (...@@ -208,8 +204,8 @@ const hubEnvironment = Effect.fn("LocalDeviceHost.hubEnvironment")(function* (
208 environment: NodeJS.ProcessEnv,204 environment: NodeJS.ProcessEnv,
209) {205) {
210 const env: NodeJS.ProcessEnv = { ...environment, FORCE_COLOR: "0", NO_COLOR: "1" };206 const env: NodeJS.ProcessEnv = { ...environment, FORCE_COLOR: "0", NO_COLOR: "1" };
211 const platform = yield* HostProcessPlatform;207 const platform = yield* HostProcess.Platform;
212 const uid = yield* HostProcessUserId;208 const uid = yield* HostProcess.UserId;
213 if (platform === "linux" && env.XDG_RUNTIME_DIR === undefined && uid !== undefined) {209 if (platform === "linux" && env.XDG_RUNTIME_DIR === undefined && uid !== undefined) {
214 // SSH sessions may omit the directory where the emulator publishes its gRPC token.210 // SSH sessions may omit the directory where the emulator publishes its gRPC token.
215 const runtimeDir = `/run/user/${uid}`;211 const runtimeDir = `/run/user/${uid}`;
...@@ -234,8 +230,8 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {...@@ -234,8 +230,8 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
234 const net = yield* NetService.NetService;230 const net = yield* NetService.NetService;
235 const runner = yield* ProcessRunner.ProcessRunner;231 const runner = yield* ProcessRunner.ProcessRunner;
236 const httpClient = yield* HttpClient.HttpClient;232 const httpClient = yield* HttpClient.HttpClient;
237 const environment = yield* HostProcessEnvironment;233 const environment = yield* HostProcess.Environment;
238 const hostPlatform = yield* HostProcessPlatform;234 const hostPlatform = yield* HostProcess.Platform;
239 const sdk = yield* androidSdk;235 const sdk = yield* androidSdk;
240 const hostEnvironment = deviceHostEnvironment(environment, sdk.root, hostPlatform, path);236 const hostEnvironment = deviceHostEnvironment(environment, sdk.root, hostPlatform, path);
241 const startLock = yield* Semaphore.make(1);237 const startLock = yield* Semaphore.make(1);
...@@ -406,7 +402,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {...@@ -406,7 +402,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
406 stderr: "pipe",402 stderr: "pipe",
407 env: yield* hubEnvironment(hostEnvironment).pipe(403 env: yield* hubEnvironment(hostEnvironment).pipe(
408 Effect.provideService(FileSystem.FileSystem, fs),404 Effect.provideService(FileSystem.FileSystem, fs),
409 Effect.provideService(HostProcessPlatform, hostPlatform),405 Effect.provideService(HostProcess.Platform, hostPlatform),
410 ),406 ),
411 },407 },
412 ),408 ),
...@@ -598,7 +594,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {...@@ -598,7 +594,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
598 const nodePath = yield* resolveNodeExecutable("Local device support", hostEnvironment).pipe(594 const nodePath = yield* resolveNodeExecutable("Local device support", hostEnvironment).pipe(
599 Effect.provideService(FileSystem.FileSystem, fs),595 Effect.provideService(FileSystem.FileSystem, fs),
600 Effect.provideService(Path.Path, path),596 Effect.provideService(Path.Path, path),
601 Effect.provideService(HostProcessPlatform, hostPlatform),597 Effect.provideService(HostProcess.Platform, hostPlatform),
602 );598 );
603 const installed = yield* isDeviceHubInstalled(config.baseDir).pipe(599 const installed = yield* isDeviceHubInstalled(config.baseDir).pipe(
604 Effect.provideService(FileSystem.FileSystem, fs),600 Effect.provideService(FileSystem.FileSystem, fs),
apps/server/src/device/sshDeviceScript.test.ts+4-4
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1// @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - verifies generated remote scripts using real shell and Node processes.1// @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - verifies generated remote scripts using real shell and Node processes.
2import * as Effect from "effect/Effect";2import * as Effect from "effect/Effect";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import { describe, expect, it } from "@effect/vitest";4import { describe, expect, it } from "@effect/vitest";
5import * as NodeChildProcess from "node:child_process";5import * as NodeChildProcess from "node:child_process";
6import * as NodeFSP from "node:fs/promises";6import * as NodeFSP from "node:fs/promises";
...@@ -14,7 +14,7 @@ const exec = NodeUtil.promisify(NodeChildProcess.execFile);...@@ -14,7 +14,7 @@ const exec = NodeUtil.promisify(NodeChildProcess.execFile);
1414
15it.effect("finds Android Studio Java for a non-interactive SSH session", () =>15it.effect("finds Android Studio Java for a non-interactive SSH session", () =>
16 Effect.gen(function* () {16 Effect.gen(function* () {
17 if ((yield* HostProcessPlatform) === "win32") return;17 if ((yield* HostProcess.Platform) === "win32") return;
18 yield* Effect.promise(async () => {18 yield* Effect.promise(async () => {
19 const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-ssh-java-"));19 const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-ssh-java-"));
20 try {20 try {
...@@ -38,7 +38,7 @@ it.effect("finds Android Studio Java for a non-interactive SSH session", () =>...@@ -38,7 +38,7 @@ it.effect("finds Android Studio Java for a non-interactive SSH session", () =>
3838
39it.effect("preserves shell metacharacters and newlines in remote arguments", () =>39it.effect("preserves shell metacharacters and newlines in remote arguments", () =>
40 Effect.gen(function* () {40 Effect.gen(function* () {
41 if ((yield* HostProcessPlatform) === "win32") return;41 if ((yield* HostProcess.Platform) === "win32") return;
42 yield* Effect.promise(async () => {42 yield* Effect.promise(async () => {
43 const value = "quotes ' \" ; $(echo expanded) $HOME\nnext line";43 const value = "quotes ' \" ; $(echo expanded) $HOME\nnext line";
44 const result = await exec("sh", ["-c", `printf %s ${quoteRemoteArg(value)}`]);44 const result = await exec("sh", ["-c", `printf %s ${quoteRemoteArg(value)}`]);
...@@ -50,7 +50,7 @@ it.effect("preserves shell metacharacters and newlines in remote arguments", ()...@@ -50,7 +50,7 @@ it.effect("preserves shell metacharacters and newlines in remote arguments", ()
50describe("remote helper lifecycle", () => {50describe("remote helper lifecycle", () => {
51 it.effect("reuses its own healthy helpers and stops only its own runtime", () =>51 it.effect("reuses its own healthy helpers and stops only its own runtime", () =>
52 Effect.gen(function* () {52 Effect.gen(function* () {
53 if ((yield* HostProcessPlatform) === "win32") return;53 if ((yield* HostProcess.Platform) === "win32") return;
54 yield* Effect.promise(async () => {54 yield* Effect.promise(async () => {
55 const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-remote-script-"));55 const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-remote-script-"));
56 const bin = NodePath.join(home, "bin");56 const bin = NodePath.join(home, "bin");
apps/server/src/environment/RemoteOpenTargets.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { it } from "@effect/vitest";1import { it } from "@effect/vitest";
2import { HostProcessHostname } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as NetService from "@t3tools/shared/Net";3import * as NetService from "@t3tools/shared/Net";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";5import * as Layer from "effect/Layer";
...@@ -54,7 +54,7 @@ const resolveTargets = (input: {...@@ -54,7 +54,7 @@ const resolveTargets = (input: {
54 readonly hostname: string;54 readonly hostname: string;
55}) =>55}) =>
56 Effect.flatMap(RemoteOpenTargets.RemoteOpenTargets, (service) => service.resolveTargets()).pipe(56 Effect.flatMap(RemoteOpenTargets.RemoteOpenTargets, (service) => service.resolveTargets()).pipe(
57 Effect.provideService(HostProcessHostname, input.hostname),57 Effect.provideService(HostProcess.Hostname, input.hostname),
58 Effect.provide(58 Effect.provide(
59 RemoteOpenTargets.layer.pipe(59 RemoteOpenTargets.layer.pipe(
60 Layer.provide(Layer.mergeAll(layerNet(input.sshd), layerSpawner(input.tailscale))),60 Layer.provide(Layer.mergeAll(layerNet(input.sshd), layerSpawner(input.tailscale))),
apps/server/src/environment/RemoteOpenTargets.ts+2-2
...@@ -9,7 +9,7 @@...@@ -9,7 +9,7 @@
9 * on the tailnet; `<hostname>.local` only on the same LAN).9 * on the tailnet; `<hostname>.local` only on the same LAN).
10 */10 */
11import { type RemoteOpenTarget } from "@t3tools/contracts";11import { type RemoteOpenTarget } from "@t3tools/contracts";
12import { HostProcessHostname } from "@t3tools/shared/hostProcess";12import * as HostProcess from "@t3tools/shared/HostProcess";
13import * as NetService from "@t3tools/shared/Net";13import * as NetService from "@t3tools/shared/Net";
14import { readTailscaleStatus } from "@t3tools/tailscale";14import { readTailscaleStatus } from "@t3tools/tailscale";
15import * as Context from "effect/Context";15import * as Context from "effect/Context";
...@@ -58,7 +58,7 @@ export const make = Effect.gen(function* () {...@@ -58,7 +58,7 @@ export const make = Effect.gen(function* () {
5858
59 // os.hostname() may already be an FQDN (macOS often reports59 // os.hostname() may already be an FQDN (macOS often reports
60 // "Name.local"); mDNS names are always `<first-label>.local`.60 // "Name.local"); mDNS names are always `<first-label>.local`.
61 const hostname = yield* HostProcessHostname;61 const hostname = yield* HostProcess.Hostname;
62 const shortHostname = hostname.split(".")[0]?.trim();62 const shortHostname = hostname.split(".")[0]?.trim();
63 if (shortHostname !== undefined && shortHostname.length > 0) {63 if (shortHostname !== undefined && shortHostname.length > 0) {
64 targets.push({ kind: "mdns", host: `${shortHostname}.local` });64 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";...@@ -10,12 +10,7 @@ import * as PlatformError from "effect/PlatformError";
10import * as Schema from "effect/Schema";10import * as Schema from "effect/Schema";
1111
12import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability";12import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability";
13import {13import * as HostProcess from "@t3tools/shared/HostProcess";
14 HostProcessArguments,
15 HostProcessEnvironment,
16 HostProcessIsExecutable,
17 HostProcessPlatform,
18} from "@t3tools/shared/hostProcess";
19import * as OtelEnvironment from "@t3tools/shared/otelEnvironment";14import * as OtelEnvironment from "@t3tools/shared/otelEnvironment";
2015
21import * as ServerSecretStore from "../auth/ServerSecretStore.ts";16import * as ServerSecretStore from "../auth/ServerSecretStore.ts";
...@@ -112,10 +107,10 @@ it.layer(NodeServices.layer)("ServerEnvironmentLive", (it) => {...@@ -112,10 +107,10 @@ it.layer(NodeServices.layer)("ServerEnvironmentLive", (it) => {
112 Layer.provide(ServerConfig.layer({ ...config, mode })),107 Layer.provide(ServerConfig.layer({ ...config, mode })),
113 ),108 ),
114 ),109 ),
115 Effect.provideService(HostProcessArguments, ["node", entry]),110 Effect.provideService(HostProcess.Arguments, ["node", entry]),
116 Effect.provideService(HostProcessIsExecutable, false),111 Effect.provideService(HostProcess.IsExecutable, false),
117 Effect.provideService(HostProcessPlatform, "linux"),112 Effect.provideService(HostProcess.Platform, "linux"),
118 Effect.provideService(HostProcessEnvironment, {}),113 Effect.provideService(HostProcess.Environment, {}),
119 );114 );
120 expect(descriptor.capabilities.serverInstallation).toEqual(115 expect(descriptor.capabilities.serverInstallation).toEqual(
121 mode === "web" ? { kind: "npm-global", prefix } : undefined,116 mode === "web" ? { kind: "npm-global", prefix } : undefined,
apps/server/src/environment/ServerEnvironment.ts+3-3
...@@ -4,7 +4,7 @@ import {...@@ -4,7 +4,7 @@ import {
4 PROVIDER_SEND_TURN_MAX_FILE_BYTES,4 PROVIDER_SEND_TURN_MAX_FILE_BYTES,
5 type ExecutionEnvironmentDescriptor,5 type ExecutionEnvironmentDescriptor,
6} from "@t3tools/contracts";6} from "@t3tools/contracts";
7import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";7import * as HostProcess from "@t3tools/shared/HostProcess";
8import * as Context from "effect/Context";8import * as Context from "effect/Context";
9import * as Crypto from "effect/Crypto";9import * as Crypto from "effect/Crypto";
10import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
...@@ -186,8 +186,8 @@ export const make = Effect.gen(function* () {...@@ -186,8 +186,8 @@ export const make = Effect.gen(function* () {
186 const serverConfig = yield* ServerConfig.ServerConfig;186 const serverConfig = yield* ServerConfig.ServerConfig;
187 const secrets = yield* ServerSecretStore.ServerSecretStore;187 const secrets = yield* ServerSecretStore.ServerSecretStore;
188 const identity = yield* ServerEnvironmentIdentity;188 const identity = yield* ServerEnvironmentIdentity;
189 const hostPlatform = yield* HostProcessPlatform;189 const hostPlatform = yield* HostProcess.Platform;
190 const hostArchitecture = yield* HostProcessArchitecture;190 const hostArchitecture = yield* HostProcess.Architecture;
191 const environmentId = yield* identity.getEnvironmentId;191 const environmentId = yield* identity.getEnvironmentId;
192 const cwdBaseName = path.basename(serverConfig.cwd).trim();192 const cwdBaseName = path.basename(serverConfig.cwd).trim();
193 const label = yield* resolveServerEnvironmentLabel({ cwdBaseName });193 const label = yield* resolveServerEnvironmentLabel({ cwdBaseName });
apps/server/src/environment/ServerEnvironmentLabel.test.ts+3-3
...@@ -7,7 +7,7 @@ import * as PlatformError from "effect/PlatformError";...@@ -7,7 +7,7 @@ import * as PlatformError from "effect/PlatformError";
7import * as References from "effect/References";7import * as References from "effect/References";
8import * as Schema from "effect/Schema";8import * as Schema from "effect/Schema";
9import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";9import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
10import { HostProcessHostname, HostProcessPlatform } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
11import { vi } from "vite-plus/test";11import { vi } from "vite-plus/test";
1212
13import * as ProcessRunner from "../processRunner.ts";13import * as ProcessRunner from "../processRunner.ts";
...@@ -52,8 +52,8 @@ const withHostPlatform = <ROut, E, RIn>(...@@ -52,8 +52,8 @@ const withHostPlatform = <ROut, E, RIn>(
52) =>52) =>
53 Layer.mergeAll(53 Layer.mergeAll(
54 layer,54 layer,
55 Layer.succeed(HostProcessPlatform, platform),55 Layer.succeed(HostProcess.Platform, platform),
56 Layer.succeed(HostProcessHostname, hostname),56 Layer.succeed(HostProcess.Hostname, hostname),
57 );57 );
5858
59afterEach(() => {59afterEach(() => {
apps/server/src/environment/ServerEnvironmentLabel.ts+3-3
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessHostname, HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as Effect from "effect/Effect";2import * as Effect from "effect/Effect";
3import * as FileSystem from "effect/FileSystem";3import * as FileSystem from "effect/FileSystem";
4import * as Option from "effect/Option";4import * as Option from "effect/Option";
...@@ -151,7 +151,7 @@ const runFriendlyLabelCommand = Effect.fn("runFriendlyLabelCommand")(function* (...@@ -151,7 +151,7 @@ const runFriendlyLabelCommand = Effect.fn("runFriendlyLabelCommand")(function* (
151});151});
152152
153const resolveFriendlyHostLabel = Effect.fn("resolveFriendlyHostLabel")(function* () {153const resolveFriendlyHostLabel = Effect.fn("resolveFriendlyHostLabel")(function* () {
154 const platform = yield* HostProcessPlatform;154 const platform = yield* HostProcess.Platform;
155 if (platform === "darwin") {155 if (platform === "darwin") {
156 return yield* runFriendlyLabelCommand({156 return yield* runFriendlyLabelCommand({
157 probe: "macos-computer-name",157 probe: "macos-computer-name",
...@@ -187,7 +187,7 @@ export const resolveServerEnvironmentLabel = Effect.fn("resolveServerEnvironment...@@ -187,7 +187,7 @@ export const resolveServerEnvironmentLabel = Effect.fn("resolveServerEnvironment
187 return friendlyHostLabel;187 return friendlyHostLabel;
188 }188 }
189189
190 const hostname = normalizeLabel(yield* HostProcessHostname);190 const hostname = normalizeLabel(yield* HostProcess.Hostname);
191 if (hostname) {191 if (hostname) {
192 return hostname;192 return hostname;
193 }193 }
apps/server/src/environment/ServerEnvironmentMachine.test.ts+2-2
...@@ -4,7 +4,7 @@ import * as FileSystem from "effect/FileSystem";...@@ -4,7 +4,7 @@ import * as FileSystem from "effect/FileSystem";
4import * as Layer from "effect/Layer";4import * as Layer from "effect/Layer";
5import * as PlatformError from "effect/PlatformError";5import * as PlatformError from "effect/PlatformError";
6import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";6import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
7import { HostProcessPlatform } from "@t3tools/shared/hostProcess";7import * as HostProcess from "@t3tools/shared/HostProcess";
8import { vi } from "vite-plus/test";8import { vi } from "vite-plus/test";
99
10import * as ProcessRunner from "../processRunner.ts";10import * as ProcessRunner from "../processRunner.ts";
...@@ -52,7 +52,7 @@ const layerDmiFileSystem = (files: Readonly<Record<string, string>>) =>...@@ -52,7 +52,7 @@ const layerDmiFileSystem = (files: Readonly<Record<string, string>>) =>
52 });52 });
5353
54const withPlatform = (platform: NodeJS.Platform, fileSystem = FileSystem.layerNoop({})) =>54const 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
57afterEach(() => {57afterEach(() => {
58 runMock.mockReset();58 runMock.mockReset();
apps/server/src/environment/ServerEnvironmentMachine.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import type { EnvironmentMachineKind } from "@t3tools/contracts";1import type { EnvironmentMachineKind } from "@t3tools/contracts";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as FileSystem from "effect/FileSystem";4import * as FileSystem from "effect/FileSystem";
55
...@@ -161,7 +161,7 @@ const detectLinuxMachineKind = Effect.fn("detectLinuxMachineKind")(function* ()...@@ -161,7 +161,7 @@ const detectLinuxMachineKind = Effect.fn("detectLinuxMachineKind")(function* ()
161161
162export const detectServerEnvironmentMachineKind = Effect.fn("detectServerEnvironmentMachineKind")(162export const detectServerEnvironmentMachineKind = Effect.fn("detectServerEnvironmentMachineKind")(
163 function* () {163 function* () {
164 const platform = yield* HostProcessPlatform;164 const platform = yield* HostProcess.Platform;
165 switch (platform) {165 switch (platform) {
166 case "darwin":166 case "darwin":
167 return yield* detectDarwinMachineKind();167 return yield* detectDarwinMachineKind();
apps/server/src/htmlRender/HtmlRender.test.ts+5-5
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2import * as NodeServices from "@effect/platform-node/NodeServices";2import * as NodeServices from "@effect/platform-node/NodeServices";
3import { describe, expect, it } from "@effect/vitest";3import { describe, expect, it } from "@effect/vitest";
4import { ThreadId } from "@t3tools/contracts";4import { ThreadId } from "@t3tools/contracts";
5import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
6import {6import {
7 HTML_RENDER_MEASURE_FONTS,7 HTML_RENDER_MEASURE_FONTS,
8 HTML_RENDER_MEASURE_WIDTHS,8 HTML_RENDER_MEASURE_WIDTHS,
...@@ -238,7 +238,7 @@ describe("HtmlRender", () => {...@@ -238,7 +238,7 @@ describe("HtmlRender", () => {
238 "screenshots the page in headless Chrome with the requested theme and every console level",238 "screenshots the page in headless Chrome with the requested theme and every console level",
239 (ctx) =>239 (ctx) =>
240 Effect.gen(function* () {240 Effect.gen(function* () {
241 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];241 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
242 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);242 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
243 yield* Effect.gen(function* () {243 yield* Effect.gen(function* () {
244 const htmlRender = yield* HtmlRender.HtmlRender;244 const htmlRender = yield* HtmlRender.HtmlRender;
...@@ -292,7 +292,7 @@ describe("HtmlRender", () => {...@@ -292,7 +292,7 @@ describe("HtmlRender", () => {
292 "keeps every local file but the page itself out of the browser",292 "keeps every local file but the page itself out of the browser",
293 (ctx) =>293 (ctx) =>
294 Effect.gen(function* () {294 Effect.gen(function* () {
295 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];295 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
296 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);296 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
297 yield* Effect.gen(function* () {297 yield* Effect.gen(function* () {
298 const fileSystem = yield* FileSystem.FileSystem;298 const fileSystem = yield* FileSystem.FileSystem;
...@@ -323,7 +323,7 @@ describe("HtmlRender", () => {...@@ -323,7 +323,7 @@ describe("HtmlRender", () => {
323 "keeps the page off this machine's local network",323 "keeps the page off this machine's local network",
324 (ctx) =>324 (ctx) =>
325 Effect.gen(function* () {325 Effect.gen(function* () {
326 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];326 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
327 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);327 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
328 // The page's connections go through a proxy that only reaches public328 // The page's connections go through a proxy that only reaches public
329 // addresses, and WebRTC is gone. Each line below is a way out that329 // addresses, and WebRTC is gone. Each line below is a way out that
...@@ -381,7 +381,7 @@ describe("HtmlRender", () => {...@@ -381,7 +381,7 @@ describe("HtmlRender", () => {
381 "measures a published page at every client width with a fresh load each",381 "measures a published page at every client width with a fresh load each",
382 (ctx) =>382 (ctx) =>
383 Effect.gen(function* () {383 Effect.gen(function* () {
384 const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV];384 const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV];
385 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);385 if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`);
386 yield* Effect.gen(function* () {386 yield* Effect.gen(function* () {
387 const htmlRender = yield* HtmlRender.HtmlRender;387 const htmlRender = yield* HtmlRender.HtmlRender;
apps/server/src/htmlRender/HtmlRender.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import type { ThreadId } from "@t3tools/contracts";1import type { ThreadId } from "@t3tools/contracts";
2import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import {3import {
4 clampHtmlRenderHeight,4 clampHtmlRenderHeight,
5 HTML_RENDER_COLUMN_WIDTH,5 HTML_RENDER_COLUMN_WIDTH,
...@@ -341,7 +341,7 @@ const make = Effect.gen(function* () {...@@ -341,7 +341,7 @@ const make = Effect.gen(function* () {
341 const browsers = yield* Semaphore.make(MAX_CONCURRENT_BROWSERS);341 const browsers = yield* Semaphore.make(MAX_CONCURRENT_BROWSERS);
342 // Chrome's sandbox stays on unless the operator explicitly turns it off.342 // Chrome's sandbox stays on unless the operator explicitly turns it off.
343 // Chrome also refuses it as root, where that opt-out is the only way to run.343 // 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);
345 const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND);345 const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND);
346346
347 /** Runs one browser launch; a host that cannot start it gets setup steps instead. */347 /** 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";...@@ -12,7 +12,7 @@ import * as Schema from "effect/Schema";
12import * as ServerConfig from "./config.ts";12import * as ServerConfig from "./config.ts";
13import * as Keybindings from "./keybindings.ts";13import * as Keybindings from "./keybindings.ts";
14import { KeybindingsConfigError, MAX_KEYBINDINGS_COUNT } from "@t3tools/contracts";14import { KeybindingsConfigError, MAX_KEYBINDINGS_COUNT } from "@t3tools/contracts";
15import { HostProcessPlatform } from "@t3tools/shared/hostProcess";15import * as HostProcess from "@t3tools/shared/HostProcess";
1616
17const KeybindingsConfigJson = Schema.fromJsonString(KeybindingsConfig);17const KeybindingsConfigJson = Schema.fromJsonString(KeybindingsConfig);
18const encodeKeybindingsConfigJson = Schema.encodeEffect(KeybindingsConfigJson);18const encodeKeybindingsConfigJson = Schema.encodeEffect(KeybindingsConfigJson);
...@@ -564,7 +564,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => {...@@ -564,7 +564,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => {
564 );564 );
565565
566 // chmod cannot make a directory unwritable on Windows, so the write succeeds.566 // 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")(
568 "fails when config directory is not writable",568 "fails when config directory is not writable",
569 () =>569 () =>
570 Effect.gen(function* () {570 Effect.gen(function* () {
apps/server/src/mcp/toolkits/device/handlers.ts+2-2
...@@ -9,7 +9,7 @@ import {...@@ -9,7 +9,7 @@ import {
9} from "@t3tools/contracts";9} from "@t3tools/contracts";
10import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
11import * as Path from "effect/Path";11import * as Path from "effect/Path";
12import { HostProcessPlatform } from "@t3tools/shared/hostProcess";12import * as HostProcess from "@t3tools/shared/HostProcess";
13import * as ServerConfig from "../../../config.ts";13import * as ServerConfig from "../../../config.ts";
14import { ensureAgentDeviceShim } from "../../../device/AgentDeviceShim.ts";14import { ensureAgentDeviceShim } from "../../../device/AgentDeviceShim.ts";
15import { nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";15import { nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";
...@@ -179,7 +179,7 @@ const handlers = {...@@ -179,7 +179,7 @@ const handlers = {
179 const targetArgs = [...agentDeviceTargetArgs(device), ...agentArgs];179 const targetArgs = [...agentDeviceTargetArgs(device), ...agentArgs];
180 const config = yield* ServerConfig.ServerConfig;180 const config = yield* ServerConfig.ServerConfig;
181 const path = yield* Path.Path;181 const path = yield* Path.Path;
182 const platform = yield* HostProcessPlatform;182 const platform = yield* HostProcess.Platform;
183 const shimDir = yield* ensureAgentDeviceShim({183 const shimDir = yield* ensureAgentDeviceShim({
184 entryPath: yield* devices.agentCli,184 entryPath: yield* devices.agentCli,
185 stateDir: config.stateDir,185 stateDir: config.stateDir,
apps/server/src/observability/HeapSnapshot.ts+2-2
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2import * as NodePath from "node:path";2import * as NodePath from "node:path";
3import * as NodeV8 from "node:v8";3import * as NodeV8 from "node:v8";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
6import * as DateTime from "effect/DateTime";6import * as DateTime from "effect/DateTime";
7import * as Effect from "effect/Effect";7import * as Effect from "effect/Effect";
8import * as FileSystem from "effect/FileSystem";8import * as FileSystem from "effect/FileSystem";
...@@ -40,7 +40,7 @@ export const writeHeapSnapshot = Effect.fn("server.heapSnapshot", { root: true }...@@ -40,7 +40,7 @@ export const writeHeapSnapshot = Effect.fn("server.heapSnapshot", { root: true }
40 */40 */
41export const layer = Layer.effectDiscard(41export const layer = Layer.effectDiscard(
42 Effect.gen(function* () {42 Effect.gen(function* () {
43 if ((yield* HostProcessPlatform) === "win32") return;43 if ((yield* HostProcess.Platform) === "win32") return;
44 const { logsDir } = yield* ServerConfig.ServerConfig;44 const { logsDir } = yield* ServerConfig.ServerConfig;
45 const runFork = Effect.runForkWith(yield* Effect.context<FileSystem.FileSystem>());45 const runFork = Effect.runForkWith(yield* Effect.context<FileSystem.FileSystem>());
46 const onSignal = () => void runFork(writeHeapSnapshot(logsDir));46 const onSignal = () => void runFork(writeHeapSnapshot(logsDir));
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts+9-9
...@@ -27,7 +27,7 @@ import {...@@ -27,7 +27,7 @@ import {
27 type OrchestrationV2ProviderThread,27 type OrchestrationV2ProviderThread,
28} from "@t3tools/contracts";28} from "@t3tools/contracts";
29import { GrokSettings } from "@t3tools/provider-grok/settings";29import { GrokSettings } from "@t3tools/provider-grok/settings";
30import { HostProcessIsExecutable, HostProcessPlatform } from "@t3tools/shared/hostProcess";30import * as HostProcess from "@t3tools/shared/HostProcess";
31import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";31import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
32import * as DateTime from "effect/DateTime";32import * as DateTime from "effect/DateTime";
33import * as Deferred from "effect/Deferred";33import * as Deferred from "effect/Deferred";
...@@ -705,7 +705,7 @@ describe("AcpAdapterV2", () => {...@@ -705,7 +705,7 @@ describe("AcpAdapterV2", () => {
705 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;705 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
706 const path = yield* Path.Path;706 const path = yield* Path.Path;
707 const selfInvocation = yield* resolveSelfInvocation().pipe(707 const selfInvocation = yield* resolveSelfInvocation().pipe(
708 Effect.provideService(HostProcessIsExecutable, true),708 Effect.provideService(HostProcess.IsExecutable, true),
709 );709 );
710 const mockAgentPath = yield* path.fromFileUrl(710 const mockAgentPath = yield* path.fromFileUrl(
711 new URL("../../../scripts/acp-mock-agent.ts", import.meta.url),711 new URL("../../../scripts/acp-mock-agent.ts", import.meta.url),
...@@ -1833,7 +1833,7 @@ describe("AcpAdapterV2", () => {...@@ -1833,7 +1833,7 @@ describe("AcpAdapterV2", () => {
18331833
1834 it.live("cleans detached fixtures when an assertion aborts the test scope", () =>1834 it.live("cleans detached fixtures when an assertion aborts the test scope", () =>
1835 Effect.gen(function* () {1835 Effect.gen(function* () {
1836 if ((yield* HostProcessPlatform) !== "linux") return;1836 if ((yield* HostProcess.Platform) !== "linux") return;
1837 const fileSystem = yield* FileSystem.FileSystem;1837 const fileSystem = yield* FileSystem.FileSystem;
1838 let published: ReadonlyArray<number> = [];1838 let published: ReadonlyArray<number> = [];
1839 const failed = yield* Effect.scoped(1839 const failed = yield* Effect.scoped(
...@@ -1947,7 +1947,7 @@ describe("AcpAdapterV2", () => {...@@ -1947,7 +1947,7 @@ describe("AcpAdapterV2", () => {
19471947
1948 it.live("reaps detached native work when the provider exits before explicit teardown", () =>1948 it.live("reaps detached native work when the provider exits before explicit teardown", () =>
1949 Effect.gen(function* () {1949 Effect.gen(function* () {
1950 if ((yield* HostProcessPlatform) !== "linux") return;1950 if ((yield* HostProcess.Platform) !== "linux") return;
1951 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;1951 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
1952 const fileSystem = yield* FileSystem.FileSystem;1952 const fileSystem = yield* FileSystem.FileSystem;
1953 const path = yield* Path.Path;1953 const path = yield* Path.Path;
...@@ -2026,7 +2026,7 @@ describe("AcpAdapterV2", () => {...@@ -2026,7 +2026,7 @@ describe("AcpAdapterV2", () => {
20262026
2027 it.live("surfaces reduced guarantee when delegated cgroup containment is unavailable", () =>2027 it.live("surfaces reduced guarantee when delegated cgroup containment is unavailable", () =>
2028 Effect.gen(function* () {2028 Effect.gen(function* () {
2029 if ((yield* HostProcessPlatform) !== "linux") return;2029 if ((yield* HostProcess.Platform) !== "linux") return;
2030 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;2030 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
2031 const path = yield* Path.Path;2031 const path = yield* Path.Path;
2032 const selfInvocation = yield* resolveSelfInvocation();2032 const selfInvocation = yield* resolveSelfInvocation();
...@@ -3100,7 +3100,7 @@ describe("AcpAdapterV2", () => {...@@ -3100,7 +3100,7 @@ describe("AcpAdapterV2", () => {
3100 instanceId,3100 instanceId,
3101 settings: DEFAULT_GROK_SETTINGS,3101 settings: DEFAULT_GROK_SETTINGS,
3102 environment: {},3102 environment: {},
3103 hostPlatform: yield* HostProcessPlatform,3103 hostPlatform: yield* HostProcess.Platform,
3104 selfInvocation: yield* resolveSelfInvocation(),3104 selfInvocation: yield* resolveSelfInvocation(),
3105 // Production Grok runtimes are wrapped by the x.ai prompt runtime.3105 // Production Grok runtimes are wrapped by the x.ai prompt runtime.
3106 makeRuntime: (input) =>3106 makeRuntime: (input) =>
...@@ -3147,7 +3147,7 @@ describe("AcpAdapterV2", () => {...@@ -3147,7 +3147,7 @@ describe("AcpAdapterV2", () => {
3147 instanceId,3147 instanceId,
3148 settings: DEFAULT_GROK_SETTINGS,3148 settings: DEFAULT_GROK_SETTINGS,
3149 environment: {},3149 environment: {},
3150 hostPlatform: yield* HostProcessPlatform,3150 hostPlatform: yield* HostProcess.Platform,
3151 selfInvocation: yield* resolveSelfInvocation(),3151 selfInvocation: yield* resolveSelfInvocation(),
3152 // Production Grok runtimes are wrapped by the x.ai prompt runtime.3152 // Production Grok runtimes are wrapped by the x.ai prompt runtime.
3153 makeRuntime: (input) =>3153 makeRuntime: (input) =>
...@@ -13147,7 +13147,7 @@ describe("AcpAdapterV2", () => {...@@ -13147,7 +13147,7 @@ describe("AcpAdapterV2", () => {
1314713147
13148 it.live("direct Stop skips uninterruptible ACP cancel and recovers after native teardown", () =>13148 it.live("direct Stop skips uninterruptible ACP cancel and recovers after native teardown", () =>
13149 Effect.gen(function* () {13149 Effect.gen(function* () {
13150 if ((yield* HostProcessPlatform) !== "linux") return;13150 if ((yield* HostProcess.Platform) !== "linux") return;
13151 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;13151 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
13152 const fileSystem = yield* FileSystem.FileSystem;13152 const fileSystem = yield* FileSystem.FileSystem;
13153 const idAllocator = yield* IdAllocator.IdAllocatorV2;13153 const idAllocator = yield* IdAllocator.IdAllocatorV2;
...@@ -13567,7 +13567,7 @@ describe("AcpAdapterV2", () => {...@@ -13567,7 +13567,7 @@ describe("AcpAdapterV2", () => {
1356713567
13568 it.live("restart_active terminates native work and reloads a clean runtime", () =>13568 it.live("restart_active terminates native work and reloads a clean runtime", () =>
13569 Effect.gen(function* () {13569 Effect.gen(function* () {
13570 if ((yield* HostProcessPlatform) !== "linux") return;13570 if ((yield* HostProcess.Platform) !== "linux") return;
13571 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;13571 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
13572 const fileSystem = yield* FileSystem.FileSystem;13572 const fileSystem = yield* FileSystem.FileSystem;
13573 const idAllocator = yield* IdAllocator.IdAllocatorV2;13573 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";...@@ -47,7 +47,7 @@ import * as Stream from "effect/Stream";
47import * as TestClock from "effect/testing/TestClock";47import * as TestClock from "effect/testing/TestClock";
48import { Tool } from "effect/ai";48import { Tool } from "effect/ai";
49import { formatClaudeResumeCompactionQuestion } from "@t3tools/shared/claudeCompaction";49import { formatClaudeResumeCompactionQuestion } from "@t3tools/shared/claudeCompaction";
50import { HostProcessPlatform } from "@t3tools/shared/hostProcess";50import * as HostProcess from "@t3tools/shared/HostProcess";
51import { SpawnExecutableResolution } from "@t3tools/shared/shell";51import { SpawnExecutableResolution } from "@t3tools/shared/shell";
5252
53import { attachmentRelativePath } from "../../attachmentStore.ts";53import { attachmentRelativePath } from "../../attachmentStore.ts";
...@@ -1171,7 +1171,7 @@ describe("ClaudeAdapterV2 executable path", () => {...@@ -1171,7 +1171,7 @@ describe("ClaudeAdapterV2 executable path", () => {
1171 const npmDir = "C:\\Users\\dev\\AppData\\Roaming\\npm";1171 const npmDir = "C:\\Users\\dev\\AppData\\Roaming\\npm";
1172 const packageExe = `${npmDir}\\node_modules\\@anthropic-ai\\claude-code\\bin\\claude.exe`;1172 const packageExe = `${npmDir}\\node_modules\\@anthropic-ai\\claude-code\\bin\\claude.exe`;
1173 const executablePaths = yield* captureSdkExecutablePaths("claude").pipe(1173 const executablePaths = yield* captureSdkExecutablePaths("claude").pipe(
1174 Effect.provideService(HostProcessPlatform, "win32"),1174 Effect.provideService(HostProcess.Platform, "win32"),
1175 Effect.provideService(SpawnExecutableResolution, () => `${npmDir}\\claude.cmd`),1175 Effect.provideService(SpawnExecutableResolution, () => `${npmDir}\\claude.cmd`),
1176 Effect.provideService(ClaudeExecutableFileCheck, (filePath) => filePath === packageExe),1176 Effect.provideService(ClaudeExecutableFileCheck, (filePath) => filePath === packageExe),
1177 );1177 );
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts+2-2
...@@ -8,7 +8,7 @@ import {...@@ -8,7 +8,7 @@ import {
8 type SDKUserMessage,8 type SDKUserMessage,
9} from "@anthropic-ai/claude-agent-sdk";9} from "@anthropic-ai/claude-agent-sdk";
10import * as NodeServices from "@effect/platform-node/NodeServices";10import * as NodeServices from "@effect/platform-node/NodeServices";
11import { HostProcessPlatform } from "@t3tools/shared/hostProcess";11import * as HostProcess from "@t3tools/shared/HostProcess";
12import { SpawnExecutableResolution } from "@t3tools/shared/shell";12import { SpawnExecutableResolution } from "@t3tools/shared/shell";
13import {13import {
14 ProviderReplayEntry,14 ProviderReplayEntry,
...@@ -1440,7 +1440,7 @@ async function recordMessagesUntilToolUse(input: {...@@ -1440,7 +1440,7 @@ async function recordMessagesUntilToolUse(input: {
1440const resolveClaudeRecordingExecutablePath = Effect.fn("resolveClaudeRecordingExecutablePath")(1440const resolveClaudeRecordingExecutablePath = Effect.fn("resolveClaudeRecordingExecutablePath")(
1441 function* (environment: NodeJS.ProcessEnv) {1441 function* (environment: NodeJS.ProcessEnv) {
1442 const resolveExecutable = yield* SpawnExecutableResolution;1442 const resolveExecutable = yield* SpawnExecutableResolution;
1443 const platform = yield* HostProcessPlatform;1443 const platform = yield* HostProcess.Platform;
1444 const resolved = resolveExecutable("claude", platform, environment);1444 const resolved = resolveExecutable("claude", platform, environment);
1445 if (resolved === undefined) {1445 if (resolved === undefined) {
1446 return undefined;1446 return undefined;
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts+4-4
...@@ -31,7 +31,7 @@ import type {...@@ -31,7 +31,7 @@ import type {
31 WebSearchOutput,31 WebSearchOutput,
32} from "@anthropic-ai/claude-agent-sdk/sdk-tools";32} from "@anthropic-ai/claude-agent-sdk/sdk-tools";
33import { parseCliArgs } from "@t3tools/shared/cliArgs";33import { parseCliArgs } from "@t3tools/shared/cliArgs";
34import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";34import * as HostProcess from "@t3tools/shared/HostProcess";
35import { applyClaudePromptEffortPrefix } from "@t3tools/shared/model";35import { applyClaudePromptEffortPrefix } from "@t3tools/shared/model";
36import {36import {
37 CLAUDE_RESUME_COMPACTION_NEVER_ANSWER,37 CLAUDE_RESUME_COMPACTION_NEVER_ANSWER,
...@@ -8176,7 +8176,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")(...@@ -8176,7 +8176,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")(
8176 ) {8176 ) {
8177 const { instanceId, environment, enabled, config } = input;8177 const { instanceId, environment, enabled, config } = input;
8178 const fileSystem = yield* FileSystem.FileSystem;8178 const fileSystem = yield* FileSystem.FileSystem;
8179 const hostEnvironment = yield* HostProcessEnvironment;8179 const hostEnvironment = yield* HostProcess.Environment;
8180 const idAllocator = yield* IdAllocator.IdAllocatorV2;8180 const idAllocator = yield* IdAllocator.IdAllocatorV2;
8181 const queryRunner = yield* ClaudeAgentSdkQueryRunner;8181 const queryRunner = yield* ClaudeAgentSdkQueryRunner;
8182 const serverConfig = yield* ServerConfig.ServerConfig;8182 const serverConfig = yield* ServerConfig.ServerConfig;
...@@ -8186,7 +8186,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")(...@@ -8186,7 +8186,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")(
8186 const path = yield* Path.Path;8186 const path = yield* Path.Path;
8187 const crypto = yield* Crypto.Crypto;8187 const crypto = yield* Crypto.Crypto;
8188 const binaryPath = yield* resolveClaudeSdkExecutablePath(8188 const binaryPath = yield* resolveClaudeSdkExecutablePath(
8189 expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),8189 expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
8190 claudeEnvironment,8190 claudeEnvironment,
8191 );8191 );
8192 return yield* makeClaudeAdapterV2({8192 return yield* makeClaudeAdapterV2({
...@@ -8231,7 +8231,7 @@ const makeDefaultClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2.layer")(function*...@@ -8231,7 +8231,7 @@ const makeDefaultClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2.layer")(function*
8231 const fileSystem = yield* FileSystem.FileSystem;8231 const fileSystem = yield* FileSystem.FileSystem;
8232 const path = yield* Path.Path;8232 const path = yield* Path.Path;
8233 const crypto = yield* Crypto.Crypto;8233 const crypto = yield* Crypto.Crypto;
8234 const hostEnvironment = yield* HostProcessEnvironment;8234 const hostEnvironment = yield* HostProcess.Environment;
8235 const idAllocator = yield* IdAllocator.IdAllocatorV2;8235 const idAllocator = yield* IdAllocator.IdAllocatorV2;
8236 const queryRunner = yield* ClaudeAgentSdkQueryRunner;8236 const queryRunner = yield* ClaudeAgentSdkQueryRunner;
8237 const serverConfig = yield* ServerConfig.ServerConfig;8237 const serverConfig = yield* ServerConfig.ServerConfig;
apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts+6-6
...@@ -29,7 +29,7 @@ import {...@@ -29,7 +29,7 @@ import {
29 TurnItemId,29 TurnItemId,
30} from "@t3tools/contracts";30} from "@t3tools/contracts";
31import { assert, describe, it } from "@effect/vitest";31import { assert, describe, it } from "@effect/vitest";
32import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";32import * as HostProcess from "@t3tools/shared/HostProcess";
33import { SpawnExecutableResolution } from "@t3tools/shared/shell";33import { SpawnExecutableResolution } from "@t3tools/shared/shell";
34import * as CodexClient from "effect-codex-app-server/client";34import * as CodexClient from "effect-codex-app-server/client";
35import * as CodexError from "effect-codex-app-server/errors";35import * as CodexError from "effect-codex-app-server/errors";
...@@ -698,8 +698,8 @@ describe("CodexAdapterV2 process spawning", () => {...@@ -698,8 +698,8 @@ describe("CodexAdapterV2 process spawning", () => {
698 assert.deepEqual(command.options.env, { CUSTOM: "1" });698 assert.deepEqual(command.options.env, { CUSTOM: "1" });
699 assert.equal(command.options.extendEnv, true);699 assert.equal(command.options.extendEnv, true);
700 }).pipe(700 }).pipe(
701 Effect.provideService(HostProcessPlatform, "win32"),701 Effect.provideService(HostProcess.Platform, "win32"),
702 Effect.provideService(HostProcessEnvironment, {702 Effect.provideService(HostProcess.Environment, {
703 PATH: "C:\\Windows\\System32",703 PATH: "C:\\Windows\\System32",
704 HOST_ONLY: "1",704 HOST_ONLY: "1",
705 }),705 }),
...@@ -726,7 +726,7 @@ describe("CodexAdapterV2 process spawning", () => {...@@ -726,7 +726,7 @@ describe("CodexAdapterV2 process spawning", () => {
726 assert.deepEqual(command.args, ["app-server"]);726 assert.deepEqual(command.args, ["app-server"]);
727 assert.equal(command.options.shell, false);727 assert.equal(command.options.shell, false);
728 }).pipe(728 }).pipe(
729 Effect.provideService(HostProcessPlatform, "win32"),729 Effect.provideService(HostProcess.Platform, "win32"),
730 Effect.provideService(SpawnExecutableResolution, () => "C:\\bin\\codex.exe"),730 Effect.provideService(SpawnExecutableResolution, () => "C:\\bin\\codex.exe"),
731 ),731 ),
732 );732 );
...@@ -774,7 +774,7 @@ describe("CodexAdapterV2 process spawning", () => {...@@ -774,7 +774,7 @@ describe("CodexAdapterV2 process spawning", () => {
774 ["app-server", "--strict-config", "-c", "model_reasoning_summary=detailed"],774 ["app-server", "--strict-config", "-c", "model_reasoning_summary=detailed"],
775 ["app-server", "--enable", "env-feature"],775 ["app-server", "--enable", "env-feature"],
776 ]);776 ]);
777 }).pipe(Effect.provideService(HostProcessPlatform, "linux")),777 }).pipe(Effect.provideService(HostProcess.Platform, "linux")),
778 );778 );
779779
780 it.effect("expands ~ in the configured binary path before spawning", () =>780 it.effect("expands ~ in the configured binary path before spawning", () =>
...@@ -821,7 +821,7 @@ describe("CodexAdapterV2 process spawning", () => {...@@ -821,7 +821,7 @@ describe("CodexAdapterV2 process spawning", () => {
821 Effect.provide(821 Effect.provide(
822 Layer.mergeAll(IdAllocator.layer, McpProviderSessions.layer, NodeServices.layer),822 Layer.mergeAll(IdAllocator.layer, McpProviderSessions.layer, NodeServices.layer),
823 ),823 ),
824 Effect.provideService(HostProcessPlatform, "linux"),824 Effect.provideService(HostProcess.Platform, "linux"),
825 ),825 ),
826 );826 );
827});827});
apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts+4-4
...@@ -30,7 +30,7 @@ import {...@@ -30,7 +30,7 @@ import {
30 type ProviderSetupError,30 type ProviderSetupError,
31} from "@t3tools/contracts";31} from "@t3tools/contracts";
32import { SKILL_MENTION_PATTERN } from "@t3tools/shared/composerInlineTokens";32import { SKILL_MENTION_PATTERN } from "@t3tools/shared/composerInlineTokens";
33import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";33import * as HostProcess from "@t3tools/shared/HostProcess";
34import { dynamicToolTitle } from "@t3tools/shared/toolActivity";34import { dynamicToolTitle } from "@t3tools/shared/toolActivity";
35import { getModelSelectionStringOptionValue, modelSelectionsEqual } from "@t3tools/shared/model";35import { getModelSelectionStringOptionValue, modelSelectionsEqual } from "@t3tools/shared/model";
36import { resolveSpawnCommand } from "@t3tools/shared/shell";36import { resolveSpawnCommand } from "@t3tools/shared/shell";
...@@ -1562,7 +1562,7 @@ export const createCodexAdapterV2 = (...@@ -1562,7 +1562,7 @@ export const createCodexAdapterV2 = (
1562 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;1562 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
1563 const crypto = yield* Crypto.Crypto;1563 const crypto = yield* Crypto.Crypto;
1564 const fileSystem = yield* FileSystem.FileSystem;1564 const fileSystem = yield* FileSystem.FileSystem;
1565 const hostEnvironment = yield* HostProcessEnvironment;1565 const hostEnvironment = yield* HostProcess.Environment;
1566 const idAllocator = yield* IdAllocator.IdAllocatorV2;1566 const idAllocator = yield* IdAllocator.IdAllocatorV2;
1567 const serverConfig = yield* ServerConfig;1567 const serverConfig = yield* ServerConfig;
1568 const homeLayout = yield* resolveCodexHomeLayout(config);1568 const homeLayout = yield* resolveCodexHomeLayout(config);
...@@ -1582,7 +1582,7 @@ export const createCodexAdapterV2 = (...@@ -1582,7 +1582,7 @@ export const createCodexAdapterV2 = (
1582 const settings = {1582 const settings = {
1583 ...config,1583 ...config,
1584 enabled,1584 enabled,
1585 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),1585 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
1586 homePath: homeLayout.effectiveHomePath ?? "",1586 homePath: homeLayout.effectiveHomePath ?? "",
1587 } satisfies CodexSettings;1587 } satisfies CodexSettings;
15881588
...@@ -1623,7 +1623,7 @@ const layer: Layer.Layer<...@@ -1623,7 +1623,7 @@ const layer: Layer.Layer<
1623 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;1623 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
1624 const crypto = yield* Crypto.Crypto;1624 const crypto = yield* Crypto.Crypto;
1625 const fileSystem = yield* FileSystem.FileSystem;1625 const fileSystem = yield* FileSystem.FileSystem;
1626 const hostEnvironment = yield* HostProcessEnvironment;1626 const hostEnvironment = yield* HostProcess.Environment;
1627 const idAllocator = yield* IdAllocator.IdAllocatorV2;1627 const idAllocator = yield* IdAllocator.IdAllocatorV2;
1628 const serverConfig = yield* ServerConfig;1628 const serverConfig = yield* ServerConfig;
16291629
apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.testkit.ts+2-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import type { InteractionUpdate, RunResult } from "@cursor/sdk";2import type { InteractionUpdate, RunResult } from "@cursor/sdk";
3import * as NodeServices from "@effect/platform-node/NodeServices";3import * as NodeServices from "@effect/platform-node/NodeServices";
4import {4import {
...@@ -519,7 +519,7 @@ export function layer(...@@ -519,7 +519,7 @@ export function layer(
519 // Skill discovery also scans user roots under HOME; an empty HOME keeps519 // Skill discovery also scans user roots under HOME; an empty HOME keeps
520 // replays from picking up the host's own skills.520 // replays from picking up the host's own skills.
521 const layerHostEnvironment = Layer.effect(521 const layerHostEnvironment = Layer.effect(
522 HostProcessEnvironment,522 HostProcess.Environment,
523 Effect.gen(function* () {523 Effect.gen(function* () {
524 const fs = yield* FileSystem.FileSystem;524 const fs = yield* FileSystem.FileSystem;
525 const home = yield* fs.makeTempDirectoryScoped({ prefix: "t3-cursor-replay-home-" });525 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 {...@@ -7,7 +7,7 @@ import {
7 ThreadId,7 ThreadId,
8} from "@t3tools/contracts";8} from "@t3tools/contracts";
9import { GrokSettings } from "@t3tools/provider-grok/settings";9import { GrokSettings } from "@t3tools/provider-grok/settings";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
11import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";11import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
12import * as EffectAcpErrors from "effect-acp/errors";12import * as EffectAcpErrors from "effect-acp/errors";
13import { xAiRateLimitedErrorCode } from "@t3tools/provider-grok/testing";13import { xAiRateLimitedErrorCode } from "@t3tools/provider-grok/testing";
...@@ -364,7 +364,7 @@ describe("Grok launch permission mode", () => {...@@ -364,7 +364,7 @@ describe("Grok launch permission mode", () => {
364 return launches;364 return launches;
365 }).pipe(365 }).pipe(
366 // Keep the launch argv unwrapped by the Linux cgroup shim.366 // Keep the launch argv unwrapped by the Linux cgroup shim.
367 Effect.provideService(HostProcessPlatform, "darwin"),367 Effect.provideService(HostProcess.Platform, "darwin"),
368 Effect.provide(layerTest),368 Effect.provide(layerTest),
369 );369 );
370370
apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.testkit.ts+2-2
...@@ -6,7 +6,7 @@ import * as Layer from "effect/Layer";...@@ -6,7 +6,7 @@ import * as Layer from "effect/Layer";
6import * as Path from "effect/Path";6import * as Path from "effect/Path";
7import * as Schema from "effect/Schema";7import * as Schema from "effect/Schema";
8import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";8import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
9import { HostProcessPlatform } from "@t3tools/shared/hostProcess";9import * as HostProcess from "@t3tools/shared/HostProcess";
10import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";10import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
1111
12import * as TestProviderHost from "@t3tools/provider-testing/TestProviderHost";12import * as TestProviderHost from "@t3tools/provider-testing/TestProviderHost";
...@@ -43,7 +43,7 @@ function layerGrokProviderAdapterRegistryReplay(...@@ -43,7 +43,7 @@ function layerGrokProviderAdapterRegistryReplay(
43 const fileSystem = yield* FileSystem.FileSystem;43 const fileSystem = yield* FileSystem.FileSystem;
44 const path = yield* Path.Path;44 const path = yield* Path.Path;
45 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;45 const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
46 const hostPlatform = yield* HostProcessPlatform;46 const hostPlatform = yield* HostProcess.Platform;
47 // Same queue the continuation worker drains when the fixture runs it.47 // Same queue the continuation worker drains when the fixture runs it.
48 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;48 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
49 const replayGate = options.replayGate;49 const replayGate = options.replayGate;
apps/server/src/orchestration-v2/workflowScriptQuery.ts+2-2
...@@ -18,7 +18,7 @@ import * as NodePath from "node:path";...@@ -18,7 +18,7 @@ import * as NodePath from "node:path";
1818
19import { OrchestrationGetWorkflowScriptError } from "@t3tools/contracts";19import { OrchestrationGetWorkflowScriptError } from "@t3tools/contracts";
20import * as Effect from "effect/Effect";20import * as Effect from "effect/Effect";
21import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";21import * as HostProcess from "@t3tools/shared/HostProcess";
2222
23const SCRIPT_BYTE_CAP = 256 * 1024;23const SCRIPT_BYTE_CAP = 256 * 1024;
2424
...@@ -38,7 +38,7 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")(...@@ -38,7 +38,7 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")(
38 });38 });
39 }39 }
4040
41 const home = yield* HostProcessHomeDirectory;41 const home = yield* HostProcess.HomeDirectory;
42 const root = yield* Effect.tryPromise({42 const root = yield* Effect.tryPromise({
43 try: () => NodeFSP.realpath(scriptsRoot(home)),43 try: () => NodeFSP.realpath(scriptsRoot(home)),
44 catch: (cause) =>44 catch: (cause) =>
apps/server/src/os-jank.ts+5-9
...@@ -1,8 +1,4 @@...@@ -1,8 +1,4 @@
1import {1import * as HostProcess from "@t3tools/shared/HostProcess";
2 HostProcessEnvironment,
3 HostProcessHomeDirectory,
4 HostProcessPlatform,
5} from "@t3tools/shared/hostProcess";
6import {2import {
7 listLoginShellCandidates,3 listLoginShellCandidates,
8 mergePathEntries,4 mergePathEntries,
...@@ -57,8 +53,8 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return<...@@ -57,8 +53,8 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return<
57 never,53 never,
58 FileSystem.FileSystem | Path.Path54 FileSystem.FileSystem | Path.Path
59> {55> {
60 const platform = yield* HostProcessPlatform;56 const platform = yield* HostProcess.Platform;
61 const env = yield* HostProcessEnvironment;57 const env = yield* HostProcess.Environment;
6258
63 if (platform === "win32") {59 if (platform === "win32") {
64 const repairedEnvironment = yield* resolveWindowsEnvironment(env).pipe(60 const repairedEnvironment = yield* resolveWindowsEnvironment(env).pipe(
...@@ -97,7 +93,7 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return<...@@ -97,7 +93,7 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return<
9793
98export const expandHomePath = Effect.fn(function* (input: string) {94export const expandHomePath = Effect.fn(function* (input: string) {
99 const { join } = yield* Path.Path;95 const { join } = yield* Path.Path;
100 const home = yield* HostProcessHomeDirectory;96 const home = yield* HostProcess.HomeDirectory;
101 if (input === "~") {97 if (input === "~") {
102 return home;98 return home;
103 }99 }
...@@ -110,7 +106,7 @@ export const expandHomePath = Effect.fn(function* (input: string) {...@@ -110,7 +106,7 @@ export const expandHomePath = Effect.fn(function* (input: string) {
110export const resolveBaseDir = Effect.fn(function* (raw: string | undefined) {106export const resolveBaseDir = Effect.fn(function* (raw: string | undefined) {
111 const { join, resolve } = yield* Path.Path;107 const { join, resolve } = yield* Path.Path;
112 if (!raw || raw.trim().length === 0) {108 if (!raw || raw.trim().length === 0) {
113 return join(yield* HostProcessHomeDirectory, ".t3");109 return join(yield* HostProcess.HomeDirectory, ".t3");
114 }110 }
115 return resolve(yield* expandHomePath(raw.trim()));111 return resolve(yield* expandHomePath(raw.trim()));
116});112});
apps/server/src/preview/PortScanner.test.ts+4-4
...@@ -6,7 +6,7 @@ import {...@@ -6,7 +6,7 @@ import {
6 PREVIEW_URL_MAX_LENGTH,6 PREVIEW_URL_MAX_LENGTH,
7 type DiscoveredLocalServer,7 type DiscoveredLocalServer,
8} from "@t3tools/contracts";8} from "@t3tools/contracts";
9import { HostProcessPlatform } from "@t3tools/shared/hostProcess";9import * as HostProcess from "@t3tools/shared/HostProcess";
10import * as Net from "@t3tools/shared/Net";10import * as Net from "@t3tools/shared/Net";
11import * as Cause from "effect/Cause";11import * as Cause from "effect/Cause";
12import * as Clock from "effect/Clock";12import * as Clock from "effect/Clock";
...@@ -74,7 +74,7 @@ const layerProbeFailure = (...@@ -74,7 +74,7 @@ const layerProbeFailure = (
74 reserveLoopbackPort: () => Effect.succeed(40_000),74 reserveLoopbackPort: () => Effect.succeed(40_000),
75 findAvailablePort: (preferred) => Effect.succeed(preferred),75 findAvailablePort: (preferred) => Effect.succeed(preferred),
76 }),76 }),
77 Layer.succeed(HostProcessPlatform, "linux"),77 Layer.succeed(HostProcess.Platform, "linux"),
78 FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetch))),78 FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetch))),
79 ),79 ),
80 ),80 ),
...@@ -86,7 +86,7 @@ const layerTestPortDiscovery = PortScanner.layer.pipe(...@@ -86,7 +86,7 @@ const layerTestPortDiscovery = PortScanner.layer.pipe(
86 layerNoProc,86 layerNoProc,
87 layerTestProcessRunner,87 layerTestProcessRunner,
88 layerTestIntegrationNet,88 layerTestIntegrationNet,
89 Layer.succeed(HostProcessPlatform, "win32"),89 Layer.succeed(HostProcess.Platform, "win32"),
90 FetchHttpClient.layer,90 FetchHttpClient.layer,
91 ),91 ),
92 ),92 ),
...@@ -122,7 +122,7 @@ const layerLsofScanner = (input: {...@@ -122,7 +122,7 @@ const layerLsofScanner = (input: {
122 reserveLoopbackPort: () => Effect.succeed(40_000),122 reserveLoopbackPort: () => Effect.succeed(40_000),
123 findAvailablePort: (preferred) => Effect.succeed(preferred),123 findAvailablePort: (preferred) => Effect.succeed(preferred),
124 }),124 }),
125 Layer.succeed(HostProcessPlatform, "linux"),125 Layer.succeed(HostProcess.Platform, "linux"),
126 FetchHttpClient.layer.pipe(126 FetchHttpClient.layer.pipe(
127 Layer.provide(Layer.succeed(FetchHttpClient.Fetch, input.fetch)),127 Layer.provide(Layer.succeed(FetchHttpClient.Fetch, input.fetch)),
128 ),128 ),
apps/server/src/preview/PortScanner.ts+2-2
...@@ -25,7 +25,7 @@ import {...@@ -25,7 +25,7 @@ import {
25 ThreadId,25 ThreadId,
26 type DiscoveredLocalServer,26 type DiscoveredLocalServer,
27} from "@t3tools/contracts";27} from "@t3tools/contracts";
28import { HostProcessPlatform } from "@t3tools/shared/hostProcess";28import * as HostProcess from "@t3tools/shared/HostProcess";
29import * as Net from "@t3tools/shared/Net";29import * as Net from "@t3tools/shared/Net";
30import { isLoopbackHost, LSOF_LOCAL_HOST_TOKENS } from "@t3tools/shared/preview";30import { isLoopbackHost, LSOF_LOCAL_HOST_TOKENS } from "@t3tools/shared/preview";
31import * as Cause from "effect/Cause";31import * as Cause from "effect/Cause";
...@@ -342,7 +342,7 @@ export const make = Effect.gen(function* PortDiscoveryMake() {...@@ -342,7 +342,7 @@ export const make = Effect.gen(function* PortDiscoveryMake() {
342 const net = yield* Net.NetService;342 const net = yield* Net.NetService;
343 const processRunner = yield* ProcessRunner.ProcessRunner;343 const processRunner = yield* ProcessRunner.ProcessRunner;
344 const fileSystem = yield* FileSystem.FileSystem;344 const fileSystem = yield* FileSystem.FileSystem;
345 const hostPlatform = yield* HostProcessPlatform;345 const hostPlatform = yield* HostProcess.Platform;
346 const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.withScope);346 const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.withScope);
347 const stateRef = yield* Ref.make<ScannerState>({347 const stateRef = yield* Ref.make<ScannerState>({
348 listeners: new Map(),348 listeners: new Map(),
apps/server/src/preview/PreviewBrowser.test.ts+4-4
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { expect, it } from "@effect/vitest";2import { expect, it } from "@effect/vitest";
3import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Deferred from "effect/Deferred";4import * as Deferred from "effect/Deferred";
5import * as Crypto from "effect/Crypto";5import * as Crypto from "effect/Crypto";
6import type * as Duration from "effect/Duration";6import type * as Duration from "effect/Duration";
...@@ -20,7 +20,7 @@ import * as PreviewBrowser from "./PreviewBrowser.ts";...@@ -20,7 +20,7 @@ import * as PreviewBrowser from "./PreviewBrowser.ts";
2020
21// POSIX modes cannot be checked on NTFS, so follow the host like the Antigravity suite.21// POSIX modes cannot be checked on NTFS, so follow the host like the Antigravity suite.
22const hostPlatform: NodeJS.Platform =22const hostPlatform: NodeJS.Platform =
23 HostProcessPlatform.defaultValue() === "win32" ? "win32" : "linux";23 HostProcess.Platform.defaultValue() === "win32" ? "win32" : "linux";
24const executableName =24const executableName =
25 hostPlatform === "win32" ? "chrome-headless-shell.exe" : "chrome-headless-shell";25 hostPlatform === "win32" ? "chrome-headless-shell.exe" : "chrome-headless-shell";
26const ROOT = "chrome-headless-shell-fixture/";26const ROOT = "chrome-headless-shell-fixture/";
...@@ -105,8 +105,8 @@ const makeHarness = Effect.fn("test.makePreviewBrowser")(function* (...@@ -105,8 +105,8 @@ const makeHarness = Effect.fn("test.makePreviewBrowser")(function* (
105 },105 },
106 ...(options.wait === undefined ? {} : { wait: options.wait }),106 ...(options.wait === undefined ? {} : { wait: options.wait }),
107 }).pipe(107 }).pipe(
108 Effect.provideService(HostProcessPlatform, hostPlatform),108 Effect.provideService(HostProcess.Platform, hostPlatform),
109 Effect.provideService(HostProcessArchitecture, "x64"),109 Effect.provideService(HostProcess.Architecture, "x64"),
110 Effect.provideService(110 Effect.provideService(
111 HttpClient.HttpClient,111 HttpClient.HttpClient,
112 HttpClient.make((request) =>112 HttpClient.make((request) =>
apps/server/src/preview/PreviewBrowser.ts+3-3
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest.1// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest.
2import * as EffectNodeStream from "@effect/platform-node/NodeStream";2import * as EffectNodeStream from "@effect/platform-node/NodeStream";
3import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Cause from "effect/Cause";4import * as Cause from "effect/Cause";
5import * as Clock from "effect/Clock";5import * as Clock from "effect/Clock";
6import * as Context from "effect/Context";6import * as Context from "effect/Context";
...@@ -175,8 +175,8 @@ export const makePreviewBrowser = Effect.fn("PreviewBrowser.make")(function* (...@@ -175,8 +175,8 @@ export const makePreviewBrowser = Effect.fn("PreviewBrowser.make")(function* (
175 const http = yield* HttpClient.HttpClient;175 const http = yield* HttpClient.HttpClient;
176 // Installs belong to the service, so they finish even when no caller is still waiting.176 // Installs belong to the service, so they finish even when no caller is still waiting.
177 const serviceScope = yield* Effect.scope;177 const serviceScope = yield* Effect.scope;
178 const platform = yield* HostProcessPlatform;178 const platform = yield* HostProcess.Platform;
179 const arch = yield* HostProcessArchitecture;179 const arch = yield* HostProcess.Architecture;
180 const release =180 const release =
181 options.release === undefined ? previewBrowserRelease(platform, arch) : options.release;181 options.release === undefined ? previewBrowserRelease(platform, arch) : options.release;
182 const wait = options.wait ?? "45 seconds";182 const wait = options.wait ?? "45 seconds";
apps/server/src/preview/PreviewBrowserHost.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { describe, expect, it } from "@effect/vitest";1import { describe, expect, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Sink from "effect/Sink";4import * as Sink from "effect/Sink";
5import * as Stream from "effect/Stream";5import * as Stream from "effect/Stream";
...@@ -67,7 +67,7 @@ const diagnose = (input: {...@@ -67,7 +67,7 @@ const diagnose = (input: {
67 setupCommand: "sudo t3 browser setup",67 setupCommand: "sudo t3 browser setup",
68 }).pipe(68 }).pipe(
69 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),69 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
70 Effect.provideService(HostProcessPlatform, input.platform),70 Effect.provideService(HostProcess.Platform, input.platform),
71 Effect.map((error) => ({ error, commands })),71 Effect.map((error) => ({ error, commands })),
72 );72 );
73};73};
apps/server/src/preview/PreviewBrowserHost.ts+3-3
...@@ -7,7 +7,7 @@...@@ -7,7 +7,7 @@
7 * gets the command instead, and only the operator's explicit7 * gets the command instead, and only the operator's explicit
8 * `T3CODE_SERVER_BROWSER_SANDBOX=0` launches without it.8 * `T3CODE_SERVER_BROWSER_SANDBOX=0` launches without it.
9 */9 */
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
11import * as Effect from "effect/Effect";11import * as Effect from "effect/Effect";
12import * as FileSystem from "effect/FileSystem";12import * as FileSystem from "effect/FileSystem";
13import * as Schema from "effect/Schema";13import * as Schema from "effect/Schema";
...@@ -108,7 +108,7 @@ export const diagnoseLaunchFailure = Effect.fn("PreviewBrowserHost.diagnoseLaunc...@@ -108,7 +108,7 @@ export const diagnoseLaunchFailure = Effect.fn("PreviewBrowserHost.diagnoseLaunc
108 if (input.output.includes(NO_SANDBOX_SIGNATURE)) {108 if (input.output.includes(NO_SANDBOX_SIGNATURE)) {
109 return new PreviewBrowserSandboxError({ setupCommand });109 return new PreviewBrowserSandboxError({ setupCommand });
110 }110 }
111 if ((yield* HostProcessPlatform) !== "linux") return undefined;111 if ((yield* HostProcess.Platform) !== "linux") return undefined;
112 const libraries = yield* missingLibraries(input.executable);112 const libraries = yield* missingLibraries(input.executable);
113 return libraries.length === 0113 return libraries.length === 0
114 ? undefined114 ? undefined
...@@ -147,7 +147,7 @@ export const missingLibraries = Effect.fn("PreviewBrowserHost.missingLibraries")...@@ -147,7 +147,7 @@ export const missingLibraries = Effect.fn("PreviewBrowserHost.missingLibraries")
147 * root, so the server checks it at startup.147 * root, so the server checks it at startup.
148 */148 */
149export const sandboxBlocked = Effect.gen(function* () {149export const sandboxBlocked = Effect.gen(function* () {
150 if ((yield* HostProcessPlatform) !== "linux") return false;150 if ((yield* HostProcess.Platform) !== "linux") return false;
151 const fs = yield* FileSystem.FileSystem;151 const fs = yield* FileSystem.FileSystem;
152 const restricted = yield* fs.readFileString(USERNS_RESTRICTION).pipe(152 const restricted = yield* fs.readFileString(USERNS_RESTRICTION).pipe(
153 Effect.map((value) => value.trim() === "1"),153 Effect.map((value) => value.trim() === "1"),
apps/server/src/preview/ServerBrowser.ts+3-7
...@@ -42,11 +42,7 @@ import {...@@ -42,11 +42,7 @@ import {
42 SERVER_BROWSER_AUTOMATION_CLIENT_ID,42 SERVER_BROWSER_AUTOMATION_CLIENT_ID,
43 type PreviewAppearancePreference,43 type PreviewAppearancePreference,
44} from "@t3tools/contracts";44} from "@t3tools/contracts";
45import {45import * as HostProcess from "@t3tools/shared/HostProcess";
46 HostProcessArchitecture,
47 HostProcessEnvironment,
48 HostProcessPlatform,
49} from "@t3tools/shared/hostProcess";
50import { normalizePreviewUrl } from "@t3tools/shared/preview";46import { normalizePreviewUrl } from "@t3tools/shared/preview";
51import { resolvePreviewViewport } from "@t3tools/shared/previewViewport";47import { resolvePreviewViewport } from "@t3tools/shared/previewViewport";
52import * as NodeCrypto from "node:crypto";48import * as NodeCrypto from "node:crypto";
...@@ -476,7 +472,7 @@ const CLIPBOARD_SCRIPT = `(() => {...@@ -476,7 +472,7 @@ const CLIPBOARD_SCRIPT = `(() => {
476472
477const make = Effect.gen(function* () {473const make = Effect.gen(function* () {
478 const config = yield* ServerConfig.ServerConfig;474 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 };
480 const manager = yield* PreviewManager.PreviewManager;476 const manager = yield* PreviewManager.PreviewManager;
481 const broker = yield* PreviewAutomationBroker.PreviewAutomationBroker;477 const broker = yield* PreviewAutomationBroker.PreviewAutomationBroker;
482 const environment = yield* ServerEnvironment.ServerEnvironment;478 const environment = yield* ServerEnvironment.ServerEnvironment;
...@@ -2367,7 +2363,7 @@ const make = Effect.gen(function* () {...@@ -2367,7 +2363,7 @@ const make = Effect.gen(function* () {
2367 yield* manager.events.pipe(Stream.runForEach(mirrorManagerEvent), Effect.forkScoped);2363 yield* manager.events.pipe(Stream.runForEach(mirrorManagerEvent), Effect.forkScoped);
2368 // Whoever runs the server learns the fix before anyone opens a tab.2364 // Whoever runs the server learns the fix before anyone opens a tab.
2369 if (2365 if (
2370 !PreviewBrowserHost.sandboxDisabled(yield* HostProcessEnvironment) &&2366 !PreviewBrowserHost.sandboxDisabled(yield* HostProcess.Environment) &&
2371 (yield* PreviewBrowserHost.sandboxBlocked)2367 (yield* PreviewBrowserHost.sandboxBlocked)
2372 ) {2368 ) {
2373 yield* Effect.logWarning(2369 yield* Effect.logWarning(
apps/server/src/process/externalLauncher.test.ts+5-5
...@@ -17,7 +17,7 @@ import * as Stream from "effect/Stream";...@@ -17,7 +17,7 @@ import * as Stream from "effect/Stream";
17import * as TestClock from "effect/testing/TestClock";17import * as TestClock from "effect/testing/TestClock";
18import { ChildProcess, ChildProcessSpawner } from "effect/process";18import { ChildProcess, ChildProcessSpawner } from "effect/process";
1919
20import { HostProcessPlatform } from "@t3tools/shared/hostProcess";20import * as HostProcess from "@t3tools/shared/HostProcess";
21import { SpawnExecutableResolution } from "@t3tools/shared/shell";21import { SpawnExecutableResolution } from "@t3tools/shared/shell";
22import * as ExternalLauncher from "./externalLauncher.ts";22import * as ExternalLauncher from "./externalLauncher.ts";
2323
...@@ -25,7 +25,7 @@ import * as ExternalLauncher from "./externalLauncher.ts";...@@ -25,7 +25,7 @@ import * as ExternalLauncher from "./externalLauncher.ts";
25// directory to a posix-mocked resolver as PATH. On a Windows host the temp25// directory to a posix-mocked resolver as PATH. On a Windows host the temp
26// path carries a drive letter, so the posix `:` split shatters it; there is26// path carries a drive letter, so the posix `:` split shatters it; there is
27// no posix executable to find there anyway.27// no posix executable to find there anyway.
28const windowsHost = HostProcessPlatform.defaultValue() === "win32";28const windowsHost = HostProcess.Platform.defaultValue() === "win32";
2929
30interface MockSpawnResult {30interface MockSpawnResult {
31 readonly exitCode?: number;31 readonly exitCode?: number;
...@@ -85,7 +85,7 @@ const layerTest = (input: {...@@ -85,7 +85,7 @@ const layerTest = (input: {
8585
86 return Layer.mergeAll(86 return Layer.mergeAll(
87 ExternalLauncher.layer.pipe(Layer.provide(Layer.merge(NodeServices.layer, layerSpawner))),87 ExternalLauncher.layer.pipe(Layer.provide(Layer.merge(NodeServices.layer, layerSpawner))),
88 Layer.succeed(HostProcessPlatform, input.platform),88 Layer.succeed(HostProcess.Platform, input.platform),
89 Layer.succeed(89 Layer.succeed(
90 SpawnExecutableResolution,90 SpawnExecutableResolution,
91 (command) => input.resolveExecutable?.(command) ?? command,91 (command) => input.resolveExecutable?.(command) ?? command,
...@@ -1302,7 +1302,7 @@ it.effect("memoizes editor discovery and refreshes after the cache window", () =...@@ -1302,7 +1302,7 @@ it.effect("memoizes editor discovery and refreshes after the cache window", () =
1302 Effect.provide(1302 Effect.provide(
1303 Layer.mergeAll(1303 Layer.mergeAll(
1304 layerLauncher,1304 layerLauncher,
1305 Layer.succeed(HostProcessPlatform, "win32"),1305 Layer.succeed(HostProcess.Platform, "win32"),
1306 ConfigProvider.layer(1306 ConfigProvider.layer(
1307 ConfigProvider.fromEnv({1307 ConfigProvider.fromEnv({
1308 env: {1308 env: {
...@@ -1367,7 +1367,7 @@ it.effect("keeps scanning after the caller is interrupted and shares that scan",...@@ -1367,7 +1367,7 @@ it.effect("keeps scanning after the caller is interrupted and shares that scan",
1367 Effect.provide(1367 Effect.provide(
1368 Layer.mergeAll(1368 Layer.mergeAll(
1369 layerLauncher,1369 layerLauncher,
1370 Layer.succeed(HostProcessPlatform, "win32"),1370 Layer.succeed(HostProcess.Platform, "win32"),
1371 ConfigProvider.layer(1371 ConfigProvider.layer(
1372 ConfigProvider.fromEnv({1372 ConfigProvider.fromEnv({
1373 env: {1373 env: {
apps/server/src/process/externalLauncher.ts+5-5
...@@ -19,7 +19,7 @@ import {...@@ -19,7 +19,7 @@ import {
19 type LaunchEditorInput,19 type LaunchEditorInput,
20} from "@t3tools/contracts";20} from "@t3tools/contracts";
21import { resolveEditorCommand } from "@t3tools/shared/editor";21import { resolveEditorCommand } from "@t3tools/shared/editor";
22import { HostProcessPlatform } from "@t3tools/shared/hostProcess";22import * as HostProcess from "@t3tools/shared/HostProcess";
23import {23import {
24 isCommandAvailable,24 isCommandAvailable,
25 resolveSpawnCommand,25 resolveSpawnCommand,
...@@ -441,20 +441,20 @@ const buildAvailableEditors = Effect.fn("externalLauncher.buildAvailableEditors"...@@ -441,20 +441,20 @@ const buildAvailableEditors = Effect.fn("externalLauncher.buildAvailableEditors"
441const resolveBrowserLaunch = Effect.fn("externalLauncher.resolveBrowserLaunch")(function* (441const resolveBrowserLaunch = Effect.fn("externalLauncher.resolveBrowserLaunch")(function* (
442 target: string,442 target: string,
443) {443) {
444 const platform = yield* HostProcessPlatform;444 const platform = yield* HostProcess.Platform;
445 const env = yield* readBrowserLaunchEnv;445 const env = yield* readBrowserLaunchEnv;
446 return buildBrowserLaunch(target, platform, env);446 return buildBrowserLaunch(target, platform, env);
447});447});
448448
449const resolveAvailableEditors = Effect.fn("externalLauncher.resolveAvailableEditors")(function* () {449const resolveAvailableEditors = Effect.fn("externalLauncher.resolveAvailableEditors")(function* () {
450 const platform = yield* HostProcessPlatform;450 const platform = yield* HostProcess.Platform;
451 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };451 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };
452 return yield* buildAvailableEditors(platform, env).pipe(withPathDirectoryListings);452 return yield* buildAvailableEditors(platform, env).pipe(withPathDirectoryListings);
453});453});
454454
455const resolveFileManagerRevealKind = Effect.fn("externalLauncher.resolveFileManagerRevealKind")(455const resolveFileManagerRevealKind = Effect.fn("externalLauncher.resolveFileManagerRevealKind")(
456 function* () {456 function* () {
457 const platform = yield* HostProcessPlatform;457 const platform = yield* HostProcess.Platform;
458 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };458 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };
459 return yield* fileManagerRevealKindForPlatform(platform, env);459 return yield* fileManagerRevealKindForPlatform(platform, env);
460 },460 },
...@@ -519,7 +519,7 @@ const resolveEditorLaunch = Effect.fn("resolveEditorLaunch")(function* (...@@ -519,7 +519,7 @@ const resolveEditorLaunch = Effect.fn("resolveEditorLaunch")(function* (
519 ExternalLauncherError,519 ExternalLauncherError,
520 FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner520 FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner
521> {521> {
522 const platform = yield* HostProcessPlatform;522 const platform = yield* HostProcess.Platform;
523 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };523 const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) };
524 yield* Effect.annotateCurrentSpan({524 yield* Effect.annotateCurrentSpan({
525 "externalLauncher.editor": input.editor,525 "externalLauncher.editor": input.editor,
apps/server/src/processRunner.test.ts+4-4
...@@ -9,7 +9,7 @@ import * as Sink from "effect/Sink";...@@ -9,7 +9,7 @@ import * as Sink from "effect/Sink";
9import * as Stream from "effect/Stream";9import * as Stream from "effect/Stream";
10import { TestClock } from "effect/testing";10import { TestClock } from "effect/testing";
11import { ChildProcessSpawner } from "effect/process";11import { ChildProcessSpawner } from "effect/process";
12import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";12import * as HostProcess from "@t3tools/shared/HostProcess";
13import { SpawnExecutableResolution } from "@t3tools/shared/shell";13import { SpawnExecutableResolution } from "@t3tools/shared/shell";
1414
15import * as ProcessRunner from "./processRunner.ts";15import * as ProcessRunner from "./processRunner.ts";
...@@ -145,8 +145,8 @@ describe("runProcess", () => {...@@ -145,8 +145,8 @@ describe("runProcess", () => {
145 args: ["repos", "pr", "list", "--source-branch", "feature & release"],145 args: ["repos", "pr", "list", "--source-branch", "feature & release"],
146 env: { AZURE_CONFIG_DIR: "C:\\Users\\tester\\.azure" },146 env: { AZURE_CONFIG_DIR: "C:\\Users\\tester\\.azure" },
147 }).pipe(147 }).pipe(
148 Effect.provideService(HostProcessPlatform, "win32"),148 Effect.provideService(HostProcess.Platform, "win32"),
149 Effect.provideService(HostProcessEnvironment, {149 Effect.provideService(HostProcess.Environment, {
150 PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm",150 PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm",
151 PATHEXT: ".COM;.EXE;.BAT;.CMD",151 PATHEXT: ".COM;.EXE;.BAT;.CMD",
152 }),152 }),
...@@ -407,7 +407,7 @@ describe("isWindowsCommandNotFound", () => {...@@ -407,7 +407,7 @@ describe("isWindowsCommandNotFound", () => {
407 const isCommandNotFound = yield* ProcessRunner.isWindowsCommandNotFound(407 const isCommandNotFound = yield* ProcessRunner.isWindowsCommandNotFound(
408 1,408 1,
409 "wird nicht als interner oder externer Befehl, betriebsfahiges Programm oder Batch-Datei erkannt",409 "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"));
411 expect(isCommandNotFound).toBe(true);411 expect(isCommandNotFound).toBe(true);
412 }),412 }),
413 );413 );
apps/server/src/project/AgentSessionScanner.ts+4-8
...@@ -44,11 +44,7 @@ import {...@@ -44,11 +44,7 @@ import {
44 parseGitHubRepositoryNameWithOwnerFromRemoteUrl,44 parseGitHubRepositoryNameWithOwnerFromRemoteUrl,
45 parseOriginUrlFromGitConfig,45 parseOriginUrlFromGitConfig,
46} from "@t3tools/shared/git";46} from "@t3tools/shared/git";
47import {47import * as HostProcess from "@t3tools/shared/HostProcess";
48 HostProcessEnvironment,
49 HostProcessHomeDirectory,
50 HostProcessPlatform,
51} from "@t3tools/shared/hostProcess";
52import { normalizeProjectPathForComparison } from "@t3tools/shared/path";48import { normalizeProjectPathForComparison } from "@t3tools/shared/path";
5349
54import * as ServerConfig from "../config.ts";50import * as ServerConfig from "../config.ts";
...@@ -633,9 +629,9 @@ export const make = Effect.gen(function* () {...@@ -633,9 +629,9 @@ export const make = Effect.gen(function* () {
633 const worktreesDir = path.resolve(serverConfig.worktreesDir);629 const worktreesDir = path.resolve(serverConfig.worktreesDir);
634 // Windows filesystems are case-insensitive, so path prefix checks there630 // Windows filesystems are case-insensitive, so path prefix checks there
635 // must case fold.631 // must case fold.
636 const foldWorktreeCase = (yield* HostProcessPlatform) === "win32";632 const foldWorktreeCase = (yield* HostProcess.Platform) === "win32";
637 const hostEnvironment = yield* HostProcessEnvironment;633 const hostEnvironment = yield* HostProcess.Environment;
638 const homeDir = yield* HostProcessHomeDirectory;634 const homeDir = yield* HostProcess.HomeDirectory;
639 // `/private/tmp` is what macOS reports for sessions started in `/tmp`.635 // `/private/tmp` is what macOS reports for sessions started in `/tmp`.
640 const excludedProjectRoots = new Set(636 const excludedProjectRoots = new Set(
641 [homeDir, NodeOS.tmpdir(), "/tmp", "/private/tmp"].map((directory) =>637 [homeDir, NodeOS.tmpdir(), "/tmp", "/private/tmp"].map((directory) =>
apps/server/src/project/ProjectSetupScriptRunner.ts+3-3
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { ProjectId, type ProjectScript } from "@t3tools/contracts";1import { ProjectId, type ProjectScript } from "@t3tools/contracts";
2import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import {3import {
4 projectScriptRuntimeEnv,4 projectScriptRuntimeEnv,
5 resolveProjectScripts,5 resolveProjectScripts,
...@@ -206,8 +206,8 @@ export const make = Effect.gen(function* () {...@@ -206,8 +206,8 @@ export const make = Effect.gen(function* () {
206 const serverSettings = yield* ServerSettings.ServerSettingsService;206 const serverSettings = yield* ServerSettings.ServerSettingsService;
207 const crypto = yield* Crypto.Crypto;207 const crypto = yield* Crypto.Crypto;
208 const completionShell = resolveCompletionShell(208 const completionShell = resolveCompletionShell(
209 yield* HostProcessPlatform,209 yield* HostProcess.Platform,
210 yield* HostProcessEnvironment,210 yield* HostProcess.Environment,
211 );211 );
212212
213 /**213 /**
apps/server/src/provider/AntigravityInstallation.test.ts+7-12
...@@ -1,11 +1,6 @@...@@ -1,11 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { expect, it } from "@effect/vitest";2import { expect, it } from "@effect/vitest";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessArchitecture,
5 HostProcessEnvironment,
6 HostProcessIsExecutable,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
9import * as Crypto from "effect/Crypto";4import * as Crypto from "effect/Crypto";
10import * as Deferred from "effect/Deferred";5import * as Deferred from "effect/Deferred";
11import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
...@@ -62,7 +57,7 @@ const zipFixtures = {...@@ -62,7 +57,7 @@ const zipFixtures = {
62// the host and let the fixture names follow; the suite is about install57// the host and let the fixture names follow; the suite is about install
63// mechanics, which are the same on every platform.58// mechanics, which are the same on every platform.
64const hostPlatform: NodeJS.Platform =59const hostPlatform: NodeJS.Platform =
65 HostProcessPlatform.defaultValue() === "win32" ? "win32" : "linux";60 HostProcess.Platform.defaultValue() === "win32" ? "win32" : "linux";
66const completeArchive = Buffer.from(61const completeArchive = Buffer.from(
67 hostPlatform === "win32" ? zipFixtures.windows : zipFixtures.complete,62 hostPlatform === "win32" ? zipFixtures.windows : zipFixtures.complete,
68 "base64",63 "base64",
...@@ -189,9 +184,9 @@ const makeHarness = Effect.fn("test.makeAntigravityInstallation")(function* (...@@ -189,9 +184,9 @@ const makeHarness = Effect.fn("test.makeAntigravityInstallation")(function* (
189 }),184 }),
190 }).pipe(185 }).pipe(
191 Effect.provideService(FileSystem.FileSystem, trackedFs),186 Effect.provideService(FileSystem.FileSystem, trackedFs),
192 Effect.provideService(HostProcessPlatform, platform),187 Effect.provideService(HostProcess.Platform, platform),
193 Effect.provideService(HostProcessArchitecture, "x64"),188 Effect.provideService(HostProcess.Architecture, "x64"),
194 Effect.provideService(HostProcessEnvironment, { PATH: options.path ?? "" }),189 Effect.provideService(HostProcess.Environment, { PATH: options.path ?? "" }),
195 Effect.provideService(190 Effect.provideService(
196 HttpClient.HttpClient,191 HttpClient.HttpClient,
197 HttpClient.make((request) =>192 HttpClient.make((request) =>
...@@ -259,7 +254,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => {...@@ -259,7 +254,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => {
259 });254 });
260 expect(requests).toEqual([]);255 expect(requests).toEqual([]);
261 expect(validations).toEqual([]);256 expect(validations).toEqual([]);
262 }).pipe(Effect.provideService(HostProcessIsExecutable, true)),257 }).pipe(Effect.provideService(HostProcess.IsExecutable, true)),
263 );258 );
264259
265 it.effect("verifies both files before activating a streamed download", () =>260 it.effect("verifies both files before activating a streamed download", () =>
...@@ -734,7 +729,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => {...@@ -734,7 +729,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => {
734729
735 // Real posix executables in a real temp dir, resolved by a linux-mocked730 // Real posix executables in a real temp dir, resolved by a linux-mocked
736 // PATH walk; a Windows temp path cannot be split on `:`.731 // 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")(
738 "honors explicit paths and reports invalid overrides without falling back",733 "honors explicit paths and reports invalid overrides without falling back",
739 () =>734 () =>
740 Effect.gen(function* () {735 Effect.gen(function* () {
apps/server/src/provider/AntigravityInstallation.ts+5-9
...@@ -1,11 +1,7 @@...@@ -1,11 +1,7 @@
1// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest or free-space query.1// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest or free-space query.
2import * as EffectNodeStream from "@effect/platform-node/NodeStream";2import * as EffectNodeStream from "@effect/platform-node/NodeStream";
3import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts";3import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts";
4import {4import * as HostProcess from "@t3tools/shared/HostProcess";
5 HostProcessArchitecture,
6 HostProcessEnvironment,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
9import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";5import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";
10import * as Clock from "effect/Clock";6import * as Clock from "effect/Clock";
11import * as Cause from "effect/Cause";7import * as Cause from "effect/Cause";
...@@ -156,9 +152,9 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma...@@ -156,9 +152,9 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma
156 const http = yield* HttpClient.HttpClient;152 const http = yield* HttpClient.HttpClient;
157 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;153 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
158 const serviceScope = yield* Effect.scope;154 const serviceScope = yield* Effect.scope;
159 const platform = yield* HostProcessPlatform;155 const platform = yield* HostProcess.Platform;
160 const arch = yield* HostProcessArchitecture;156 const arch = yield* HostProcess.Architecture;
161 const environment = yield* HostProcessEnvironment;157 const environment = yield* HostProcess.Environment;
162 const releaseAsset =158 const releaseAsset =
163 options.releaseAsset === undefined159 options.releaseAsset === undefined
164 ? resolveAntigravityReleaseAsset(platform, arch)160 ? resolveAntigravityReleaseAsset(platform, arch)
...@@ -410,7 +406,7 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma...@@ -410,7 +406,7 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma
410 yield* resolveNodeExecutable("Antigravity", environment).pipe(406 yield* resolveNodeExecutable("Antigravity", environment).pipe(
411 Effect.provideService(FileSystem.FileSystem, fs),407 Effect.provideService(FileSystem.FileSystem, fs),
412 Effect.provideService(Path.Path, path),408 Effect.provideService(Path.Path, path),
413 Effect.provideService(HostProcessPlatform, platform),409 Effect.provideService(HostProcess.Platform, platform),
414 Effect.mapError((cause) =>410 Effect.mapError((cause) =>
415 installationError("verify", nodeRuntimeUnavailableMessage("Antigravity"), cause),411 installationError("verify", nodeRuntimeUnavailableMessage("Antigravity"), cause),
416 ),412 ),
apps/server/src/provider/CodexInstallation.test.ts+4-8
...@@ -1,11 +1,7 @@...@@ -1,11 +1,7 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import * as ModelManifest from "./ModelManifest.ts";2import * as ModelManifest from "./ModelManifest.ts";
3import { expect, it } from "@effect/vitest";3import { expect, it } from "@effect/vitest";
4import {4import * as HostProcess from "@t3tools/shared/HostProcess";
5 HostProcessArchitecture,
6 HostProcessEnvironment,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
9import * as Crypto from "effect/Crypto";5import * as Crypto from "effect/Crypto";
10import * as Deferred from "effect/Deferred";6import * as Deferred from "effect/Deferred";
11import * as Effect from "effect/Effect";7import * as Effect from "effect/Effect";
...@@ -66,9 +62,9 @@ const makeHarness = Effect.fn("test.makeCodexInstallation")(function* (...@@ -66,9 +62,9 @@ const makeHarness = Effect.fn("test.makeCodexInstallation")(function* (
66 forceRefresh: Effect.succeed(ModelManifest.BUNDLED_MODEL_MANIFEST),62 forceRefresh: Effect.succeed(ModelManifest.BUNDLED_MODEL_MANIFEST),
67 refreshInBackground: Effect.void,63 refreshInBackground: Effect.void,
68 }),64 }),
69 Effect.provideService(HostProcessPlatform, "darwin"),65 Effect.provideService(HostProcess.Platform, "darwin"),
70 Effect.provideService(HostProcessArchitecture, "arm64"),66 Effect.provideService(HostProcess.Architecture, "arm64"),
71 Effect.provideService(HostProcessEnvironment, { PATH: input.local ? localDirectory : "" }),67 Effect.provideService(HostProcess.Environment, { PATH: input.local ? localDirectory : "" }),
72 Effect.provideService(68 Effect.provideService(
73 HttpClient.HttpClient,69 HttpClient.HttpClient,
74 HttpClient.make((request) =>70 HttpClient.make((request) =>
apps/server/src/provider/CodexInstallation.ts+6-10
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest.1// @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest.
2import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts";2import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessArchitecture,
5 HostProcessEnvironment,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
8import { resolveCommandPath, resolveSpawnCommand } from "@t3tools/shared/shell";4import { resolveCommandPath, resolveSpawnCommand } from "@t3tools/shared/shell";
9import * as Clock from "effect/Clock";5import * as Clock from "effect/Clock";
10import * as Cause from "effect/Cause";6import * as Cause from "effect/Cause";
...@@ -169,9 +165,9 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function...@@ -169,9 +165,9 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function
169 const http = yield* HttpClient.HttpClient;165 const http = yield* HttpClient.HttpClient;
170 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;166 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
171 const serviceScope = yield* Effect.scope;167 const serviceScope = yield* Effect.scope;
172 const platform = yield* HostProcessPlatform;168 const platform = yield* HostProcess.Platform;
173 const environment = yield* HostProcessEnvironment;169 const environment = yield* HostProcess.Environment;
174 const arch = yield* HostProcessArchitecture;170 const arch = yield* HostProcess.Architecture;
175 const asset =171 const asset =
176 options.releaseAsset === undefined172 options.releaseAsset === undefined
177 ? resolveCodexReleaseAsset(platform, arch)173 ? resolveCodexReleaseAsset(platform, arch)
...@@ -311,7 +307,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function...@@ -311,7 +307,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function
311 args: ReadonlyArray<string>,307 args: ReadonlyArray<string>,
312 ) {308 ) {
313 const resolved = yield* resolveSpawnCommand(command, args).pipe(309 const resolved = yield* resolveSpawnCommand(command, args).pipe(
314 Effect.provideService(HostProcessPlatform, platform),310 Effect.provideService(HostProcess.Platform, platform),
315 );311 );
316 const child = yield* spawner.spawn(312 const child = yield* spawner.spawn(
317 ChildProcess.make(resolved.command, resolved.args, { shell: resolved.shell }),313 ChildProcess.make(resolved.command, resolved.args, { shell: resolved.shell }),
...@@ -335,7 +331,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function...@@ -335,7 +331,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function
335 const resolveLocal = Effect.fn("CodexInstallation.resolveLocal")(331 const resolveLocal = Effect.fn("CodexInstallation.resolveLocal")(
336 function* () {332 function* () {
337 const executablePath = yield* resolveCommandPath("codex", { env: environment }).pipe(333 const executablePath = yield* resolveCommandPath("codex", { env: environment }).pipe(
338 Effect.provideService(HostProcessPlatform, platform),334 Effect.provideService(HostProcess.Platform, platform),
339 Effect.provideService(FileSystem.FileSystem, fs),335 Effect.provideService(FileSystem.FileSystem, fs),
340 Effect.provideService(Path.Path, path),336 Effect.provideService(Path.Path, path),
341 );337 );
apps/server/src/provider/CodexProvider.ts+2-2
...@@ -47,7 +47,7 @@ import {...@@ -47,7 +47,7 @@ import {
47 type CodexRateLimitSnapshot,47 type CodexRateLimitSnapshot,
48 type CodexResetCreditsSummary,48 type CodexResetCreditsSummary,
49} from "./codexUsageLimits.ts";49} from "./codexUsageLimits.ts";
50import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";50import * as HostProcess from "@t3tools/shared/HostProcess";
51import packageJson from "../../package.json" with { type: "json" };51import packageJson from "../../package.json" with { type: "json" };
52const isCodexAppServerSpawnError = Schema.is(CodexErrors.CodexAppServerSpawnError);52const isCodexAppServerSpawnError = Schema.is(CodexErrors.CodexAppServerSpawnError);
53const RATE_LIMITS_PROBE_TIMEOUT_MS = 3_000;53const RATE_LIMITS_PROBE_TIMEOUT_MS = 3_000;
...@@ -376,7 +376,7 @@ export const withCodexAppServerClient = Effect.fn("withCodexAppServerClient")(fu...@@ -376,7 +376,7 @@ export const withCodexAppServerClient = Effect.fn("withCodexAppServerClient")(fu
376 // "CODEX_HOME points to '~/.codex_work', but that path does not exist".376 // "CODEX_HOME points to '~/.codex_work', but that path does not exist".
377 // Expand here for parity with `CodexTextGeneration`.377 // Expand here for parity with `CodexTextGeneration`.
378 const resolvedHomePath = input.homePath378 const resolvedHomePath = input.homePath
379 ? expandHomePath(input.homePath, yield* HostProcessHomeDirectory)379 ? expandHomePath(input.homePath, yield* HostProcess.HomeDirectory)
380 : undefined;380 : undefined;
381 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;381 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
382 const environment = {382 const environment = {
apps/server/src/provider/Drivers/AntigravityDriver.test.ts+6-11
...@@ -5,12 +5,7 @@ import {...@@ -5,12 +5,7 @@ import {
5 ProviderInstanceId,5 ProviderInstanceId,
6 type AntigravitySettings,6 type AntigravitySettings,
7} from "@t3tools/contracts";7} from "@t3tools/contracts";
8import {8import * as HostProcess from "@t3tools/shared/HostProcess";
9 HostProcessEnvironment,
10 HostProcessExecutablePath,
11 HostProcessIsExecutable,
12 HostProcessPlatform,
13} from "@t3tools/shared/hostProcess";
14import * as Effect from "effect/Effect";9import * as Effect from "effect/Effect";
15import * as Deferred from "effect/Deferred";10import * as Deferred from "effect/Deferred";
16import * as Fiber from "effect/Fiber";11import * as Fiber from "effect/Fiber";
...@@ -37,7 +32,7 @@ import { AntigravityDriver } from "./AntigravityDriver.ts";...@@ -37,7 +32,7 @@ import { AntigravityDriver } from "./AntigravityDriver.ts";
37import * as ProviderHostLive from "../ProviderHostLive.ts";32import * as ProviderHostLive from "../ProviderHostLive.ts";
38import * as ServerSecretStore from "../../auth/ServerSecretStore.ts";33import * as ServerSecretStore from "../../auth/ServerSecretStore.ts";
3934
40const hostPlatform = HostProcessPlatform.defaultValue();35const hostPlatform = HostProcess.Platform.defaultValue();
41const windowsHost = hostPlatform === "win32";36const windowsHost = hostPlatform === "win32";
42const decodeRequest = Schema.decodeEffect(37const decodeRequest = Schema.decodeEffect(
43 Schema.fromJsonString(38 Schema.fromJsonString(
...@@ -65,8 +60,8 @@ const makeHarness = Effect.fn("makeAntigravityDriverHarness")(function* (...@@ -65,8 +60,8 @@ const makeHarness = Effect.fn("makeAntigravityDriverHarness")(function* (
65 const path = yield* Path.Path;60 const path = yield* Path.Path;
66 const config = yield* ServerConfig.ServerConfig;61 const config = yield* ServerConfig.ServerConfig;
67 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;62 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
68 const nodePath = yield* HostProcessExecutablePath;63 const nodePath = yield* HostProcess.ExecutablePath;
69 const baseEnv = yield* HostProcessEnvironment;64 const baseEnv = yield* HostProcess.Environment;
70 const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-antigravity-driver-" });65 const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-antigravity-driver-" });
71 const instanceId = ProviderInstanceId.make(path.basename(root));66 const instanceId = ProviderInstanceId.make(path.basename(root));
72 const mockAgentPath = yield* path.fromFileUrl(67 const mockAgentPath = yield* path.fromFileUrl(
...@@ -283,8 +278,8 @@ it.layer(layerTest)("AntigravityDriver", (it) => {...@@ -283,8 +278,8 @@ it.layer(layerTest)("AntigravityDriver", (it) => {
283 expect(h.launches).toEqual([]);278 expect(h.launches).toEqual([]);
284 }).pipe(279 }).pipe(
285 Effect.scoped,280 Effect.scoped,
286 Effect.provideService(HostProcessIsExecutable, true),281 Effect.provideService(HostProcess.IsExecutable, true),
287 Effect.provideService(HostProcessEnvironment, { PATH: "" }),282 Effect.provideService(HostProcess.Environment, { PATH: "" }),
288 ),283 ),
289 );284 );
290285
apps/server/src/provider/Drivers/AntigravityDriver.ts+3-3
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1import { withAgentDeviceEnvironment } from "@t3tools/provider-core/server/mcpSession";1import { withAgentDeviceEnvironment } from "@t3tools/provider-core/server/mcpSession";
2import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions";2import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions";
3import { AntigravitySettings, ProviderDriverKind, ProviderSetupError } from "@t3tools/contracts";3import { AntigravitySettings, ProviderDriverKind, ProviderSetupError } from "@t3tools/contracts";
4import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
5import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";5import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime";
6import {6import {
7 NodeRuntimeUnavailableError,7 NodeRuntimeUnavailableError,
...@@ -115,9 +115,9 @@ export const AntigravityDriver: ProviderDriver<...@@ -115,9 +115,9 @@ export const AntigravityDriver: ProviderDriver<
115 const authConfigIssue = antigravityAuthConfigIssue(auth);115 const authConfigIssue = antigravityAuthConfigIssue(auth);
116 const processEnvironment = yield* mergeProviderInstanceEnvironment(environment);116 const processEnvironment = yield* mergeProviderInstanceEnvironment(environment);
117 const userHome = resolveAntigravityUserHome(117 const userHome = resolveAntigravityUserHome(
118 yield* HostProcessPlatform,118 yield* HostProcess.Platform,
119 processEnvironment,119 processEnvironment,
120 yield* HostProcessHomeDirectory,120 yield* HostProcess.HomeDirectory,
121 );121 );
122 const directories = yield* resolveAntigravityInstanceDirectories(122 const directories = yield* resolveAntigravityInstanceDirectories(
123 host.paths.stateDir,123 host.paths.stateDir,
apps/server/src/provider/Drivers/AntigravityUsage.ts+3-3
...@@ -17,7 +17,7 @@ import type {...@@ -17,7 +17,7 @@ import type {
17 ProviderUsageReader,17 ProviderUsageReader,
18 ProviderUsageScan,18 ProviderUsageScan,
19} from "@t3tools/provider-core/server/usage";19} from "@t3tools/provider-core/server/usage";
20import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";20import * as HostProcess from "@t3tools/shared/HostProcess";
21import * as Context from "effect/Context";21import * as Context from "effect/Context";
22import * as Crypto from "effect/Crypto";22import * as Crypto from "effect/Crypto";
23import * as Effect from "effect/Effect";23import * as Effect from "effect/Effect";
...@@ -44,12 +44,12 @@ const make = Effect.gen(function* () {...@@ -44,12 +44,12 @@ const make = Effect.gen(function* () {
44 const fileSystem = yield* FileSystem.FileSystem;44 const fileSystem = yield* FileSystem.FileSystem;
45 const path = yield* Path.Path;45 const path = yield* Path.Path;
46 const host = yield* ProviderHost.ProviderHost;46 const host = yield* ProviderHost.ProviderHost;
47 const hostEnvironment = yield* HostProcessEnvironment;47 const hostEnvironment = yield* HostProcess.Environment;
48 const cache = makeAntigravityUsageCache();48 const cache = makeAntigravityUsageCache();
4949
50 /** `ANTIGRAVITY_DATA_DIR` (comma-separated) or the defaults, canonicalized. */50 /** `ANTIGRAVITY_DATA_DIR` (comma-separated) or the defaults, canonicalized. */
51 const dataRoots = Effect.gen(function* () {51 const dataRoots = Effect.gen(function* () {
52 const home = yield* HostProcessHomeDirectory;52 const home = yield* HostProcess.HomeDirectory;
53 const configured = hostEnvironment["ANTIGRAVITY_DATA_DIR"]53 const configured = hostEnvironment["ANTIGRAVITY_DATA_DIR"]
54 ?.split(",")54 ?.split(",")
55 .map((value) => value.trim())55 .map((value) => value.trim())
apps/server/src/provider/Drivers/ClaudeDriver.ts+2-2
...@@ -71,7 +71,7 @@ import {...@@ -71,7 +71,7 @@ import {
71 makeClaudeContinuationGroupKey,71 makeClaudeContinuationGroupKey,
72 resolveClaudeHomePath,72 resolveClaudeHomePath,
73} from "./ClaudeHome.ts";73} from "./ClaudeHome.ts";
74import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";74import * as HostProcess from "@t3tools/shared/HostProcess";
75const decodeClaudeSettings = Schema.decodeSync(ClaudeSettings);75const decodeClaudeSettings = Schema.decodeSync(ClaudeSettings);
7676
77const DRIVER_KIND = ProviderDriverKind.make("claudeAgent");77const DRIVER_KIND = ProviderDriverKind.make("claudeAgent");
...@@ -139,7 +139,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv, Path....@@ -139,7 +139,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv, Path.
139 const effectiveConfig = {139 const effectiveConfig = {
140 ...config,140 ...config,
141 enabled,141 enabled,
142 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),142 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
143 } satisfies ClaudeSettings;143 } satisfies ClaudeSettings;
144 const resolveMaintenance = yield* makeCachedProviderMaintenanceResolution(144 const resolveMaintenance = yield* makeCachedProviderMaintenanceResolution(
145 resolveProviderMaintenanceCapabilitiesEffect(UPDATE, {145 resolveProviderMaintenanceCapabilitiesEffect(UPDATE, {
apps/server/src/provider/Drivers/ClaudeExecutable.test.ts+3-3
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { describe, expect, it } from "@effect/vitest";1import { describe, expect, it } from "@effect/vitest";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import { SpawnExecutableResolution } from "@t3tools/shared/shell";3import { SpawnExecutableResolution } from "@t3tools/shared/shell";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
55
...@@ -17,7 +17,7 @@ function withWindowsResolution(input: {...@@ -17,7 +17,7 @@ function withWindowsResolution(input: {
17 const existing = new Set(input.existingFiles ?? []);17 const existing = new Set(input.existingFiles ?? []);
18 return <A, E, R>(effect: Effect.Effect<A, E, R>) =>18 return <A, E, R>(effect: Effect.Effect<A, E, R>) =>
19 effect.pipe(19 effect.pipe(
20 Effect.provideService(HostProcessPlatform, "win32"),20 Effect.provideService(HostProcess.Platform, "win32"),
21 Effect.provideService(SpawnExecutableResolution, () => input.resolvedCommand),21 Effect.provideService(SpawnExecutableResolution, () => input.resolvedCommand),
22 Effect.provideService(ClaudeExecutableFileCheck, (filePath) => existing.has(filePath)),22 Effect.provideService(ClaudeExecutableFileCheck, (filePath) => existing.has(filePath)),
23 );23 );
...@@ -28,7 +28,7 @@ describe("resolveClaudeSdkExecutablePath", () => {...@@ -28,7 +28,7 @@ describe("resolveClaudeSdkExecutablePath", () => {
28 Effect.gen(function* () {28 Effect.gen(function* () {
29 expect(29 expect(
30 yield* resolveClaudeSdkExecutablePath("claude", {}).pipe(30 yield* resolveClaudeSdkExecutablePath("claude", {}).pipe(
31 Effect.provideService(HostProcessPlatform, "darwin"),31 Effect.provideService(HostProcess.Platform, "darwin"),
32 Effect.provideService(SpawnExecutableResolution, () => {32 Effect.provideService(SpawnExecutableResolution, () => {
33 throw new Error("must not resolve on non-Windows platforms");33 throw new Error("must not resolve on non-Windows platforms");
34 }),34 }),
apps/server/src/provider/Drivers/ClaudeExecutable.ts+2-2
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2import * as NodeFS from "node:fs";2import * as NodeFS from "node:fs";
3import * as NodePath from "node:path";3import * as NodePath from "node:path";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
6import { SpawnExecutableResolution } from "@t3tools/shared/shell";6import { SpawnExecutableResolution } from "@t3tools/shared/shell";
7import * as Context from "effect/Context";7import * as Context from "effect/Context";
8import * as Effect from "effect/Effect";8import * as Effect from "effect/Effect";
...@@ -67,7 +67,7 @@ export const ClaudeExecutableFileCheck = Context.Reference<ExecutableFileCheck>(...@@ -67,7 +67,7 @@ export const ClaudeExecutableFileCheck = Context.Reference<ExecutableFileCheck>(
67 */67 */
68export const resolveClaudeSdkExecutablePath = Effect.fn("resolveClaudeSdkExecutablePath")(68export const resolveClaudeSdkExecutablePath = Effect.fn("resolveClaudeSdkExecutablePath")(
69 function* (binaryPath: string, environment: NodeJS.ProcessEnv): Effect.fn.Return<string> {69 function* (binaryPath: string, environment: NodeJS.ProcessEnv): Effect.fn.Return<string> {
70 const platform = yield* HostProcessPlatform;70 const platform = yield* HostProcess.Platform;
71 if (platform !== "win32") {71 if (platform !== "win32") {
72 return binaryPath;72 return binaryPath;
73 }73 }
apps/server/src/provider/Drivers/ClaudeHome.ts+2-2
...@@ -4,7 +4,7 @@ import * as Path from "effect/Path";...@@ -4,7 +4,7 @@ import * as Path from "effect/Path";
4import * as Schema from "effect/Schema";4import * as Schema from "effect/Schema";
55
6import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";6import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";
7import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";7import * as HostProcess from "@t3tools/shared/HostProcess";
88
9const quotePath = Schema.encodeSync(Schema.fromJsonString(Schema.String));9const quotePath = Schema.encodeSync(Schema.fromJsonString(Schema.String));
1010
...@@ -20,7 +20,7 @@ export const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function...@@ -20,7 +20,7 @@ export const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function
20 environment?: NodeJS.ProcessEnv,20 environment?: NodeJS.ProcessEnv,
21): Effect.fn.Return<string, never, Path.Path> {21): Effect.fn.Return<string, never, Path.Path> {
22 const path = yield* Path.Path;22 const path = yield* Path.Path;
23 const home = yield* HostProcessHomeDirectory;23 const home = yield* HostProcess.HomeDirectory;
24 const homePath = config.homePath.trim();24 const homePath = config.homePath.trim();
25 if (homePath.length > 0) {25 if (homePath.length > 0) {
26 return path.resolve(expandHomePath(homePath, home));26 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";...@@ -19,7 +19,7 @@ import * as Effect from "effect/Effect";
19import * as FileSystem from "effect/FileSystem";19import * as FileSystem from "effect/FileSystem";
20import * as Path from "effect/Path";20import * as Path from "effect/Path";
21import * as Schema from "effect/Schema";21import * as Schema from "effect/Schema";
22import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";22import * as HostProcess from "@t3tools/shared/HostProcess";
23import { fromLenientJson } from "@t3tools/shared/schemaJson";23import { fromLenientJson } from "@t3tools/shared/schemaJson";
24import { parse as parseYamlDocument } from "yaml";24import { parse as parseYamlDocument } from "yaml";
2525
...@@ -242,7 +242,7 @@ const readSkillOverrides = Effect.fn("readSkillOverrides")(function* (...@@ -242,7 +242,7 @@ const readSkillOverrides = Effect.fn("readSkillOverrides")(function* (
242): Effect.fn.Return<ReadonlyMap<string, SkillOverride>, never, FileSystem.FileSystem | Path.Path> {242): Effect.fn.Return<ReadonlyMap<string, SkillOverride>, never, FileSystem.FileSystem | Path.Path> {
243 const fileSystem = yield* FileSystem.FileSystem;243 const fileSystem = yield* FileSystem.FileSystem;
244 const path = yield* Path.Path;244 const path = yield* Path.Path;
245 const platform = yield* HostProcessPlatform;245 const platform = yield* HostProcess.Platform;
246 const overridesByName = new Map<string, SkillOverride>();246 const overridesByName = new Map<string, SkillOverride>();
247 const repositoryRoot = cwd === undefined ? undefined : yield* findRepositoryRoot(cwd);247 const repositoryRoot = cwd === undefined ? undefined : yield* findRepositoryRoot(cwd);
248248
...@@ -295,7 +295,7 @@ const resolveClaudeConfigDirPath = Effect.fn("resolveClaudeConfigDirPath")(funct...@@ -295,7 +295,7 @@ const resolveClaudeConfigDirPath = Effect.fn("resolveClaudeConfigDirPath")(funct
295 cwd?: string,295 cwd?: string,
296): Effect.fn.Return<string, never, Path.Path> {296): Effect.fn.Return<string, never, Path.Path> {
297 const path = yield* Path.Path;297 const path = yield* Path.Path;
298 const home = yield* HostProcessHomeDirectory;298 const home = yield* HostProcess.HomeDirectory;
299 const homePath = config.homePath.trim();299 const homePath = config.homePath.trim();
300 if (homePath.length > 0) {300 if (homePath.length > 0) {
301 return path.resolve(expandHomePath(homePath, home));301 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";...@@ -7,7 +7,7 @@ import * as NodeOS from "node:os";
7import * as NodePath from "node:path";7import * as NodePath from "node:path";
8import { expect, it } from "@effect/vitest";8import { expect, it } from "@effect/vitest";
9import { EnvironmentId, ProviderInstanceId, ProviderSessionId, ThreadId } from "@t3tools/contracts";9import { EnvironmentId, ProviderInstanceId, ProviderSessionId, ThreadId } from "@t3tools/contracts";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
11import * as Effect from "effect/Effect";11import * as Effect from "effect/Effect";
12import * as Deferred from "effect/Deferred";12import * as Deferred from "effect/Deferred";
13import * as Fiber from "effect/Fiber";13import * as Fiber from "effect/Fiber";
...@@ -88,7 +88,7 @@ const layerDeps = ServerConfig.layerTest(process.cwd(), {...@@ -88,7 +88,7 @@ const layerDeps = ServerConfig.layerTest(process.cwd(), {
88const layerTest = ProviderHostLive.layer.pipe(Layer.provideMerge(layerDeps));88const layerTest = ProviderHostLive.layer.pipe(Layer.provideMerge(layerDeps));
8989
90// The `#!/bin/sh` stub below cannot be resolved as an executable on Windows.90// 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
93const noSpawn = ChildProcessSpawner.make(() =>93const noSpawn = ChildProcessSpawner.make(() =>
94 Effect.die("Disabled Codex must not spawn a process"),94 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";...@@ -77,7 +77,7 @@ import { codexUsageReader } from "./codexUsage.ts";
77import * as CodexInstallation from "../CodexInstallation.ts";77import * as CodexInstallation from "../CodexInstallation.ts";
78import * as ServerSecretStore from "../../auth/ServerSecretStore.ts";78import * as ServerSecretStore from "../../auth/ServerSecretStore.ts";
79import * as ServerEnvironment from "../../environment/ServerEnvironment.ts";79import * as ServerEnvironment from "../../environment/ServerEnvironment.ts";
80import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";80import * as HostProcess from "@t3tools/shared/HostProcess";
81const decodeCodexSettings = Schema.decodeSync(CodexSettings);81const decodeCodexSettings = Schema.decodeSync(CodexSettings);
8282
83const DRIVER_KIND = ProviderDriverKind.make("codex");83const DRIVER_KIND = ProviderDriverKind.make("codex");
...@@ -179,7 +179,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv, Path.Pat...@@ -179,7 +179,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv, Path.Pat
179 const effectiveConfig = {179 const effectiveConfig = {
180 ...config,180 ...config,
181 enabled,181 enabled,
182 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),182 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
183 homePath: homeLayout.effectiveHomePath ?? "",183 homePath: homeLayout.effectiveHomePath ?? "",
184 } satisfies CodexSettings;184 } satisfies CodexSettings;
185 const resolveMaintenance = yield* makeCachedProviderMaintenanceResolution(185 const resolveMaintenance = yield* makeCachedProviderMaintenanceResolution(
apps/server/src/provider/Drivers/CodexHomeLayout.ts+2-2
...@@ -6,7 +6,7 @@ import * as Schema from "effect/Schema";...@@ -6,7 +6,7 @@ import * as Schema from "effect/Schema";
6import * as PlatformError from "effect/PlatformError";6import * as PlatformError from "effect/PlatformError";
77
8import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";8import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";
9import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";9import * as HostProcess from "@t3tools/shared/HostProcess";
1010
11export interface CodexHomeLayout {11export interface CodexHomeLayout {
12 readonly mode: "direct" | "authOverlay";12 readonly mode: "direct" | "authOverlay";
...@@ -42,7 +42,7 @@ export const resolveCodexHomeLayout = Effect.fn("resolveCodexHomeLayout")(functi...@@ -42,7 +42,7 @@ export const resolveCodexHomeLayout = Effect.fn("resolveCodexHomeLayout")(functi
42 config: CodexSettings,42 config: CodexSettings,
43): Effect.fn.Return<CodexHomeLayout, never, Path.Path> {43): Effect.fn.Return<CodexHomeLayout, never, Path.Path> {
44 const path = yield* Path.Path;44 const path = yield* Path.Path;
45 const home = yield* HostProcessHomeDirectory;45 const home = yield* HostProcess.HomeDirectory;
46 const sharedHomePath = resolveHomePath(path, home, config.homePath);46 const sharedHomePath = resolveHomePath(path, home, config.homePath);
47 const shadowHomePath = config.shadowHomePath.trim();47 const shadowHomePath = config.shadowHomePath.trim();
48 if (shadowHomePath.length === 0) {48 if (shadowHomePath.length === 0) {
apps/server/src/provider/Drivers/claudeUsage.ts+2-2
...@@ -17,7 +17,7 @@ import {...@@ -17,7 +17,7 @@ import {
17 type TranscriptUsageFormat,17 type TranscriptUsageFormat,
18 type UsageRecord,18 type UsageRecord,
19} from "@t3tools/provider-core/server/usage";19} from "@t3tools/provider-core/server/usage";
20import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";20import * as HostProcess from "@t3tools/shared/HostProcess";
2121
22/**22/**
23 * Parses one line of a Claude Code transcript.23 * Parses one line of a Claude Code transcript.
...@@ -111,7 +111,7 @@ export const claudeUsageReader: ProviderUsageReader<ClaudeSettings, Path.Path> =...@@ -111,7 +111,7 @@ export const claudeUsageReader: ProviderUsageReader<ClaudeSettings, Path.Path> =
111 // An undecodable config has no trustworthy home to read.111 // An undecodable config has no trustworthy home to read.
112 if (config === undefined) return [];112 if (config === undefined) return [];
113 const path = yield* Path.Path;113 const path = yield* Path.Path;
114 const homeDirectory = yield* HostProcessHomeDirectory;114 const homeDirectory = yield* HostProcess.HomeDirectory;
115 const configured = config.homePath.trim();115 const configured = config.homePath.trim();
116 const home = configured116 const home = configured
117 ? expandHomePath(configured, homeDirectory)117 ? 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...@@ -39,11 +39,7 @@ import * as ProviderLatestVersions from "@t3tools/provider-core/server/ProviderL
39import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions";39import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions";
40import type { GrokSettings } from "@t3tools/provider-grok/settings";40import type { GrokSettings } from "@t3tools/provider-grok/settings";
41import type { CursorSettings } from "@t3tools/provider-cursor/settings";41import type { CursorSettings } from "@t3tools/provider-cursor/settings";
42import {42import * as HostProcess from "@t3tools/shared/HostProcess";
43 HostProcessHomeDirectory,
44 HostProcessPlatform,
45 isHostWindows,
46} from "@t3tools/shared/hostProcess";
47import * as DateTime from "effect/DateTime";43import * as DateTime from "effect/DateTime";
48import * as Effect from "effect/Effect";44import * as Effect from "effect/Effect";
49import * as FileSystem from "effect/FileSystem";45import * as FileSystem from "effect/FileSystem";
...@@ -156,7 +152,7 @@ const makeTildeProviderFixtures = Effect.fn(...@@ -156,7 +152,7 @@ const makeTildeProviderFixtures = Effect.fn(
156)(function* () {152)(function* () {
157 const fileSystem = yield* FileSystem.FileSystem;153 const fileSystem = yield* FileSystem.FileSystem;
158 const path = yield* Path.Path;154 const path = yield* Path.Path;
159 const homePath = yield* HostProcessHomeDirectory;155 const homePath = yield* HostProcess.HomeDirectory;
160 const fixtureDir = yield* fileSystem.makeTempDirectoryScoped({156 const fixtureDir = yield* fileSystem.makeTempDirectoryScoped({
161 directory: homePath,157 directory: homePath,
162 prefix: ".t3-provider-path-test-",158 prefix: ".t3-provider-path-test-",
...@@ -349,7 +345,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {...@@ -349,7 +345,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {
349345
350 it.live("reports Codex's answer when a redemption changed nothing", () =>346 it.live("reports Codex's answer when a redemption changed nothing", () =>
351 Effect.gen(function* () {347 Effect.gen(function* () {
352 if (yield* isHostWindows) return;348 if (yield* HostProcess.isWindows) return;
353 const fileSystem = yield* FileSystem.FileSystem;349 const fileSystem = yield* FileSystem.FileSystem;
354 const fixtures = yield* makeTildeProviderFixtures();350 const fixtures = yield* makeTildeProviderFixtures();
355 yield* fileSystem.writeFileString(351 yield* fileSystem.writeFileString(
...@@ -386,7 +382,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {...@@ -386,7 +382,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {
386382
387 it.live("runs Codex and Claude readiness probes from configured tilde paths", () =>383 it.live("runs Codex and Claude readiness probes from configured tilde paths", () =>
388 Effect.gen(function* () {384 Effect.gen(function* () {
389 if (yield* isHostWindows) return;385 if (yield* HostProcess.isWindows) return;
390386
391 const fixtures = yield* makeTildeProviderFixtures();387 const fixtures = yield* makeTildeProviderFixtures();
392388
...@@ -503,7 +499,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {...@@ -503,7 +499,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => {
503 return { outcome, after: yield* instance!.snapshot.getSnapshot };499 return { outcome, after: yield* instance!.snapshot.getSnapshot };
504 }).pipe(500 }).pipe(
505 // macOS logins live in the Keychain, where resets are never read.501 // macOS logins live in the Keychain, where resets are never read.
506 Effect.provideService(HostProcessPlatform, "linux"),502 Effect.provideService(HostProcess.Platform, "linux"),
507 Effect.provide(layerTest),503 Effect.provide(layerTest),
508 );504 );
509505
apps/server/src/provider/acp/AcpSessionRuntime.processTree.test.ts+5-5
...@@ -5,7 +5,7 @@ import * as NodePath from "node:path";...@@ -5,7 +5,7 @@ import * as NodePath from "node:path";
5import * as NodeURL from "node:url";5import * as NodeURL from "node:url";
66
7import { describe, expect, it, vi } from "@effect/vitest";7import { describe, expect, it, vi } from "@effect/vitest";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
9import * as Clock from "effect/Clock";9import * as Clock from "effect/Clock";
10import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
11import * as Exit from "effect/Exit";11import * as Exit from "effect/Exit";
...@@ -155,7 +155,7 @@ describe("terminatePosixOwnedProcessTree", () => {...@@ -155,7 +155,7 @@ describe("terminatePosixOwnedProcessTree", () => {
155155
156 it.live("preserves exact argv and strips wrapper-only environment before exec", () =>156 it.live("preserves exact argv and strips wrapper-only environment before exec", () =>
157 Effect.gen(function* () {157 Effect.gen(function* () {
158 if ((yield* HostProcessPlatform) !== "linux") return;158 if ((yield* HostProcess.Platform) !== "linux") return;
159 const lease = AcpSessionRuntime.makeLinuxCgroupController().create();159 const lease = AcpSessionRuntime.makeLinuxCgroupController().create();
160 if (lease === undefined) return;160 if (lease === undefined) return;
161 const scratchRoot = NodePath.join(process.cwd(), "tmp");161 const scratchRoot = NodePath.join(process.cwd(), "tmp");
...@@ -235,7 +235,7 @@ describe("terminatePosixOwnedProcessTree", () => {...@@ -235,7 +235,7 @@ describe("terminatePosixOwnedProcessTree", () => {
235 );235 );
236236
237 it("contains a packaged-runtime command without requiring cgroup delegation", () => {237 it("contains a packaged-runtime command without requiring cgroup delegation", () => {
238 if (HostProcessPlatform.defaultValue() !== "linux") return;238 if (HostProcess.Platform.defaultValue() !== "linux") return;
239 const scratchRoot = NodePath.join(process.cwd(), "tmp");239 const scratchRoot = NodePath.join(process.cwd(), "tmp");
240 NodeFS.mkdirSync(scratchRoot, { recursive: true });240 NodeFS.mkdirSync(scratchRoot, { recursive: true });
241 const scratch = NodeFS.mkdtempSync(NodePath.join(scratchRoot, "acp-cgroup-wrapper-fake-"));241 const scratch = NodeFS.mkdtempSync(NodePath.join(scratchRoot, "acp-cgroup-wrapper-fake-"));
...@@ -316,7 +316,7 @@ describe("terminatePosixOwnedProcessTree", () => {...@@ -316,7 +316,7 @@ describe("terminatePosixOwnedProcessTree", () => {
316316
317 it.live("kills a post-TERM detached double fork without touching an unrelated sentinel", () =>317 it.live("kills a post-TERM detached double fork without touching an unrelated sentinel", () =>
318 Effect.gen(function* () {318 Effect.gen(function* () {
319 if ((yield* HostProcessPlatform) !== "linux") return;319 if ((yield* HostProcess.Platform) !== "linux") return;
320 const controller = AcpSessionRuntime.makeLinuxCgroupController();320 const controller = AcpSessionRuntime.makeLinuxCgroupController();
321 const lease = controller.create();321 const lease = controller.create();
322 if (lease === undefined) return;322 if (lease === undefined) return;
...@@ -531,7 +531,7 @@ describe("terminatePosixOwnedProcessTree", () => {...@@ -531,7 +531,7 @@ describe("terminatePosixOwnedProcessTree", () => {
531531
532 it.live("finds a child forked by a non-leader pthread", () =>532 it.live("finds a child forked by a non-leader pthread", () =>
533 Effect.gen(function* () {533 Effect.gen(function* () {
534 if ((yield* HostProcessPlatform) !== "linux") return;534 if ((yield* HostProcess.Platform) !== "linux") return;
535 const scratchRoot = NodePath.join(process.cwd(), "tmp");535 const scratchRoot = NodePath.join(process.cwd(), "tmp");
536 NodeFS.mkdirSync(scratchRoot, { recursive: true });536 NodeFS.mkdirSync(scratchRoot, { recursive: true });
537 const scratch = NodeFS.mkdtempSync(NodePath.join(scratchRoot, "acp-pthread-spawn-"));537 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";...@@ -5,11 +5,7 @@ import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
5import * as NodePath from "@effect/platform-node/NodePath";5import * as NodePath from "@effect/platform-node/NodePath";
6import * as NodeServices from "@effect/platform-node/NodeServices";6import * as NodeServices from "@effect/platform-node/NodeServices";
7import { ProviderInstanceId } from "@t3tools/contracts";7import { ProviderInstanceId } from "@t3tools/contracts";
8import {8import * as HostProcess from "@t3tools/shared/HostProcess";
9 HostProcessExecutablePath,
10 HostProcessIsExecutable,
11 HostProcessPlatform,
12} from "@t3tools/shared/hostProcess";
13import { describe, expect, it } from "@effect/vitest";9import { describe, expect, it } from "@effect/vitest";
14import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
15import * as FileSystem from "effect/FileSystem";11import * as FileSystem from "effect/FileSystem";
...@@ -574,8 +570,8 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {...@@ -574,8 +570,8 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {
574 expect(profile.browserCommand).not.toContain("/packaged/t3");570 expect(profile.browserCommand).not.toContain("/packaged/t3");
575 expect(yield* fs.exists(profile.acpDirectory)).toBe(true);571 expect(yield* fs.exists(profile.acpDirectory)).toBe(true);
576 }).pipe(572 }).pipe(
577 Effect.provideService(HostProcessIsExecutable, true),573 Effect.provideService(HostProcess.IsExecutable, true),
578 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),574 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
579 ),575 ),
580 );576 );
581577
...@@ -601,7 +597,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {...@@ -601,7 +597,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {
601 });597 });
602 }598 }
603 expect(yield* fs.exists(profileDirectory)).toBe(false);599 expect(yield* fs.exists(profileDirectory)).toBe(false);
604 }).pipe(Effect.provideService(HostProcessIsExecutable, true)),600 }).pipe(Effect.provideService(HostProcess.IsExecutable, true)),
605 );601 );
606602
607 it.effect("preflights the no-browser helper and creates private directories only", () =>603 it.effect("preflights the no-browser helper and creates private directories only", () =>
...@@ -616,7 +612,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {...@@ -616,7 +612,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => {
616 expect(profile.geminiHome).toBe(path.join(temporaryDirectory, "profile"));612 expect(profile.geminiHome).toBe(path.join(temporaryDirectory, "profile"));
617 expect(yield* fs.exists(profile.acpDirectory)).toBe(true);613 expect(yield* fs.exists(profile.acpDirectory)).toBe(true);
618 expect(yield* fs.exists(profile.tokenPath)).toBe(false);614 expect(yield* fs.exists(profile.tokenPath)).toBe(false);
619 if ((yield* HostProcessPlatform) !== "win32") {615 if ((yield* HostProcess.Platform) !== "win32") {
620 expect((yield* fs.stat(profile.geminiHome)).mode & 0o777).toBe(0o700);616 expect((yield* fs.stat(profile.geminiHome)).mode & 0o777).toBe(0o700);
621 expect((yield* fs.stat(profile.acpDirectory)).mode & 0o777).toBe(0o700);617 expect((yield* fs.stat(profile.acpDirectory)).mode & 0o777).toBe(0o700);
622 }618 }
apps/server/src/provider/antigravityAuthSupport.ts+3-3
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2import * as NodeFSP from "node:fs/promises";2import * as NodeFSP from "node:fs/promises";
33
4import type { AntigravityAuthMethod, ProviderInstanceId } from "@t3tools/contracts";4import type { AntigravityAuthMethod, ProviderInstanceId } from "@t3tools/contracts";
5import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
6import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";6import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime";
7import * as Crypto from "effect/Crypto";7import * as Crypto from "effect/Crypto";
8import * as Effect from "effect/Effect";8import * as Effect from "effect/Effect";
...@@ -315,13 +315,13 @@ export const prepareAntigravityProfile = Effect.fn("prepareAntigravityProfile")(...@@ -315,13 +315,13 @@ export const prepareAntigravityProfile = Effect.fn("prepareAntigravityProfile")(
315 const fs = yield* FileSystem.FileSystem;315 const fs = yield* FileSystem.FileSystem;
316 const path = yield* Path.Path;316 const path = yield* Path.Path;
317 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;317 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
318 const platform = input.platform ?? (yield* HostProcessPlatform);318 const platform = input.platform ?? (yield* HostProcess.Platform);
319 const userHome =319 const userHome =
320 input.userHome ??320 input.userHome ??
321 resolveAntigravityUserHome(321 resolveAntigravityUserHome(
322 platform,322 platform,
323 input.baseEnv ?? process.env,323 input.baseEnv ?? process.env,
324 yield* HostProcessHomeDirectory,324 yield* HostProcess.HomeDirectory,
325 );325 );
326 const runtimeExecutablePath =326 const runtimeExecutablePath =
327 input.runtimeExecutablePath ??327 input.runtimeExecutablePath ??
apps/server/src/provider/claudeResetCredits.test.ts+6-6
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { it as effectIt } from "@effect/vitest";2import { it as effectIt } from "@effect/vitest";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Deferred from "effect/Deferred";4import * as Deferred from "effect/Deferred";
5import * as Effect from "effect/Effect";5import * as Effect from "effect/Effect";
6import * as FileSystem from "effect/FileSystem";6import * as FileSystem from "effect/FileSystem";
...@@ -111,7 +111,7 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => {...@@ -111,7 +111,7 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => {
111 );111 );
112 });112 });
113 const credits = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(113 const credits = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(
114 Effect.provideService(HostProcessPlatform, "linux"),114 Effect.provideService(HostProcess.Platform, "linux"),
115 Effect.provideService(HttpClient.HttpClient, client),115 Effect.provideService(HttpClient.HttpClient, client),
116 );116 );
117 expect(credits).toEqual({ availableCount: 1, nextCreditId: "grant_a" });117 expect(credits).toEqual({ availableCount: 1, nextCreditId: "grant_a" });
...@@ -122,11 +122,11 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => {...@@ -122,11 +122,11 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => {
122 Effect.gen(function* () {122 Effect.gen(function* () {
123 const { configDir } = yield* writeLogin;123 const { configDir } = yield* writeLogin;
124 const darwin = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(124 const darwin = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(
125 Effect.provideService(HostProcessPlatform, "darwin"),125 Effect.provideService(HostProcess.Platform, "darwin"),
126 Effect.provideService(HttpClient.HttpClient, refuseRequests),126 Effect.provideService(HttpClient.HttpClient, refuseRequests),
127 );127 );
128 const limited = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(128 const limited = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe(
129 Effect.provideService(HostProcessPlatform, "linux"),129 Effect.provideService(HostProcess.Platform, "linux"),
130 Effect.provideService(HttpClient.HttpClient, respond(429, {})),130 Effect.provideService(HttpClient.HttpClient, respond(429, {})),
131 );131 );
132 expect([darwin, limited]).toEqual([undefined, undefined]);132 expect([darwin, limited]).toEqual([undefined, undefined]);
...@@ -147,7 +147,7 @@ const consume = (client: HttpClient.HttpClient, ids = { grantId: "grant_a", requ...@@ -147,7 +147,7 @@ const consume = (client: HttpClient.HttpClient, ids = { grantId: "grant_a", requ
147 version: "2.1.0",147 version: "2.1.0",
148 ...ids,148 ...ids,
149 }).pipe(149 }).pipe(
150 Effect.provideService(HostProcessPlatform, "linux"),150 Effect.provideService(HostProcess.Platform, "linux"),
151 Effect.provideService(HttpClient.HttpClient, client),151 Effect.provideService(HttpClient.HttpClient, client),
152 Effect.result,152 Effect.result,
153 );153 );
...@@ -228,7 +228,7 @@ effectIt.layer(NodeServices.layer)("consumeClaudeResetCredit", (it) => {...@@ -228,7 +228,7 @@ effectIt.layer(NodeServices.layer)("consumeClaudeResetCredit", (it) => {
228 grantId: "grant_a",228 grantId: "grant_a",
229 requestId: "r-1",229 requestId: "r-1",
230 }).pipe(230 }).pipe(
231 Effect.provideService(HostProcessPlatform, "linux"),231 Effect.provideService(HostProcess.Platform, "linux"),
232 Effect.provideService(HttpClient.HttpClient, client),232 Effect.provideService(HttpClient.HttpClient, client),
233 Effect.result,233 Effect.result,
234 Effect.forkChild,234 Effect.forkChild,
apps/server/src/provider/claudeResetCredits.ts+3-3
...@@ -11,7 +11,7 @@ import type {...@@ -11,7 +11,7 @@ import type {
11 ProviderConsumeResetCreditOutcome,11 ProviderConsumeResetCreditOutcome,
12 ServerProviderResetCredits,12 ServerProviderResetCredits,
13} from "@t3tools/contracts";13} from "@t3tools/contracts";
14import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
15import * as DateTime from "effect/DateTime";15import * as DateTime from "effect/DateTime";
16import * as Effect from "effect/Effect";16import * as Effect from "effect/Effect";
17import * as FileSystem from "effect/FileSystem";17import * as FileSystem from "effect/FileSystem";
...@@ -149,7 +149,7 @@ const readJson = <S extends Schema.Top>(schema: S, file: string) =>...@@ -149,7 +149,7 @@ const readJson = <S extends Schema.Top>(schema: S, file: string) =>
149149
150const readAccessToken = (configDir: string) =>150const readAccessToken = (configDir: string) =>
151 Effect.gen(function* () {151 Effect.gen(function* () {
152 if ((yield* HostProcessPlatform) === "darwin") return undefined;152 if ((yield* HostProcess.Platform) === "darwin") return undefined;
153 const path = yield* Path.Path;153 const path = yield* Path.Path;
154 const credentials = yield* readJson(Credentials, path.join(configDir, ".credentials.json"));154 const credentials = yield* readJson(Credentials, path.join(configDir, ".credentials.json"));
155 return credentials.claudeAiOauth?.accessToken?.trim() || undefined;155 return credentials.claudeAiOauth?.accessToken?.trim() || undefined;
...@@ -195,7 +195,7 @@ export const claudeAccountConfigPath = Effect.fn("claudeAccountConfigPath")(func...@@ -195,7 +195,7 @@ export const claudeAccountConfigPath = Effect.fn("claudeAccountConfigPath")(func
195 const path = yield* Path.Path;195 const path = yield* Path.Path;
196 return configDir196 return configDir
197 ? path.join(configDir, ".claude.json")197 ? path.join(configDir, ".claude.json")
198 : path.join(yield* HostProcessHomeDirectory, ".claude.json");198 : path.join(yield* HostProcess.HomeDirectory, ".claude.json");
199});199});
200200
201const CLAIM_OUTCOMES = {201const CLAIM_OUTCOMES = {
apps/server/src/provider/providerInstallation.test.ts+2-2
...@@ -5,7 +5,7 @@ import {...@@ -5,7 +5,7 @@ import {
5 ProviderInstanceId,5 ProviderInstanceId,
6 type ProviderInstallState,6 type ProviderInstallState,
7} from "@t3tools/contracts";7} from "@t3tools/contracts";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
9import * as Effect from "effect/Effect";9import * as Effect from "effect/Effect";
10import * as FileSystem from "effect/FileSystem";10import * as FileSystem from "effect/FileSystem";
11import * as Layer from "effect/Layer";11import * as Layer from "effect/Layer";
...@@ -215,7 +215,7 @@ describe("provider installation routing", () => {...@@ -215,7 +215,7 @@ describe("provider installation routing", () => {
215 Effect.gen(function* () {215 Effect.gen(function* () {
216 const fs = yield* FileSystem.FileSystem;216 const fs = yield* FileSystem.FileSystem;
217 const path = yield* Path.Path;217 const path = yield* Path.Path;
218 const platform = yield* HostProcessPlatform;218 const platform = yield* HostProcess.Platform;
219 const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-provider-install-route-" });219 const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-provider-install-route-" });
220 const binary = platform === "win32" ? "agy-test.exe" : "agy-test";220 const binary = platform === "win32" ? "agy-test.exe" : "agy-test";
221 const executable = path.join(directory, binary);221 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";...@@ -20,7 +20,7 @@ import * as Stream from "effect/Stream";
20import * as TestClock from "effect/testing/TestClock";20import * as TestClock from "effect/testing/TestClock";
21import { HttpClient, HttpClientResponse } from "effect/http";21import { HttpClient, HttpClientResponse } from "effect/http";
22import { ChildProcessSpawner } from "effect/process";22import { ChildProcessSpawner } from "effect/process";
23import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";23import * as HostProcess from "@t3tools/shared/HostProcess";
24import { SpawnExecutableResolution } from "@t3tools/shared/shell";24import { SpawnExecutableResolution } from "@t3tools/shared/shell";
2525
26import * as ProviderRegistry from "./ProviderRegistry.ts";26import * as ProviderRegistry from "./ProviderRegistry.ts";
...@@ -45,7 +45,7 @@ const encoder = new TextEncoder();...@@ -45,7 +45,7 @@ const encoder = new TextEncoder();
45// `{ command, args }` assertions below hold deterministically on any host45// `{ command, args }` assertions below hold deterministically on any host
46// (including Windows). Windows-specific resolution is covered by the dedicated46// (including Windows). Windows-specific resolution is covered by the dedicated
47// win32 case at the end of this suite.47// win32 case at the end of this suite.
48const layerNonWindowsPlatform = Layer.succeed(HostProcessPlatform, "linux");48const layerNonWindowsPlatform = Layer.succeed(HostProcess.Platform, "linux");
4949
50function lifecycleFor(provider: ProviderDriverKind): ProviderMaintenanceCapabilities {50function lifecycleFor(provider: ProviderDriverKind): ProviderMaintenanceCapabilities {
51 if (provider === NATIVE_CLI_DRIVER) {51 if (provider === NATIVE_CLI_DRIVER) {
...@@ -962,8 +962,8 @@ describe("providerMaintenanceRunner", () => {...@@ -962,8 +962,8 @@ describe("providerMaintenanceRunner", () => {
962 }).pipe(962 }).pipe(
963 Effect.provide(963 Effect.provide(
964 Layer.mergeAll(964 Layer.mergeAll(
965 Layer.succeed(HostProcessPlatform, "win32"),965 Layer.succeed(HostProcess.Platform, "win32"),
966 Layer.succeed(HostProcessEnvironment, {966 Layer.succeed(HostProcess.Environment, {
967 PATH: "C:\\fake\\npm",967 PATH: "C:\\fake\\npm",
968 PATHEXT: ".COM;.EXE;.BAT;.CMD",968 PATHEXT: ".COM;.EXE;.BAT;.CMD",
969 }),969 }),
apps/server/src/resourceTelemetry/HostResources.ts+2-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeOS from "node:os";1import * as NodeOS from "node:os";
2import type { HostResourcesSnapshot } from "@t3tools/contracts";2import type { HostResourcesSnapshot } from "@t3tools/contracts";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Cache from "effect/Cache";4import * as Cache from "effect/Cache";
5import * as Context from "effect/Context";5import * as Context from "effect/Context";
6import * as DateTime from "effect/DateTime";6import * as DateTime from "effect/DateTime";
...@@ -40,7 +40,7 @@ function darwinAvailableMemory(output: string): number | null {...@@ -40,7 +40,7 @@ function darwinAvailableMemory(output: string): number | null {
4040
41const make = Effect.fn("makeHostResources")(function* () {41const make = Effect.fn("makeHostResources")(function* () {
42 const fs = yield* FileSystem.FileSystem;42 const fs = yield* FileSystem.FileSystem;
43 const platform = yield* HostProcessPlatform;43 const platform = yield* HostProcess.Platform;
44 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;44 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
4545
46 const sample = Effect.fn("HostResources.sample")(function* () {46 const sample = Effect.fn("HostResources.sample")(function* () {
apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts+20-24
...@@ -1,9 +1,5 @@...@@ -1,9 +1,5 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import {2import * as HostProcess from "@t3tools/shared/HostProcess";
3 HostProcessArchitecture,
4 HostProcessEnvironment,
5 HostProcessPlatform,
6} from "@t3tools/shared/hostProcess";
7import { afterEach, assert, describe, expect, it, vi } from "@effect/vitest";3import { afterEach, assert, describe, expect, it, vi } from "@effect/vitest";
8import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
9import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
...@@ -13,7 +9,7 @@ import * as ResourceMonitorBinary from "./ResourceMonitorBinary.ts";...@@ -13,7 +9,7 @@ import * as ResourceMonitorBinary from "./ResourceMonitorBinary.ts";
139
14// The override checks POSIX exec bits on a real file under a linux platform10// The override checks POSIX exec bits on a real file under a linux platform
15// mock; NTFS never reports those bits, so the check cannot be satisfied there.11// 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
18describe("ResourceMonitorBinary", () => {14describe("ResourceMonitorBinary", () => {
19 afterEach(() => {15 afterEach(() => {
...@@ -34,9 +30,9 @@ describe("ResourceMonitorBinary", () => {...@@ -34,9 +30,9 @@ describe("ResourceMonitorBinary", () => {
3430
35 const service = yield* ResourceMonitorBinary.make().pipe(31 const service = yield* ResourceMonitorBinary.make().pipe(
36 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),32 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
37 Effect.provideService(HostProcessPlatform, "win32"),33 Effect.provideService(HostProcess.Platform, "win32"),
38 Effect.provideService(HostProcessArchitecture, "arm64"),34 Effect.provideService(HostProcess.Architecture, "arm64"),
39 Effect.provideService(HostProcessEnvironment, {35 Effect.provideService(HostProcess.Environment, {
40 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,36 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
41 }),37 }),
42 );38 );
...@@ -58,10 +54,10 @@ describe("ResourceMonitorBinary", () => {...@@ -58,10 +54,10 @@ describe("ResourceMonitorBinary", () => {
5854
59 const service = yield* ResourceMonitorBinary.make().pipe(55 const service = yield* ResourceMonitorBinary.make().pipe(
60 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),56 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
61 Effect.provideService(HostProcessPlatform, "linux"),57 Effect.provideService(HostProcess.Platform, "linux"),
62 Effect.provideService(HostProcessArchitecture, "x64"),58 Effect.provideService(HostProcess.Architecture, "x64"),
63 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"),59 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"),
64 Effect.provideService(HostProcessEnvironment, {60 Effect.provideService(HostProcess.Environment, {
65 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,61 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
66 }),62 }),
67 );63 );
...@@ -82,9 +78,9 @@ describe("ResourceMonitorBinary", () => {...@@ -82,9 +78,9 @@ describe("ResourceMonitorBinary", () => {
8278
83 const service = yield* ResourceMonitorBinary.make().pipe(79 const service = yield* ResourceMonitorBinary.make().pipe(
84 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),80 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
85 Effect.provideService(HostProcessPlatform, "freebsd"),81 Effect.provideService(HostProcess.Platform, "freebsd"),
86 Effect.provideService(HostProcessArchitecture, "ia32"),82 Effect.provideService(HostProcess.Architecture, "ia32"),
87 Effect.provideService(HostProcessEnvironment, {83 Effect.provideService(HostProcess.Environment, {
88 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,84 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
89 }),85 }),
90 );86 );
...@@ -105,10 +101,10 @@ describe("ResourceMonitorBinary", () => {...@@ -105,10 +101,10 @@ describe("ResourceMonitorBinary", () => {
105101
106 const service = yield* ResourceMonitorBinary.make().pipe(102 const service = yield* ResourceMonitorBinary.make().pipe(
107 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),103 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
108 Effect.provideService(HostProcessPlatform, "linux"),104 Effect.provideService(HostProcess.Platform, "linux"),
109 Effect.provideService(HostProcessArchitecture, "x64"),105 Effect.provideService(HostProcess.Architecture, "x64"),
110 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "gnu"),106 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "gnu"),
111 Effect.provideService(HostProcessEnvironment, {107 Effect.provideService(HostProcess.Environment, {
112 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,108 T3CODE_RESOURCE_MONITOR_PATH: binaryPath,
113 }),109 }),
114 );110 );
...@@ -127,9 +123,9 @@ describe("ResourceMonitorBinary", () => {...@@ -127,9 +123,9 @@ describe("ResourceMonitorBinary", () => {
127 });123 });
128 const service = yield* ResourceMonitorBinary.make().pipe(124 const service = yield* ResourceMonitorBinary.make().pipe(
129 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),125 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
130 Effect.provideService(HostProcessPlatform, "freebsd"),126 Effect.provideService(HostProcess.Platform, "freebsd"),
131 Effect.provideService(HostProcessArchitecture, "ia32"),127 Effect.provideService(HostProcess.Architecture, "ia32"),
132 Effect.provideService(HostProcessEnvironment, {}),128 Effect.provideService(HostProcess.Environment, {}),
133 );129 );
134 const error = yield* Effect.flip(service.resolve);130 const error = yield* Effect.flip(service.resolve);
135131
...@@ -145,10 +141,10 @@ describe("ResourceMonitorBinary", () => {...@@ -145,10 +141,10 @@ describe("ResourceMonitorBinary", () => {
145 });141 });
146 const service = yield* ResourceMonitorBinary.make().pipe(142 const service = yield* ResourceMonitorBinary.make().pipe(
147 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),143 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
148 Effect.provideService(HostProcessPlatform, "linux"),144 Effect.provideService(HostProcess.Platform, "linux"),
149 Effect.provideService(HostProcessArchitecture, "x64"),145 Effect.provideService(HostProcess.Architecture, "x64"),
150 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"),146 Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"),
151 Effect.provideService(HostProcessEnvironment, {}),147 Effect.provideService(HostProcess.Environment, {}),
152 );148 );
153 const error = yield* Effect.flip(service.resolve);149 const error = yield* Effect.flip(service.resolve);
154150
apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts+4-8
...@@ -1,8 +1,4 @@...@@ -1,8 +1,4 @@
1import {1import * as HostProcess from "@t3tools/shared/HostProcess";
2 HostProcessArchitecture,
3 HostProcessEnvironment,
4 HostProcessPlatform,
5} from "@t3tools/shared/hostProcess";
6import * as Context from "effect/Context";2import * as Context from "effect/Context";
7import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
8import * as FileSystem from "effect/FileSystem";4import * as FileSystem from "effect/FileSystem";
...@@ -139,9 +135,9 @@ export const make = Effect.fn("resourceTelemetry.resourceMonitorBinary.make")(fu...@@ -139,9 +135,9 @@ export const make = Effect.fn("resourceTelemetry.resourceMonitorBinary.make")(fu
139 const config = yield* ServerConfig.ServerConfig;135 const config = yield* ServerConfig.ServerConfig;
140 const fileSystem = yield* FileSystem.FileSystem;136 const fileSystem = yield* FileSystem.FileSystem;
141 const path = yield* Path.Path;137 const path = yield* Path.Path;
142 const platform = yield* HostProcessPlatform;138 const platform = yield* HostProcess.Platform;
143 const architecture = yield* HostProcessArchitecture;139 const architecture = yield* HostProcess.Architecture;
144 const environment = yield* HostProcessEnvironment;140 const environment = yield* HostProcess.Environment;
145 const linuxLibc = platform === "linux" ? yield* ResourceMonitorHostLinuxLibc : undefined;141 const linuxLibc = platform === "linux" ? yield* ResourceMonitorHostLinuxLibc : undefined;
146 const executableName = binaryName(platform);142 const executableName = binaryName(platform);
147 const platformKey = resourceMonitorPlatformKey(platform, architecture);143 const platformKey = resourceMonitorPlatformKey(platform, architecture);
apps/server/src/review/ReviewService.ts+2-2
...@@ -20,7 +20,7 @@ import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";...@@ -20,7 +20,7 @@ import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";
20import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts";20import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts";
21import * as ServerSettings from "../serverSettings.ts";21import * as ServerSettings from "../serverSettings.ts";
22import { isFilesystemRoot, managedWorktreesDirectories } from "../worktreesDirectory.ts";22import { isFilesystemRoot, managedWorktreesDirectories } from "../worktreesDirectory.ts";
23import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";23import * as HostProcess from "@t3tools/shared/HostProcess";
2424
25export class ReviewService extends Context.Service<25export class ReviewService extends Context.Service<
26 ReviewService,26 ReviewService,
...@@ -74,7 +74,7 @@ export const make = Effect.gen(function* () {...@@ -74,7 +74,7 @@ export const make = Effect.gen(function* () {
74 const worktreesDirectories = yield* settings.getSettings.pipe(74 const worktreesDirectories = yield* settings.getSettings.pipe(
75 Effect.orElseSucceed(() => ({ worktreesDirectory: "", previousWorktreesDirectories: [] })),75 Effect.orElseSucceed(() => ({ worktreesDirectory: "", previousWorktreesDirectories: [] })),
76 );76 );
77 const home = yield* HostProcessHomeDirectory;77 const home = yield* HostProcess.HomeDirectory;
78 const [candidate, workspaceRoot, worktreesRoots] = yield* Effect.all([78 const [candidate, workspaceRoot, worktreesRoots] = yield* Effect.all([
79 canonicalizePath(cwd),79 canonicalizePath(cwd),
80 canonicalizePath(config.cwd),80 canonicalizePath(config.cwd),
apps/server/src/sourceControl/SourceControlRepositoryService.ts+2-2
...@@ -29,7 +29,7 @@ import {...@@ -29,7 +29,7 @@ import {
29import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";29import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";
30import * as BitbucketApi from "@t3tools/source-control-bitbucket/server/BitbucketApi";30import * as BitbucketApi from "@t3tools/source-control-bitbucket/server/BitbucketApi";
31import * as SourceControlProviderRegistry from "./SourceControlProviderRegistry.ts";31import * as SourceControlProviderRegistry from "./SourceControlProviderRegistry.ts";
32import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";32import * as HostProcess from "@t3tools/shared/HostProcess";
33const isSourceControlRepositoryError = Schema.is(SourceControlRepositoryError);33const isSourceControlRepositoryError = Schema.is(SourceControlRepositoryError);
34const isSourceControlProviderError = Schema.is(SourceControlProviderError);34const isSourceControlProviderError = Schema.is(SourceControlProviderError);
35const isBitbucketRepositoryLocatorError = Schema.is(BitbucketApi.BitbucketRepositoryLocatorError);35const isBitbucketRepositoryLocatorError = Schema.is(BitbucketApi.BitbucketRepositoryLocatorError);
...@@ -214,7 +214,7 @@ export const make = Effect.gen(function* () {...@@ -214,7 +214,7 @@ export const make = Effect.gen(function* () {
214 });214 });
215 }215 }
216216
217 return path.resolve(expandHomePath(trimmed, yield* HostProcessHomeDirectory));217 return path.resolve(expandHomePath(trimmed, yield* HostProcess.HomeDirectory));
218 },218 },
219 );219 );
220220
apps/server/src/storageCleanup.ts+2-2
...@@ -38,7 +38,7 @@ import * as TerminalManager from "./terminal/Manager.ts";...@@ -38,7 +38,7 @@ import * as TerminalManager from "./terminal/Manager.ts";
38import { isFilesystemRoot, managedWorktreesDirectories } from "./worktreesDirectory.ts";38import { isFilesystemRoot, managedWorktreesDirectories } from "./worktreesDirectory.ts";
39import * as GitVcsDriver from "./vcs/GitVcsDriver.ts";39import * as GitVcsDriver from "./vcs/GitVcsDriver.ts";
40import { withWorkspaceLease } from "./workspace/workspaceLease.ts";40import { withWorkspaceLease } from "./workspace/workspaceLease.ts";
41import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";41import * as HostProcess from "@t3tools/shared/HostProcess";
4242
43const decodeCleanupThread = Schema.decodeUnknownEffect(43const decodeCleanupThread = Schema.decodeUnknownEffect(
44 Schema.fromJsonString(OrchestrationV2AppThreadJson),44 Schema.fromJsonString(OrchestrationV2AppThreadJson),
...@@ -214,7 +214,7 @@ export const make = Effect.gen(function* () {...@@ -214,7 +214,7 @@ export const make = Effect.gen(function* () {
214 serverSettings,214 serverSettings,
215 config.worktreesDir,215 config.worktreesDir,
216 path,216 path,
217 yield* HostProcessHomeDirectory,217 yield* HostProcess.HomeDirectory,
218 )) {218 )) {
219 // An unmounted drive only skips its own worktrees.219 // An unmounted drive only skips its own worktrees.
220 const root = yield* fs.exists(directory).pipe(220 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";...@@ -11,7 +11,7 @@ import * as HttpClientError from "effect/http/HttpClientError";
11import * as HttpServer from "effect/http/HttpServer";11import * as HttpServer from "effect/http/HttpServer";
12import * as HttpServerRequest from "effect/http/HttpServerRequest";12import * as HttpServerRequest from "effect/http/HttpServerRequest";
13import * as HttpServerResponse from "effect/http/HttpServerResponse";13import * as HttpServerResponse from "effect/http/HttpServerResponse";
14import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
1515
16import * as ServerConfig from "../config.ts";16import * as ServerConfig from "../config.ts";
17import { getTelemetryIdentifier } from "./Identify.ts";17import { getTelemetryIdentifier } from "./Identify.ts";
...@@ -105,8 +105,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {...@@ -105,8 +105,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {
105 ),105 ),
106 Layer.provide(106 Layer.provide(
107 Layer.mergeAll(107 Layer.mergeAll(
108 Layer.succeed(HostProcessPlatform, "win32"),108 Layer.succeed(HostProcess.Platform, "win32"),
109 Layer.succeed(HostProcessArchitecture, "x64"),109 Layer.succeed(HostProcess.Architecture, "x64"),
110 layerAcceptThenFailClient(batches),110 layerAcceptThenFailClient(batches),
111 ),111 ),
112 ),112 ),
...@@ -167,8 +167,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {...@@ -167,8 +167,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {
167 Layer.provide(layerConfig),167 Layer.provide(layerConfig),
168 Layer.provide(168 Layer.provide(
169 Layer.mergeAll(169 Layer.mergeAll(
170 Layer.succeed(HostProcessPlatform, "linux"),170 Layer.succeed(HostProcess.Platform, "linux"),
171 Layer.succeed(HostProcessArchitecture, "arm64"),171 Layer.succeed(HostProcess.Architecture, "arm64"),
172 ),172 ),
173 ),173 ),
174 Layer.provideMerge(NodeHttpServer.layerTest),174 Layer.provideMerge(NodeHttpServer.layerTest),
...@@ -257,8 +257,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {...@@ -257,8 +257,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => {
257 Layer.provide(layerConfig),257 Layer.provide(layerConfig),
258 Layer.provide(258 Layer.provide(
259 Layer.mergeAll(259 Layer.mergeAll(
260 Layer.succeed(HostProcessPlatform, "linux"),260 Layer.succeed(HostProcess.Platform, "linux"),
261 Layer.succeed(HostProcessArchitecture, "arm64"),261 Layer.succeed(HostProcess.Architecture, "arm64"),
262 ),262 ),
263 ),263 ),
264 Layer.provideMerge(NodeHttpServer.layerTest),264 Layer.provideMerge(NodeHttpServer.layerTest),
apps/server/src/telemetry/AnalyticsService.ts+3-3
...@@ -8,7 +8,7 @@...@@ -8,7 +8,7 @@
8 *8 *
9 * @module AnalyticsService9 * @module AnalyticsService
10 */10 */
11import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";11import * as HostProcess from "@t3tools/shared/HostProcess";
12import type { ClientOs } from "@t3tools/contracts";12import type { ClientOs } from "@t3tools/contracts";
13import * as Clock from "effect/Clock";13import * as Clock from "effect/Clock";
14import * as Config from "effect/Config";14import * as Config from "effect/Config";
...@@ -136,8 +136,8 @@ export const make = Effect.gen(function* () {...@@ -136,8 +136,8 @@ export const make = Effect.gen(function* () {
136 // The background flush and the shutdown flush must not send the same batch at once.136 // The background flush and the shutdown flush must not send the same batch at once.
137 const flushLock = yield* Semaphore.make(1);137 const flushLock = yield* Semaphore.make(1);
138 const clientType = serverConfig.mode === "desktop" ? "desktop-app" : "cli-web-client";138 const clientType = serverConfig.mode === "desktop" ? "desktop-app" : "cli-web-client";
139 const hostPlatform = yield* HostProcessPlatform;139 const hostPlatform = yield* HostProcess.Platform;
140 const hostArchitecture = yield* HostProcessArchitecture;140 const hostArchitecture = yield* HostProcess.Architecture;
141141
142 const enqueueBufferedEvent = (142 const enqueueBufferedEvent = (
143 uuid: string,143 uuid: string,
apps/server/src/telemetry/Identify.ts+2-2
...@@ -9,7 +9,7 @@ import * as Schema from "effect/Schema";...@@ -9,7 +9,7 @@ import * as Schema from "effect/Schema";
99
10import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite";10import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite";
11import * as ServerConfig from "../config.ts";11import * as ServerConfig from "../config.ts";
12import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";12import * as HostProcess from "@t3tools/shared/HostProcess";
1313
14/**14/**
15 * Codex writes `tokens` only for ChatGPT logins and omits the key for API-key,15 * Codex writes `tokens` only for ChatGPT logins and omits the key for API-key,
...@@ -312,6 +312,6 @@ export const getTelemetryIdentifierForHome = Effect.fn("getTelemetryIdentifierFo...@@ -312,6 +312,6 @@ export const getTelemetryIdentifierForHome = Effect.fn("getTelemetryIdentifierFo
312);312);
313313
314export const getTelemetryIdentifier = Effect.flatMap(314export const getTelemetryIdentifier = Effect.flatMap(
315 HostProcessHomeDirectory,315 HostProcess.HomeDirectory,
316 getTelemetryIdentifierForHome,316 getTelemetryIdentifierForHome,
317);317);
apps/server/src/terminal/Manager.test.ts+6-6
...@@ -12,7 +12,7 @@ import {...@@ -12,7 +12,7 @@ import {
12 ServerSettingsError,12 ServerSettingsError,
13 TerminalProviderInstanceNotFoundError,13 TerminalProviderInstanceNotFoundError,
14} from "@t3tools/contracts";14} from "@t3tools/contracts";
15import { HostProcessPlatform, HostProcessArchitecture } from "@t3tools/shared/hostProcess";15import * as HostProcess from "@t3tools/shared/HostProcess";
16import * as Data from "effect/Data";16import * as Data from "effect/Data";
17import * as Clock from "effect/Clock";17import * as Clock from "effect/Clock";
18import * as Deferred from "effect/Deferred";18import * as Deferred from "effect/Deferred";
...@@ -315,7 +315,7 @@ const createManager = (...@@ -315,7 +315,7 @@ const createManager = (
315 );315 );
316316
317const layerWithHostPlatform = (platform: NodeJS.Platform) =>317const layerWithHostPlatform = (platform: NodeJS.Platform) =>
318 Layer.succeed(HostProcessPlatform, platform);318 Layer.succeed(HostProcess.Platform, platform);
319319
320// Apply the existing line policy, then find the longest code-point-aligned byte tail.320// Apply the existing line policy, then find the longest code-point-aligned byte tail.
321function retainedHistory(text: string, maxLines: number, maxBytes = Infinity): string {321function retainedHistory(text: string, maxLines: number, maxBytes = Infinity): string {
...@@ -619,7 +619,7 @@ it.layer(...@@ -619,7 +619,7 @@ it.layer(
619619
620 it.effect("preserves non-notFound cwd stat failures", () =>620 it.effect("preserves non-notFound cwd stat failures", () =>
621 Effect.gen(function* () {621 Effect.gen(function* () {
622 if ((yield* HostProcessPlatform) === "win32") return;622 if ((yield* HostProcess.Platform) === "win32") return;
623623
624 const path = yield* Path.Path;624 const path = yield* Path.Path;
625625
...@@ -1826,7 +1826,7 @@ it.layer(...@@ -1826,7 +1826,7 @@ it.layer(
18261826
1827 it.effect("retries with fallback shells when preferred shell spawn fails", () =>1827 it.effect("retries with fallback shells when preferred shell spawn fails", () =>
1828 Effect.gen(function* () {1828 Effect.gen(function* () {
1829 const platform = yield* HostProcessPlatform;1829 const platform = yield* HostProcess.Platform;
1830 const missingShell =1830 const missingShell =
1831 platform === "win32" ? "C:\\definitely\\missing-shell.exe" : "/definitely/missing-shell -l";1831 platform === "win32" ? "C:\\definitely\\missing-shell.exe" : "/definitely/missing-shell -l";
1832 const { manager, ptyAdapter } = yield* createManager(5, {1832 const { manager, ptyAdapter } = yield* createManager(5, {
...@@ -1933,7 +1933,7 @@ it.layer(...@@ -1933,7 +1933,7 @@ it.layer(
1933 Effect.provide(1933 Effect.provide(
1934 Layer.merge(1934 Layer.merge(
1935 layerWithHostPlatform("win32"),1935 layerWithHostPlatform("win32"),
1936 Layer.succeed(HostProcessArchitecture, "x64"),1936 Layer.succeed(HostProcess.Architecture, "x64"),
1937 ),1937 ),
1938 ),1938 ),
1939 );1939 );
...@@ -2513,7 +2513,7 @@ it.layer(...@@ -2513,7 +2513,7 @@ it.layer(
25132513
2514 it.effect("starts zsh with prompt spacer disabled to avoid `%` end markers", () =>2514 it.effect("starts zsh with prompt spacer disabled to avoid `%` end markers", () =>
2515 Effect.gen(function* () {2515 Effect.gen(function* () {
2516 if ((yield* HostProcessPlatform) === "win32") return;2516 if ((yield* HostProcess.Platform) === "win32") return;
2517 const { manager, ptyAdapter } = yield* createManager(5, {2517 const { manager, ptyAdapter } = yield* createManager(5, {
2518 shellResolver: () => "/bin/zsh",2518 shellResolver: () => "/bin/zsh",
2519 });2519 });
apps/server/src/terminal/Manager.ts+4-8
...@@ -42,11 +42,7 @@ import {...@@ -42,11 +42,7 @@ import {
42} from "@t3tools/contracts";42} from "@t3tools/contracts";
43import { makeKeyedCoalescingWorker } from "@t3tools/shared/KeyedCoalescingWorker";43import { makeKeyedCoalescingWorker } from "@t3tools/shared/KeyedCoalescingWorker";
44import * as KeyedLock from "@t3tools/shared/KeyedLock";44import * as KeyedLock from "@t3tools/shared/KeyedLock";
45import {45import * as HostProcess from "@t3tools/shared/HostProcess";
46 HostProcessArchitecture,
47 HostProcessHomeDirectory,
48 HostProcessPlatform,
49} from "@t3tools/shared/hostProcess";
50import { mergePathEntries } from "@t3tools/shared/shell";46import { mergePathEntries } from "@t3tools/shared/shell";
5147
52import { acpRegistryManagedBinaryDirectories } from "@t3tools/provider-acp-registry/server";48import { acpRegistryManagedBinaryDirectories } from "@t3tools/provider-acp-registry/server";
...@@ -1482,8 +1478,8 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func...@@ -1482,8 +1478,8 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func
1482 const logsDir = options.logsDir;1478 const logsDir = options.logsDir;
1483 const historyLineLimit = options.historyLineLimit ?? DEFAULT_HISTORY_LINE_LIMIT;1479 const historyLineLimit = options.historyLineLimit ?? DEFAULT_HISTORY_LINE_LIMIT;
1484 const historyByteLimit = options.historyByteLimit ?? DEFAULT_HISTORY_BYTE_LIMIT;1480 const historyByteLimit = options.historyByteLimit ?? DEFAULT_HISTORY_BYTE_LIMIT;
1485 const platform = yield* HostProcessPlatform;1481 const platform = yield* HostProcess.Platform;
1486 const architecture = yield* HostProcessArchitecture;1482 const architecture = yield* HostProcess.Architecture;
1487 // Terminals must inherit the user's full environment (minus the blocklist1483 // Terminals must inherit the user's full environment (minus the blocklist
1488 // applied in createTerminalSpawnEnv) — an allowlist here silently strips1484 // applied in createTerminalSpawnEnv) — an allowlist here silently strips
1489 // things like PSModulePath, DISPLAY, proxies, and toolchain variables.1485 // things like PSModulePath, DISPLAY, proxies, and toolchain variables.
...@@ -2253,7 +2249,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func...@@ -2253,7 +2249,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func
2253 baseEnv,2249 baseEnv,
2254 session.runtimeEnv,2250 session.runtimeEnv,
2255 platform,2251 platform,
2256 yield* HostProcessHomeDirectory,2252 yield* HostProcess.HomeDirectory,
2257 );2253 );
2258 // Append (never prepend) managed ACP agent install directories so2254 // Append (never prepend) managed ACP agent install directories so
2259 // `kimi login` and friends resolve by name without shadowing any2255 // `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";...@@ -3,7 +3,7 @@ import * as NodeNet from "node:net";
33
4import * as NodeServices from "@effect/platform-node/NodeServices";4import * as NodeServices from "@effect/platform-node/NodeServices";
5import { assert, it } from "@effect/vitest";5import { assert, it } from "@effect/vitest";
6import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";6import * as HostProcess from "@t3tools/shared/HostProcess";
7import * as Cause from "effect/Cause";7import * as Cause from "effect/Cause";
8import * as Effect from "effect/Effect";8import * as Effect from "effect/Effect";
9import * as Exit from "effect/Exit";9import * as Exit from "effect/Exit";
...@@ -66,8 +66,8 @@ const layerTestFor = (platform: NodeJS.Platform = "win32") =>...@@ -66,8 +66,8 @@ const layerTestFor = (platform: NodeJS.Platform = "win32") =>
66 Layer.provide(66 Layer.provide(
67 Layer.mergeAll(67 Layer.mergeAll(
68 NodeServices.layer,68 NodeServices.layer,
69 Layer.succeed(HostProcessPlatform, platform),69 Layer.succeed(HostProcess.Platform, platform),
70 Layer.succeed(HostProcessArchitecture, "x64"),70 Layer.succeed(HostProcess.Architecture, "x64"),
71 Layer.succeed(NodePtyAdapter.NodePtyModuleLoaderRef, () => Promise.resolve(fakeNodePty)),71 Layer.succeed(NodePtyAdapter.NodePtyModuleLoaderRef, () => Promise.resolve(fakeNodePty)),
72 ),72 ),
73 ),73 ),
...@@ -272,8 +272,8 @@ it.effect("reports native module load failures as structured startup defects", (...@@ -272,8 +272,8 @@ it.effect("reports native module load failures as structured startup defects", (
272 Effect.provide(272 Effect.provide(
273 Layer.mergeAll(273 Layer.mergeAll(
274 NodeServices.layer,274 NodeServices.layer,
275 Layer.succeed(HostProcessPlatform, "win32"),275 Layer.succeed(HostProcess.Platform, "win32"),
276 Layer.succeed(HostProcessArchitecture, "x64"),276 Layer.succeed(HostProcess.Architecture, "x64"),
277 ),277 ),
278 ),278 ),
279 ),279 ),
apps/server/src/terminal/NodePtyAdapter.ts+8-8
...@@ -7,7 +7,7 @@ import * as FileSystem from "effect/FileSystem";...@@ -7,7 +7,7 @@ import * as FileSystem from "effect/FileSystem";
7import * as Layer from "effect/Layer";7import * as Layer from "effect/Layer";
8import * as Path from "effect/Path";8import * as Path from "effect/Path";
9import * as Schema from "effect/Schema";9import * as Schema from "effect/Schema";
10import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
1111
12import * as PtyAdapter from "@t3tools/shared/PtyAdapter";12import * as PtyAdapter from "@t3tools/shared/PtyAdapter";
1313
...@@ -46,8 +46,8 @@ let didEnsureSpawnHelperExecutable = false;...@@ -46,8 +46,8 @@ let didEnsureSpawnHelperExecutable = false;
46const resolveNodePtySpawnHelperPath = Effect.gen(function* () {46const resolveNodePtySpawnHelperPath = Effect.gen(function* () {
47 const path = yield* Path.Path;47 const path = yield* Path.Path;
48 const fs = yield* FileSystem.FileSystem;48 const fs = yield* FileSystem.FileSystem;
49 const platform = yield* HostProcessPlatform;49 const platform = yield* HostProcess.Platform;
50 const architecture = yield* HostProcessArchitecture;50 const architecture = yield* HostProcess.Architecture;
5151
52 const packageJsonPath = requireForNodePty.resolve("node-pty/package.json");52 const packageJsonPath = requireForNodePty.resolve("node-pty/package.json");
53 const packageDir = path.dirname(packageJsonPath);53 const packageDir = path.dirname(packageJsonPath);
...@@ -67,7 +67,7 @@ const resolveNodePtySpawnHelperPath = Effect.gen(function* () {...@@ -67,7 +67,7 @@ const resolveNodePtySpawnHelperPath = Effect.gen(function* () {
6767
68const ensureNodePtySpawnHelperExecutable = Effect.fn(function* () {68const ensureNodePtySpawnHelperExecutable = Effect.fn(function* () {
69 const fs = yield* FileSystem.FileSystem;69 const fs = yield* FileSystem.FileSystem;
70 const platform = yield* HostProcessPlatform;70 const platform = yield* HostProcess.Platform;
71 if (platform === "win32") return;71 if (platform === "win32") return;
72 if (didEnsureSpawnHelperExecutable) return;72 if (didEnsureSpawnHelperExecutable) return;
7373
...@@ -236,8 +236,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () {...@@ -236,8 +236,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () {
236 const loadNodePtyModule = yield* NodePtyModuleLoaderRef;236 const loadNodePtyModule = yield* NodePtyModuleLoaderRef;
237 const fs = yield* FileSystem.FileSystem;237 const fs = yield* FileSystem.FileSystem;
238 const path = yield* Path.Path;238 const path = yield* Path.Path;
239 const platform = yield* HostProcessPlatform;239 const platform = yield* HostProcess.Platform;
240 const architecture = yield* HostProcessArchitecture;240 const architecture = yield* HostProcess.Architecture;
241241
242 const nodePty = yield* Effect.tryPromise({242 const nodePty = yield* Effect.tryPromise({
243 try: loadNodePtyModule,243 try: loadNodePtyModule,
...@@ -253,8 +253,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () {...@@ -253,8 +253,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () {
253 ensureNodePtySpawnHelperExecutable().pipe(253 ensureNodePtySpawnHelperExecutable().pipe(
254 Effect.provideService(FileSystem.FileSystem, fs),254 Effect.provideService(FileSystem.FileSystem, fs),
255 Effect.provideService(Path.Path, path),255 Effect.provideService(Path.Path, path),
256 Effect.provideService(HostProcessPlatform, platform),256 Effect.provideService(HostProcess.Platform, platform),
257 Effect.provideService(HostProcessArchitecture, architecture),257 Effect.provideService(HostProcess.Architecture, architecture),
258 Effect.orElseSucceed(() => undefined),258 Effect.orElseSucceed(() => undefined),
259 ),259 ),
260 );260 );
apps/server/src/textGeneration/ClaudeTextGeneration.test.ts+3-3
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { it } from "@effect/vitest";2import { it } from "@effect/vitest";
3import { ClaudeSettings, ProviderInstanceId } from "@t3tools/contracts";3import { ClaudeSettings, ProviderInstanceId } from "@t3tools/contracts";
4import { HostProcessPlatform, isHostWindows } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
5import { createModelSelection } from "@t3tools/shared/model";5import { createModelSelection } from "@t3tools/shared/model";
6import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
7import * as FileSystem from "effect/FileSystem";7import * as FileSystem from "effect/FileSystem";
...@@ -35,7 +35,7 @@ function makeFakeClaudeBinary(dir: string) {...@@ -35,7 +35,7 @@ function makeFakeClaudeBinary(dir: string) {
35 return Effect.gen(function* () {35 return Effect.gen(function* () {
36 const path = yield* Path.Path;36 const path = yield* Path.Path;
37 const fs = yield* FileSystem.FileSystem;37 const fs = yield* FileSystem.FileSystem;
38 const platform = yield* HostProcessPlatform;38 const platform = yield* HostProcess.Platform;
39 const binDir = path.join(dir, "bin");39 const binDir = path.join(dir, "bin");
40 const fixturePath = yield* path.fromFileUrl(40 const fixturePath = yield* path.fromFileUrl(
41 new URL("./testing/ClaudeTextGeneration.fixture.mjs", import.meta.url),41 new URL("./testing/ClaudeTextGeneration.fixture.mjs", import.meta.url),
...@@ -69,7 +69,7 @@ function withFakeClaudeEnv<A, E, R>(...@@ -69,7 +69,7 @@ function withFakeClaudeEnv<A, E, R>(
69 const fs = yield* FileSystem.FileSystem;69 const fs = yield* FileSystem.FileSystem;
70 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3code-claude-text-" });70 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3code-claude-text-" });
71 const binDir = yield* makeFakeClaudeBinary(tempDir);71 const binDir = yield* makeFakeClaudeBinary(tempDir);
72 const pathDelimiter = (yield* isHostWindows) ? ";" : ":";72 const pathDelimiter = (yield* HostProcess.isWindows) ? ";" : ":";
73 const previousPath = process.env.PATH;73 const previousPath = process.env.PATH;
74 const previousOutput = process.env.T3_FAKE_CLAUDE_OUTPUT;74 const previousOutput = process.env.T3_FAKE_CLAUDE_OUTPUT;
75 const previousExitCode = process.env.T3_FAKE_CLAUDE_EXIT_CODE;75 const previousExitCode = process.env.T3_FAKE_CLAUDE_EXIT_CODE;
apps/server/src/textGeneration/CodexTextGeneration.ts+2-2
...@@ -26,7 +26,7 @@ import {...@@ -26,7 +26,7 @@ import {
26} from "@t3tools/provider-core/server/textGenerationUtils";26} from "@t3tools/provider-core/server/textGenerationUtils";
27import { codexModelFamily, getModelSelectionStringOptionValue } from "@t3tools/shared/model";27import { codexModelFamily, getModelSelectionStringOptionValue } from "@t3tools/shared/model";
28import { getCodexServiceTierOptionValue } from "../codexModelOptions.ts";28import { getCodexServiceTierOptionValue } from "../codexModelOptions.ts";
29import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";29import * as HostProcess from "@t3tools/shared/HostProcess";
3030
31const CODEX_TIMEOUT_MS = 180_000;31const CODEX_TIMEOUT_MS = 180_000;
32const encodeJsonString = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown));32const encodeJsonString = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown));
...@@ -218,7 +218,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func...@@ -218,7 +218,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func
218 ? {218 ? {
219 CODEX_HOME: expandHomePath(219 CODEX_HOME: expandHomePath(
220 effectiveConfig.homePath,220 effectiveConfig.homePath,
221 yield* HostProcessHomeDirectory,221 yield* HostProcess.HomeDirectory,
222 ),222 ),
223 }223 }
224 : {}),224 : {}),
apps/server/src/usage/UsageService.test.ts+5-5
...@@ -8,7 +8,7 @@ import * as NodeSqlite from "node:sqlite";...@@ -8,7 +8,7 @@ import * as NodeSqlite from "node:sqlite";
88
9import { assert, describe, it } from "@effect/vitest";9import { assert, describe, it } from "@effect/vitest";
10import * as NodeServices from "@effect/platform-node/NodeServices";10import * as NodeServices from "@effect/platform-node/NodeServices";
11import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";11import * as HostProcess from "@t3tools/shared/HostProcess";
12import { mergeUsage } from "@t3tools/shared/usageMerge";12import { mergeUsage } from "@t3tools/shared/usageMerge";
13import {13import {
14 EnvironmentId,14 EnvironmentId,
...@@ -134,7 +134,7 @@ const layerService = (input: {...@@ -134,7 +134,7 @@ const layerService = (input: {
134 Layer.provideMerge(Layer.mock(ServerSecretStore.ServerSecretStore)({})),134 Layer.provideMerge(Layer.mock(ServerSecretStore.ServerSecretStore)({})),
135 Layer.provideMerge(ServerConfig.layerTest(process.cwd(), { prefix: input.prefix })),135 Layer.provideMerge(ServerConfig.layerTest(process.cwd(), { prefix: input.prefix })),
136 Layer.provideMerge(NodeServices.layer),136 Layer.provideMerge(NodeServices.layer),
137 Layer.provideMerge(Layer.succeed(HostProcessPlatform, input.platform ?? "linux")),137 Layer.provideMerge(Layer.succeed(HostProcess.Platform, input.platform ?? "linux")),
138 Layer.provideMerge(ServerSettings.layerTest(input.settings)),138 Layer.provideMerge(ServerSettings.layerTest(input.settings)),
139 Layer.provideMerge(139 Layer.provideMerge(
140 Layer.succeed(140 Layer.succeed(
...@@ -150,7 +150,7 @@ const layerService = (input: {...@@ -150,7 +150,7 @@ const layerService = (input: {
150 ),150 ),
151 ),151 ),
152 Layer.provideMerge(152 Layer.provideMerge(
153 Layer.succeed(HostProcessEnvironment, {153 Layer.succeed(HostProcess.Environment, {
154 HOME: input.home,154 HOME: input.home,
155 GROK_HOME: NodePath.join(input.home, "grok"),155 GROK_HOME: NodePath.join(input.home, "grok"),
156 OPENCODE_DATA_DIR: NodePath.join(input.home, "opencode"),156 OPENCODE_DATA_DIR: NodePath.join(input.home, "opencode"),
...@@ -1356,7 +1356,7 @@ describe("UsageService", () => {...@@ -1356,7 +1356,7 @@ describe("UsageService", () => {
1356 }).pipe(Effect.scoped),1356 }).pipe(Effect.scoped),
1357 );1357 );
13581358
1359 it.live.skipIf(HostProcessPlatform.defaultValue() === "win32")(1359 it.live.skipIf(HostProcess.Platform.defaultValue() === "win32")(
1360 "keeps a newer cached read when a slower scan of another window finishes later",1360 "keeps a newer cached read when a slower scan of another window finishes later",
1361 () =>1361 () =>
1362 Effect.gen(function* () {1362 Effect.gen(function* () {
...@@ -1387,7 +1387,7 @@ describe("UsageService", () => {...@@ -1387,7 +1387,7 @@ describe("UsageService", () => {
1387 }).pipe(Effect.scoped),1387 }).pipe(Effect.scoped),
1388 );1388 );
13891389
1390 it.live.skipIf(HostProcessPlatform.defaultValue() === "win32")(1390 it.live.skipIf(HostProcess.Platform.defaultValue() === "win32")(
1391 "keeps the later read when a scan that read earlier finishes first",1391 "keeps the later read when a scan that read earlier finishes first",
1392 () =>1392 () =>
1393 Effect.gen(function* () {1393 Effect.gen(function* () {
apps/server/src/usage/UsageService.ts+2-2
...@@ -31,7 +31,7 @@ import {...@@ -31,7 +31,7 @@ import {
31 type UsageSummaryInput,31 type UsageSummaryInput,
32 UsageReadError,32 UsageReadError,
33} from "@t3tools/contracts";33} from "@t3tools/contracts";
34import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";34import * as HostProcess from "@t3tools/shared/HostProcess";
35import * as Cause from "effect/Cause";35import * as Cause from "effect/Cause";
36import * as Clock from "effect/Clock";36import * as Clock from "effect/Clock";
37import * as Context from "effect/Context";37import * as Context from "effect/Context";
...@@ -227,7 +227,7 @@ export const make = Effect.gen(function* () {...@@ -227,7 +227,7 @@ export const make = Effect.gen(function* () {
227 const config = yield* ServerConfig.ServerConfig;227 const config = yield* ServerConfig.ServerConfig;
228 const settingsService = yield* ServerSettings.ServerSettingsService;228 const settingsService = yield* ServerSettings.ServerSettingsService;
229 const httpClient = yield* HttpClient.HttpClient;229 const httpClient = yield* HttpClient.HttpClient;
230 const hostEnvironment = yield* HostProcessEnvironment;230 const hostEnvironment = yield* HostProcess.Environment;
231 // The readers yield their own services; scans run them against this context.231 // The readers yield their own services; scans run them against this context.
232 const readerContext = yield* Effect.context<BuiltInUsageReadersEnv>();232 const readerContext = yield* Effect.context<BuiltInUsageReadersEnv>();
233233
apps/server/src/vcs/GitVcsDriverCore.test.ts+5-5
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1// @effect-diagnostics nodeBuiltinImport:off - realpathSync.native resolves Windows 8.3 short names, which the Effect realPath does not.1// @effect-diagnostics nodeBuiltinImport:off - realpathSync.native resolves Windows 8.3 short names, which the Effect realPath does not.
2import * as NodeFS from "node:fs";2import * as NodeFS from "node:fs";
3import * as NodeServices from "@effect/platform-node/NodeServices";3import * as NodeServices from "@effect/platform-node/NodeServices";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
5import { assert, it, describe } from "@effect/vitest";5import { assert, it, describe } from "@effect/vitest";
6import * as Deferred from "effect/Deferred";6import * as Deferred from "effect/Deferred";
7import * as Effect from "effect/Effect";7import * as Effect from "effect/Effect";
...@@ -1864,7 +1864,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {...@@ -1864,7 +1864,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
1864 yield* writeTextFile(cwd, " leading.txt", "whitespace path\n");1864 yield* writeTextFile(cwd, " leading.txt", "whitespace path\n");
1865 yield* writeTextFile(cwd, "l.txt", "other\n");1865 yield* writeTextFile(cwd, "l.txt", "other\n");
1866 yield* writeTextFile(cwd, "binary.dat", "binary\0data");1866 yield* writeTextFile(cwd, "binary.dat", "binary\0data");
1867 if ((yield* HostProcessPlatform) !== "win32") {1867 if ((yield* HostProcess.Platform) !== "win32") {
1868 yield* writeTextFile(cwd, "tab\tand\nnewline.txt", "unusual path\n");1868 yield* writeTextFile(cwd, "tab\tand\nnewline.txt", "unusual path\n");
1869 }1869 }
1870 yield* git(cwd, ["add", "."]);1870 yield* git(cwd, ["add", "."]);
...@@ -1906,7 +1906,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {...@@ -1906,7 +1906,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
1906 additions: 0,1906 additions: 0,
1907 deletions: 0,1907 deletions: 0,
1908 });1908 });
1909 if ((yield* HostProcessPlatform) !== "win32") {1909 if ((yield* HostProcess.Platform) !== "win32") {
1910 assert.deepInclude(branch.files ?? [], {1910 assert.deepInclude(branch.files ?? [], {
1911 path: "tab\tand\nnewline.txt",1911 path: "tab\tand\nnewline.txt",
1912 previousPath: null,1912 previousPath: null,
...@@ -2890,7 +2890,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {...@@ -2890,7 +2890,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
2890 });2890 });
28912891
2892 // NTFS rejects a newline in a file name, so there is nothing to preserve there.2892 // 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")(
2894 "preserves newline characters in worktree paths when listing refs",2894 "preserves newline characters in worktree paths when listing refs",
2895 () =>2895 () =>
2896 Effect.gen(function* () {2896 Effect.gen(function* () {
...@@ -3965,7 +3965,7 @@ describe("Windows long path configuration", () => {...@@ -3965,7 +3965,7 @@ describe("Windows long path configuration", () => {
3965 const layer = GitVcsDriver.layer.pipe(3965 const layer = GitVcsDriver.layer.pipe(
3966 Layer.provide(layerServerConfig),3966 Layer.provide(layerServerConfig),
3967 Layer.provideMerge(NodeServices.layer),3967 Layer.provideMerge(NodeServices.layer),
3968 Layer.provide(Layer.succeed(HostProcessPlatform, platform)),3968 Layer.provide(Layer.succeed(HostProcess.Platform, platform)),
3969 );3969 );
3970 return yield* Effect.gen(function* () {3970 return yield* Effect.gen(function* () {
3971 const driver = yield* GitVcsDriver.GitVcsDriver;3971 const driver = yield* GitVcsDriver.GitVcsDriver;
apps/server/src/vcs/GitVcsDriverCore.ts+4-4
...@@ -29,7 +29,7 @@ import {...@@ -29,7 +29,7 @@ import {
29 type VcsRef,29 type VcsRef,
30} from "@t3tools/contracts";30} from "@t3tools/contracts";
31import { dedupeRemoteBranchesWithLocalMatches, normalizeGitRemoteUrl } from "@t3tools/shared/git";31import { dedupeRemoteBranchesWithLocalMatches, normalizeGitRemoteUrl } from "@t3tools/shared/git";
32import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";32import * as HostProcess from "@t3tools/shared/HostProcess";
33import { compactTraceAttributes } from "@t3tools/shared/observability";33import { compactTraceAttributes } from "@t3tools/shared/observability";
34import { decodeJsonResult } from "@t3tools/shared/schemaJson";34import { decodeJsonResult } from "@t3tools/shared/schemaJson";
35import { parseT3ProjectFile } from "@t3tools/shared/t3ProjectFile";35import { parseT3ProjectFile } from "@t3tools/shared/t3ProjectFile";
...@@ -944,7 +944,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*...@@ -944,7 +944,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
944 const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;944 const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
945 const { worktreesDir } = yield* ServerConfig.ServerConfig;945 const { worktreesDir } = yield* ServerConfig.ServerConfig;
946 const crypto = yield* Crypto.Crypto;946 const crypto = yield* Crypto.Crypto;
947 const hostPlatform = yield* HostProcessPlatform;947 const hostPlatform = yield* HostProcess.Platform;
948948
949 const executeRaw: GitVcsDriver.GitVcsDriver["Service"]["execute"] = Effect.fnUntraced(949 const executeRaw: GitVcsDriver.GitVcsDriver["Service"]["execute"] = Effect.fnUntraced(
950 function* (input) {950 function* (input) {
...@@ -2657,7 +2657,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*...@@ -2657,7 +2657,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
2657 "hash-object",2657 "hash-object",
2658 "-t",2658 "-t",
2659 "tree",2659 "tree",
2660 (yield* HostProcessPlatform) === "win32" ? "NUL" : "/dev/null",2660 (yield* HostProcess.Platform) === "win32" ? "NUL" : "/dev/null",
2661 ]);2661 ]);
2662 return stdout.trim();2662 return stdout.trim();
2663 });2663 });
...@@ -3403,7 +3403,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*...@@ -3403,7 +3403,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
3403 options?.worktreesDirectory ?? "",3403 options?.worktreesDirectory ?? "",
3404 worktreesDir,3404 worktreesDir,
3405 path,3405 path,
3406 yield* HostProcessHomeDirectory,3406 yield* HostProcess.HomeDirectory,
3407 );3407 );
3408 if (parentDir === null) {3408 if (parentDir === null) {
3409 return yield* new GitCommandError({3409 return yield* new GitCommandError({
apps/server/src/vcs/VcsProcess.test.ts+2-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, describe, expect, it } from "@effect/vitest";2import { assert, describe, expect, it } from "@effect/vitest";
3import { HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Duration from "effect/Duration";4import * as Duration from "effect/Duration";
5import * as Deferred from "effect/Deferred";5import * as Deferred from "effect/Deferred";
6import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
...@@ -535,7 +535,7 @@ describe("VcsProcess.run", () => {...@@ -535,7 +535,7 @@ describe("VcsProcess.run", () => {
535 operation: "test.output-limit",535 operation: "test.output-limit",
536 command: "node",536 command: "node",
537 args: ["-e", "process.stdout.write('x'.repeat(2048))"],537 args: ["-e", "process.stdout.write('x'.repeat(2048))"],
538 cwd: yield* HostProcessWorkingDirectory,538 cwd: yield* HostProcess.WorkingDirectory,
539 maxOutputBytes: 128,539 maxOutputBytes: 128,
540 outputMode: "error",540 outputMode: "error",
541 }).pipe(Effect.flip);541 }).pipe(Effect.flip);
apps/server/src/workspace/WorkspaceEntries.test.ts+3-3
...@@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError";...@@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError";
11import { vi } from "vite-plus/test";11import { vi } from "vite-plus/test";
1212
13import * as ServerConfig from "../config.ts";13import * as ServerConfig from "../config.ts";
14import { HostProcessPlatform } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
15import * as VcsProcess from "../vcs/VcsProcess.ts";15import * as VcsProcess from "../vcs/VcsProcess.ts";
16import * as WorkspaceEntries from "./WorkspaceEntries.ts";16import * as WorkspaceEntries from "./WorkspaceEntries.ts";
17import * as WorkspacePaths from "./WorkspacePaths.ts";17import * as WorkspacePaths from "./WorkspacePaths.ts";
...@@ -84,7 +84,7 @@ const searchWorkspaceEntries = (input: {...@@ -84,7 +84,7 @@ const searchWorkspaceEntries = (input: {
84 });84 });
8585
86const appendSeparator = (input: string) =>86const appendSeparator = (input: string) =>
87 Effect.map(HostProcessPlatform, (platform) =>87 Effect.map(HostProcess.Platform, (platform) =>
88 input.endsWith("/") || input.endsWith("\\")88 input.endsWith("/") || input.endsWith("\\")
89 ? input89 ? input
90 : `${input}${platform === "win32" ? "\\" : "/"}`,90 : `${input}${platform === "win32" ? "\\" : "/"}`,
...@@ -143,7 +143,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceEntries", (it) => {...@@ -143,7 +143,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceEntries", (it) => {
143 const fileSystem = yield* FileSystem.FileSystem;143 const fileSystem = yield* FileSystem.FileSystem;
144 const path = yield* Path.Path;144 const path = yield* Path.Path;
145 yield* writeTextFile(cwd, ".git/HEAD");145 yield* writeTextFile(cwd, ".git/HEAD");
146 const platform = yield* HostProcessPlatform;146 const platform = yield* HostProcess.Platform;
147 if (platform !== "win32") yield* fileSystem.symlink(outside, path.join(cwd, "external"));147 if (platform !== "win32") yield* fileSystem.symlink(outside, path.join(cwd, "external"));
148 const workspaceEntries = yield* WorkspaceEntries.WorkspaceEntries;148 const workspaceEntries = yield* WorkspaceEntries.WorkspaceEntries;
149 for (const directoryPath of [149 for (const directoryPath of [
apps/server/src/workspace/WorkspaceEntries.ts+4-4
...@@ -19,7 +19,7 @@ import type {...@@ -19,7 +19,7 @@ import type {
19 ProjectSearchEntriesInput,19 ProjectSearchEntriesInput,
20 ProjectSearchEntriesResult,20 ProjectSearchEntriesResult,
21} from "@t3tools/contracts";21} from "@t3tools/contracts";
22import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";22import * as HostProcess from "@t3tools/shared/HostProcess";
23import { isExplicitRelativePath, isWindowsAbsolutePath } from "@t3tools/shared/path";23import { isExplicitRelativePath, isWindowsAbsolutePath } from "@t3tools/shared/path";
24import { normalizeSearchQuery } from "@t3tools/shared/searchRanking";24import { normalizeSearchQuery } from "@t3tools/shared/searchRanking";
2525
...@@ -110,7 +110,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu...@@ -110,7 +110,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
110 input: FilesystemBrowseInput,110 input: FilesystemBrowseInput,
111 path: Path.Path,111 path: Path.Path,
112): Effect.fn.Return<string, WorkspaceEntriesBrowseError> {112): Effect.fn.Return<string, WorkspaceEntriesBrowseError> {
113 const platform = yield* HostProcessPlatform;113 const platform = yield* HostProcess.Platform;
114 if (platform !== "win32" && isWindowsAbsolutePath(input.partialPath)) {114 if (platform !== "win32" && isWindowsAbsolutePath(input.partialPath)) {
115 return yield* new WorkspaceEntriesWindowsPathUnsupportedError({115 return yield* new WorkspaceEntriesWindowsPathUnsupportedError({
116 cwd: input.cwd,116 cwd: input.cwd,
...@@ -120,7 +120,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu...@@ -120,7 +120,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
120 }120 }
121121
122 if (!isExplicitRelativePath(input.partialPath)) {122 if (!isExplicitRelativePath(input.partialPath)) {
123 return path.resolve(expandHomePath(input.partialPath, yield* HostProcessHomeDirectory));123 return path.resolve(expandHomePath(input.partialPath, yield* HostProcess.HomeDirectory));
124 }124 }
125125
126 if (!input.cwd) {126 if (!input.cwd) {
...@@ -129,7 +129,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu...@@ -129,7 +129,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
129 });129 });
130 }130 }
131 return path.resolve(131 return path.resolve(
132 expandHomePath(input.cwd, yield* HostProcessHomeDirectory),132 expandHomePath(input.cwd, yield* HostProcess.HomeDirectory),
133 input.partialPath,133 input.partialPath,
134 );134 );
135});135});
apps/server/src/workspace/WorkspaceFileSystem.test.ts+2-2
...@@ -14,7 +14,7 @@ import * as VcsProcess from "../vcs/VcsProcess.ts";...@@ -14,7 +14,7 @@ import * as VcsProcess from "../vcs/VcsProcess.ts";
14import * as WorkspaceEntries from "./WorkspaceEntries.ts";14import * as WorkspaceEntries from "./WorkspaceEntries.ts";
15import * as WorkspaceFileSystem from "./WorkspaceFileSystem.ts";15import * as WorkspaceFileSystem from "./WorkspaceFileSystem.ts";
16import * as WorkspacePaths from "./WorkspacePaths.ts";16import * as WorkspacePaths from "./WorkspacePaths.ts";
17import { HostProcessPlatform } from "@t3tools/shared/hostProcess";17import * as HostProcess from "@t3tools/shared/HostProcess";
18import { symlinksSupported } from "@t3tools/shared/testing/symlinks";18import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
1919
20const layerProject = WorkspaceFileSystem.layer.pipe(20const layerProject = WorkspaceFileSystem.layer.pipe(
...@@ -102,7 +102,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceFileSystemLive", (i...@@ -102,7 +102,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceFileSystemLive", (i
102 );102 );
103103
104 // Needs mkfifo; Windows has no FIFOs to reject.104 // Needs mkfifo; Windows has no FIFOs to reject.
105 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(105 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
106 "rejects a FIFO without blocking on open",106 "rejects a FIFO without blocking on open",
107 () =>107 () =>
108 Effect.gen(function* () {108 Effect.gen(function* () {
apps/server/src/workspace/WorkspacePaths.ts+2-2
...@@ -15,7 +15,7 @@ import * as Path from "effect/Path";...@@ -15,7 +15,7 @@ import * as Path from "effect/Path";
15import * as Schema from "effect/Schema";15import * as Schema from "effect/Schema";
1616
17import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";17import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";
18import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";18import * as HostProcess from "@t3tools/shared/HostProcess";
1919
20export class WorkspaceRootNotExistsError extends Schema.TaggedError<WorkspaceRootNotExistsError>()(20export class WorkspaceRootNotExistsError extends Schema.TaggedError<WorkspaceRootNotExistsError>()(
21 "WorkspaceRootNotExistsError",21 "WorkspaceRootNotExistsError",
...@@ -154,7 +154,7 @@ export const make = Effect.gen(function* () {...@@ -154,7 +154,7 @@ export const make = Effect.gen(function* () {
154 "WorkspacePaths.normalizeWorkspaceRoot",154 "WorkspacePaths.normalizeWorkspaceRoot",
155 )(function* (workspaceRoot, options) {155 )(function* (workspaceRoot, options) {
156 const normalizedWorkspaceRoot = path.resolve(156 const normalizedWorkspaceRoot = path.resolve(
157 expandHomePath(workspaceRoot.trim(), yield* HostProcessHomeDirectory),157 expandHomePath(workspaceRoot.trim(), yield* HostProcess.HomeDirectory),
158 );158 );
159 let workspaceStat = yield* statWorkspaceRoot(159 let workspaceStat = yield* statWorkspaceRoot(
160 workspaceRoot,160 workspaceRoot,
apps/server/src/ws.test.ts+2-2
...@@ -4,7 +4,7 @@ import {...@@ -4,7 +4,7 @@ import {
4 type ServerConfig,4 type ServerConfig,
5 type ServerConfigStreamEvent,5 type ServerConfigStreamEvent,
6} from "@t3tools/contracts";6} from "@t3tools/contracts";
7import { HostProcessPlatform } from "@t3tools/shared/hostProcess";7import * as HostProcess from "@t3tools/shared/HostProcess";
8import * as ConfigProvider from "effect/ConfigProvider";8import * as ConfigProvider from "effect/ConfigProvider";
9import * as Deferred from "effect/Deferred";9import * as Deferred from "effect/Deferred";
10import * as Duration from "effect/Duration";10import * as Duration from "effect/Duration";
...@@ -164,7 +164,7 @@ const makeParkedWindowsLauncher = Effect.gen(function* () {...@@ -164,7 +164,7 @@ const makeParkedWindowsLauncher = Effect.gen(function* () {
164 );164 );
165 const onWindows = <A, E, R>(effect: Effect.Effect<A, E, R>) =>165 const onWindows = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
166 effect.pipe(166 effect.pipe(
167 Effect.provideService(HostProcessPlatform, "win32"),167 Effect.provideService(HostProcess.Platform, "win32"),
168 Effect.provide(168 Effect.provide(
169 ConfigProvider.layer(169 ConfigProvider.layer(
170 ConfigProvider.fromEnv({170 ConfigProvider.fromEnv({
oxlint-plugin-t3code/rules/no-global-process-runtime.test.ts+6-6
...@@ -8,10 +8,10 @@ describe("t3code/no-global-process-runtime", () => {...@@ -8,10 +8,10 @@ describe("t3code/no-global-process-runtime", () => {
8 rule.valid(8 rule.valid(
9 "allows injected host process references",9 "allows injected host process references",
10 `10 `
11 import { HostProcessPlatform } from "@t3tools/shared/hostProcess";11 import * as HostProcess from "@t3tools/shared/HostProcess";
12 import * as Effect from "effect/Effect";12 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");
15 `,15 `,
16 );16 );
1717
...@@ -38,7 +38,7 @@ describe("t3code/no-global-process-runtime", () => {...@@ -38,7 +38,7 @@ describe("t3code/no-global-process-runtime", () => {
38 export const isWindows = process.platform === "win32";38 export const isWindows = process.platform === "win32";
39 `,39 `,
40 (output) => {40 (output) => {
41 assert.match(output, /Use HostProcessPlatform/);41 assert.match(output, /Use HostProcess\.Platform/);
42 },42 },
43 );43 );
4444
...@@ -48,7 +48,7 @@ describe("t3code/no-global-process-runtime", () => {...@@ -48,7 +48,7 @@ describe("t3code/no-global-process-runtime", () => {
48 export const isArm = process.arch === "arm64";48 export const isArm = process.arch === "arm64";
49 `,49 `,
50 (output) => {50 (output) => {
51 assert.match(output, /Use HostProcessArchitecture/);51 assert.match(output, /Use HostProcess\.Architecture/);
52 },52 },
53 );53 );
5454
...@@ -67,7 +67,7 @@ describe("t3code/no-global-process-runtime", () => {...@@ -67,7 +67,7 @@ describe("t3code/no-global-process-runtime", () => {
67 export const isWindows = NodeOS.platform() === "win32";67 export const isWindows = NodeOS.platform() === "win32";
68 `,68 `,
69 (output) => {69 (output) => {
70 assert.match(output, /Use HostProcessPlatform/);70 assert.match(output, /Use HostProcess\.Platform/);
71 },71 },
72 );72 );
7373
...@@ -79,7 +79,7 @@ describe("t3code/no-global-process-runtime", () => {...@@ -79,7 +79,7 @@ describe("t3code/no-global-process-runtime", () => {
79 export const isArm = hostArch() === "arm64";79 export const isArm = hostArch() === "arm64";
80 `,80 `,
81 (output) => {81 (output) => {
82 assert.match(output, /Use HostProcessArchitecture/);82 assert.match(output, /Use HostProcess\.Architecture/);
83 },83 },
84 );84 );
8585
oxlint-plugin-t3code/rules/no-global-process-runtime.ts+1-1
...@@ -19,7 +19,7 @@ const isGlobalProcessObject = (node: unknown): boolean => {...@@ -19,7 +19,7 @@ const isGlobalProcessObject = (node: unknown): boolean => {
19};19};
2020
21const message = (property: string) =>21const 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
24const getLiteralStringValue = (node: unknown): Option.Option<string> => {24const getLiteralStringValue = (node: unknown): Option.Option<string> => {
25 if (typeof node !== "object" || node === null) return Option.none();25 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 {...@@ -6,11 +6,7 @@ import {
6 ProviderInstanceId,6 ProviderInstanceId,
7} from "@t3tools/contracts";7} from "@t3tools/contracts";
8import { AcpRegistrySettings } from "../settings.ts";8import { AcpRegistrySettings } from "../settings.ts";
9import {9import * as HostProcess from "@t3tools/shared/HostProcess";
10 HostProcessArchitecture,
11 HostProcessEnvironment,
12 HostProcessPlatform,
13} from "@t3tools/shared/hostProcess";
14import { SpawnExecutableResolution } from "@t3tools/shared/shell";10import { SpawnExecutableResolution } from "@t3tools/shared/shell";
15import * as Deferred from "effect/Deferred";11import * as Deferred from "effect/Deferred";
16import * as Effect from "effect/Effect";12import * as Effect from "effect/Effect";
...@@ -63,9 +59,9 @@ function layerResolver(...@@ -63,9 +59,9 @@ function layerResolver(
63 return Layer.mergeAll(59 return Layer.mergeAll(
64 NodeServices.layer,60 NodeServices.layer,
65 TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)),61 TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)),
66 Layer.succeed(HostProcessPlatform, "linux"),62 Layer.succeed(HostProcess.Platform, "linux"),
67 Layer.succeed(HostProcessArchitecture, "x64"),63 Layer.succeed(HostProcess.Architecture, "x64"),
68 Layer.succeed(HostProcessEnvironment, environment),64 Layer.succeed(HostProcess.Environment, environment),
69 Layer.succeed(HttpClient.HttpClient, HttpClient.make(execute)),65 Layer.succeed(HttpClient.HttpClient, HttpClient.make(execute)),
70 );66 );
71}67}
...@@ -229,7 +225,7 @@ describe("AcpRegistrySupport", () => {...@@ -229,7 +225,7 @@ describe("AcpRegistrySupport", () => {
229 cacheDir,225 cacheDir,
230 toolsDir: `${cacheDir}/tools`,226 toolsDir: `${cacheDir}/tools`,
231 registryUrl,227 registryUrl,
232 }).pipe(Effect.provideService(HostProcessEnvironment, hostEnvironment));228 }).pipe(Effect.provideService(HostProcess.Environment, hostEnvironment));
233 const localSettings = decodeAcpRegistrySettings({229 const localSettings = decodeAcpRegistrySettings({
234 source: "local",230 source: "local",
235 commandPath: "dsh",231 commandPath: "dsh",
...@@ -279,7 +275,7 @@ describe("AcpRegistrySupport", () => {...@@ -279,7 +275,7 @@ describe("AcpRegistrySupport", () => {
279 cacheDir,275 cacheDir,
280 toolsDir: `${cacheDir}/tools`,276 toolsDir: `${cacheDir}/tools`,
281 registryUrl,277 registryUrl,
282 }).pipe(Effect.provideService(HostProcessEnvironment, environment));278 }).pipe(Effect.provideService(HostProcess.Environment, environment));
283 const resolved = yield* resolver.resolve(279 const resolved = yield* resolver.resolve(
284 decodeAcpRegistrySettings({ source: "local", commandPath }),280 decodeAcpRegistrySettings({ source: "local", commandPath }),
285 "/workspace",281 "/workspace",
...@@ -300,7 +296,7 @@ describe("AcpRegistrySupport", () => {...@@ -300,7 +296,7 @@ describe("AcpRegistrySupport", () => {
300 toolsDir: `${cacheDir}/tools`,296 toolsDir: `${cacheDir}/tools`,
301 registryUrl,297 registryUrl,
302 }).pipe(298 }).pipe(
303 Effect.provideService(HostProcessPlatform, "win32"),299 Effect.provideService(HostProcess.Platform, "win32"),
304 Effect.provideService(SpawnExecutableResolution, () => `C:\\bin\\dsh${extension}`),300 Effect.provideService(SpawnExecutableResolution, () => `C:\\bin\\dsh${extension}`),
305 );301 );
306 const localSettings = decodeAcpRegistrySettings({ source: "local", commandPath: "dsh" });302 const localSettings = decodeAcpRegistrySettings({ source: "local", commandPath: "dsh" });
...@@ -432,7 +428,7 @@ describe("AcpRegistrySupport", () => {...@@ -432,7 +428,7 @@ describe("AcpRegistrySupport", () => {
432 cacheDir,428 cacheDir,
433 toolsDir: `${cacheDir}/tools`,429 toolsDir: `${cacheDir}/tools`,
434 registryUrl,430 registryUrl,
435 }).pipe(Effect.provideService(HostProcessEnvironment, toolchain.environment));431 }).pipe(Effect.provideService(HostProcess.Environment, toolchain.environment));
436432
437 const first = yield* resolver.resolve(settings(), "/workspace", toolchain.environment);433 const first = yield* resolver.resolve(settings(), "/workspace", toolchain.environment);
438 const second = yield* resolver.resolve(settings(), "/workspace", toolchain.environment);434 const second = yield* resolver.resolve(settings(), "/workspace", toolchain.environment);
...@@ -478,7 +474,7 @@ describe("AcpRegistrySupport", () => {...@@ -478,7 +474,7 @@ describe("AcpRegistrySupport", () => {
478 cacheDir,474 cacheDir,
479 toolsDir: `${cacheDir}/tools`,475 toolsDir: `${cacheDir}/tools`,
480 registryUrl,476 registryUrl,
481 }).pipe(Effect.provideService(HostProcessEnvironment, environment));477 }).pipe(Effect.provideService(HostProcess.Environment, environment));
482478
483 const resolved = yield* resolver.resolve(settings(), "/workspace", environment);479 const resolved = yield* resolver.resolve(settings(), "/workspace", environment);
484 const userGlobalBin = toolchain.globalBin;480 const userGlobalBin = toolchain.globalBin;
...@@ -559,7 +555,7 @@ describe("AcpRegistrySupport", () => {...@@ -559,7 +555,7 @@ describe("AcpRegistrySupport", () => {
559 toolsDir: `${cacheDir}/tools`,555 toolsDir: `${cacheDir}/tools`,
560 registryUrl,556 registryUrl,
561 }).pipe(557 }).pipe(
562 Effect.provideService(HostProcessPlatform, "win32"),558 Effect.provideService(HostProcess.Platform, "win32"),
563 Effect.provideService(SpawnExecutableResolution, (command) => {559 Effect.provideService(SpawnExecutableResolution, (command) => {
564 if (command === "uv") return toolchain.uvPath;560 if (command === "uv") return toolchain.uvPath;
565 if (command === "fast-agent") return toolchain.executablePath;561 if (command === "fast-agent") return toolchain.executablePath;
...@@ -677,7 +673,7 @@ describe("AcpRegistrySupport", () => {...@@ -677,7 +673,7 @@ describe("AcpRegistrySupport", () => {
677 cacheDir,673 cacheDir,
678 toolsDir: `${cacheDir}/tools`,674 toolsDir: `${cacheDir}/tools`,
679 registryUrl,675 registryUrl,
680 }).pipe(Effect.provideService(HostProcessEnvironment, environment));676 }).pipe(Effect.provideService(HostProcess.Environment, environment));
681 yield* resolver.search({ query: "example" });677 yield* resolver.search({ query: "example" });
682 expect(yield* resolver.inspect(settings(), environment)).toMatchObject({678 expect(yield* resolver.inspect(settings(), environment)).toMatchObject({
683 status: "unprepared",679 status: "unprepared",
...@@ -781,8 +777,8 @@ describe("AcpRegistrySupport", () => {...@@ -781,8 +777,8 @@ describe("AcpRegistrySupport", () => {
781 TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)),777 TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)),
782 ),778 ),
783 ),779 ),
784 Effect.provideService(HostProcessPlatform, "linux"),780 Effect.provideService(HostProcess.Platform, "linux"),
785 Effect.provideService(HostProcessArchitecture, "x64"),781 Effect.provideService(HostProcess.Architecture, "x64"),
786 );782 );
787 });783 });
788784
...@@ -1097,7 +1093,7 @@ describe("AcpRegistrySupport", () => {...@@ -1097,7 +1093,7 @@ describe("AcpRegistrySupport", () => {
1097 cacheDir,1093 cacheDir,
1098 toolsDir: `${cacheDir}/tools`,1094 toolsDir: `${cacheDir}/tools`,
1099 registryUrl,1095 registryUrl,
1100 }).pipe(Effect.provideService(HostProcessEnvironment, toolchain.environment));1096 }).pipe(Effect.provideService(HostProcess.Environment, toolchain.environment));
1101 const prepared = yield* resolver.prepare({ agentId: agent.id });1097 const prepared = yield* resolver.prepare({ agentId: agent.id });
1102 expect(prepared).toEqual({1098 expect(prepared).toEqual({
1103 agentId: "example-agent",1099 agentId: "example-agent",
packages/provider-acp-registry/src/server/AcpRegistrySupport.ts+4-8
...@@ -12,11 +12,7 @@ import {...@@ -12,11 +12,7 @@ import {
12} from "@t3tools/contracts";12} from "@t3tools/contracts";
13import type { AcpRegistryDistributionPreference } from "../settings.ts";13import type { AcpRegistryDistributionPreference } from "../settings.ts";
14import type { AcpRegistrySettings } from "../settings.ts";14import type { AcpRegistrySettings } from "../settings.ts";
15import {15import * as HostProcess from "@t3tools/shared/HostProcess";
16 HostProcessArchitecture,
17 HostProcessEnvironment,
18 HostProcessPlatform,
19} from "@t3tools/shared/hostProcess";
20import {16import {
21 mergePathEntries,17 mergePathEntries,
22 resolveSpawnCommand,18 resolveSpawnCommand,
...@@ -637,9 +633,9 @@ export const makeAcpRegistryCatalog = Effect.fn("AcpRegistryCatalog.make")(funct...@@ -637,9 +633,9 @@ export const makeAcpRegistryCatalog = Effect.fn("AcpRegistryCatalog.make")(funct
637 const httpClient = yield* HttpClient.HttpClient;633 const httpClient = yield* HttpClient.HttpClient;
638 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;634 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
639 const { settings: hostSettings } = yield* ProviderHost.ProviderHost;635 const { settings: hostSettings } = yield* ProviderHost.ProviderHost;
640 const platform = yield* HostProcessPlatform;636 const platform = yield* HostProcess.Platform;
641 const architecture = yield* HostProcessArchitecture;637 const architecture = yield* HostProcess.Architecture;
642 const hostEnvironment = yield* HostProcessEnvironment;638 const hostEnvironment = yield* HostProcess.Environment;
643 const resolveExecutable = yield* SpawnExecutableResolution;639 const resolveExecutable = yield* SpawnExecutableResolution;
644 const platformTarget = resolveAcpRegistryPlatformTarget(platform, architecture);640 const platformTarget = resolveAcpRegistryPlatformTarget(platform, architecture);
645 const registryUrl = input.registryUrl ?? ACP_REGISTRY_URL;641 const registryUrl = input.registryUrl ?? ACP_REGISTRY_URL;
packages/provider-acp-registry/src/server/adapter.ts+2-2
...@@ -5,7 +5,7 @@ import {...@@ -5,7 +5,7 @@ import {
5} from "./devinAcp.ts";5} from "./devinAcp.ts";
6import { defaultInstanceIdForDriver, ProviderDriverKind } from "@t3tools/contracts";6import { defaultInstanceIdForDriver, ProviderDriverKind } from "@t3tools/contracts";
7import { AcpRegistrySettings } from "../settings.ts";7import { AcpRegistrySettings } from "../settings.ts";
8import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
9import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime";9import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime";
10import * as Crypto from "effect/Crypto";10import * as Crypto from "effect/Crypto";
11import * as Effect from "effect/Effect";11import * as Effect from "effect/Effect";
...@@ -271,7 +271,7 @@ export const AcpRegistryAdapterV2Driver: ProviderAdapterDriver<...@@ -271,7 +271,7 @@ export const AcpRegistryAdapterV2Driver: ProviderAdapterDriver<
271 defaultConfig: (): AcpRegistrySettings => DEFAULT_ACP_REGISTRY_SETTINGS,271 defaultConfig: (): AcpRegistrySettings => DEFAULT_ACP_REGISTRY_SETTINGS,
272 create: Effect.fn("AcpRegistryAdapterV2Driver.create")(272 create: Effect.fn("AcpRegistryAdapterV2Driver.create")(
273 function* (input: ProviderAdapterDriverCreateInput<AcpRegistrySettings>) {273 function* (input: ProviderAdapterDriverCreateInput<AcpRegistrySettings>) {
274 const hostEnvironment = yield* HostProcessEnvironment;274 const hostEnvironment = yield* HostProcess.Environment;
275 const selfInvocation = yield* resolveSelfInvocation();275 const selfInvocation = yield* resolveSelfInvocation();
276 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;276 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
277 const makeNativeLogger = yield* makeAcpNativeLoggerFactory();277 const makeNativeLogger = yield* makeAcpNativeLoggerFactory();
packages/provider-acp-registry/src/server/driver.ts+2-2
...@@ -8,7 +8,7 @@ import {...@@ -8,7 +8,7 @@ import {
8 type ServerProviderModel,8 type ServerProviderModel,
9} from "@t3tools/contracts";9} from "@t3tools/contracts";
10import { AcpRegistrySettings } from "../settings.ts";10import { AcpRegistrySettings } from "../settings.ts";
11import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";11import * as HostProcess from "@t3tools/shared/HostProcess";
12import { createModelCapabilities } from "@t3tools/shared/model";12import { createModelCapabilities } from "@t3tools/shared/model";
13import * as Clock from "effect/Clock";13import * as Clock from "effect/Clock";
14import * as Crypto from "effect/Crypto";14import * as Crypto from "effect/Crypto";
...@@ -484,7 +484,7 @@ export const AcpRegistryDriver: ProviderDriver<AcpRegistrySettings, AcpRegistryD...@@ -484,7 +484,7 @@ export const AcpRegistryDriver: ProviderDriver<AcpRegistrySettings, AcpRegistryD
484 }484 }
485 const crypto = yield* Crypto.Crypto;485 const crypto = yield* Crypto.Crypto;
486 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;486 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
487 const hostEnvironment = yield* HostProcessEnvironment;487 const hostEnvironment = yield* HostProcess.Environment;
488 const host = yield* ProviderHost.ProviderHost;488 const host = yield* ProviderHost.ProviderHost;
489 const continuationIdentity = defaultProviderContinuationIdentity({489 const continuationIdentity = defaultProviderContinuationIdentity({
490 driverKind: DRIVER_KIND,490 driverKind: DRIVER_KIND,
packages/provider-acp/src/server/AcpSessionRuntime.ts+3-3
...@@ -27,7 +27,7 @@ import * as EffectAcpErrors from "effect-acp/errors";...@@ -27,7 +27,7 @@ import * as EffectAcpErrors from "effect-acp/errors";
27import type * as EffectAcpSchema from "effect-acp/compat";27import type * as EffectAcpSchema from "effect-acp/compat";
28import type * as EffectAcpProtocol from "effect-acp/protocol";28import type * as EffectAcpProtocol from "effect-acp/protocol";
29import { resolveSpawnCommand } from "@t3tools/shared/shell";29import { resolveSpawnCommand } from "@t3tools/shared/shell";
30import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";30import * as HostProcess from "@t3tools/shared/HostProcess";
3131
32import { signalProcessGroup } from "@t3tools/provider-core/server/processGroup";32import { signalProcessGroup } from "@t3tools/provider-core/server/processGroup";
33import { appendAcpStderrTail, sanitizeAcpStderrExcerpt } from "./stderr.ts";33import { appendAcpStderrTail, sanitizeAcpStderrExcerpt } from "./stderr.ts";
...@@ -1408,7 +1408,7 @@ export const make = (...@@ -1408,7 +1408,7 @@ export const make = (
1408 const stoppingRef = yield* Ref.make(false);1408 const stoppingRef = yield* Ref.make(false);
1409 const stderrFailure = yield* Deferred.make<never, EffectAcpErrors.AcpError>();1409 const stderrFailure = yield* Deferred.make<never, EffectAcpErrors.AcpError>();
1410 const stderrTailRef = yield* Ref.make("");1410 const stderrTailRef = yield* Ref.make("");
1411 const homeDirectory = yield* HostProcessHomeDirectory;1411 const homeDirectory = yield* HostProcess.HomeDirectory;
1412 const stderrDrained = yield* Deferred.make<void>();1412 const stderrDrained = yield* Deferred.make<void>();
1413 const runtimeClosed = yield* Deferred.make<void>();1413 const runtimeClosed = yield* Deferred.make<void>();
1414 const promptSerializationSemaphore = yield* Semaphore.make(1);1414 const promptSerializationSemaphore = yield* Semaphore.make(1);
...@@ -1729,7 +1729,7 @@ export const make = (...@@ -1729,7 +1729,7 @@ export const make = (
1729 Effect.uninterruptible(terminateOwnedProcessGroupImpl),1729 Effect.uninterruptible(terminateOwnedProcessGroupImpl),
1730 );1730 );
1731 if (options.ownDetachedProcessGroup === true) {1731 if (options.ownDetachedProcessGroup === true) {
1732 const hostPlatform = yield* HostProcessPlatform;1732 const hostPlatform = yield* HostProcess.Platform;
1733 const forceTerminateOwnedProcessGroup =1733 const forceTerminateOwnedProcessGroup =
1734 hostPlatform === "win32"1734 hostPlatform === "win32"
1735 ? terminateWindowsProcessTreeWithTaskkill(Number(child.pid)).pipe(1735 ? 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";...@@ -2,7 +2,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
2import { describe, expect, it } from "@effect/vitest";2import { describe, expect, it } from "@effect/vitest";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Path from "effect/Path";4import * as Path from "effect/Path";
5import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
66
7import { mergeProviderInstanceEnvironment } from "./instanceEnvironment.ts";7import { mergeProviderInstanceEnvironment } from "./instanceEnvironment.ts";
88
...@@ -36,7 +36,7 @@ describe("mergeProviderInstanceEnvironment", () => {...@@ -36,7 +36,7 @@ describe("mergeProviderInstanceEnvironment", () => {
36 CLAUDE_CONFIG_DIR: "~/.inherited-claude",36 CLAUDE_CONFIG_DIR: "~/.inherited-claude",
37 });37 });
38 }).pipe(38 }).pipe(
39 Effect.provideService(HostProcessHomeDirectory, "/home/ada"),39 Effect.provideService(HostProcess.HomeDirectory, "/home/ada"),
40 Effect.provide(NodeServices.layer),40 Effect.provide(NodeServices.layer),
41 ),41 ),
42 );42 );
packages/provider-core/src/server/instanceEnvironment.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import type { ProviderInstanceEnvironment } from "@t3tools/contracts";1import type { ProviderInstanceEnvironment } from "@t3tools/contracts";
2import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
44
5import { expandHomePath } from "./pathExpansion.ts";5import { expandHomePath } from "./pathExpansion.ts";
...@@ -12,7 +12,7 @@ export const mergeProviderInstanceEnvironment = Effect.fn(function* (...@@ -12,7 +12,7 @@ export const mergeProviderInstanceEnvironment = Effect.fn(function* (
12 return baseEnv;12 return baseEnv;
13 }13 }
1414
15 const home = yield* HostProcessHomeDirectory;15 const home = yield* HostProcess.HomeDirectory;
16 const next: NodeJS.ProcessEnv = { ...baseEnv };16 const next: NodeJS.ProcessEnv = { ...baseEnv };
17 for (const variable of environment) {17 for (const variable of environment) {
18 // Child processes do not apply shell expansion to environment values.18 // 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";...@@ -6,7 +6,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
6import * as NodeOS from "node:os";6import * as NodeOS from "node:os";
7import * as NodePath from "node:path";7import * as NodePath from "node:path";
8import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3tools/contracts";8import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3tools/contracts";
9import { HostProcessPlatform } from "@t3tools/shared/hostProcess";9import * as HostProcess from "@t3tools/shared/HostProcess";
10import * as Crypto from "effect/Crypto";10import * as Crypto from "effect/Crypto";
11import * as Deferred from "effect/Deferred";11import * as Deferred from "effect/Deferred";
12import * as Effect from "effect/Effect";12import * as Effect from "effect/Effect";
...@@ -37,7 +37,7 @@ import { symlinksSupported } from "@t3tools/shared/testing/symlinks";...@@ -37,7 +37,7 @@ import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
37const driver = (value: string) => ProviderDriverKind.make(value);37const driver = (value: string) => ProviderDriverKind.make(value);
38// These write `#!/bin/sh` stubs and evaluate them with darwin/linux path38// These write `#!/bin/sh` stubs and evaluate them with darwin/linux path
39// semantics; a Windows temp path cannot be split on `:`.39// semantics; a Windows temp path cannot be split on `:`.
40const windowsHost = HostProcessPlatform.defaultValue() === "win32";40const windowsHost = HostProcess.Platform.defaultValue() === "win32";
41const makeTempDir = (name: string) =>41const makeTempDir = (name: string) =>
42 Crypto.Crypto.pipe(42 Crypto.Crypto.pipe(
43 Effect.flatMap((crypto) => crypto.randomUUIDv4),43 Effect.flatMap((crypto) => crypto.randomUUIDv4),
...@@ -332,7 +332,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -332,7 +332,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
332 env: {},332 env: {},
333 platform: "win32",333 platform: "win32",
334 },334 },
335 ).pipe(Effect.provideService(HostProcessPlatform, "win32"));335 ).pipe(Effect.provideService(HostProcess.Platform, "win32"));
336336
337 expect(capabilities.update).toMatchObject({337 expect(capabilities.update).toMatchObject({
338 executable: visiblePath,338 executable: visiblePath,
...@@ -360,7 +360,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -360,7 +360,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
360 binaryPath: shim,360 binaryPath: shim,
361 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },361 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
362 }).pipe(362 }).pipe(
363 Effect.provideService(HostProcessPlatform, "win32"),363 Effect.provideService(HostProcess.Platform, "win32"),
364 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),364 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
365 );365 );
366366
...@@ -376,7 +376,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -376,7 +376,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
376 binaryPath: script,376 binaryPath: script,
377 env: { PATH: "" },377 env: { PATH: "" },
378 }).pipe(378 }).pipe(
379 Effect.provideService(HostProcessPlatform, "linux"),379 Effect.provideService(HostProcess.Platform, "linux"),
380 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),380 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
381 );381 );
382 expect(posix.update).toBeNull();382 expect(posix.update).toBeNull();
...@@ -429,7 +429,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -429,7 +429,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
429 env: { PATH: bunBinDir },429 env: { PATH: bunBinDir },
430 },430 },
431 ).pipe(431 ).pipe(
432 Effect.provideService(HostProcessPlatform, "darwin"),432 Effect.provideService(HostProcess.Platform, "darwin"),
433 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),433 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
434 );434 );
435435
...@@ -454,7 +454,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -454,7 +454,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
454 env: { PATH: nativeBinDir },454 env: { PATH: nativeBinDir },
455 },455 },
456 ).pipe(456 ).pipe(
457 Effect.provideService(HostProcessPlatform, "darwin"),457 Effect.provideService(HostProcess.Platform, "darwin"),
458 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),458 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn),
459 );459 );
460460
...@@ -659,7 +659,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -659,7 +659,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
659 env: { PATH: brewBinDir },659 env: { PATH: brewBinDir },
660 },660 },
661 ).pipe(661 ).pipe(
662 Effect.provideService(HostProcessPlatform, "darwin"),662 Effect.provideService(HostProcess.Platform, "darwin"),
663 Effect.provideService(663 Effect.provideService(
664 ChildProcessSpawner.ChildProcessSpawner,664 ChildProcessSpawner.ChildProcessSpawner,
665 stdoutSpawner((command, args) => {665 stdoutSpawner((command, args) => {
...@@ -725,7 +725,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -725,7 +725,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
725 env: { PATH: brewBinDir },725 env: { PATH: brewBinDir },
726 },726 },
727 ).pipe(727 ).pipe(
728 Effect.provideService(HostProcessPlatform, "darwin"),728 Effect.provideService(HostProcess.Platform, "darwin"),
729 Effect.provideService(729 Effect.provideService(
730 ChildProcessSpawner.ChildProcessSpawner,730 ChildProcessSpawner.ChildProcessSpawner,
731 stdoutSpawner(() => "/opt/homebrew\n"),731 stdoutSpawner(() => "/opt/homebrew\n"),
...@@ -864,7 +864,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -864,7 +864,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
864 binaryPath: kegBinary,864 binaryPath: kegBinary,
865 env: { PATH: "" },865 env: { PATH: "" },
866 }).pipe(866 }).pipe(
867 Effect.provideService(HostProcessPlatform, "darwin"),867 Effect.provideService(HostProcess.Platform, "darwin"),
868 Effect.provideService(868 Effect.provideService(
869 ChildProcessSpawner.ChildProcessSpawner,869 ChildProcessSpawner.ChildProcessSpawner,
870 stdoutSpawner((_command, args) => (args[0] === "--prefix" ? `${tempDir}\n` : "{}")),870 stdoutSpawner((_command, args) => (args[0] === "--prefix" ? `${tempDir}\n` : "{}")),
packages/provider-core/src/server/maintenanceResolver.ts+4-4
...@@ -12,7 +12,7 @@ import {...@@ -12,7 +12,7 @@ import {
12 type ServerProviderVersionAdvisory,12 type ServerProviderVersionAdvisory,
13} from "@t3tools/contracts";13} from "@t3tools/contracts";
14import { compareSemverVersions } from "@t3tools/shared/semver";14import { compareSemverVersions } from "@t3tools/shared/semver";
15import { HostProcessPlatform } from "@t3tools/shared/hostProcess";15import * as HostProcess from "@t3tools/shared/HostProcess";
16import { causeErrorTag } from "@t3tools/shared/observability";16import { causeErrorTag } from "@t3tools/shared/observability";
17import { resolveCommandPath } from "@t3tools/shared/shell";17import { resolveCommandPath } from "@t3tools/shared/shell";
18import * as Cache from "effect/Cache";18import * as Cache from "effect/Cache";
...@@ -141,7 +141,7 @@ export function makeProviderMaintenanceCapabilities(input: {...@@ -141,7 +141,7 @@ export function makeProviderMaintenanceCapabilities(input: {
141 readonly env?: NodeJS.ProcessEnv;141 readonly env?: NodeJS.ProcessEnv;
142 readonly latestVersion?: string | null;142 readonly latestVersion?: string | null;
143}): ProviderMaintenanceCapabilities {143}): ProviderMaintenanceCapabilities {
144 const platform = input.platform ?? HostProcessPlatform.defaultValue();144 const platform = input.platform ?? HostProcess.Platform.defaultValue();
145 const update =145 const update =
146 input.updateExecutable === null || input.updateLockKey === null146 input.updateExecutable === null || input.updateLockKey === null
147 ? null147 ? null
...@@ -587,7 +587,7 @@ const resolveNpmGlobalPrefix = Effect.fn("resolveNpmGlobalPrefix")(function* (...@@ -587,7 +587,7 @@ const resolveNpmGlobalPrefix = Effect.fn("resolveNpmGlobalPrefix")(function* (
587 if (fromRealPath) {587 if (fromRealPath) {
588 return fromRealPath;588 return fromRealPath;
589 }589 }
590 if ((yield* HostProcessPlatform) !== "win32") {590 if ((yield* HostProcess.Platform) !== "win32") {
591 return null;591 return null;
592 }592 }
593 const fileSystem = yield* FileSystem.FileSystem;593 const fileSystem = yield* FileSystem.FileSystem;
...@@ -667,7 +667,7 @@ export const resolveProviderMaintenanceCapabilitiesEffect = Effect.fn(...@@ -667,7 +667,7 @@ export const resolveProviderMaintenanceCapabilitiesEffect = Effect.fn(
667 resolvedCommandPath,667 resolvedCommandPath,
668 realCommandPath,668 realCommandPath,
669 env,669 env,
670 platform: yield* HostProcessPlatform,670 platform: yield* HostProcess.Platform,
671 });671 });
672});672});
673673
packages/provider-core/src/server/pathExpansion.ts+1-1
...@@ -3,7 +3,7 @@ import * as NodePath from "node:path";...@@ -3,7 +3,7 @@ import * as NodePath from "node:path";
33
4/**4/**
5 * Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to `home`,5 * Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to `home`,
6 * the current user's home directory (`HostProcessHomeDirectory`). Spawned6 * the current user's home directory (`HostProcess.HomeDirectory`). Spawned
7 * processes don't get shell expansion, so env vars like7 * processes don't get shell expansion, so env vars like
8 * `CODEX_HOME=~/.codex-work` would be passed verbatim and treated as relative8 * `CODEX_HOME=~/.codex-work` would be passed verbatim and treated as relative
9 * paths by the receiver.9 * paths by the receiver.
packages/provider-core/src/server/processGroup.test.ts+2-2
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2import * as NodeChildProcess from "node:child_process";2import * as NodeChildProcess from "node:child_process";
33
4import { describe, expect, it } from "@effect/vitest";4import { describe, expect, it } from "@effect/vitest";
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
66
7import { signalProcessGroup } from "./processGroup.ts";7import { signalProcessGroup } from "./processGroup.ts";
88
...@@ -15,7 +15,7 @@ const errorCode = (run: () => void) => {...@@ -15,7 +15,7 @@ const errorCode = (run: () => void) => {
15 }15 }
16};16};
1717
18describe.skipIf(HostProcessPlatform.defaultValue() === "win32")("signalProcessGroup", () => {18describe.skipIf(HostProcess.Platform.defaultValue() === "win32")("signalProcessGroup", () => {
19 // Signal 0 only probes, so this is safe to run unguarded: `kill(-1, 0)` and19 // Signal 0 only probes, so this is safe to run unguarded: `kill(-1, 0)` and
20 // `kill(0, 0)` succeed, which is how a fake spawner's pid 1 became20 // `kill(0, 0)` succeed, which is how a fake spawner's pid 1 became
21 // `kill(-1, SIGKILL)` and took down every process the user owned.21 // `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 @@...@@ -1,6 +1,6 @@
1import { describe, expect, it } from "@effect/vitest";1import { describe, expect, it } from "@effect/vitest";
2import type { ModelCapabilities } from "@t3tools/contracts";2import type { ModelCapabilities } from "@t3tools/contracts";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import { createModelCapabilities } from "@t3tools/shared/model";4import { createModelCapabilities } from "@t3tools/shared/model";
5import * as Effect from "effect/Effect";5import * as Effect from "effect/Effect";
6import * as Layer from "effect/Layer";6import * as Layer from "effect/Layer";
...@@ -158,7 +158,7 @@ describe("ProviderCommandNotFoundError", () => {...@@ -158,7 +158,7 @@ describe("ProviderCommandNotFoundError", () => {
158 ChildProcess.make("codex", ["--version"]),158 ChildProcess.make("codex", ["--version"]),
159 ).pipe(159 ).pipe(
160 Effect.provide(Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner)),160 Effect.provide(Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner)),
161 Effect.provideService(HostProcessPlatform, "win32"),161 Effect.provideService(HostProcess.Platform, "win32"),
162 Effect.flip,162 Effect.flip,
163 );163 );
164164
packages/provider-core/src/server/snapshotProbe.ts+2-2
...@@ -19,7 +19,7 @@ import * as Stream from "effect/Stream";...@@ -19,7 +19,7 @@ import * as Stream from "effect/Stream";
19import * as ChildProcess from "effect/process/ChildProcess";19import * as ChildProcess from "effect/process/ChildProcess";
20import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";20import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
21import { readCustomModelEntries } from "@t3tools/shared/model";21import { readCustomModelEntries } from "@t3tools/shared/model";
22import { HostProcessPlatform } from "@t3tools/shared/hostProcess";22import * as HostProcess from "@t3tools/shared/HostProcess";
23import { createProviderVersionAdvisory } from "./maintenanceResolver.ts";23import { createProviderVersionAdvisory } from "./maintenanceResolver.ts";
24import { collectUint8StreamText } from "./collectStreamText.ts";24import { collectUint8StreamText } from "./collectStreamText.ts";
2525
...@@ -38,7 +38,7 @@ export const isWindowsCommandNotFound = Effect.fn("isWindowsCommandNotFound")(fu...@@ -38,7 +38,7 @@ export const isWindowsCommandNotFound = Effect.fn("isWindowsCommandNotFound")(fu
38 code: number | null,38 code: number | null,
39 stderr: string,39 stderr: string,
40) {40) {
41 const platform = yield* HostProcessPlatform;41 const platform = yield* HostProcess.Platform;
42 if (platform !== "win32") return false;42 if (platform !== "win32") return false;
43 if (code === 9009) return true;43 if (code === 9009) return true;
44 return WINDOWS_COMMAND_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(stderr));44 return WINDOWS_COMMAND_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(stderr));
packages/provider-cursor/src/server/CursorUsageAccounts.ts+4-8
...@@ -14,11 +14,7 @@...@@ -14,11 +14,7 @@
14import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost";14import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost";
15import type { ProviderUsageScan } from "@t3tools/provider-core/server/usage";15import type { ProviderUsageScan } from "@t3tools/provider-core/server/usage";
16import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite";16import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite";
17import {17import * as HostProcess from "@t3tools/shared/HostProcess";
18 HostProcessEnvironment,
19 HostProcessHomeDirectory,
20 HostProcessPlatform,
21} from "@t3tools/shared/hostProcess";
22import * as Clock from "effect/Clock";18import * as Clock from "effect/Clock";
23import * as Context from "effect/Context";19import * as Context from "effect/Context";
24import * as Deferred from "effect/Deferred";20import * as Deferred from "effect/Deferred";
...@@ -71,8 +67,8 @@ const make = Effect.gen(function* () {...@@ -71,8 +67,8 @@ const make = Effect.gen(function* () {
71 const path = yield* Path.Path;67 const path = yield* Path.Path;
72 const host = yield* ProviderHost.ProviderHost;68 const host = yield* ProviderHost.ProviderHost;
73 const accountReader = yield* CursorAccountReader.CursorAccountReader;69 const accountReader = yield* CursorAccountReader.CursorAccountReader;
74 const hostEnvironment = yield* HostProcessEnvironment;70 const hostEnvironment = yield* HostProcess.Environment;
75 const platform = yield* HostProcessPlatform;71 const platform = yield* HostProcess.Platform;
7672
77 const cachePath = path.join(host.paths.stateDir, CURSOR_ACCOUNT_CACHE_FILE_NAME);73 const cachePath = path.join(host.paths.stateDir, CURSOR_ACCOUNT_CACHE_FILE_NAME);
78 /** Account caches by credential source. */74 /** Account caches by credential source. */
...@@ -286,7 +282,7 @@ const make = Effect.gen(function* () {...@@ -286,7 +282,7 @@ const make = Effect.gen(function* () {
286282
287 const scan: CursorUsageAccounts["Service"]["scan"] = Effect.fn("CursorUsageAccounts.scan")(283 const scan: CursorUsageAccounts["Service"]["scan"] = Effect.fn("CursorUsageAccounts.scan")(
288 function* ({ keychainUsageEnabled, windowStartMs, retentionCutoffMs, awaitRefresh }) {284 function* ({ keychainUsageEnabled, windowStartMs, retentionCutoffMs, awaitRefresh }) {
289 const home = yield* HostProcessHomeDirectory;285 const home = yield* HostProcess.HomeDirectory;
290 const userHome =286 const userHome =
291 (platform === "win32" ? hostEnvironment["USERPROFILE"] : hostEnvironment["HOME"]) || home;287 (platform === "win32" ? hostEnvironment["USERPROFILE"] : hostEnvironment["HOME"]) || home;
292 const configHome = hostEnvironment["XDG_CONFIG_HOME"]?.trim();288 const configHome = hostEnvironment["XDG_CONFIG_HOME"]?.trim();
packages/provider-cursor/src/server/adapter.ts+2-2
...@@ -9,7 +9,7 @@ import type {...@@ -9,7 +9,7 @@ import type {
9 ToolCall,9 ToolCall,
10} from "@cursor/sdk";10} from "@cursor/sdk";
11import { formatReadToolLabel, formatSearchToolLabel } from "@t3tools/shared/toolActivity";11import { formatReadToolLabel, formatSearchToolLabel } from "@t3tools/shared/toolActivity";
12import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";12import * as HostProcess from "@t3tools/shared/HostProcess";
13import {13import {
14 isOrchestrationV2WorkActive,14 isOrchestrationV2WorkActive,
15 defaultInstanceIdForDriver,15 defaultInstanceIdForDriver,
...@@ -2620,7 +2620,7 @@ export const CursorAdapterV2Driver: ProviderAdapterDriver<...@@ -2620,7 +2620,7 @@ export const CursorAdapterV2Driver: ProviderAdapterDriver<
2620 defaultConfig: (): CursorSettings => DEFAULT_CURSOR_SETTINGS,2620 defaultConfig: (): CursorSettings => DEFAULT_CURSOR_SETTINGS,
2621 create: Effect.fn("CursorAdapterV2Driver.create")(2621 create: Effect.fn("CursorAdapterV2Driver.create")(
2622 function* (input: ProviderAdapterDriverCreateInput<CursorSettings>) {2622 function* (input: ProviderAdapterDriverCreateInput<CursorSettings>) {
2623 const hostEnvironment = yield* HostProcessEnvironment;2623 const hostEnvironment = yield* HostProcess.Environment;
2624 return yield* makeCursorAdapterV2({2624 return yield* makeCursorAdapterV2({
2625 instanceId: input.instanceId,2625 instanceId: input.instanceId,
2626 settings: {2626 settings: {
packages/provider-cursor/src/server/skills.ts+2-2
...@@ -17,7 +17,7 @@ import * as Path from "effect/Path";...@@ -17,7 +17,7 @@ import * as Path from "effect/Path";
17import * as PlatformError from "effect/PlatformError";17import * as PlatformError from "effect/PlatformError";
18import * as Schema from "effect/Schema";18import * as Schema from "effect/Schema";
19import { parse as parseYamlDocument } from "yaml";19import { parse as parseYamlDocument } from "yaml";
20import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";20import * as HostProcess from "@t3tools/shared/HostProcess";
2121
22const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;22const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
23const SKILL_MENTION_PATTERN =23const SKILL_MENTION_PATTERN =
...@@ -224,7 +224,7 @@ const inspectCursorSkills = Effect.fn("inspectCursorSkills")(function* (...@@ -224,7 +224,7 @@ const inspectCursorSkills = Effect.fn("inspectCursorSkills")(function* (
224 const userHome =224 const userHome =
225 environment.HOME?.trim() ||225 environment.HOME?.trim() ||
226 environment.USERPROFILE?.trim() ||226 environment.USERPROFILE?.trim() ||
227 (yield* HostProcessHomeDirectory);227 (yield* HostProcess.HomeDirectory);
228 const rootsBelow = (base: string, scope: "user" | "project") => [228 const rootsBelow = (base: string, scope: "user" | "project") => [
229 { directory: path.join(base, ".cursor", "skills"), scope },229 { directory: path.join(base, ".cursor", "skills"), scope },
230 { directory: path.join(base, ".agents", "skills"), scope },230 { 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...@@ -12,7 +12,7 @@ import * as TextGenerationOperations from "@t3tools/provider-core/server/textGen
12import { cursorSdkModelSelection } from "./sdkModel.ts";12import { cursorSdkModelSelection } from "./sdkModel.ts";
13import type { CursorAuth } from "./auth.ts";13import type { CursorAuth } from "./auth.ts";
14import * as CursorSdk from "./CursorSdk.ts";14import * as CursorSdk from "./CursorSdk.ts";
15import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";15import * as HostProcess from "@t3tools/shared/HostProcess";
1616
17const CURSOR_TIMEOUT_MS = 180_000;17const CURSOR_TIMEOUT_MS = 180_000;
1818
...@@ -90,7 +90,7 @@ export const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(fu...@@ -90,7 +90,7 @@ export const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(fu
90 const apiKey = yield* resolveCursorApiKey(operation);90 const apiKey = yield* resolveCursorApiKey(operation);
91 // The SDK loads sandbox.json independently of settingSources and lets it91 // The SDK loads sandbox.json independently of settingSources and lets it
92 // expand the writable paths. Its public API cannot override that policy.92 // 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`)) {
94 return yield* new TextGenerationError({94 return yield* new TextGenerationError({
95 operation,95 operation,
96 detail:96 detail:
packages/provider-cursor/src/server/usageLimits.test.ts+6-6
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import { describe, expect, it } from "@effect/vitest";1import { describe, expect, it } from "@effect/vitest";
2import { NodeServices } from "@effect/platform-node";2import { NodeServices } from "@effect/platform-node";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
6import * as Path from "effect/Path";6import * as Path from "effect/Path";
...@@ -106,7 +106,7 @@ describe("Cursor usage limits", () => {...@@ -106,7 +106,7 @@ describe("Cursor usage limits", () => {
106 { apiEndpoint: "https://cursor.example/" },106 { apiEndpoint: "https://cursor.example/" },
107 { XDG_CONFIG_HOME: directory, HOME: directory, AGENT_CLI_CREDENTIAL_STORE: "file" },107 { XDG_CONFIG_HOME: directory, HOME: directory, AGENT_CLI_CREDENTIAL_STORE: "file" },
108 ).pipe(108 ).pipe(
109 Effect.provideService(HostProcessPlatform, platform),109 Effect.provideService(HostProcess.Platform, platform),
110 Effect.provideService(HttpClient.HttpClient, client),110 Effect.provideService(HttpClient.HttpClient, client),
111 );111 );
112 expect(limits.windows[0]?.usedPercent).toBe(42);112 expect(limits.windows[0]?.usedPercent).toBe(42);
...@@ -131,7 +131,7 @@ describe("Cursor usage limits", () => {...@@ -131,7 +131,7 @@ describe("Cursor usage limits", () => {
131 },131 },
132 false,132 false,
133 ).pipe(133 ).pipe(
134 Effect.provideService(HostProcessPlatform, platform),134 Effect.provideService(HostProcess.Platform, platform),
135 Effect.provideService(135 Effect.provideService(
136 FileSystem.FileSystem,136 FileSystem.FileSystem,
137 FileSystem.makeNoop({137 FileSystem.makeNoop({
...@@ -202,7 +202,7 @@ describe("Cursor usage limits", () => {...@@ -202,7 +202,7 @@ describe("Cursor usage limits", () => {
202 Effect.gen(function* () {202 Effect.gen(function* () {
203 const limits = yield* withNodeServices(203 const limits = yield* withNodeServices(
204 readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe(204 readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe(
205 Effect.provideService(HostProcessPlatform, "darwin"),205 Effect.provideService(HostProcess.Platform, "darwin"),
206 Effect.provideService(206 Effect.provideService(
207 FileSystem.FileSystem,207 FileSystem.FileSystem,
208 FileSystem.makeNoop({208 FileSystem.makeNoop({
...@@ -232,7 +232,7 @@ describe("Cursor usage limits", () => {...@@ -232,7 +232,7 @@ describe("Cursor usage limits", () => {
232 Effect.gen(function* () {232 Effect.gen(function* () {
233 const limits = yield* withNodeServices(233 const limits = yield* withNodeServices(
234 readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe(234 readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe(
235 Effect.provideService(HostProcessPlatform, "darwin"),235 Effect.provideService(HostProcess.Platform, "darwin"),
236 Effect.provideService(236 Effect.provideService(
237 HttpClient.HttpClient,237 HttpClient.HttpClient,
238 HttpClient.make(() => Effect.die("must not request limits without a login")),238 HttpClient.make(() => Effect.die("must not request limits without a login")),
...@@ -258,7 +258,7 @@ describe("Cursor usage limits", () => {...@@ -258,7 +258,7 @@ describe("Cursor usage limits", () => {
258 ] as const) {258 ] as const) {
259 const limits = yield* withNodeServices(259 const limits = yield* withNodeServices(
260 readCursorUsageLimits({ apiEndpoint }, environment, true).pipe(260 readCursorUsageLimits({ apiEndpoint }, environment, true).pipe(
261 Effect.provideService(HostProcessPlatform, "darwin"),261 Effect.provideService(HostProcess.Platform, "darwin"),
262 Effect.provideService(262 Effect.provideService(
263 HttpClient.HttpClient,263 HttpClient.HttpClient,
264 HttpClient.make(() => Effect.die("must not send a Keychain credential to a proxy")),264 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 @@...@@ -1,6 +1,6 @@
1import type { ServerProviderUsageWindow } from "@t3tools/contracts";1import type { ServerProviderUsageWindow } from "@t3tools/contracts";
2import type { CursorSettings } from "../settings.ts";2import type { CursorSettings } from "../settings.ts";
3import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import { CURSOR_USAGE_WINDOWS } from "@t3tools/shared/usageLimits";4import { CURSOR_USAGE_WINDOWS } from "@t3tools/shared/usageLimits";
5import * as DateTime from "effect/DateTime";5import * as DateTime from "effect/DateTime";
6import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
...@@ -70,7 +70,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function...@@ -70,7 +70,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function
70 return yield* Effect.gen(function* () {70 return yield* Effect.gen(function* () {
71 const fs = yield* FileSystem.FileSystem;71 const fs = yield* FileSystem.FileSystem;
72 const path = yield* Path.Path;72 const path = yield* Path.Path;
73 const platform = yield* HostProcessPlatform;73 const platform = yield* HostProcess.Platform;
74 const endpoint = (74 const endpoint = (
75 settings.apiEndpoint?.trim() ||75 settings.apiEndpoint?.trim() ||
76 environment.CURSOR_API_ENDPOINT?.trim() ||76 environment.CURSOR_API_ENDPOINT?.trim() ||
...@@ -109,7 +109,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function...@@ -109,7 +109,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function
109 } else if (!token) {109 } else if (!token) {
110 const home =110 const home =
111 (platform === "win32" ? environment.USERPROFILE : environment.HOME) ||111 (platform === "win32" ? environment.USERPROFILE : environment.HOME) ||
112 (yield* HostProcessHomeDirectory);112 (yield* HostProcess.HomeDirectory);
113 const directory =113 const directory =
114 platform === "win32"114 platform === "win32"
115 ? path.join(environment.APPDATA || path.join(home, "AppData", "Roaming"), "Cursor")115 ? 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";...@@ -12,7 +12,7 @@ import * as Layer from "effect/Layer";
12import * as Scope from "effect/Scope";12import * as Scope from "effect/Scope";
13import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";13import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
14import * as EffectAcpErrors from "effect-acp/errors";14import * as EffectAcpErrors from "effect-acp/errors";
15import { HostProcessPlatform } from "@t3tools/shared/hostProcess";15import * as HostProcess from "@t3tools/shared/HostProcess";
16import { normalizeModelSlug } from "@t3tools/shared/model";16import { normalizeModelSlug } from "@t3tools/shared/model";
1717
18import * as AcpSessionRuntime from "@t3tools/provider-acp/server/AcpSessionRuntime";18import * as AcpSessionRuntime from "@t3tools/provider-acp/server/AcpSessionRuntime";
...@@ -159,7 +159,7 @@ export const makeGrokAcpRuntime = (...@@ -159,7 +159,7 @@ export const makeGrokAcpRuntime = (
159 ChildProcessSpawner.ChildProcessSpawner | Crypto.Crypto | Scope.Scope159 ChildProcessSpawner.ChildProcessSpawner | Crypto.Crypto | Scope.Scope
160> =>160> =>
161 Effect.gen(function* () {161 Effect.gen(function* () {
162 const processGroupPlatform = yield* HostProcessPlatform.pipe(162 const processGroupPlatform = yield* HostProcess.Platform.pipe(
163 Effect.provide(NodeServices.layer),163 Effect.provide(NodeServices.layer),
164 );164 );
165 const acpContext = yield* Layer.build(165 const acpContext = yield* Layer.build(
packages/provider-grok/src/server/adapter.ts+6-10
...@@ -4,11 +4,7 @@ import {...@@ -4,11 +4,7 @@ import {
4 isXAiTaskCompletedWakeNotification,4 isXAiTaskCompletedWakeNotification,
5 xAiRateLimitedErrorCode,5 xAiRateLimitedErrorCode,
6} from "./xaiAcpExtension.ts";6} from "./xaiAcpExtension.ts";
7import {7import * as HostProcess from "@t3tools/shared/HostProcess";
8 HostProcessEnvironment,
9 HostProcessHomeDirectory,
10 HostProcessPlatform,
11} from "@t3tools/shared/hostProcess";
12import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime";8import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime";
13import {9import {
14 defaultInstanceIdForDriver,10 defaultInstanceIdForDriver,
...@@ -339,7 +335,7 @@ export const makeGrokAdapterV2 = Effect.fn("makeGrokAdapterV2")(function* (...@@ -339,7 +335,7 @@ export const makeGrokAdapterV2 = Effect.fn("makeGrokAdapterV2")(function* (
339) {335) {
340 return yield* makeAcpAdapterV2({336 return yield* makeAcpAdapterV2({
341 instanceId: options.instanceId,337 instanceId: options.instanceId,
342 flavor: makeGrokAcpAdapterFlavor(options, yield* HostProcessHomeDirectory),338 flavor: makeGrokAcpAdapterFlavor(options, yield* HostProcess.HomeDirectory),
343 selfInvocation: options.selfInvocation,339 selfInvocation: options.selfInvocation,
344 ...(options.nativeLogging === undefined ? {} : { nativeLogging: options.nativeLogging }),340 ...(options.nativeLogging === undefined ? {} : { nativeLogging: options.nativeLogging }),
345 ...(options.continuationRequests === undefined341 ...(options.continuationRequests === undefined
...@@ -365,8 +361,8 @@ export const GrokAdapterV2Driver: ProviderAdapterDriver<GrokSettings, GrokAdapte...@@ -365,8 +361,8 @@ export const GrokAdapterV2Driver: ProviderAdapterDriver<GrokSettings, GrokAdapte
365 defaultConfig: (): GrokSettings => DEFAULT_GROK_SETTINGS,361 defaultConfig: (): GrokSettings => DEFAULT_GROK_SETTINGS,
366 create: Effect.fn("GrokAdapterV2Driver.create")(362 create: Effect.fn("GrokAdapterV2Driver.create")(
367 function* (input: ProviderAdapterDriverCreateInput<GrokSettings>) {363 function* (input: ProviderAdapterDriverCreateInput<GrokSettings>) {
368 const hostEnvironment = yield* HostProcessEnvironment;364 const hostEnvironment = yield* HostProcess.Environment;
369 const hostPlatform = yield* HostProcessPlatform;365 const hostPlatform = yield* HostProcess.Platform;
370 const selfInvocation = yield* resolveSelfInvocation();366 const selfInvocation = yield* resolveSelfInvocation();
371 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;367 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
372 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;368 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
...@@ -415,8 +411,8 @@ const layer: Layer.Layer<...@@ -415,8 +411,8 @@ const layer: Layer.Layer<
415> = Layer.effect(411> = Layer.effect(
416 ProviderAdapter.ProviderAdapterV2,412 ProviderAdapter.ProviderAdapterV2,
417 Effect.gen(function* () {413 Effect.gen(function* () {
418 const hostEnvironment = yield* HostProcessEnvironment;414 const hostEnvironment = yield* HostProcess.Environment;
419 const hostPlatform = yield* HostProcessPlatform;415 const hostPlatform = yield* HostProcess.Platform;
420 const selfInvocation = yield* resolveSelfInvocation();416 const selfInvocation = yield* resolveSelfInvocation();
421 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;417 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
422 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;418 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
packages/provider-grok/src/server/driver.test.ts+2-2
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { expect, it } from "@effect/vitest";2import { expect, it } from "@effect/vitest";
3import { ProviderInstanceId } from "@t3tools/contracts";3import { ProviderInstanceId } from "@t3tools/contracts";
4import { HostProcessPlatform } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
5import * as Effect from "effect/Effect";5import * as Effect from "effect/Effect";
6import * as FileSystem from "effect/FileSystem";6import * as FileSystem from "effect/FileSystem";
7import * as Layer from "effect/Layer";7import * as Layer from "effect/Layer";
...@@ -41,7 +41,7 @@ const noSpawner = ChildProcessSpawner.make(() =>...@@ -41,7 +41,7 @@ const noSpawner = ChildProcessSpawner.make(() =>
41);41);
4242
43// The `#!/bin/sh` stub below cannot be resolved as an executable on Windows.43// 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
46it.layer(layerTest)("GrokDriver", (it) => {46it.layer(layerTest)("GrokDriver", (it) => {
47 it.effect.skipIf(windowsHost)("updates through the configured executable's own updater", () =>47 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 {...@@ -19,7 +19,7 @@ import {
19} from "@t3tools/provider-core/server/usage";19} from "@t3tools/provider-core/server/usage";
2020
21import type { GrokSettings } from "../settings.ts";21import type { GrokSettings } from "../settings.ts";
22import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";22import * as HostProcess from "@t3tools/shared/HostProcess";
2323
24/**24/**
25 * Grok reports cost in integer ticks where `1 USD = 10^10` ticks. See Grok25 * 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> = {...@@ -229,7 +229,7 @@ export const grokUsageReader: ProviderUsageReader<GrokSettings, Path.Path> = {
229 format: grokUsageFormat,229 format: grokUsageFormat,
230 directories: Effect.fn("grokUsageReader.directories")(function* ({ environment }) {230 directories: Effect.fn("grokUsageReader.directories")(function* ({ environment }) {
231 const path = yield* Path.Path;231 const path = yield* Path.Path;
232 const homeDirectory = yield* HostProcessHomeDirectory;232 const homeDirectory = yield* HostProcess.HomeDirectory;
233 const home = expandHomePath(233 const home = expandHomePath(
234 environment.GROK_HOME?.trim() || path.join(homeDirectory, ".grok"),234 environment.GROK_HOME?.trim() || path.join(homeDirectory, ".grok"),
235 homeDirectory,235 homeDirectory,
packages/provider-grok/src/server/usageLimits.ts+2-2
...@@ -13,7 +13,7 @@ import {...@@ -13,7 +13,7 @@ import {
13 makeUnavailableUsageLimits,13 makeUnavailableUsageLimits,
14 makeUsageLimits,14 makeUsageLimits,
15} from "@t3tools/provider-core/server/usageLimits";15} from "@t3tools/provider-core/server/usageLimits";
16import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";16import * as HostProcess from "@t3tools/shared/HostProcess";
1717
18const GrokCredentials = Schema.Record(18const GrokCredentials = Schema.Record(
19 Schema.String,19 Schema.String,
...@@ -101,7 +101,7 @@ const readGrokCredential = Effect.fn("readGrokCredential")(function* (...@@ -101,7 +101,7 @@ const readGrokCredential = Effect.fn("readGrokCredential")(function* (
101 const home =101 const home =
102 environment.GROK_HOME?.trim() ||102 environment.GROK_HOME?.trim() ||
103 path.join(103 path.join(
104 environment.HOME || environment.USERPROFILE || (yield* HostProcessHomeDirectory),104 environment.HOME || environment.USERPROFILE || (yield* HostProcess.HomeDirectory),
105 ".grok",105 ".grok",
106 );106 );
107 for (const configPath of [107 for (const configPath of [
packages/provider-muse/src/server/driver.ts+3-3
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import { ProviderDriverKind } from "@t3tools/contracts";1import { ProviderDriverKind } from "@t3tools/contracts";
2import { MuseSettings } from "../settings.ts";2import { MuseSettings } from "../settings.ts";
3import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
6import * as Path from "effect/Path";6import * as Path from "effect/Path";
...@@ -69,7 +69,7 @@ export const MuseDriver: ProviderDriver<MuseSettings, MuseDriverEnv> = {...@@ -69,7 +69,7 @@ export const MuseDriver: ProviderDriver<MuseSettings, MuseDriverEnv> = {
69 const eventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;69 const eventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
70 const { cwd } = host.paths;70 const { cwd } = host.paths;
71 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;71 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
72 const hostEnvironment = yield* HostProcessEnvironment;72 const hostEnvironment = yield* HostProcess.Environment;
73 // Drop an inherited META_API_KEY so Muse uses its login; an instance value still wins.73 // Drop an inherited META_API_KEY so Muse uses its login; an instance value still wins.
74 const processEnvironment = yield* mergeProviderInstanceEnvironment(74 const processEnvironment = yield* mergeProviderInstanceEnvironment(
75 environment,75 environment,
...@@ -78,7 +78,7 @@ export const MuseDriver: ProviderDriver<MuseSettings, MuseDriverEnv> = {...@@ -78,7 +78,7 @@ export const MuseDriver: ProviderDriver<MuseSettings, MuseDriverEnv> = {
78 const effectiveConfig = {78 const effectiveConfig = {
79 ...config,79 ...config,
80 enabled,80 enabled,
81 binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory),81 binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory),
82 } satisfies MuseSettings;82 } satisfies MuseSettings;
83 const continuationIdentity = defaultProviderContinuationIdentity({83 const continuationIdentity = defaultProviderContinuationIdentity({
84 driverKind: DRIVER_KIND,84 driverKind: DRIVER_KIND,
packages/provider-opencode/src/server/OpenCodeRuntime.environment.test.ts+4-8
...@@ -1,11 +1,7 @@...@@ -1,11 +1,7 @@
1import type { OpencodeClient } from "@opencode-ai/sdk/v2";1import type { OpencodeClient } from "@opencode-ai/sdk/v2";
2import * as NodeServices from "@effect/platform-node/NodeServices";2import * as NodeServices from "@effect/platform-node/NodeServices";
3import { it as effectIt } from "@effect/vitest";3import { it as effectIt } from "@effect/vitest";
4import {4import * as HostProcess from "@t3tools/shared/HostProcess";
5 HostProcessEnvironment,
6 HostProcessExecutablePath,
7 HostProcessPlatform,
8} from "@t3tools/shared/hostProcess";
9import * as Effect from "effect/Effect";5import * as Effect from "effect/Effect";
10import * as Fiber from "effect/Fiber";6import * as Fiber from "effect/Fiber";
11import * as FileSystem from "effect/FileSystem";7import * as FileSystem from "effect/FileSystem";
...@@ -168,9 +164,9 @@ describe("OpenCode server output", () => {...@@ -168,9 +164,9 @@ describe("OpenCode server output", () => {
168 Effect.gen(function* () {164 Effect.gen(function* () {
169 const fs = yield* FileSystem.FileSystem;165 const fs = yield* FileSystem.FileSystem;
170 const path = yield* Path.Path;166 const path = yield* Path.Path;
171 const environment = yield* HostProcessEnvironment;167 const environment = yield* HostProcess.Environment;
172 const executablePath = yield* HostProcessExecutablePath;168 const executablePath = yield* HostProcess.ExecutablePath;
173 const platform = yield* HostProcessPlatform;169 const platform = yield* HostProcess.Platform;
174 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-output-" });170 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-output-" });
175 const isWindows = platform === "win32";171 const isWindows = platform === "win32";
176 const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode");172 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";...@@ -9,11 +9,7 @@ import * as FileSystem from "effect/FileSystem";
9import * as Layer from "effect/Layer";9import * as Layer from "effect/Layer";
10import * as Path from "effect/Path";10import * as Path from "effect/Path";
11import * as Queue from "effect/Queue";11import * as Queue from "effect/Queue";
12import {12import * as HostProcess from "@t3tools/shared/HostProcess";
13 HostProcessEnvironment,
14 HostProcessExecutablePath,
15 HostProcessPlatform,
16} from "@t3tools/shared/hostProcess";
1713
18import * as OpenCodeRuntime from "./OpenCodeRuntime.ts";14import * as OpenCodeRuntime from "./OpenCodeRuntime.ts";
19import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts";15import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts";
...@@ -217,9 +213,9 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => {...@@ -217,9 +213,9 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => {
217 Effect.gen(function* () {213 Effect.gen(function* () {
218 const fs = yield* FileSystem.FileSystem;214 const fs = yield* FileSystem.FileSystem;
219 const path = yield* Path.Path;215 const path = yield* Path.Path;
220 const hostEnvironment = yield* HostProcessEnvironment;216 const hostEnvironment = yield* HostProcess.Environment;
221 const executablePath = yield* HostProcessExecutablePath;217 const executablePath = yield* HostProcess.ExecutablePath;
222 const hostPlatform = yield* HostProcessPlatform;218 const hostPlatform = yield* HostProcess.Platform;
223 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-inventory-" });219 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-inventory-" });
224 const isWindows = hostPlatform === "win32";220 const isWindows = hostPlatform === "win32";
225 const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode");221 const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode");
...@@ -271,7 +267,7 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => {...@@ -271,7 +267,7 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => {
271 it.effect("caps and drains command stdout and stderr when requested", () =>267 it.effect("caps and drains command stdout and stderr when requested", () =>
272 Effect.gen(function* () {268 Effect.gen(function* () {
273 const runtime = yield* OpenCodeRuntime.OpenCodeRuntime;269 const runtime = yield* OpenCodeRuntime.OpenCodeRuntime;
274 const executablePath = yield* HostProcessExecutablePath;270 const executablePath = yield* HostProcess.ExecutablePath;
275 const outputBytes = 2 * 1024 * 1024;271 const outputBytes = 2 * 1024 * 1024;
276 const result = yield* runtime.runOpenCodeCommand({272 const result = yield* runtime.runOpenCodeCommand({
277 binaryPath: executablePath,273 binaryPath: executablePath,
packages/provider-opencode/src/server/OpenCodeRuntime.ts+2-2
...@@ -36,7 +36,7 @@ import { isWindowsCommandNotFound } from "@t3tools/provider-core/server/snapshot...@@ -36,7 +36,7 @@ import { isWindowsCommandNotFound } from "@t3tools/provider-core/server/snapshot
36import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts";36import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts";
37import { collectStreamAsString } from "@t3tools/provider-core/server/snapshotProbe";37import { collectStreamAsString } from "@t3tools/provider-core/server/snapshotProbe";
38import * as NetService from "@t3tools/shared/Net";38import * as NetService from "@t3tools/shared/Net";
39import { HostProcessPlatform } from "@t3tools/shared/hostProcess";39import * as HostProcess from "@t3tools/shared/HostProcess";
40import { compareSemverVersions, parseSemver } from "@t3tools/shared/semver";40import { compareSemverVersions, parseSemver } from "@t3tools/shared/semver";
41import { resolveSpawnCommand } from "@t3tools/shared/shell";41import { resolveSpawnCommand } from "@t3tools/shared/shell";
42const encodeUnknownJsonStringExit = Schema.encodeUnknownExit(Schema.fromJsonString(Schema.Unknown));42const encodeUnknownJsonStringExit = Schema.encodeUnknownExit(Schema.fromJsonString(Schema.Unknown));
...@@ -595,7 +595,7 @@ function ensureRuntimeError(...@@ -595,7 +595,7 @@ function ensureRuntimeError(
595const makeOpenCodeRuntime = Effect.gen(function* () {595const makeOpenCodeRuntime = Effect.gen(function* () {
596 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;596 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
597 const netService = yield* NetService.NetService;597 const netService = yield* NetService.NetService;
598 const hostPlatform = yield* HostProcessPlatform;598 const hostPlatform = yield* HostProcess.Platform;
599 const serverLedger = yield* OpenCodeServerLedger.OpenCodeServerLedger;599 const serverLedger = yield* OpenCodeServerLedger.OpenCodeServerLedger;
600 const resolveCommand = (command: string, args: ReadonlyArray<string>, env?: NodeJS.ProcessEnv) =>600 const resolveCommand = (command: string, args: ReadonlyArray<string>, env?: NodeJS.ProcessEnv) =>
601 resolveSpawnCommand(command, args, env ? { env } : {});601 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";...@@ -3,7 +3,7 @@ import * as NodeChildProcess from "node:child_process";
33
4import * as NodeServices from "@effect/platform-node/NodeServices";4import * as NodeServices from "@effect/platform-node/NodeServices";
5import { describe, expect, it } from "@effect/vitest";5import { describe, expect, it } from "@effect/vitest";
6import { HostProcessPlatform } from "@t3tools/shared/hostProcess";6import * as HostProcess from "@t3tools/shared/HostProcess";
7import * as Deferred from "effect/Deferred";7import * as Deferred from "effect/Deferred";
8import * as Effect from "effect/Effect";8import * as Effect from "effect/Effect";
9import * as Exit from "effect/Exit";9import * as Exit from "effect/Exit";
...@@ -67,7 +67,7 @@ const recordFromDeadServer = (stateDir: string, server: { readonly pid: number }...@@ -67,7 +67,7 @@ const recordFromDeadServer = (stateDir: string, server: { readonly pid: number }
67 yield* previousServer.exited;67 yield* previousServer.exited;
68 });68 });
6969
70const hostPlatform = HostProcessPlatform.defaultValue();70const hostPlatform = HostProcess.Platform.defaultValue();
71// procps accepts the same `ps` flags as macOS, so Linux also covers the macOS path.71// procps accepts the same `ps` flags as macOS, so Linux also covers the macOS path.
72const observedPlatforms: ReadonlyArray<NodeJS.Platform> =72const observedPlatforms: ReadonlyArray<NodeJS.Platform> =
73 hostPlatform === "linux" ? ["linux", "darwin"] : hostPlatform === "darwin" ? ["darwin"] : [];73 hostPlatform === "linux" ? ["linux", "darwin"] : hostPlatform === "darwin" ? ["darwin"] : [];
...@@ -75,7 +75,7 @@ const observedPlatforms: ReadonlyArray<NodeJS.Platform> =...@@ -75,7 +75,7 @@ const observedPlatforms: ReadonlyArray<NodeJS.Platform> =
75describe.each(observedPlatforms)("OpenCodeServerLedger observing as %s", (platform) => {75describe.each(observedPlatforms)("OpenCodeServerLedger observing as %s", (platform) => {
76 const provideHost = <A, E, R>(effect: Effect.Effect<A, E, R>) =>76 const provideHost = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
77 effect.pipe(77 effect.pipe(
78 Effect.provideService(HostProcessPlatform, platform),78 Effect.provideService(HostProcess.Platform, platform),
79 Effect.provide(NodeServices.layer),79 Effect.provide(NodeServices.layer),
80 );80 );
8181
packages/provider-opencode/src/server/OpenCodeServerLedger.ts+2-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as Context from "effect/Context";2import * as Context from "effect/Context";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as FileSystem from "effect/FileSystem";4import * as FileSystem from "effect/FileSystem";
...@@ -119,7 +119,7 @@ export const make = Effect.fn("OpenCodeServerLedger.make")(function* (input: {...@@ -119,7 +119,7 @@ export const make = Effect.fn("OpenCodeServerLedger.make")(function* (input: {
119 const fs = yield* FileSystem.FileSystem;119 const fs = yield* FileSystem.FileSystem;
120 const path = yield* Path.Path;120 const path = yield* Path.Path;
121 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;121 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
122 const platform = yield* HostProcessPlatform;122 const platform = yield* HostProcess.Platform;
123 const directory = path.join(input.stateDir, ENTRY_DIRECTORY);123 const directory = path.join(input.stateDir, ENTRY_DIRECTORY);
124 // Windows servers are not detached and are never recorded.124 // Windows servers are not detached and are never recorded.
125 const recordable = platform === "linux" || platform === "darwin";125 const recordable = platform === "linux" || platform === "darwin";
packages/provider-opencode/src/server/adapter.ts+3-3
...@@ -9,7 +9,7 @@ import type {...@@ -9,7 +9,7 @@ import type {
9 Todo as OpenCodeTodo,9 Todo as OpenCodeTodo,
10 ToolPart,10 ToolPart,
11} from "@opencode-ai/sdk/v2";11} from "@opencode-ai/sdk/v2";
12import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";12import * as HostProcess from "@t3tools/shared/HostProcess";
13import { getModelSelectionStringOptionValue } from "@t3tools/shared/model";13import { getModelSelectionStringOptionValue } from "@t3tools/shared/model";
14import { causeErrorTag } from "@t3tools/shared/observability";14import { causeErrorTag } from "@t3tools/shared/observability";
15import {15import {
...@@ -3739,7 +3739,7 @@ export const OpenCodeAdapterV2Driver: ProviderAdapterDriver<...@@ -3739,7 +3739,7 @@ export const OpenCodeAdapterV2Driver: ProviderAdapterDriver<
3739 defaultConfig: (): OpenCodeSettings => DEFAULT_OPENCODE_SETTINGS,3739 defaultConfig: (): OpenCodeSettings => DEFAULT_OPENCODE_SETTINGS,
3740 create: Effect.fn("OpenCodeAdapterV2Driver.create")(3740 create: Effect.fn("OpenCodeAdapterV2Driver.create")(
3741 function* (input: ProviderAdapterDriverCreateInput<OpenCodeSettings>) {3741 function* (input: ProviderAdapterDriverCreateInput<OpenCodeSettings>) {
3742 const hostEnvironment = yield* HostProcessEnvironment;3742 const hostEnvironment = yield* HostProcess.Environment;
3743 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;3743 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
3744 return yield* makeOpenCodeAdapterV2({3744 return yield* makeOpenCodeAdapterV2({
3745 instanceId: input.instanceId,3745 instanceId: input.instanceId,
...@@ -3769,7 +3769,7 @@ const layer: Layer.Layer<ProviderAdapter.ProviderAdapterV2, never, OpenCodeAdapt...@@ -3769,7 +3769,7 @@ const layer: Layer.Layer<ProviderAdapter.ProviderAdapterV2, never, OpenCodeAdapt
3769 Layer.effect(3769 Layer.effect(
3770 ProviderAdapter.ProviderAdapterV2,3770 ProviderAdapter.ProviderAdapterV2,
3771 Effect.gen(function* () {3771 Effect.gen(function* () {
3772 const hostEnvironment = yield* HostProcessEnvironment;3772 const hostEnvironment = yield* HostProcess.Environment;
3773 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;3773 const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers;
3774 return yield* makeOpenCodeAdapterV2({3774 return yield* makeOpenCodeAdapterV2({
3775 instanceId: OPENCODE_DEFAULT_INSTANCE_ID,3775 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";...@@ -7,7 +7,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices";
7import { assert, it } from "@effect/vitest";7import { assert, it } from "@effect/vitest";
8import { ProviderInstanceId } from "@t3tools/contracts";8import { ProviderInstanceId } from "@t3tools/contracts";
9import type { OpenCodeSettings } from "../settings.ts";9import type { OpenCodeSettings } from "../settings.ts";
10import { HostProcessPlatform } from "@t3tools/shared/hostProcess";10import * as HostProcess from "@t3tools/shared/HostProcess";
11import * as Effect from "effect/Effect";11import * as Effect from "effect/Effect";
12import * as Fiber from "effect/Fiber";12import * as Fiber from "effect/Fiber";
13import * as Layer from "effect/Layer";13import * as Layer from "effect/Layer";
...@@ -156,7 +156,7 @@ const resolveUpdate = (generation: "v1" | "v2", binaryPath: string) =>...@@ -156,7 +156,7 @@ const resolveUpdate = (generation: "v1" | "v2", binaryPath: string) =>
156 Effect.provide(NodeServices.layer),156 Effect.provide(NodeServices.layer),
157 );157 );
158158
159it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(159it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
160 "updates an npm-global OpenCode 2 install as @opencode/cli and a 1.x one as opencode-ai",160 "updates an npm-global OpenCode 2 install as @opencode/cli and a 1.x one as opencode-ai",
161 () =>161 () =>
162 Effect.gen(function* () {162 Effect.gen(function* () {
...@@ -243,7 +243,7 @@ it.layer(layerUpdate)("OpenCodeDriver updates", (it) => {...@@ -243,7 +243,7 @@ it.layer(layerUpdate)("OpenCodeDriver updates", (it) => {
243 }).pipe(Effect.scoped),243 }).pipe(Effect.scoped),
244 );244 );
245245
246 it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")(246 it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
247 "offers no package update for an unknown version and follows a changed one on a fresh read",247 "offers no package update for an unknown version and follows a changed one on a fresh read",
248 () =>248 () =>
249 Effect.gen(function* () {249 Effect.gen(function* () {
packages/provider-opencode/src/server/usage.ts+3-3
...@@ -11,7 +11,7 @@ import {...@@ -11,7 +11,7 @@ import {
11 type ProviderUsageReader,11 type ProviderUsageReader,
12 type UsageRecord,12 type UsageRecord,
13} from "@t3tools/provider-core/server/usage";13} from "@t3tools/provider-core/server/usage";
14import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
15import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";15import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
16import * as Effect from "effect/Effect";16import * as Effect from "effect/Effect";
17import * as Exit from "effect/Exit";17import * as Exit from "effect/Exit";
...@@ -257,8 +257,8 @@ export const readOpenCodeUsage = Effect.fn("readOpenCodeUsage")(function* (...@@ -257,8 +257,8 @@ export const readOpenCodeUsage = Effect.fn("readOpenCodeUsage")(function* (
257const resolveOpenCodeDataDirs = Effect.fn("resolveOpenCodeDataDirs")(function* () {257const resolveOpenCodeDataDirs = Effect.fn("resolveOpenCodeDataDirs")(function* () {
258 const fileSystem = yield* FileSystem.FileSystem;258 const fileSystem = yield* FileSystem.FileSystem;
259 const path = yield* Path.Path;259 const path = yield* Path.Path;
260 const environment = yield* HostProcessEnvironment;260 const environment = yield* HostProcess.Environment;
261 const homeDirectory = yield* HostProcessHomeDirectory;261 const homeDirectory = yield* HostProcess.HomeDirectory;
262 const roots = environment["OPENCODE_DATA_DIR"]262 const roots = environment["OPENCODE_DATA_DIR"]
263 ?.split(",")263 ?.split(",")
264 .map((value) => value.trim())264 .map((value) => value.trim())
packages/provider-opencode/src/server/usageLimits.ts+2-2
...@@ -16,7 +16,7 @@ import {...@@ -16,7 +16,7 @@ import {
16 makeUnavailableUsageLimits,16 makeUnavailableUsageLimits,
17 makeUsageLimits,17 makeUsageLimits,
18} from "@t3tools/provider-core/server/usageLimits";18} from "@t3tools/provider-core/server/usageLimits";
19import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess";19import * as HostProcess from "@t3tools/shared/HostProcess";
2020
21const AuthFile = Schema.Struct({ "opencode-go": Schema.optionalKey(Schema.Unknown) });21const AuthFile = Schema.Struct({ "opencode-go": Schema.optionalKey(Schema.Unknown) });
22const ApiAuth = Schema.Struct({ type: Schema.Literal("api"), key: Schema.String });22const ApiAuth = Schema.Struct({ type: Schema.Literal("api"), key: Schema.String });
...@@ -47,7 +47,7 @@ export const readOpenCodeGoUsageLimits = Effect.fn("readOpenCodeGoUsageLimits")(...@@ -47,7 +47,7 @@ export const readOpenCodeGoUsageLimits = Effect.fn("readOpenCodeGoUsageLimits")(
47 const dataHome =47 const dataHome =
48 env.XDG_DATA_HOME ||48 env.XDG_DATA_HOME ||
49 path.join(49 path.join(
50 env.HOME || env.USERPROFILE || (yield* HostProcessHomeDirectory),50 env.HOME || env.USERPROFILE || (yield* HostProcess.HomeDirectory),
51 ".local",51 ".local",
52 "share",52 "share",
53 );53 );
packages/provider-opencode/src/server/v2/OpenCode2Server.test.ts+5-9
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, it } from "@effect/vitest";2import { assert, it } from "@effect/vitest";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessEnvironment,
5 HostProcessExecutablePath,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
8import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
9import * as Fiber from "effect/Fiber";5import * as Fiber from "effect/Fiber";
10import * as FileSystem from "effect/FileSystem";6import * as FileSystem from "effect/FileSystem";
...@@ -221,7 +217,7 @@ describe("OpenCode2Server spawned server", () => {...@@ -221,7 +217,7 @@ describe("OpenCode2Server spawned server", () => {
221 Effect.gen(function* () {217 Effect.gen(function* () {
222 const fs = yield* FileSystem.FileSystem;218 const fs = yield* FileSystem.FileSystem;
223 const path = yield* Path.Path;219 const path = yield* Path.Path;
224 const platform = yield* HostProcessPlatform;220 const platform = yield* HostProcess.Platform;
225 const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode2-fake-" });221 const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode2-fake-" });
226 const isWindows = platform === "win32";222 const isWindows = platform === "win32";
227 const binaryPath = path.join(directory, isWindows ? "opencode.cmd" : "opencode");223 const binaryPath = path.join(directory, isWindows ? "opencode.cmd" : "opencode");
...@@ -230,8 +226,8 @@ describe("OpenCode2Server spawned server", () => {...@@ -230,8 +226,8 @@ describe("OpenCode2Server spawned server", () => {
230 yield* fs.writeFileString(226 yield* fs.writeFileString(
231 binaryPath,227 binaryPath,
232 isWindows228 isWindows
233 ? `@echo off\r\n"${yield* HostProcessExecutablePath}" "${scriptPath}" %*\r\n`229 ? `@echo off\r\n"${yield* HostProcess.ExecutablePath}" "${scriptPath}" %*\r\n`
234 : `#!/bin/sh\nexec "${yield* HostProcessExecutablePath}" "${scriptPath}" "$@"\n`,230 : `#!/bin/sh\nexec "${yield* HostProcess.ExecutablePath}" "${scriptPath}" "$@"\n`,
235 );231 );
236 if (!isWindows) yield* fs.chmod(binaryPath, 0o755);232 if (!isWindows) yield* fs.chmod(binaryPath, 0o755);
237233
...@@ -240,7 +236,7 @@ describe("OpenCode2Server spawned server", () => {...@@ -240,7 +236,7 @@ describe("OpenCode2Server spawned server", () => {
240 serverUrl: "",236 serverUrl: "",
241 serverPassword: "",237 serverPassword: "",
242 directory,238 directory,
243 environment: { ...(yield* HostProcessEnvironment), OPENCODE_SERVER_PASSWORD: "ambient" },239 environment: { ...(yield* HostProcess.Environment), OPENCODE_SERVER_PASSWORD: "ambient" },
244 });240 });
245 const first = yield* server.withConnection((connection) => Effect.succeed(connection));241 const first = yield* server.withConnection((connection) => Effect.succeed(connection));
246 const second = yield* server.withConnection((connection) => Effect.succeed(connection));242 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...@@ -38,7 +38,7 @@ import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderS
38import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator";38import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator";
39import * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";39import * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";
40import { handoffBudget } from "@t3tools/provider-core/server/handoffBudget";40import { handoffBudget } from "@t3tools/provider-core/server/handoffBudget";
41import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";41import * as HostProcess from "@t3tools/shared/HostProcess";
42import {42import {
43 makePiAdapterV2,43 makePiAdapterV2,
44 PiAdapterV2Driver,44 PiAdapterV2Driver,
...@@ -336,7 +336,7 @@ const makeAdapter = Effect.fnUntraced(function* (...@@ -336,7 +336,7 @@ const makeAdapter = Effect.fnUntraced(function* (
336 config: { enabled: true, binaryPath: "pi", launchArgs, customModels: [] },336 config: { enabled: true, binaryPath: "pi", launchArgs, customModels: [] },
337 }).pipe(337 }).pipe(
338 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),338 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
339 Effect.provideService(HostProcessEnvironment, {}),339 Effect.provideService(HostProcess.Environment, {}),
340 Effect.provideService(ProviderContinuationRequests.ProviderContinuationRequests, {340 Effect.provideService(ProviderContinuationRequests.ProviderContinuationRequests, {
341 ...continuationRequests,341 ...continuationRequests,
342 take: Effect.never,342 take: Effect.never,
packages/provider-pi/src/server/adapter.ts+3-3
...@@ -23,7 +23,7 @@...@@ -23,7 +23,7 @@
23 * Terminal-only decoration such as status, widget, title, and editor-text23 * Terminal-only decoration such as status, widget, title, and editor-text
24 * updates has no matching T3 surface and is ignored.24 * updates has no matching T3 surface and is ignored.
25 */25 */
26import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";26import * as HostProcess from "@t3tools/shared/HostProcess";
27import { getModelSelectionStringOptionValue } from "@t3tools/shared/model";27import { getModelSelectionStringOptionValue } from "@t3tools/shared/model";
28import {28import {
29 defaultInstanceIdForDriver,29 defaultInstanceIdForDriver,
...@@ -3271,7 +3271,7 @@ export const PiAdapterV2Driver: ProviderAdapterDriver<PiSettings, PiAdapterV2Dri...@@ -3271,7 +3271,7 @@ export const PiAdapterV2Driver: ProviderAdapterDriver<PiSettings, PiAdapterV2Dri
3271 defaultConfig: (): PiSettings => DEFAULT_PI_SETTINGS,3271 defaultConfig: (): PiSettings => DEFAULT_PI_SETTINGS,
3272 create: Effect.fn("PiAdapterV2Driver.create")(3272 create: Effect.fn("PiAdapterV2Driver.create")(
3273 function* (input: ProviderAdapterDriverCreateInput<PiSettings>) {3273 function* (input: ProviderAdapterDriverCreateInput<PiSettings>) {
3274 const hostEnvironment = yield* HostProcessEnvironment;3274 const hostEnvironment = yield* HostProcess.Environment;
3275 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;3275 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
3276 return yield* makePiAdapterV2({3276 return yield* makePiAdapterV2({
3277 instanceId: input.instanceId,3277 instanceId: input.instanceId,
...@@ -3299,7 +3299,7 @@ const layer: Layer.Layer<ProviderAdapter.ProviderAdapterV2, never, PiAdapterV2Dr...@@ -3299,7 +3299,7 @@ const layer: Layer.Layer<ProviderAdapter.ProviderAdapterV2, never, PiAdapterV2Dr
3299 Layer.effect(3299 Layer.effect(
3300 ProviderAdapter.ProviderAdapterV2,3300 ProviderAdapter.ProviderAdapterV2,
3301 Effect.gen(function* () {3301 Effect.gen(function* () {
3302 const hostEnvironment = yield* HostProcessEnvironment;3302 const hostEnvironment = yield* HostProcess.Environment;
3303 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;3303 const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests;
3304 return yield* makePiAdapterV2({3304 return yield* makePiAdapterV2({
3305 instanceId: PI_DEFAULT_INSTANCE_ID,3305 instanceId: PI_DEFAULT_INSTANCE_ID,
packages/provider-pi/src/server/rpc.ts+2-2
...@@ -28,7 +28,7 @@ import * as Schema from "effect/Schema";...@@ -28,7 +28,7 @@ import * as Schema from "effect/Schema";
28import * as Stream from "effect/Stream";28import * as Stream from "effect/Stream";
29import * as ChildProcess from "effect/process/ChildProcess";29import * as ChildProcess from "effect/process/ChildProcess";
30import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";30import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
31import { HostProcessPlatform } from "@t3tools/shared/hostProcess";31import * as HostProcess from "@t3tools/shared/HostProcess";
32import { resolveSpawnCommand } from "@t3tools/shared/shell";32import { resolveSpawnCommand } from "@t3tools/shared/shell";
3333
34import { signalProcessGroup } from "@t3tools/provider-core/server/processGroup";34import { signalProcessGroup } from "@t3tools/provider-core/server/processGroup";
...@@ -215,7 +215,7 @@ const terminatePiProcess = (kill: (signal: NodeJS.Signals) => boolean, hasExited...@@ -215,7 +215,7 @@ const terminatePiProcess = (kill: (signal: NodeJS.Signals) => boolean, hasExited
215215
216export const makePiRpcConnection = Effect.fnUntraced(function* (options: PiRpcSpawnOptions) {216export const makePiRpcConnection = Effect.fnUntraced(function* (options: PiRpcSpawnOptions) {
217 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;217 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
218 const platform = yield* HostProcessPlatform;218 const platform = yield* HostProcess.Platform;
219 const scope = yield* Effect.scope;219 const scope = yield* Effect.scope;
220220
221 const spawnCommand = yield* resolveSpawnCommand(options.command, [...options.args], {221 const spawnCommand = yield* resolveSpawnCommand(options.command, [...options.args], {
packages/provider-testing/src/fakeCli.ts+3-3
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2import * as NodeFS from "node:fs";2import * as NodeFS from "node:fs";
3import * as NodePath from "node:path";3import * as NodePath from "node:path";
44
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
66
7export interface FakeCliOptions {7export interface FakeCliOptions {
8 /** Directory the launcher and its stub are written into. */8 /** Directory the launcher and its stub are written into. */
...@@ -15,7 +15,7 @@ export interface FakeCliOptions {...@@ -15,7 +15,7 @@ export interface FakeCliOptions {
15 readonly env?: Readonly<Record<string, string>>;15 readonly env?: Readonly<Record<string, string>>;
16 /**16 /**
17 * Platform the launcher is shaped for. Effect callers should pass the value17 * 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;
19 * defaults to the real host for plain tests.19 * defaults to the real host for plain tests.
20 */20 */
21 readonly platform?: NodeJS.Platform;21 readonly platform?: NodeJS.Platform;
...@@ -45,7 +45,7 @@ export function writeFakeCli(options: FakeCliOptions): string {...@@ -45,7 +45,7 @@ export function writeFakeCli(options: FakeCliOptions): string {
45 "utf8",45 "utf8",
46 );46 );
4747
48 if ((options.platform ?? HostProcessPlatform.defaultValue()) === "win32") {48 if ((options.platform ?? HostProcess.Platform.defaultValue()) === "win32") {
49 const launcherPath = NodePath.join(options.directory, `${options.name}.cmd`);49 const launcherPath = NodePath.join(options.directory, `${options.name}.cmd`);
50 NodeFS.writeFileSync(50 NodeFS.writeFileSync(
51 launcherPath,51 launcherPath,
packages/shared/package.json+3-3
...@@ -311,9 +311,9 @@...@@ -311,9 +311,9 @@
311 "types": "./src/nodeRuntime.ts",311 "types": "./src/nodeRuntime.ts",
312 "import": "./src/nodeRuntime.ts"312 "import": "./src/nodeRuntime.ts"
313 },313 },
314 "./hostProcess": {314 "./HostProcess": {
315 "types": "./src/hostProcess.ts",315 "types": "./src/HostProcess.ts",
316 "import": "./src/hostProcess.ts"316 "import": "./src/HostProcess.ts"
317 },317 },
318 "./testing/longTempDir": {318 "./testing/longTempDir": {
319 "types": "./src/testing/longTempDir.ts",319 "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";...@@ -4,7 +4,7 @@ import * as FileSystem from "effect/FileSystem";
4import * as Option from "effect/Option";4import * as Option from "effect/Option";
5import * as Path from "effect/Path";5import * as Path from "effect/Path";
66
7import * as HostProcess from "./hostProcess.ts";7import * as HostProcess from "./HostProcess.ts";
8import { isCommandAvailable } from "./shell.ts";8import { isCommandAvailable } from "./shell.ts";
99
10type Editor = (typeof EDITORS)[number];10type Editor = (typeof EDITORS)[number];
...@@ -37,7 +37,7 @@ export const resolveEditorCommand = Effect.fn("editor.resolveEditorCommand")(fun...@@ -37,7 +37,7 @@ export const resolveEditorCommand = Effect.fn("editor.resolveEditorCommand")(fun
37 if (yield* isCommandAvailable(command, { env })) return Option.some({ command, baseArgs });37 if (yield* isCommandAvailable(command, { env })) return Option.some({ command, baseArgs });
38 }38 }
3939
40 const platform = yield* HostProcess.HostProcessPlatform;40 const platform = yield* HostProcess.Platform;
41 const path = yield* Path.Path;41 const path = yield* Path.Path;
42 const fs = yield* FileSystem.FileSystem;42 const fs = yield* FileSystem.FileSystem;
43 const home = env.HOME;43 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";...@@ -3,7 +3,7 @@ import * as NodeFS from "node:fs";
3import * as NodeOS from "node:os";3import * as NodeOS from "node:os";
4import * as NodePath from "node:path";4import * as NodePath from "node:path";
5import { afterEach, describe, expect, it } from "vite-plus/test";5import { afterEach, describe, expect, it } from "vite-plus/test";
6import { HostProcessPlatform } from "./hostProcess.ts";6import * as HostProcess from "./HostProcess.ts";
77
8import {8import {
9 RotatingFileSink,9 RotatingFileSink,
...@@ -11,7 +11,7 @@ import {...@@ -11,7 +11,7 @@ import {
11 RotatingFileSinkError,11 RotatingFileSinkError,
12} from "./logging.ts";12} from "./logging.ts";
1313
14const windowsHost = HostProcessPlatform.defaultValue() === "win32";14const windowsHost = HostProcess.Platform.defaultValue() === "win32";
15const tempDirectories: string[] = [];15const tempDirectories: string[] = [];
1616
17const makeTempDirectory = (): string => {17const makeTempDirectory = (): string => {
packages/shared/src/nodeRuntime.test.ts+28-33
...@@ -5,12 +5,7 @@ import * as FileSystem from "effect/FileSystem";...@@ -5,12 +5,7 @@ import * as FileSystem from "effect/FileSystem";
5import * as Path from "effect/Path";5import * as Path from "effect/Path";
6import * as Result from "effect/Result";6import * as Result from "effect/Result";
77
8import {8import * as HostProcess from "./HostProcess.ts";
9 HostProcessArguments,
10 HostProcessExecutablePath,
11 HostProcessIsExecutable,
12 HostProcessPlatform,
13} from "./hostProcess.ts";
14import { resolveNodeExecutable, resolveSelfInvocation, selfInvocationArgs } from "./nodeRuntime.ts";9import { resolveNodeExecutable, resolveSelfInvocation, selfInvocationArgs } from "./nodeRuntime.ts";
15import { symlinksSupported } from "./testing/symlinks.ts";10import { symlinksSupported } from "./testing/symlinks.ts";
1611
...@@ -19,9 +14,9 @@ describe("Self invocation", () => {...@@ -19,9 +14,9 @@ describe("Self invocation", () => {
19 Effect.gen(function* () {14 Effect.gen(function* () {
20 const path = yield* Path.Path;15 const path = yield* Path.Path;
21 const invocation = yield* resolveSelfInvocation().pipe(16 const invocation = yield* resolveSelfInvocation().pipe(
22 Effect.provideService(HostProcessExecutablePath, "/runtime/node"),17 Effect.provideService(HostProcess.ExecutablePath, "/runtime/node"),
23 Effect.provideService(HostProcessIsExecutable, false),18 Effect.provideService(HostProcess.IsExecutable, false),
24 Effect.provideService(HostProcessArguments, ["/runtime/node", "dist/bin.mjs", "serve"]),19 Effect.provideService(HostProcess.Arguments, ["/runtime/node", "dist/bin.mjs", "serve"]),
25 );20 );
26 expect(invocation.command).toBe("/runtime/node");21 expect(invocation.command).toBe("/runtime/node");
27 expect(invocation.entrypoint).toBe(path.resolve("dist/bin.mjs"));22 expect(invocation.entrypoint).toBe(path.resolve("dist/bin.mjs"));
...@@ -36,9 +31,9 @@ describe("Self invocation", () => {...@@ -36,9 +31,9 @@ describe("Self invocation", () => {
36 Effect.gen(function* () {31 Effect.gen(function* () {
37 // Node repeats the binary at argv[1] for a single-executable; it is not a script.32 // Node repeats the binary at argv[1] for a single-executable; it is not a script.
38 const invocation = yield* resolveSelfInvocation().pipe(33 const invocation = yield* resolveSelfInvocation().pipe(
39 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),34 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
40 Effect.provideService(HostProcessIsExecutable, true),35 Effect.provideService(HostProcess.IsExecutable, true),
41 Effect.provideService(HostProcessArguments, ["/packaged/t3", "/packaged/t3", "serve"]),36 Effect.provideService(HostProcess.Arguments, ["/packaged/t3", "/packaged/t3", "serve"]),
42 );37 );
43 expect(invocation).toEqual({ command: "/packaged/t3", entrypoint: undefined });38 expect(invocation).toEqual({ command: "/packaged/t3", entrypoint: undefined });
44 expect(selfInvocationArgs(invocation, ["acp-mcp-bridge"])).toEqual(["acp-mcp-bridge"]);39 expect(selfInvocationArgs(invocation, ["acp-mcp-bridge"])).toEqual(["acp-mcp-bridge"]);
...@@ -52,8 +47,8 @@ describe("Node runtime selection", () => {...@@ -52,8 +47,8 @@ describe("Node runtime selection", () => {
52 for (const executable of ["/runtime/node", "/Applications/T3 Code.app/Electron"]) {47 for (const executable of ["/runtime/node", "/Applications/T3 Code.app/Electron"]) {
53 expect(48 expect(
54 yield* resolveNodeExecutable("Local device support", { PATH: "" }).pipe(49 yield* resolveNodeExecutable("Local device support", { PATH: "" }).pipe(
55 Effect.provideService(HostProcessExecutablePath, executable),50 Effect.provideService(HostProcess.ExecutablePath, executable),
56 Effect.provideService(HostProcessIsExecutable, false),51 Effect.provideService(HostProcess.IsExecutable, false),
57 ),52 ),
58 ).toBe(executable);53 ).toBe(executable);
59 }54 }
...@@ -69,8 +64,8 @@ describe("Node runtime selection", () => {...@@ -69,8 +64,8 @@ describe("Node runtime selection", () => {
69 }),64 }),
70 ).toBe(process.execPath);65 ).toBe(process.execPath);
71 }).pipe(66 }).pipe(
72 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),67 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
73 Effect.provideService(HostProcessIsExecutable, true),68 Effect.provideService(HostProcess.IsExecutable, true),
74 Effect.provide(NodeServices.layer),69 Effect.provide(NodeServices.layer),
75 ),70 ),
76 );71 );
...@@ -84,7 +79,7 @@ describe("Node runtime selection", () => {...@@ -84,7 +79,7 @@ describe("Node runtime selection", () => {
84 expect(error.message).toContain("Local device support requires Node.js");79 expect(error.message).toContain("Local device support requires Node.js");
85 expect(error.message).toContain("Install Node.js");80 expect(error.message).toContain("Install Node.js");
86 }).pipe(81 }).pipe(
87 Effect.provideService(HostProcessIsExecutable, true),82 Effect.provideService(HostProcess.IsExecutable, true),
88 Effect.provide(NodeServices.layer),83 Effect.provide(NodeServices.layer),
89 ),84 ),
90 );85 );
...@@ -94,7 +89,7 @@ describe("Node runtime selection", () => {...@@ -94,7 +89,7 @@ describe("Node runtime selection", () => {
94 const fs = yield* FileSystem.FileSystem;89 const fs = yield* FileSystem.FileSystem;
95 const path = yield* Path.Path;90 const path = yield* Path.Path;
96 const directory = yield* fs.makeTempDirectoryScoped();91 const directory = yield* fs.makeTempDirectoryScoped();
97 const platform = yield* HostProcessPlatform;92 const platform = yield* HostProcess.Platform;
98 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");93 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
99 const env = { PATH: directory };94 const env = { PATH: directory };
100 expect(95 expect(
...@@ -107,8 +102,8 @@ describe("Node runtime selection", () => {...@@ -107,8 +102,8 @@ describe("Node runtime selection", () => {
107 expect(yield* resolveNodeExecutable("Local device support", env)).toBe(node);102 expect(yield* resolveNodeExecutable("Local device support", env)).toBe(node);
108 }).pipe(103 }).pipe(
109 Effect.scoped,104 Effect.scoped,
110 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),105 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
111 Effect.provideService(HostProcessIsExecutable, true),106 Effect.provideService(HostProcess.IsExecutable, true),
112 Effect.provide(NodeServices.layer),107 Effect.provide(NodeServices.layer),
113 ),108 ),
114 );109 );
...@@ -134,9 +129,9 @@ describe("Node runtime selection", () => {...@@ -134,9 +129,9 @@ describe("Node runtime selection", () => {
134 ).toBe(node);129 ).toBe(node);
135 }).pipe(130 }).pipe(
136 Effect.scoped,131 Effect.scoped,
137 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),132 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
138 Effect.provideService(HostProcessIsExecutable, true),133 Effect.provideService(HostProcess.IsExecutable, true),
139 Effect.provideService(HostProcessPlatform, "win32"),134 Effect.provideService(HostProcess.Platform, "win32"),
140 Effect.provide(NodeServices.layer),135 Effect.provide(NodeServices.layer),
141 ),136 ),
142 );137 );
...@@ -156,8 +151,8 @@ describe("Node runtime selection", () => {...@@ -156,8 +151,8 @@ describe("Node runtime selection", () => {
156 expect(error.message).toContain("Install Node.js");151 expect(error.message).toContain("Install Node.js");
157 }).pipe(152 }).pipe(
158 Effect.scoped,153 Effect.scoped,
159 Effect.provideService(HostProcessIsExecutable, true),154 Effect.provideService(HostProcess.IsExecutable, true),
160 Effect.provideService(HostProcessPlatform, "win32"),155 Effect.provideService(HostProcess.Platform, "win32"),
161 Effect.provide(NodeServices.layer),156 Effect.provide(NodeServices.layer),
162 ),157 ),
163 );158 );
...@@ -167,21 +162,21 @@ describe("Node runtime selection", () => {...@@ -167,21 +162,21 @@ describe("Node runtime selection", () => {
167 const fs = yield* FileSystem.FileSystem;162 const fs = yield* FileSystem.FileSystem;
168 const path = yield* Path.Path;163 const path = yield* Path.Path;
169 const directory = yield* fs.makeTempDirectoryScoped();164 const directory = yield* fs.makeTempDirectoryScoped();
170 const platform = yield* HostProcessPlatform;165 const platform = yield* HostProcess.Platform;
171 const executable = path.join(directory, platform === "win32" ? "t3.exe" : "t3");166 const executable = path.join(directory, platform === "win32" ? "t3.exe" : "t3");
172 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");167 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
173 yield* fs.writeFileString(executable, "standalone executable fixture");168 yield* fs.writeFileString(executable, "standalone executable fixture");
174 yield* fs.chmod(executable, 0o755);169 yield* fs.chmod(executable, 0o755);
175 yield* fs.link(executable, node);170 yield* fs.link(executable, node);
176 const error = yield* resolveNodeExecutable("Local device support", { PATH: directory }).pipe(171 const error = yield* resolveNodeExecutable("Local device support", { PATH: directory }).pipe(
177 Effect.provideService(HostProcessExecutablePath, executable),172 Effect.provideService(HostProcess.ExecutablePath, executable),
178 Effect.flip,173 Effect.flip,
179 );174 );
180 expect(error._tag).toBe("NodeRuntimeUnavailableError");175 expect(error._tag).toBe("NodeRuntimeUnavailableError");
181 expect(error.message).toContain("Install Node.js");176 expect(error.message).toContain("Install Node.js");
182 }).pipe(177 }).pipe(
183 Effect.scoped,178 Effect.scoped,
184 Effect.provideService(HostProcessIsExecutable, true),179 Effect.provideService(HostProcess.IsExecutable, true),
185 Effect.provide(NodeServices.layer),180 Effect.provide(NodeServices.layer),
186 ),181 ),
187 );182 );
...@@ -191,14 +186,14 @@ describe("Node runtime selection", () => {...@@ -191,14 +186,14 @@ describe("Node runtime selection", () => {
191 const fs = yield* FileSystem.FileSystem;186 const fs = yield* FileSystem.FileSystem;
192 const path = yield* Path.Path;187 const path = yield* Path.Path;
193 const directory = yield* fs.makeTempDirectoryScoped();188 const directory = yield* fs.makeTempDirectoryScoped();
194 const platform = yield* HostProcessPlatform;189 const platform = yield* HostProcess.Platform;
195 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");190 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
196 yield* fs.symlink(process.execPath, node);191 yield* fs.symlink(process.execPath, node);
197 expect(yield* resolveNodeExecutable("Local device support", { PATH: directory })).toBe(node);192 expect(yield* resolveNodeExecutable("Local device support", { PATH: directory })).toBe(node);
198 }).pipe(193 }).pipe(
199 Effect.scoped,194 Effect.scoped,
200 Effect.provideService(HostProcessExecutablePath, "/packaged/t3"),195 Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"),
201 Effect.provideService(HostProcessIsExecutable, true),196 Effect.provideService(HostProcess.IsExecutable, true),
202 Effect.provide(NodeServices.layer),197 Effect.provide(NodeServices.layer),
203 ),198 ),
204 );199 );
...@@ -210,7 +205,7 @@ describe("Node runtime selection", () => {...@@ -210,7 +205,7 @@ describe("Node runtime selection", () => {
210 const fs = yield* FileSystem.FileSystem;205 const fs = yield* FileSystem.FileSystem;
211 const path = yield* Path.Path;206 const path = yield* Path.Path;
212 const directory = yield* fs.makeTempDirectoryScoped();207 const directory = yield* fs.makeTempDirectoryScoped();
213 const platform = yield* HostProcessPlatform;208 const platform = yield* HostProcess.Platform;
214 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");209 const node = path.join(directory, platform === "win32" ? "node.exe" : "node");
215 yield* fs.symlink(process.execPath, node);210 yield* fs.symlink(process.execPath, node);
216 const error = yield* resolveNodeExecutable("Local device support", {211 const error = yield* resolveNodeExecutable("Local device support", {
...@@ -219,7 +214,7 @@ describe("Node runtime selection", () => {...@@ -219,7 +214,7 @@ describe("Node runtime selection", () => {
219 expect(error.message).toContain("Install Node.js");214 expect(error.message).toContain("Install Node.js");
220 }).pipe(215 }).pipe(
221 Effect.scoped,216 Effect.scoped,
222 Effect.provideService(HostProcessIsExecutable, true),217 Effect.provideService(HostProcess.IsExecutable, true),
223 Effect.provide(NodeServices.layer),218 Effect.provide(NodeServices.layer),
224 ),219 ),
225 );220 );
packages/shared/src/nodeRuntime.ts+8-14
...@@ -4,13 +4,7 @@ import * as Path from "effect/Path";...@@ -4,13 +4,7 @@ import * as Path from "effect/Path";
4import * as Option from "effect/Option";4import * as Option from "effect/Option";
5import * as Schema from "effect/Schema";5import * as Schema from "effect/Schema";
66
7import {7import * as HostProcess from "./HostProcess.ts";
8 HostProcessArguments,
9 HostProcessEnvironment,
10 HostProcessExecutablePath,
11 HostProcessIsExecutable,
12 HostProcessPlatform,
13} from "./hostProcess.ts";
14import { CommandResolutionCache, resolveCommandPath } from "./shell.ts";8import { CommandResolutionCache, resolveCommandPath } from "./shell.ts";
159
16const NodeRuntimeFeature = Schema.Literals([10const NodeRuntimeFeature = Schema.Literals([
...@@ -51,11 +45,11 @@ export interface SelfInvocation {...@@ -51,11 +45,11 @@ export interface SelfInvocation {
51 * assemble the pair themselves.45 * assemble the pair themselves.
52 */46 */
53export const resolveSelfInvocation = Effect.fn("nodeRuntime.resolveSelfInvocation")(function* () {47export const resolveSelfInvocation = Effect.fn("nodeRuntime.resolveSelfInvocation")(function* () {
54 const command = yield* HostProcessExecutablePath;48 const command = yield* HostProcess.ExecutablePath;
55 if (yield* HostProcessIsExecutable)49 if (yield* HostProcess.IsExecutable)
56 return { command, entrypoint: undefined } satisfies SelfInvocation;50 return { command, entrypoint: undefined } satisfies SelfInvocation;
57 const path = yield* Path.Path;51 const path = yield* Path.Path;
58 const entry = (yield* HostProcessArguments)[1];52 const entry = (yield* HostProcess.Arguments)[1];
59 // Children spawn from their own working directory, so the script path must be absolute.53 // Children spawn from their own working directory, so the script path must be absolute.
60 return {54 return {
61 command,55 command,
...@@ -75,13 +69,13 @@ export const resolveNodeExecutable = Effect.fn("nodeRuntime.resolveNodeExecutabl...@@ -75,13 +69,13 @@ export const resolveNodeExecutable = Effect.fn("nodeRuntime.resolveNodeExecutabl
75 feature: typeof NodeRuntimeFeature.Type,69 feature: typeof NodeRuntimeFeature.Type,
76 environment?: NodeJS.ProcessEnv,70 environment?: NodeJS.ProcessEnv,
77) {71) {
78 const executablePath = yield* HostProcessExecutablePath;72 const executablePath = yield* HostProcess.ExecutablePath;
79 if (!(yield* HostProcessIsExecutable)) return executablePath;73 if (!(yield* HostProcess.IsExecutable)) return executablePath;
8074
81 const fs = yield* FileSystem.FileSystem;75 const fs = yield* FileSystem.FileSystem;
82 const path = yield* Path.Path;76 const path = yield* Path.Path;
83 const platform = yield* HostProcessPlatform;77 const platform = yield* HostProcess.Platform;
84 const env = environment ?? (yield* HostProcessEnvironment);78 const env = environment ?? (yield* HostProcess.Environment);
85 const nodePath = yield* resolveCommandPath(platform === "win32" ? "node.exe" : "node", {79 const nodePath = yield* resolveCommandPath(platform === "win32" ? "node.exe" : "node", {
86 // Batch wrappers require a shell; helper callers launch the runtime directly.80 // Batch wrappers require a shell; helper callers launch the runtime directly.
87 env: platform === "win32" ? { ...env, PATHEXT: ".EXE" } : env,81 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";...@@ -14,18 +14,18 @@ import * as Stream from "effect/Stream";
14import * as TestClock from "effect/testing/TestClock";14import * as TestClock from "effect/testing/TestClock";
15import { HttpClient, HttpClientResponse } from "effect/http";15import { HttpClient, HttpClientResponse } from "effect/http";
16import { ChildProcess, ChildProcessSpawner } from "effect/process";16import { ChildProcess, ChildProcessSpawner } from "effect/process";
17import { HostProcessArchitecture, HostProcessPlatform } from "./hostProcess.ts";17import * as HostProcess from "./HostProcess.ts";
1818
19import * as RelayClient from "./relayClient.ts";19import * as RelayClient from "./relayClient.ts";
2020
21// The suite runs the linux code path against the real filesystem, checking21// The suite runs the linux code path against the real filesystem, checking
22// POSIX exec bits that NTFS never reports; the win32 branch skips that check.22// 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
25const layerHostRuntime = (env: Record<string, string> = {}, platform: NodeJS.Platform = "linux") =>25const layerHostRuntime = (env: Record<string, string> = {}, platform: NodeJS.Platform = "linux") =>
26 Layer.mergeAll(26 Layer.mergeAll(
27 Layer.succeed(HostProcessPlatform, platform),27 Layer.succeed(HostProcess.Platform, platform),
28 Layer.succeed(HostProcessArchitecture, "x64"),28 Layer.succeed(HostProcess.Architecture, "x64"),
29 ConfigProvider.layer(ConfigProvider.fromEnv({ env })),29 ConfigProvider.layer(ConfigProvider.fromEnv({ env })),
30 );30 );
3131
packages/shared/src/relayClient.ts+3-3
...@@ -21,7 +21,7 @@ import * as Schedule from "effect/Schedule";...@@ -21,7 +21,7 @@ import * as Schedule from "effect/Schedule";
21import * as Semaphore from "effect/Semaphore";21import * as Semaphore from "effect/Semaphore";
22import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http";22import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http";
23import { ChildProcess, ChildProcessSpawner } from "effect/process";23import { ChildProcess, ChildProcessSpawner } from "effect/process";
24import { HostProcessArchitecture, HostProcessPlatform } from "./hostProcess.ts";24import * as HostProcess from "./HostProcess.ts";
2525
26export const CLOUDFLARED_VERSION = "2026.10.0";26export const CLOUDFLARED_VERSION = "2026.10.0";
27// The oldest release that accepts every flag the connector is started with27// The oldest release that accepts every flag the connector is started with
...@@ -257,8 +257,8 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function...@@ -257,8 +257,8 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function
257 const path = yield* Path.Path;257 const path = yield* Path.Path;
258 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;258 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
259 const installSemaphore = yield* Semaphore.make(1);259 const installSemaphore = yield* Semaphore.make(1);
260 const platform = yield* HostProcessPlatform;260 const platform = yield* HostProcess.Platform;
261 const arch = yield* HostProcessArchitecture;261 const arch = yield* HostProcess.Architecture;
262 const releaseAsset = options.releaseAsset ?? resolveReleaseAsset(platform, arch);262 const releaseAsset = options.releaseAsset ?? resolveReleaseAsset(platform, arch);
263 const loadCloudflaredConfig = Effect.suspend(() => CloudflaredConfig).pipe(Effect.orDie);263 const loadCloudflaredConfig = Effect.suspend(() => CloudflaredConfig).pipe(Effect.orDie);
264 const managedRoot = path.join(options.baseDir, "tools", "cloudflared");264 const managedRoot = path.join(options.baseDir, "tools", "cloudflared");
packages/shared/src/shell.test.ts+13-13
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { it as effectIt } from "@effect/vitest";2import { it as effectIt } from "@effect/vitest";
3import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
6import * as Path from "effect/Path";6import * as Path from "effect/Path";
...@@ -342,7 +342,7 @@ effectIt.layer(NodeServices.layer)("isCommandAvailable", (it) => {...@@ -342,7 +342,7 @@ effectIt.layer(NodeServices.layer)("isCommandAvailable", (it) => {
342 expect(342 expect(
343 yield* isCommandAvailable("definitely-not-installed", {343 yield* isCommandAvailable("definitely-not-installed", {
344 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },344 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
345 }).pipe(Effect.provideService(HostProcessPlatform, "win32")),345 }).pipe(Effect.provideService(HostProcess.Platform, "win32")),
346 ).toBe(false);346 ).toBe(false);
347 }),347 }),
348 );348 );
...@@ -353,7 +353,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {...@@ -353,7 +353,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
353 Effect.gen(function* () {353 Effect.gen(function* () {
354 const result = yield* resolveCommandPath("definitely-not-installed", {354 const result = yield* resolveCommandPath("definitely-not-installed", {
355 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },355 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
358 expect(result._tag).toBe("Failure");358 expect(result._tag).toBe("Failure");
359 }),359 }),
...@@ -367,7 +367,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {...@@ -367,7 +367,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
367 Effect.gen(function* () {367 Effect.gen(function* () {
368 const probed: Array<string> = [];368 const probed: Array<string> = [];
369 const result = yield* resolveCommandPath("definitely-not-installed", { env }).pipe(369 const result = yield* resolveCommandPath("definitely-not-installed", { env }).pipe(
370 Effect.provideService(HostProcessPlatform, "win32"),370 Effect.provideService(HostProcess.Platform, "win32"),
371 Effect.provideService(CommandResolutionCache, new Map()),371 Effect.provideService(CommandResolutionCache, new Map()),
372 Effect.provide(372 Effect.provide(
373 FileSystem.layerNoop({373 FileSystem.layerNoop({
...@@ -425,7 +425,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {...@@ -425,7 +425,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
425 const resolved = yield* resolveCommandPath(command, {425 const resolved = yield* resolveCommandPath(command, {
426 env: { PATH: cwd, PATHEXT: ".CMD" },426 env: { PATH: cwd, PATHEXT: ".CMD" },
427 }).pipe(427 }).pipe(
428 Effect.provideService(HostProcessPlatform, "win32"),428 Effect.provideService(HostProcess.Platform, "win32"),
429 Effect.provideService(CommandResolutionCache, new Map()),429 Effect.provideService(CommandResolutionCache, new Map()),
430 Effect.provideService(FileSystem.FileSystem, {430 Effect.provideService(FileSystem.FileSystem, {
431 ...fs,431 ...fs,
...@@ -458,7 +458,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {...@@ -458,7 +458,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
458 yield* TestClock.adjust("30 seconds");458 yield* TestClock.adjust("30 seconds");
459 expect(yield* resolveCommandPath("appeared", options)).toBe(executable);459 expect(yield* resolveCommandPath("appeared", options)).toBe(executable);
460 }).pipe(460 }).pipe(
461 Effect.provideService(HostProcessPlatform, "win32"),461 Effect.provideService(HostProcess.Platform, "win32"),
462 Effect.provideService(CommandResolutionCache, new Map()),462 Effect.provideService(CommandResolutionCache, new Map()),
463 ),463 ),
464 );464 );
...@@ -505,7 +505,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {...@@ -505,7 +505,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => {
505 );505 );
506 expect(probed).toEqual([path.join(first, "cursor.CMD"), path.join(second, "late.EXE")]);506 expect(probed).toEqual([path.join(first, "cursor.CMD"), path.join(second, "late.EXE")]);
507 }).pipe(507 }).pipe(
508 Effect.provideService(HostProcessPlatform, "win32"),508 Effect.provideService(HostProcess.Platform, "win32"),
509 Effect.provideService(CommandResolutionCache, new Map()),509 Effect.provideService(CommandResolutionCache, new Map()),
510 ),510 ),
511 );511 );
...@@ -517,7 +517,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {...@@ -517,7 +517,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
517 const command = yield* resolveSpawnCommand("node.exe", ["script.js", "hello & goodbye"], {517 const command = yield* resolveSpawnCommand("node.exe", ["script.js", "hello & goodbye"], {
518 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },518 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
519 }).pipe(519 }).pipe(
520 Effect.provideService(HostProcessPlatform, "win32"),520 Effect.provideService(HostProcess.Platform, "win32"),
521 Effect.provideService(CommandResolutionCache, new Map()),521 Effect.provideService(CommandResolutionCache, new Map()),
522 );522 );
523523
...@@ -536,7 +536,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {...@@ -536,7 +536,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
536 ["run", "value & calc", "%PATH%", 'quote"value'],536 ["run", "value & calc", "%PATH%", 'quote"value'],
537 { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" } },537 { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" } },
538 ).pipe(538 ).pipe(
539 Effect.provideService(HostProcessPlatform, "win32"),539 Effect.provideService(HostProcess.Platform, "win32"),
540 Effect.provideService(CommandResolutionCache, new Map()),540 Effect.provideService(CommandResolutionCache, new Map()),
541 Effect.provideService(541 Effect.provideService(
542 SpawnExecutableResolution,542 SpawnExecutableResolution,
...@@ -563,9 +563,9 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {...@@ -563,9 +563,9 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
563 env: { CODEX_HOME: "C:\\Users\\tester\\.codex" },563 env: { CODEX_HOME: "C:\\Users\\tester\\.codex" },
564 extendEnv: true,564 extendEnv: true,
565 }).pipe(565 }).pipe(
566 Effect.provideService(HostProcessPlatform, "win32"),566 Effect.provideService(HostProcess.Platform, "win32"),
567 Effect.provideService(CommandResolutionCache, new Map()),567 Effect.provideService(CommandResolutionCache, new Map()),
568 Effect.provideService(HostProcessEnvironment, {568 Effect.provideService(HostProcess.Environment, {
569 PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm",569 PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm",
570 PATHEXT: ".COM;.EXE;.BAT;.CMD",570 PATHEXT: ".COM;.EXE;.BAT;.CMD",
571 }),571 }),
...@@ -592,7 +592,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {...@@ -592,7 +592,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
592 };592 };
593 const resolve = (command: string, path: string, resolver = scan) =>593 const resolve = (command: string, path: string, resolver = scan) =>
594 resolveSpawnCommand(command, [], { env: { PATH: path, PATHEXT: ".EXE" } }).pipe(594 resolveSpawnCommand(command, [], { env: { PATH: path, PATHEXT: ".EXE" } }).pipe(
595 Effect.provideService(HostProcessPlatform, "win32"),595 Effect.provideService(HostProcess.Platform, "win32"),
596 Effect.provideService(SpawnExecutableResolution, resolver),596 Effect.provideService(SpawnExecutableResolution, resolver),
597 );597 );
598598
...@@ -632,7 +632,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {...@@ -632,7 +632,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => {
632 const command = yield* resolveSpawnCommand("missing & calc", ["unsafe & value"], {632 const command = yield* resolveSpawnCommand("missing & calc", ["unsafe & value"], {
633 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },633 env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" },
634 }).pipe(634 }).pipe(
635 Effect.provideService(HostProcessPlatform, "win32"),635 Effect.provideService(HostProcess.Platform, "win32"),
636 Effect.provideService(CommandResolutionCache, new Map()),636 Effect.provideService(CommandResolutionCache, new Map()),
637 );637 );
638638
packages/shared/src/shell.ts+6-6
...@@ -11,7 +11,7 @@ import * as FileSystem from "effect/FileSystem";...@@ -11,7 +11,7 @@ import * as FileSystem from "effect/FileSystem";
11import * as Option from "effect/Option";11import * as Option from "effect/Option";
12import * as Path from "effect/Path";12import * as Path from "effect/Path";
1313
14import { HostProcessEnvironment, HostProcessPlatform } from "./hostProcess.ts";14import * as HostProcess from "./HostProcess.ts";
15import * as Context from "effect/Context";15import * as Context from "effect/Context";
16const SHELL_ENV_NAME_PATTERN = /^[A-Z0-9_]+$/;16const SHELL_ENV_NAME_PATTERN = /^[A-Z0-9_]+$/;
17const WINDOWS_PATH_DELIMITER = ";";17const WINDOWS_PATH_DELIMITER = ";";
...@@ -503,7 +503,7 @@ interface CommandResolutionCacheEntry {...@@ -503,7 +503,7 @@ interface CommandResolutionCacheEntry {
503 readonly expiresAtNanos: bigint;503 readonly expiresAtNanos: bigint;
504}504}
505505
506// The cache lives in the Effect environment (like HostProcessPlatform above)506// The cache lives in the Effect environment (like HostProcess.Platform above)
507// so tests and embedders can provide an isolated instance; the default is a507// so tests and embedders can provide an isolated instance; the default is a
508// single process-wide map shared by all consumers.508// single process-wide map shared by all consumers.
509export const CommandResolutionCache = Context.Reference<Map<string, CommandResolutionCacheEntry>>(509export const CommandResolutionCache = Context.Reference<Map<string, CommandResolutionCacheEntry>>(
...@@ -688,8 +688,8 @@ export const resolveCommandPath = Effect.fn("shell.resolveCommandPath")(function...@@ -688,8 +688,8 @@ export const resolveCommandPath = Effect.fn("shell.resolveCommandPath")(function
688 options: CommandAvailabilityOptions = {},688 options: CommandAvailabilityOptions = {},
689) {689) {
690 return yield* resolveCommandPathForPlatform(command, {690 return yield* resolveCommandPathForPlatform(command, {
691 env: options.env ?? (yield* HostProcessEnvironment),691 env: options.env ?? (yield* HostProcess.Environment),
692 platform: yield* HostProcessPlatform,692 platform: yield* HostProcess.Platform,
693 });693 });
694});694});
695695
...@@ -699,12 +699,12 @@ export const resolveSpawnCommand = Effect.fnUntraced(function* (...@@ -699,12 +699,12 @@ export const resolveSpawnCommand = Effect.fnUntraced(function* (
699 args: ReadonlyArray<string>,699 args: ReadonlyArray<string>,
700 options: CommandAvailabilityOptions = {},700 options: CommandAvailabilityOptions = {},
701): Effect.fn.Return<ResolvedSpawnCommand> {701): Effect.fn.Return<ResolvedSpawnCommand> {
702 const platform = yield* HostProcessPlatform;702 const platform = yield* HostProcess.Platform;
703 if (platform !== "win32") {703 if (platform !== "win32") {
704 return { command, args: [...args], shell: false };704 return { command, args: [...args], shell: false };
705 }705 }
706706
707 const hostEnvironment = yield* HostProcessEnvironment;707 const hostEnvironment = yield* HostProcess.Environment;
708 const env =708 const env =
709 options.env === undefined709 options.env === undefined
710 ? hostEnvironment710 ? hostEnvironment
packages/shared/src/testing/longTempDir.ts+2-2
...@@ -1,14 +1,14 @@...@@ -1,14 +1,14 @@
1// @effect-diagnostics nodeBuiltinImport:off - runs once at test setup, outside any Effect runtime.1// @effect-diagnostics nodeBuiltinImport:off - runs once at test setup, outside any Effect runtime.
2import * as NodeFS from "node:fs";2import * as NodeFS from "node:fs";
3import * as NodeOS from "node:os";3import * as NodeOS from "node:os";
4import { HostProcessPlatform } from "../hostProcess.ts";4import * as HostProcess from "../HostProcess.ts";
55
6// GitHub's Windows runners hand out the temp directory by its 8.3 short name6// GitHub's Windows runners hand out the temp directory by its 8.3 short name
7// (C:\Users\RUNNER~1\...). Anything that canonicalises a path, such as git or7// (C:\Users\RUNNER~1\...). Anything that canonicalises a path, such as git or
8// realpath, reports the long form, so equality checks between a temp path and8// realpath, reports the long form, so equality checks between a temp path and
9// its canonical form fail. Node reads TEMP/TMP on every os.tmpdir() call, so9// its canonical form fail. Node reads TEMP/TMP on every os.tmpdir() call, so
10// pointing them at the long form fixes every temp directory the suite makes.10// pointing them at the long form fixes every temp directory the suite makes.
11if (HostProcessPlatform.defaultValue() === "win32") {11if (HostProcess.Platform.defaultValue() === "win32") {
12 try {12 try {
13 const longForm = NodeFS.realpathSync.native(NodeOS.tmpdir());13 const longForm = NodeFS.realpathSync.native(NodeOS.tmpdir());
14 process.env.TEMP = longForm;14 process.env.TEMP = longForm;
packages/source-control-forgejo/src/server/ForgejoCli.ts+3-3
...@@ -11,7 +11,7 @@ import * as NodePath from "node:path";...@@ -11,7 +11,7 @@ import * as NodePath from "node:path";
11import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http";11import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http";
12import { ChildProcessSpawner } from "effect/process";12import { ChildProcessSpawner } from "effect/process";
13import { decodeJsonResult } from "@t3tools/shared/schemaJson";13import { decodeJsonResult } from "@t3tools/shared/schemaJson";
14import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
15import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost";15import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost";
16import { collectUint8StreamText } from "@t3tools/provider-core/server/collectStreamText";16import { collectUint8StreamText } from "@t3tools/provider-core/server/collectStreamText";
17import type { SourceControlProviderContext } from "@t3tools/source-control-core/server/SourceControlProvider";17import type { SourceControlProviderContext } from "@t3tools/source-control-core/server/SourceControlProvider";
...@@ -248,8 +248,8 @@ export const make = Effect.gen(function* () {...@@ -248,8 +248,8 @@ export const make = Effect.gen(function* () {
248248
249 const readKeys = Effect.fn("ForgejoCli.readKeys")(function* (cwd: string) {249 const readKeys = Effect.fn("ForgejoCli.readKeys")(function* (cwd: string) {
250 for (const path of forgejoKeysPaths({250 for (const path of forgejoKeysPaths({
251 platform: yield* HostProcessPlatform,251 platform: yield* HostProcess.Platform,
252 home: yield* HostProcessHomeDirectory,252 home: yield* HostProcess.HomeDirectory,
253 ...(globalThis.process.env.XDG_DATA_HOME253 ...(globalThis.process.env.XDG_DATA_HOME
254 ? { dataHome: globalThis.process.env.XDG_DATA_HOME }254 ? { dataHome: globalThis.process.env.XDG_DATA_HOME }
255 : {}),255 : {}),
packages/source-control-github/src/server/GitHubCredentials.ts+3-3
...@@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError";...@@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError";
11import * as Redacted from "effect/Redacted";11import * as Redacted from "effect/Redacted";
12import * as Schema from "effect/Schema";12import * as Schema from "effect/Schema";
1313
14import { HostProcessEnvironment, HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess";14import * as HostProcess from "@t3tools/shared/HostProcess";
1515
16import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost";16import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost";
1717
...@@ -130,8 +130,8 @@ export const make = Effect.gen(function* () {...@@ -130,8 +130,8 @@ export const make = Effect.gen(function* () {
130 const sourceControlHost = yield* SourceControlHost.SourceControlHost;130 const sourceControlHost = yield* SourceControlHost.SourceControlHost;
131 const process = sourceControlHost.process;131 const process = sourceControlHost.process;
132 const crypto = yield* Crypto.Crypto;132 const crypto = yield* Crypto.Crypto;
133 const environment = yield* HostProcessEnvironment;133 const environment = yield* HostProcess.Environment;
134 const workingDirectory = yield* HostProcessWorkingDirectory;134 const workingDirectory = yield* HostProcess.WorkingDirectory;
135135
136 /** `host:sha256(token)`, safe for cache keys and rate-limit scopes. */136 /** `host:sha256(token)`, safe for cache keys and rate-limit scopes. */
137 const fingerprintOf = (host: string, token: string) =>137 const fingerprintOf = (host: string, token: string) =>
packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts+3-3
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import { assert, describe, it } from "@effect/vitest";2import { assert, describe, it } from "@effect/vitest";
3import * as NodeServices from "@effect/platform-node/NodeServices";3import * as NodeServices from "@effect/platform-node/NodeServices";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
...@@ -1075,7 +1075,7 @@ it.live.each([...@@ -1075,7 +1075,7 @@ it.live.each([
1075 remoteName: "enterprise",1075 remoteName: "enterprise",
1076 remoteBranch: "feature",1076 remoteBranch: "feature",
1077 });1077 });
1078 }).pipe(Effect.provide(layer), Effect.provideService(HostProcessEnvironment, {}), Effect.scoped);1078 }).pipe(Effect.provide(layer), Effect.provideService(HostProcess.Environment, {}), Effect.scoped);
1079});1079});
10801080
1081it.effect.each([1081it.effect.each([
...@@ -1162,7 +1162,7 @@ it.effect.each([...@@ -1162,7 +1162,7 @@ it.effect.each([
1162 ]);1162 ]);
1163 }).pipe(1163 }).pipe(
1164 Effect.provide(layer),1164 Effect.provide(layer),
1165 Effect.provideService(HostProcessEnvironment, { GH_REPO: envRepository }),1165 Effect.provideService(HostProcess.Environment, { GH_REPO: envRepository }),
1166 Effect.scoped,1166 Effect.scoped,
1167 );1167 );
1168 },1168 },
packages/source-control-github/src/server/GitHubSourceControlProvider.ts+3-3
...@@ -18,7 +18,7 @@ import {...@@ -18,7 +18,7 @@ import {
18 type SourceControlRepositoryCloneUrls,18 type SourceControlRepositoryCloneUrls,
19} from "@t3tools/contracts";19} from "@t3tools/contracts";
20import { normalizeGitRemoteUrl } from "@t3tools/shared/git";20import { normalizeGitRemoteUrl } from "@t3tools/shared/git";
21import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";21import * as HostProcess from "@t3tools/shared/HostProcess";
22import { decodeJsonResult } from "@t3tools/shared/schemaJson";22import { decodeJsonResult } from "@t3tools/shared/schemaJson";
23import { isSshRemoteUrl } from "@t3tools/shared/sourceControl";23import { isSshRemoteUrl } from "@t3tools/shared/sourceControl";
2424
...@@ -193,7 +193,7 @@ export const makeDiscovery = Effect.gen(function* () {...@@ -193,7 +193,7 @@ export const makeDiscovery = Effect.gen(function* () {
193 const api = yield* GitHubApi.GitHubApi;193 const api = yield* GitHubApi.GitHubApi;
194 const sourceControlHost = yield* SourceControlHost.SourceControlHost;194 const sourceControlHost = yield* SourceControlHost.SourceControlHost;
195 const process = sourceControlHost.process;195 const process = sourceControlHost.process;
196 const environment = yield* HostProcessEnvironment;196 const environment = yield* HostProcess.Environment;
197197
198 return {198 return {
199 type: "managed-cli",199 type: "managed-cli",
...@@ -478,7 +478,7 @@ export const make = Effect.gen(function* () {...@@ -478,7 +478,7 @@ export const make = Effect.gen(function* () {
478 const api = yield* GitHubApi.GitHubApi;478 const api = yield* GitHubApi.GitHubApi;
479 const sourceControlHost = yield* SourceControlHost.SourceControlHost;479 const sourceControlHost = yield* SourceControlHost.SourceControlHost;
480 const process = sourceControlHost.process;480 const process = sourceControlHost.process;
481 const environment = yield* HostProcessEnvironment;481 const environment = yield* HostProcess.Environment;
482 const git = sourceControlHost.git;482 const git = sourceControlHost.git;
483 const fileSystem = yield* FileSystem.FileSystem;483 const fileSystem = yield* FileSystem.FileSystem;
484484
packages/ssh/src/auth.test.ts+3-3
...@@ -5,7 +5,7 @@ import * as Effect from "effect/Effect";...@@ -5,7 +5,7 @@ import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
6import * as Layer from "effect/Layer";6import * as Layer from "effect/Layer";
7import * as Path from "effect/Path";7import * as Path from "effect/Path";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import * as HostProcess from "@t3tools/shared/HostProcess";
99
10import {10import {
11 buildSshAskpassHelperDescriptor,11 buildSshAskpassHelperDescriptor,
...@@ -50,7 +50,7 @@ describe("ssh auth", () => {...@@ -50,7 +50,7 @@ describe("ssh auth", () => {
50 assert.equal(yield* fs.exists(askpassPath), true);50 assert.equal(yield* fs.exists(askpassPath), true);
51 assert.include(yield* fs.readFileString(askpassPath), 'printf "%s\\n" "$T3_SSH_AUTH_SECRET"');51 assert.include(yield* fs.readFileString(askpassPath), 'printf "%s\\n" "$T3_SSH_AUTH_SECRET"');
52 }).pipe(52 }).pipe(
53 Effect.provide(Layer.merge(NodeServices.layer, Layer.succeed(HostProcessPlatform, "linux"))),53 Effect.provide(Layer.merge(NodeServices.layer, Layer.succeed(HostProcess.Platform, "linux"))),
54 Effect.scoped,54 Effect.scoped,
55 ),55 ),
56 );56 );
...@@ -61,7 +61,7 @@ describe("ssh auth", () => {...@@ -61,7 +61,7 @@ describe("ssh auth", () => {
61 directory: "C:\\temp\\t3code-ssh-askpass",61 directory: "C:\\temp\\t3code-ssh-askpass",
62 }).pipe(62 }).pipe(
63 Effect.provide(63 Effect.provide(
64 Layer.merge(NodeServices.layer, Layer.succeed(HostProcessPlatform, "win32")),64 Layer.merge(NodeServices.layer, Layer.succeed(HostProcess.Platform, "win32")),
65 ),65 ),
66 );66 );
6767
packages/ssh/src/auth.ts+4-4
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as Config from "effect/Config";2import * as Config from "effect/Config";
3import * as Context from "effect/Context";3import * as Context from "effect/Context";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
...@@ -113,7 +113,7 @@ export const buildSshAskpassHelperDescriptor = Effect.fn(...@@ -113,7 +113,7 @@ export const buildSshAskpassHelperDescriptor = Effect.fn(
113)(function* (input: {113)(function* (input: {
114 readonly directory: string;114 readonly directory: string;
115}): Effect.fn.Return<SshAskpassHelperDescriptor, never, Path.Path> {115}): Effect.fn.Return<SshAskpassHelperDescriptor, never, Path.Path> {
116 const platform = yield* HostProcessPlatform;116 const platform = yield* HostProcess.Platform;
117 const path = yield* Path.Path;117 const path = yield* Path.Path;
118 const directory = input.directory;118 const directory = input.directory;
119119
...@@ -152,7 +152,7 @@ const ensureSshAskpassHelpers = Effect.fn("ssh/auth.ensureSshAskpassHelpers")(fu...@@ -152,7 +152,7 @@ const ensureSshAskpassHelpers = Effect.fn("ssh/auth.ensureSshAskpassHelpers")(fu
152 const fs = yield* FileSystem.FileSystem;152 const fs = yield* FileSystem.FileSystem;
153 const path = yield* Path.Path;153 const path = yield* Path.Path;
154 const descriptor = yield* buildSshAskpassHelperDescriptor(input);154 const descriptor = yield* buildSshAskpassHelperDescriptor(input);
155 const platform = yield* HostProcessPlatform;155 const platform = yield* HostProcess.Platform;
156156
157 yield* fs.makeDirectory(path.dirname(descriptor.launcherPath), { recursive: true });157 yield* fs.makeDirectory(path.dirname(descriptor.launcherPath), { recursive: true });
158158
...@@ -182,7 +182,7 @@ export const buildSshChildEnvironment = Effect.fn("ssh/auth.buildSshChildEnviron...@@ -182,7 +182,7 @@ export const buildSshChildEnvironment = Effect.fn("ssh/auth.buildSshChildEnviron
182 return baseEnv;182 return baseEnv;
183 }183 }
184184
185 const platform = yield* HostProcessPlatform;185 const platform = yield* HostProcess.Platform;
186 const hostDisplay = input.baseEnv186 const hostDisplay = input.baseEnv
187 ? input.baseEnv.DISPLAY187 ? input.baseEnv.DISPLAY
188 : yield* Config.String("DISPLAY").pipe(188 : yield* Config.String("DISPLAY").pipe(
packages/ssh/src/command.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import type { DesktopSshEnvironmentTarget } from "@t3tools/contracts";1import type { DesktopSshEnvironmentTarget } from "@t3tools/contracts";
2import { HostProcessPlatform } from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import * as Crypto from "effect/Crypto";3import * as Crypto from "effect/Crypto";
4import * as Duration from "effect/Duration";4import * as Duration from "effect/Duration";
5import * as Effect from "effect/Effect";5import * as Effect from "effect/Effect";
...@@ -25,7 +25,7 @@ const MAX_SSH_ERROR_OUTPUT_LENGTH = 4_000;...@@ -25,7 +25,7 @@ const MAX_SSH_ERROR_OUTPUT_LENGTH = 4_000;
25const sshCommandForPlatform = (platform: NodeJS.Platform): string =>25const sshCommandForPlatform = (platform: NodeJS.Platform): string =>
26 platform === "win32" ? "ssh.exe" : "ssh";26 platform === "win32" ? "ssh.exe" : "ssh";
2727
28export const resolveSshCommand = Effect.map(HostProcessPlatform, sshCommandForPlatform);28export const resolveSshCommand = Effect.map(HostProcess.Platform, sshCommandForPlatform);
2929
30const encoder = new TextEncoder();30const encoder = new TextEncoder();
3131
packages/ssh/src/runnerProcess.test.ts+3-3
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, describe, it } from "@effect/vitest";2import { assert, describe, it } from "@effect/vitest";
3import { HostProcessPlatform } from "@t3tools/shared/hostProcess";3import * as HostProcess from "@t3tools/shared/HostProcess";
4import * as Deferred from "effect/Deferred";4import * as Deferred from "effect/Deferred";
5import * as Effect from "effect/Effect";5import * as Effect from "effect/Effect";
6import * as Fiber from "effect/Fiber";6import * as Fiber from "effect/Fiber";
...@@ -21,7 +21,7 @@ const Started = Schema.Struct({...@@ -21,7 +21,7 @@ const Started = Schema.Struct({
21});21});
22const decodeStarted = Schema.decodeUnknownSync(Schema.fromJsonString(Started));22const decodeStarted = Schema.decodeUnknownSync(Schema.fromJsonString(Started));
2323
24describe.skipIf(HostProcessPlatform.defaultValue() === "win32")(24describe.skipIf(HostProcess.Platform.defaultValue() === "win32")(
25 "remote runner process ownership",25 "remote runner process ownership",
26 () => {26 () => {
27 it.live("keeps the server PID and graceful shutdown through the node-script runner", () =>27 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", () => {...@@ -130,7 +130,7 @@ server.listen(Number(process.env.T3_TEST_PORT ?? 0), "127.0.0.1", () => {
130 },130 },
131);131);
132132
133describe.skipIf(HostProcessPlatform.defaultValue() === "win32")(133describe.skipIf(HostProcess.Platform.defaultValue() === "win32")(
134 "remote stop process ownership",134 "remote stop process ownership",
135 () => {135 () => {
136 it.live.each(["graceful", "timeout", "external"] as const)(136 it.live.each(["graceful", "timeout", "external"] as const)(
packages/ssh/src/tunnel.test.ts+3-3
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1import { assert, describe, it } from "@effect/vitest";1import { assert, describe, it } from "@effect/vitest";
2import * as NodeServices from "@effect/platform-node/NodeServices";2import * as NodeServices from "@effect/platform-node/NodeServices";
3import * as NetService from "@t3tools/shared/Net";3import * as NetService from "@t3tools/shared/Net";
4import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";4import * as HostProcess from "@t3tools/shared/HostProcess";
5import * as Deferred from "effect/Deferred";5import * as Deferred from "effect/Deferred";
6import * as Duration from "effect/Duration";6import * as Duration from "effect/Duration";
7import * as Effect from "effect/Effect";7import * as Effect from "effect/Effect";
...@@ -691,8 +691,8 @@ describe("ssh tunnel scripts", () => {...@@ -691,8 +691,8 @@ describe("ssh tunnel scripts", () => {
691// lock excludes concurrent installers. Run the real script against a tiny691// lock excludes concurrent installers. Run the real script against a tiny
692// fake archive served from a file:// mirror.692// fake archive served from a file:// mirror.
693describe("archive runner script", () => {693describe("archive runner script", () => {
694 const hostPlatform = HostProcessPlatform.defaultValue();694 const hostPlatform = HostProcess.Platform.defaultValue();
695 const hostArch = HostProcessArchitecture.defaultValue();695 const hostArch = HostProcess.Architecture.defaultValue();
696 const windowsHost = hostPlatform === "win32";696 const windowsHost = hostPlatform === "win32";
697 const archiveVersion = "1.2.3-preview.20260911.4";697 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";...@@ -8,7 +8,7 @@ import * as Sink from "effect/Sink";
8import * as Stream from "effect/Stream";8import * as Stream from "effect/Stream";
9import * as TestClock from "effect/testing/TestClock";9import * as TestClock from "effect/testing/TestClock";
10import { ChildProcessSpawner } from "effect/process";10import { ChildProcessSpawner } from "effect/process";
11import { HostProcessPlatform } from "@t3tools/shared/hostProcess";11import * as HostProcess from "@t3tools/shared/HostProcess";
1212
13import {13import {
14 buildTailscaleHttpsBaseUrl,14 buildTailscaleHttpsBaseUrl,
...@@ -104,7 +104,7 @@ function neverFinishingMockHandle() {...@@ -104,7 +104,7 @@ function neverFinishingMockHandle() {
104function layerSpawner(spawner: ChildProcessSpawner.ChildProcessSpawner["Service"]) {104function layerSpawner(spawner: ChildProcessSpawner.ChildProcessSpawner["Service"]) {
105 return Layer.merge(105 return Layer.merge(
106 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner),106 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner),
107 Layer.succeed(HostProcessPlatform, "linux"),107 Layer.succeed(HostProcess.Platform, "linux"),
108 );108 );
109}109}
110110
packages/tailscale/src/tailscale.ts+3-3
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as Duration from "effect/Duration";2import * as Duration from "effect/Duration";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Option from "effect/Option";4import * as Option from "effect/Option";
...@@ -217,7 +217,7 @@ export const parseTailscaleStatus = (...@@ -217,7 +217,7 @@ export const parseTailscaleStatus = (
217export const readTailscaleStatus = Effect.gen(function* () {217export const readTailscaleStatus = Effect.gen(function* () {
218 const args = ["status", "--json"];218 const args = ["status", "--json"];
219 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;219 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
220 const hostPlatform = yield* HostProcessPlatform;220 const hostPlatform = yield* HostProcess.Platform;
221 const executable = tailscaleCommandForPlatform(hostPlatform);221 const executable = tailscaleCommandForPlatform(hostPlatform);
222 const commandContext = {222 const commandContext = {
223 executable,223 executable,
...@@ -291,7 +291,7 @@ const runTailscaleCommand = (...@@ -291,7 +291,7 @@ const runTailscaleCommand = (
291): Effect.Effect<void, TailscaleCommandError, ChildProcessSpawner.ChildProcessSpawner> =>291): Effect.Effect<void, TailscaleCommandError, ChildProcessSpawner.ChildProcessSpawner> =>
292 Effect.gen(function* () {292 Effect.gen(function* () {
293 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;293 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
294 const hostPlatform = yield* HostProcessPlatform;294 const hostPlatform = yield* HostProcess.Platform;
295 const executable = tailscaleCommandForPlatform(hostPlatform);295 const executable = tailscaleCommandForPlatform(hostPlatform);
296 const commandContext = {296 const commandContext = {
297 executable,297 executable,
scripts/build-cli-archive.ts+3-3
...@@ -28,7 +28,7 @@ import * as Schema from "effect/Schema";...@@ -28,7 +28,7 @@ import * as Schema from "effect/Schema";
28import { Command, Flag } from "effect/cli";28import { Command, Flag } from "effect/cli";
29import { ChildProcess, ChildProcessSpawner } from "effect/process";29import { ChildProcess, ChildProcessSpawner } from "effect/process";
3030
31import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";31import * as HostProcess from "@t3tools/shared/HostProcess";
32import { fromYaml } from "@t3tools/shared/schemaYaml";32import { fromYaml } from "@t3tools/shared/schemaYaml";
33import { resolveSpawnCommand } from "@t3tools/shared/shell";33import { resolveSpawnCommand } from "@t3tools/shared/shell";
34import rootPackageJson from "../package.json" with { type: "json" };34import rootPackageJson from "../package.json" with { type: "json" };
...@@ -478,8 +478,8 @@ const buildCliArchive = Effect.fn("buildCliArchive")(function* (input: {...@@ -478,8 +478,8 @@ const buildCliArchive = Effect.fn("buildCliArchive")(function* (input: {
478 );478 );
479 // The unsuffixed host build is only a valid stand-in when it was built for479 // The unsuffixed host build is only a valid stand-in when it was built for
480 // this platform and architecture; otherwise a missing target must fail.480 // this platform and architecture; otherwise a missing target must fail.
481 const hostPlatform = yield* HostProcessPlatform;481 const hostPlatform = yield* HostProcess.Platform;
482 const hostKey = `${hostPlatform === "win32" ? "win" : hostPlatform}-${yield* HostProcessArchitecture}`;482 const hostKey = `${hostPlatform === "win32" ? "win" : hostPlatform}-${yield* HostProcess.Architecture}`;
483 const builtExecutable = (yield* fs.exists(targetExecutable))483 const builtExecutable = (yield* fs.exists(targetExecutable))
484 ? targetExecutable484 ? targetExecutable
485 : targetKey === hostKey485 : targetKey === hostKey
scripts/build-desktop-artifact.test.ts+17-17
...@@ -93,7 +93,7 @@ import {...@@ -93,7 +93,7 @@ import {
93 wslRuntimeArchiveStem,93 wslRuntimeArchiveStem,
94} from "./build-desktop-artifact.ts";94} from "./build-desktop-artifact.ts";
95import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts";95import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts";
96import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";96import * as HostProcess from "@t3tools/shared/HostProcess";
97import { symlinksSupported } from "@t3tools/shared/testing/symlinks";97import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
9898
99// Keeps pnpm from auto-installing TypeScript, a types-only peer, into the app.99// 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) => {...@@ -1263,7 +1263,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
1263 assert.isBelow(result.fileCount, WINDOWS_PACKAGED_PAYLOAD_FILE_LIMIT);1263 assert.isBelow(result.fileCount, WINDOWS_PACKAGED_PAYLOAD_FILE_LIMIT);
1264 assert.deepStrictEqual(secondAsar, firstAsar);1264 assert.deepStrictEqual(secondAsar, firstAsar);
1265 }),1265 }),
1266 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),1266 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
1267 );1267 );
12681268
1269 it.effect("accepts an embedded Linux CLI release archive with a matching digest", () =>1269 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) => {...@@ -1283,7 +1283,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
12831283
1284 assert.equal(result.packagedAppDir, fixture.packagedAppDir);1284 assert.equal(result.packagedAppDir, fixture.packagedAppDir);
1285 }),1285 }),
1286 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),1286 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
1287 );1287 );
12881288
1289 it.effect.each(["x64", "arm64"] as const)(1289 it.effect.each(["x64", "arm64"] as const)(
...@@ -1307,7 +1307,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -1307,7 +1307,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
13071307
1308 assert.equal(result.packagedAppDir, fixture.packagedAppDir);1308 assert.equal(result.packagedAppDir, fixture.packagedAppDir);
1309 }),1309 }),
1310 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),1310 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
1311 );1311 );
13121312
1313 it.effect.each(["x64", "arm64"] as const)(1313 it.effect.each(["x64", "arm64"] as const)(
...@@ -1498,8 +1498,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -1498,8 +1498,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
1498 Effect.provide(1498 Effect.provide(
1499 Layer.mergeAll(1499 Layer.mergeAll(
1500 spawnerLayer,1500 spawnerLayer,
1501 Layer.succeed(HostProcessPlatform, "win32"),1501 Layer.succeed(HostProcess.Platform, "win32"),
1502 Layer.succeed(HostProcessArchitecture, "x64"),1502 Layer.succeed(HostProcess.Architecture, "x64"),
1503 ),1503 ),
1504 ),1504 ),
1505 );1505 );
...@@ -1541,8 +1541,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -1541,8 +1541,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
1541 Effect.provide(1541 Effect.provide(
1542 Layer.mergeAll(1542 Layer.mergeAll(
1543 spawnerLayer,1543 spawnerLayer,
1544 Layer.succeed(HostProcessPlatform, "linux"),1544 Layer.succeed(HostProcess.Platform, "linux"),
1545 Layer.succeed(HostProcessArchitecture, "x64"),1545 Layer.succeed(HostProcess.Architecture, "x64"),
1546 ),1546 ),
1547 ),1547 ),
1548 );1548 );
...@@ -1577,8 +1577,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -1577,8 +1577,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
1577 Effect.provide(1577 Effect.provide(
1578 Layer.mergeAll(1578 Layer.mergeAll(
1579 spawnerLayer,1579 spawnerLayer,
1580 Layer.succeed(HostProcessPlatform, "darwin"),1580 Layer.succeed(HostProcess.Platform, "darwin"),
1581 Layer.succeed(HostProcessArchitecture, "arm64"),1581 Layer.succeed(HostProcess.Architecture, "arm64"),
1582 ),1582 ),
1583 ),1583 ),
1584 );1584 );
...@@ -1623,8 +1623,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -1623,8 +1623,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
1623 Effect.provide(1623 Effect.provide(
1624 Layer.mergeAll(1624 Layer.mergeAll(
1625 spawnerLayer,1625 spawnerLayer,
1626 Layer.succeed(HostProcessPlatform, "win32"),1626 Layer.succeed(HostProcess.Platform, "win32"),
1627 Layer.succeed(HostProcessArchitecture, "x64"),1627 Layer.succeed(HostProcess.Architecture, "x64"),
1628 ),1628 ),
1629 ),1629 ),
1630 );1630 );
...@@ -1652,8 +1652,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -1652,8 +1652,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
1652 ).pipe(1652 ).pipe(
1653 Effect.provide(1653 Effect.provide(
1654 Layer.mergeAll(1654 Layer.mergeAll(
1655 Layer.succeed(HostProcessPlatform, "win32"),1655 Layer.succeed(HostProcess.Platform, "win32"),
1656 Layer.succeed(HostProcessArchitecture, "x64"),1656 Layer.succeed(HostProcess.Architecture, "x64"),
1657 ),1657 ),
1658 ),1658 ),
1659 ),1659 ),
...@@ -1764,7 +1764,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -1764,7 +1764,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
1764 assert.instanceOf(error, BundleNotSelfContainedError);1764 assert.instanceOf(error, BundleNotSelfContainedError);
1765 assert.include(error.output, "t3code-deliberately-missing-package");1765 assert.include(error.output, "t3code-deliberately-missing-package");
1766 }),1766 }),
1767 ).pipe(Effect.provideService(HostProcessPlatform, "linux")),1767 ).pipe(Effect.provideService(HostProcess.Platform, "linux")),
1768 );1768 );
17691769
1770 it.effect("preserves both Linux icon resize failures with structural context", () => {1770 it.effect("preserves both Linux icon resize failures with structural context", () => {
...@@ -2333,8 +2333,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {...@@ -2333,8 +2333,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
2333 }).pipe(2333 }).pipe(
2334 Effect.provide(2334 Effect.provide(
2335 Layer.mergeAll(2335 Layer.mergeAll(
2336 Layer.succeed(HostProcessPlatform, "win32"),2336 Layer.succeed(HostProcess.Platform, "win32"),
2337 Layer.succeed(HostProcessArchitecture, "x64"),2337 Layer.succeed(HostProcess.Architecture, "x64"),
2338 ConfigProvider.layer(2338 ConfigProvider.layer(
2339 ConfigProvider.fromEnv({2339 ConfigProvider.fromEnv({
2340 env: {2340 env: {
scripts/build-desktop-artifact.ts+7-7
...@@ -16,7 +16,7 @@ import {...@@ -16,7 +16,7 @@ import {
16} from "@electron/asar";16} from "@electron/asar";
1717
18import { fromYaml } from "@t3tools/shared/schemaYaml";18import { fromYaml } from "@t3tools/shared/schemaYaml";
19import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";19import * as HostProcess from "@t3tools/shared/HostProcess";
20import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";20import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";
21import { resolveSpawnCommand } from "@t3tools/shared/shell";21import { resolveSpawnCommand } from "@t3tools/shared/shell";
22import rootPackageJson from "../package.json" with { type: "json" };22import rootPackageJson from "../package.json" with { type: "json" };
...@@ -869,7 +869,7 @@ const resolveGitCommitHash = Effect.fn("resolveGitCommitHash")(function* (repoRo...@@ -869,7 +869,7 @@ const resolveGitCommitHash = Effect.fn("resolveGitCommitHash")(function* (repoRo
869const resolvePythonForNodeGyp = Effect.fn("resolvePythonForNodeGyp")(function* () {869const resolvePythonForNodeGyp = Effect.fn("resolvePythonForNodeGyp")(function* () {
870 const fs = yield* FileSystem.FileSystem;870 const fs = yield* FileSystem.FileSystem;
871 const path = yield* Path.Path;871 const path = yield* Path.Path;
872 const hostPlatform = yield* HostProcessPlatform;872 const hostPlatform = yield* HostProcess.Platform;
873 const env = yield* Config.all({873 const env = yield* Config.all({
874 configuredPython: Config.String("npm_config_python").pipe(874 configuredPython: Config.String("npm_config_python").pipe(
875 Config.orElse(() => Config.String("PYTHON")),875 Config.orElse(() => Config.String("PYTHON")),
...@@ -1716,7 +1716,7 @@ export const resolveBuildOptions = Effect.fn("resolveBuildOptions")(function* (...@@ -1716,7 +1716,7 @@ export const resolveBuildOptions = Effect.fn("resolveBuildOptions")(function* (
1716 const path = yield* Path.Path;1716 const path = yield* Path.Path;
1717 const repoRoot = yield* RepoRoot;1717 const repoRoot = yield* RepoRoot;
1718 const env = yield* BuildEnvConfig;1718 const env = yield* BuildEnvConfig;
1719 const hostPlatform = yield* HostProcessPlatform;1719 const hostPlatform = yield* HostProcess.Platform;
17201720
1721 const platform = mergeOptions(1721 const platform = mergeOptions(
1722 input.platform,1722 input.platform,
...@@ -2404,7 +2404,7 @@ export const stageBrowserSecret = Effect.fn("stageBrowserSecret")(function* (inp...@@ -2404,7 +2404,7 @@ export const stageBrowserSecret = Effect.fn("stageBrowserSecret")(function* (inp
2404 // silently. `universal` is a mac-only arch the option type still admits;2404 // silently. `universal` is a mac-only arch the option type still admits;
2405 // the helper script rejects it, so it maps to the concrete x64 the Linux2405 // the helper script rejects it, so it maps to the concrete x64 the Linux
2406 // resource monitor uses for the same request.2406 // resource monitor uses for the same request.
2407 const hostPlatform = yield* HostProcessPlatform;2407 const hostPlatform = yield* HostProcess.Platform;
2408 if (hostPlatform !== "linux") {2408 if (hostPlatform !== "linux") {
2409 return yield* new LinuxBrowserSecretHostError({ hostPlatform });2409 return yield* new LinuxBrowserSecretHostError({ hostPlatform });
2410 }2410 }
...@@ -3165,8 +3165,8 @@ export const verifyWindowsPrimaryFffNativeLoad = Effect.fn(...@@ -3165,8 +3165,8 @@ export const verifyWindowsPrimaryFffNativeLoad = Effect.fn(
3165 readonly targetArch: typeof BuildArch.Type;3165 readonly targetArch: typeof BuildArch.Type;
3166 readonly verbose: boolean;3166 readonly verbose: boolean;
3167}) {3167}) {
3168 const hostPlatform = yield* HostProcessPlatform;3168 const hostPlatform = yield* HostProcess.Platform;
3169 const hostArchitecture = yield* HostProcessArchitecture;3169 const hostArchitecture = yield* HostProcess.Architecture;
3170 const fs = yield* FileSystem.FileSystem;3170 const fs = yield* FileSystem.FileSystem;
3171 const path = yield* Path.Path;3171 const path = yield* Path.Path;
3172 const executablePath = path.join(input.packagedAppDir, input.appExecutableName);3172 const executablePath = path.join(input.packagedAppDir, input.appExecutableName);
...@@ -3485,7 +3485,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* (...@@ -3485,7 +3485,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* (
3485 const repoRoot = yield* RepoRoot;3485 const repoRoot = yield* RepoRoot;
3486 const path = yield* Path.Path;3486 const path = yield* Path.Path;
3487 const fs = yield* FileSystem.FileSystem;3487 const fs = yield* FileSystem.FileSystem;
3488 const hostPlatform = yield* HostProcessPlatform;3488 const hostPlatform = yield* HostProcess.Platform;
3489 if (hostPlatform === "linux" && options.platform === "linux") {3489 if (hostPlatform === "linux" && options.platform === "linux") {
3490 yield* preflightLinuxDesktopBuild(options.arch);3490 yield* preflightLinuxDesktopBuild(options.arch);
3491 }3491 }
scripts/build-npm-platform-packages.test.ts+3-3
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as NodeServices from "@effect/platform-node/NodeServices";2import * as NodeServices from "@effect/platform-node/NodeServices";
3import { assert, it } from "@effect/vitest";3import { assert, it } from "@effect/vitest";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
...@@ -203,8 +203,8 @@ it.layer(NodeServices.layer)("build-npm-platform-packages", (it) => {...@@ -203,8 +203,8 @@ it.layer(NodeServices.layer)("build-npm-platform-packages", (it) => {
203203
204 // NODE_PATH stands in for node_modules: require.resolve finds the204 // NODE_PATH stands in for node_modules: require.resolve finds the
205 // platform package there exactly as it would after `npm install`.205 // platform package there exactly as it would after `npm install`.
206 const hostPlatform = yield* HostProcessPlatform;206 const hostPlatform = yield* HostProcess.Platform;
207 const hostArch = yield* HostProcessArchitecture;207 const hostArch = yield* HostProcess.Architecture;
208 const env = { ...process.env, NODE_PATH: fixture.outputDir } as Record<string, string>;208 const env = { ...process.env, NODE_PATH: fixture.outputDir } as Record<string, string>;
209 if (KEYS.some((key) => key === `${hostPlatform}-${hostArch}`)) {209 if (KEYS.some((key) => key === `${hostPlatform}-${hostArch}`)) {
210 const passthrough = yield* run(process.execPath, ["bin/t3.js", "serve", "--port", "1234"], {210 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 {...@@ -36,7 +36,7 @@ import {
36 cliArchiveFileName,36 cliArchiveFileName,
37 type CliArchivePlatformKey,37 type CliArchivePlatformKey,
38} from "@t3tools/shared/cliRelease";38} from "@t3tools/shared/cliRelease";
39import { HostProcessPlatform } from "@t3tools/shared/hostProcess";39import * as HostProcess from "@t3tools/shared/HostProcess";
40import { fromJsonStringPretty } from "@t3tools/shared/schemaJson";40import { fromJsonStringPretty } from "@t3tools/shared/schemaJson";
41import { isCommandAvailable } from "@t3tools/shared/shell";41import { isCommandAvailable } from "@t3tools/shared/shell";
42import serverPackageJson from "../apps/server/package.json" with { type: "json" };42import serverPackageJson from "../apps/server/package.json" with { type: "json" };
...@@ -253,7 +253,7 @@ const runCommand = Effect.fn("runCommand")(function* (...@@ -253,7 +253,7 @@ const runCommand = Effect.fn("runCommand")(function* (
253const extractArchive = Effect.fn("extractArchive")(function* (archive: string, into: string) {253const extractArchive = Effect.fn("extractArchive")(function* (archive: string, into: string) {
254 const fs = yield* FileSystem.FileSystem;254 const fs = yield* FileSystem.FileSystem;
255 const path = yield* Path.Path;255 const path = yield* Path.Path;
256 const platform = yield* HostProcessPlatform;256 const platform = yield* HostProcess.Platform;
257 if (!archive.endsWith(".zip")) {257 if (!archive.endsWith(".zip")) {
258 yield* runCommand(ChildProcess.make("tar", ["-xf", archive, "-C", into]), "tar -xf");258 yield* runCommand(ChildProcess.make("tar", ["-xf", archive, "-C", into]), "tar -xf");
259 } else if (platform === "win32") {259 } else if (platform === "win32") {
...@@ -282,7 +282,7 @@ const extractArchive = Effect.fn("extractArchive")(function* (archive: string, i...@@ -282,7 +282,7 @@ const extractArchive = Effect.fn("extractArchive")(function* (archive: string, i
282});282});
283283
284/** Tar to build npm tarballs with; see build-cli-archive.ts for why Windows names bsdtar by path. */284/** 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) =>
286 platform === "win32" ? windowsSystemTar() : "tar",286 platform === "win32" ? windowsSystemTar() : "tar",
287);287);
288288
scripts/dev-runner.test.ts+16-20
...@@ -4,11 +4,7 @@ import * as NodeFS from "node:fs";...@@ -4,11 +4,7 @@ import * as NodeFS from "node:fs";
4import * as NodeOS from "node:os";4import * as NodeOS from "node:os";
5import * as NodePath from "node:path";5import * as NodePath from "node:path";
6import * as NetService from "@t3tools/shared/Net";6import * as NetService from "@t3tools/shared/Net";
7import {7import * as HostProcess from "@t3tools/shared/HostProcess";
8 HostProcessEnvironment,
9 HostProcessPlatform,
10 HostProcessWorkingDirectory,
11} from "@t3tools/shared/hostProcess";
12import { assert, describe, it } from "@effect/vitest";8import { assert, describe, it } from "@effect/vitest";
13import * as ConfigProvider from "effect/ConfigProvider";9import * as ConfigProvider from "effect/ConfigProvider";
14import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
...@@ -887,7 +883,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -887,7 +883,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
887 return Effect.gen(function* () {883 return Effect.gen(function* () {
888 const error = yield* runDevRunnerWithInput(devServerInput).pipe(884 const error = yield* runDevRunnerWithInput(devServerInput).pipe(
889 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),885 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
890 Effect.provideService(HostProcessPlatform, "linux"),886 Effect.provideService(HostProcess.Platform, "linux"),
891 Effect.flip,887 Effect.flip,
892 );888 );
893889
...@@ -953,7 +949,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -953,7 +949,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
953 share: true,949 share: true,
954 }).pipe(950 }).pipe(
955 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),951 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
956 Effect.provideService(HostProcessPlatform, "linux"),952 Effect.provideService(HostProcess.Platform, "linux"),
957 );953 );
958954
959 assert.equal(spawnCount, 1);955 assert.equal(spawnCount, 1);
...@@ -977,7 +973,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -977,7 +973,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
977 host: "192.168.1.10",973 host: "192.168.1.10",
978 }).pipe(974 }).pipe(
979 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),975 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
980 Effect.provideService(HostProcessPlatform, "linux"),976 Effect.provideService(HostProcess.Platform, "linux"),
981 Effect.flip,977 Effect.flip,
982 );978 );
983979
...@@ -1012,7 +1008,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1012,7 +1008,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
1012 host: "0.0.0.0",1008 host: "0.0.0.0",
1013 }).pipe(1009 }).pipe(
1014 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1010 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1015 Effect.provideService(HostProcessPlatform, "linux"),1011 Effect.provideService(HostProcess.Platform, "linux"),
1016 );1012 );
10171013
1018 assert.equal(spawnCount, 1);1014 assert.equal(spawnCount, 1);
...@@ -1037,7 +1033,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1037,7 +1033,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
1037 host: "192.168.1.10",1033 host: "192.168.1.10",
1038 }).pipe(1034 }).pipe(
1039 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1035 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1040 Effect.provideService(HostProcessPlatform, "linux"),1036 Effect.provideService(HostProcess.Platform, "linux"),
1041 );1037 );
10421038
1043 assert.equal(spawnCount, 1);1039 assert.equal(spawnCount, 1);
...@@ -1097,9 +1093,9 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1097,9 +1093,9 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
1097 share: true,1093 share: true,
1098 }).pipe(1094 }).pipe(
1099 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1095 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1100 Effect.provideService(HostProcessPlatform, "linux"),1096 Effect.provideService(HostProcess.Platform, "linux"),
1101 Effect.provideService(1097 Effect.provideService(
1102 HostProcessEnvironment,1098 HostProcess.Environment,
1103 input.ambientBundledDev === undefined1099 input.ambientBundledDev === undefined
1104 ? {}1100 ? {}
1105 : { T3CODE_BUNDLED_DEV: input.ambientBundledDev },1101 : { T3CODE_BUNDLED_DEV: input.ambientBundledDev },
...@@ -1144,8 +1140,8 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1144,8 +1140,8 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
1144 port: undefined,1140 port: undefined,
1145 }).pipe(1141 }).pipe(
1146 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1142 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1147 Effect.provideService(HostProcessPlatform, "linux"),1143 Effect.provideService(HostProcess.Platform, "linux"),
1148 Effect.provideService(HostProcessEnvironment, {}),1144 Effect.provideService(HostProcess.Environment, {}),
1149 );1145 );
11501146
1151 assert.equal(captured?.T3CODE_BUNDLED_DEV, undefined);1147 assert.equal(captured?.T3CODE_BUNDLED_DEV, undefined);
...@@ -1172,7 +1168,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1172,7 +1168,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
1172 share: true,1168 share: true,
1173 }).pipe(1169 }).pipe(
1174 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1170 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1175 Effect.provideService(HostProcessPlatform, "linux"),1171 Effect.provideService(HostProcess.Platform, "linux"),
1176 );1172 );
11771173
1178 assert.equal(spawnCount, 0);1174 assert.equal(spawnCount, 0);
...@@ -1188,7 +1184,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1188,7 +1184,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
1188 return Effect.gen(function* () {1184 return Effect.gen(function* () {
1189 const error = yield* runDevRunnerWithInput(devServerInput).pipe(1185 const error = yield* runDevRunnerWithInput(devServerInput).pipe(
1190 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1186 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1191 Effect.provideService(HostProcessPlatform, "linux"),1187 Effect.provideService(HostProcess.Platform, "linux"),
1192 Effect.flip,1188 Effect.flip,
1193 );1189 );
11941190
...@@ -1221,7 +1217,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1221,7 +1217,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
1221 return Effect.gen(function* () {1217 return Effect.gen(function* () {
1222 const error = yield* runDevRunnerWithInput(devServerInput).pipe(1218 const error = yield* runDevRunnerWithInput(devServerInput).pipe(
1223 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1219 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1224 Effect.provideService(HostProcessPlatform, "linux"),1220 Effect.provideService(HostProcess.Platform, "linux"),
1225 Effect.flip,1221 Effect.flip,
1226 );1222 );
12271223
...@@ -1274,10 +1270,10 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {...@@ -1274,10 +1270,10 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
12741270
1275 yield* runDevRunnerWithInput({ ...devServerInput, t3Home: input.t3Home }).pipe(1271 yield* runDevRunnerWithInput({ ...devServerInput, t3Home: input.t3Home }).pipe(
1276 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),1272 Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
1277 Effect.provideService(HostProcessPlatform, "linux"),1273 Effect.provideService(HostProcess.Platform, "linux"),
1278 Effect.provideService(HostProcessWorkingDirectory, input.cwd),1274 Effect.provideService(HostProcess.WorkingDirectory, input.cwd),
1279 Effect.provideService(1275 Effect.provideService(
1280 HostProcessEnvironment,1276 HostProcess.Environment,
1281 input.ambientHome === undefined ? {} : { T3CODE_HOME: input.ambientHome },1277 input.ambientHome === undefined ? {} : { T3CODE_HOME: input.ambientHome },
1282 ),1278 ),
1283 );1279 );
scripts/dev-runner.ts+4-4
...@@ -6,7 +6,7 @@ import * as NodeRuntime from "@effect/platform-node/NodeRuntime";...@@ -6,7 +6,7 @@ import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
6import * as NodeServices from "@effect/platform-node/NodeServices";6import * as NodeServices from "@effect/platform-node/NodeServices";
7import * as NetService from "@t3tools/shared/Net";7import * as NetService from "@t3tools/shared/Net";
8import { resolveGitWorktreePath, resolveWorktreeT3Home } from "@t3tools/shared/devHome";8import { resolveGitWorktreePath, resolveWorktreeT3Home } from "@t3tools/shared/devHome";
9import { HostProcessEnvironment, HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess";9import * as HostProcess from "@t3tools/shared/HostProcess";
10import { resolveSpawnCommand } from "@t3tools/shared/shell";10import { resolveSpawnCommand } from "@t3tools/shared/shell";
11import * as Config from "effect/Config";11import * as Config from "effect/Config";
12import * as Effect from "effect/Effect";12import * as Effect from "effect/Effect";
...@@ -645,7 +645,7 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) {...@@ -645,7 +645,7 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) {
645 return yield* new DevRunnerHostNotProxiableError({ mode: input.mode, host: input.host });645 return yield* new DevRunnerHostNotProxiableError({ mode: input.mode, host: input.host });
646 }646 }
647647
648 const worktreePath = yield* resolveGitWorktreePath(yield* HostProcessWorkingDirectory);648 const worktreePath = yield* resolveGitWorktreePath(yield* HostProcess.WorkingDirectory);
649649
650 const { offset, source } = yield* resolveOffset({650 const { offset, source } = yield* resolveOffset({
651 portOffset,651 portOffset,
...@@ -663,11 +663,11 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) {...@@ -663,11 +663,11 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) {
663 checkPortAvailability: makeDefaultCheckPortAvailability(input.host),663 checkPortAvailability: makeDefaultCheckPortAvailability(input.host),
664 });664 });
665665
666 const hostEnvironment = yield* HostProcessEnvironment;666 const hostEnvironment = yield* HostProcess.Environment;
667 // A dev server started inside a worktree defaults to that worktree's own667 // A dev server started inside a worktree defaults to that worktree's own
668 // (gitignored) `.t3` — see @t3tools/shared/devHome for why this must668 // (gitignored) `.t3` — see @t3tools/shared/devHome for why this must
669 // outrank an ambient T3CODE_HOME. `--home-dir` still wins.669 // outrank an ambient T3CODE_HOME. `--home-dir` still wins.
670 const worktreeHome = yield* resolveWorktreeT3Home(yield* HostProcessWorkingDirectory);670 const worktreeHome = yield* resolveWorktreeT3Home(yield* HostProcess.WorkingDirectory);
671 // Trim before choosing: `--home-dir ""` is not a selection, and treating it671 // Trim before choosing: `--home-dir ""` is not a selection, and treating it
672 // as one would skip the worktree default and land on the shared home —672 // as one would skip the worktree default and land on the shared home —
673 // exactly the outcome this precedence exists to prevent.673 // exactly the outcome this precedence exists to prevent.
scripts/export-brand-icons.ts+2-2
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
22
3import * as NodeRuntime from "@effect/platform-node/NodeRuntime";3import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
4import * as NodeServices from "@effect/platform-node/NodeServices";4import * as NodeServices from "@effect/platform-node/NodeServices";
5import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
6import * as Console from "effect/Console";6import * as Console from "effect/Console";
7import * as Effect from "effect/Effect";7import * as Effect from "effect/Effect";
8import * as FileSystem from "effect/FileSystem";8import * as FileSystem from "effect/FileSystem";
...@@ -408,7 +408,7 @@ const probeIconComposerTool = Effect.fn("iconExport.probeIconComposerTool")(func...@@ -408,7 +408,7 @@ const probeIconComposerTool = Effect.fn("iconExport.probeIconComposerTool")(func
408408
409const resolveIconComposerTool = Effect.fn("iconExport.resolveIconComposerTool")(function* () {409const resolveIconComposerTool = Effect.fn("iconExport.resolveIconComposerTool")(function* () {
410 const path = yield* Path.Path;410 const path = yield* Path.Path;
411 const environment = yield* HostProcessEnvironment;411 const environment = yield* HostProcess.Environment;
412 const configuredTool = environment.ICON_COMPOSER_TOOL?.trim();412 const configuredTool = environment.ICON_COMPOSER_TOOL?.trim();
413 if (configuredTool) {413 if (configuredTool) {
414 const tool = yield* probeIconComposerTool(configuredTool);414 const tool = yield* probeIconComposerTool(configuredTool);
scripts/install.test.ts+3-3
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1// @effect-diagnostics nodeBuiltinImport:off - Drives the real shell installer through a PTY and a gated HTTP fixture.1// @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";
3import * as NodeChildProcess from "node:child_process";3import * as NodeChildProcess from "node:child_process";
4import * as NodeCrypto from "node:crypto";4import * as NodeCrypto from "node:crypto";
5import * as NodeFSP from "node:fs/promises";5import * as NodeFSP from "node:fs/promises";
...@@ -9,13 +9,13 @@ import * as NodePath from "node:path";...@@ -9,13 +9,13 @@ import * as NodePath from "node:path";
9import { describe, expect, it } from "vite-plus/test";9import { describe, expect, it } from "vite-plus/test";
1010
11// util-linux's script gives the real installer a terminal without a browser or extra packages.11// 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", () => {
13 it.each([false, true])(13 it.each([false, true])(
14 "preserves download and install behavior (HTTP failure: %s)",14 "preserves download and install behavior (HTTP failure: %s)",
15 async (fail) => {15 async (fail) => {
16 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-install-progress-"));16 const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-install-progress-"));
17 const version = "1.2.3";17 const version = "1.2.3";
18 const stem = `t3-${version}-linux-${HostProcessArchitecture.defaultValue()}`;18 const stem = `t3-${version}-linux-${HostProcess.Architecture.defaultValue()}`;
19 const archiveName = `${stem}.tar.gz`;19 const archiveName = `${stem}.tar.gz`;
20 let resumeDownload: (() => void) | undefined;20 let resumeDownload: (() => void) | undefined;
21 let sawPartialProgress = false;21 let sawPartialProgress = false;
scripts/lib/build-target-arch.test.ts+3-3
...@@ -2,7 +2,7 @@ import { assert, describe, it } from "@effect/vitest";...@@ -2,7 +2,7 @@ import { assert, describe, it } from "@effect/vitest";
2import * as ConfigProvider from "effect/ConfigProvider";2import * as ConfigProvider from "effect/ConfigProvider";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";4import * as Layer from "effect/Layer";
5import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";5import * as HostProcess from "@t3tools/shared/HostProcess";
66
7import { getDefaultBuildArch } from "./build-target-arch.ts";7import { getDefaultBuildArch } from "./build-target-arch.ts";
88
...@@ -18,8 +18,8 @@ const withHostRuntime = (...@@ -18,8 +18,8 @@ const withHostRuntime = (
18) =>18) =>
19 Effect.provide(19 Effect.provide(
20 Layer.mergeAll(20 Layer.mergeAll(
21 Layer.succeed(HostProcessPlatform, platform),21 Layer.succeed(HostProcess.Platform, platform),
22 Layer.succeed(HostProcessArchitecture, arch),22 Layer.succeed(HostProcess.Architecture, arch),
23 ConfigProvider.layer(ConfigProvider.fromEnv({ env: compactEnv(env) })),23 ConfigProvider.layer(ConfigProvider.fromEnv({ env: compactEnv(env) })),
24 ),24 ),
25 );25 );
scripts/lib/build-target-arch.ts+3-3
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";1import * as HostProcess from "@t3tools/shared/HostProcess";
2import * as Config from "effect/Config";2import * as Config from "effect/Config";
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Option from "effect/Option";4import * as Option from "effect/Option";
...@@ -27,8 +27,8 @@ const optionToUndefined = <A>(value: Option.Option<A>): A | undefined =>...@@ -27,8 +27,8 @@ const optionToUndefined = <A>(value: Option.Option<A>): A | undefined =>
27 Option.getOrUndefined(value);27 Option.getOrUndefined(value);
2828
29const resolveHostProcessArch = Effect.fn("resolveHostProcessArch")(function* () {29const resolveHostProcessArch = Effect.fn("resolveHostProcessArch")(function* () {
30 const platform = yield* HostProcessPlatform;30 const platform = yield* HostProcess.Platform;
31 const processArch = yield* HostProcessArchitecture;31 const processArch = yield* HostProcess.Architecture;
32 if (processArch === "arm64") return "arm64";32 if (processArch === "arm64") return "arm64";
33 if (processArch === "x64") {33 if (processArch === "x64") {
34 if (platform !== "win32") return "x64";34 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...@@ -34,7 +34,7 @@ const decodeManifest = Schema.decodeUnknownSync(Schema.fromJsonString(PackageMan
3434
35describe("shouldBundleCliDependency", () => {35describe("shouldBundleCliDependency", () => {
36 it("bundles ordinary runtime dependencies", () => {36 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"]) {
38 assert.strictEqual(shouldBundleCliDependency(id), true, id);38 assert.strictEqual(shouldBundleCliDependency(id), true, id);
39 }39 }
40 });40 });
scripts/mobile-native-client.ts+7-11
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1import * as NodeRuntime from "@effect/platform-node/NodeRuntime";1import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
2import * as NodeServices from "@effect/platform-node/NodeServices";2import * as NodeServices from "@effect/platform-node/NodeServices";
3import {3import * as HostProcess from "@t3tools/shared/HostProcess";
4 HostProcessEnvironment,
5 HostProcessExecutablePath,
6 HostProcessPlatform,
7} from "@t3tools/shared/hostProcess";
8import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell";4import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell";
9import * as Console from "effect/Console";5import * as Console from "effect/Console";
10import * as Crypto from "effect/Crypto";6import * as Crypto from "effect/Crypto";
...@@ -155,9 +151,9 @@ const collect = <E>(stream: Stream.Stream<Uint8Array, E>) =>...@@ -155,9 +151,9 @@ const collect = <E>(stream: Stream.Stream<Uint8Array, E>) =>
155 );151 );
156export const resolveAdb = Effect.gen(function* () {152export const resolveAdb = Effect.gen(function* () {
157 if (yield* isCommandAvailable("adb")) return "adb";153 if (yield* isCommandAvailable("adb")) return "adb";
158 const environment = yield* HostProcessEnvironment;154 const environment = yield* HostProcess.Environment;
159 const path = yield* Path.Path;155 const path = yield* Path.Path;
160 const executable = (yield* HostProcessPlatform) === "win32" ? "adb.exe" : "adb";156 const executable = (yield* HostProcess.Platform) === "win32" ? "adb.exe" : "adb";
161 for (const sdk of [environment.ANDROID_SDK_ROOT, environment.ANDROID_HOME]) {157 for (const sdk of [environment.ANDROID_SDK_ROOT, environment.ANDROID_HOME]) {
162 if (!sdk) continue;158 if (!sdk) continue;
163 const candidate = path.join(sdk, "platform-tools", executable);159 const candidate = path.join(sdk, "platform-tools", executable);
...@@ -176,7 +172,7 @@ const command = Effect.fn("nativeClient.command")(function* (...@@ -176,7 +172,7 @@ const command = Effect.fn("nativeClient.command")(function* (
176 cwd?: string,172 cwd?: string,
177) {173) {
178 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;174 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
179 const environment = yield* HostProcessEnvironment;175 const environment = yield* HostProcess.Environment;
180 const spawn = yield* resolveSpawnCommand(program === "adb" ? yield* resolveAdb : program, args);176 const spawn = yield* resolveSpawnCommand(program === "adb" ? yield* resolveAdb : program, args);
181 const child = yield* spawner.spawn(177 const child = yield* spawner.spawn(
182 ChildProcess.make(spawn.command, spawn.args, {178 ChildProcess.make(spawn.command, spawn.args, {
...@@ -207,7 +203,7 @@ const command = Effect.fn("nativeClient.command")(function* (...@@ -207,7 +203,7 @@ const command = Effect.fn("nativeClient.command")(function* (
207}, Effect.scoped);203}, Effect.scoped);
208204
209const fingerprint = Effect.fn("nativeClient.fingerprint")(function* (platform: NativePlatform) {205const fingerprint = Effect.fn("nativeClient.fingerprint")(function* (platform: NativePlatform) {
210 const output = yield* command(yield* HostProcessExecutablePath, [206 const output = yield* command(yield* HostProcess.ExecutablePath, [
211 "--eval",207 "--eval",
212 `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; });`,208 `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; });`,
213 platform,209 platform,
...@@ -226,7 +222,7 @@ const validateDevice = Effect.fn("nativeClient.validateDevice")(function* (...@@ -226,7 +222,7 @@ const validateDevice = Effect.fn("nativeClient.validateDevice")(function* (
226 device: string,222 device: string,
227) {223) {
228 if (platform === "ios") {224 if (platform === "ios") {
229 if ((yield* HostProcessPlatform) !== "darwin")225 if ((yield* HostProcess.Platform) !== "darwin")
230 return yield* new NativeClientError({226 return yield* new NativeClientError({
231 message: "Run iOS check/ensure on the Mac that hosts the simulator.",227 message: "Run iOS check/ensure on the Mac that hosts the simulator.",
232 });228 });
...@@ -299,7 +295,7 @@ const main = Command.make(...@@ -299,7 +295,7 @@ const main = Command.make(
299 yield* validateDevice(platform, device);295 yield* validateDevice(platform, device);
300 const fs = yield* FileSystem.FileSystem;296 const fs = yield* FileSystem.FileSystem;
301 const path = yield* Path.Path;297 const path = yield* Path.Path;
302 const environment = yield* HostProcessEnvironment;298 const environment = yield* HostProcess.Environment;
303 const home = environment.HOME ?? environment.USERPROFILE;299 const home = environment.HOME ?? environment.USERPROFILE;
304 if (!home)300 if (!home)
305 return yield* new NativeClientError({301 return yield* new NativeClientError({
scripts/mobile-native-static-check.test.ts+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import * as NodeServices from "@effect/platform-node/NodeServices";1import * as NodeServices from "@effect/platform-node/NodeServices";
2import * as HostProcess from "@t3tools/shared/hostProcess";2import * as HostProcess from "@t3tools/shared/HostProcess";
3import { assert, it } from "@effect/vitest";3import { assert, it } from "@effect/vitest";
4import * as Effect from "effect/Effect";4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
...@@ -33,7 +33,7 @@ const provideSpawner = (spawn: ChildProcessSpawner.ChildProcessSpawner["Service"...@@ -33,7 +33,7 @@ const provideSpawner = (spawn: ChildProcessSpawner.ChildProcessSpawner["Service"
33 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, ChildProcessSpawner.make(spawn));33 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, ChildProcessSpawner.make(spawn));
3434
35const runSwiftLint = runCommand("swiftlint", ["lint", "--strict"], "/repo/apps/mobile").pipe(35const runSwiftLint = runCommand("swiftlint", ["lint", "--strict"], "/repo/apps/mobile").pipe(
36 Effect.provideService(HostProcess.HostProcessPlatform, "linux"),36 Effect.provideService(HostProcess.Platform, "linux"),
37);37);
3838
39it.layer(NodeServices.layer)("mobile native source discovery", (it) => {39it.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";...@@ -22,7 +22,7 @@ import { Command, Flag } from "effect/cli";
22import { ChildProcess, ChildProcessSpawner } from "effect/process";22import { ChildProcess, ChildProcessSpawner } from "effect/process";
2323
24import * as NetService from "@t3tools/shared/Net";24import * as NetService from "@t3tools/shared/Net";
25import { HostProcessPlatform } from "@t3tools/shared/hostProcess";25import * as HostProcess from "@t3tools/shared/HostProcess";
26import { windowsSystemTar } from "./build-cli-archive.ts";26import { windowsSystemTar } from "./build-cli-archive.ts";
27import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http";27import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http";
2828
...@@ -72,7 +72,7 @@ const smokeCliArchive = Effect.fn("smokeCliArchive")(function* (input: {...@@ -72,7 +72,7 @@ const smokeCliArchive = Effect.fn("smokeCliArchive")(function* (input: {
72}) {72}) {
73 const fs = yield* FileSystem.FileSystem;73 const fs = yield* FileSystem.FileSystem;
74 const path = yield* Path.Path;74 const path = yield* Path.Path;
75 const platform = yield* HostProcessPlatform;75 const platform = yield* HostProcess.Platform;
76 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;76 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
77 const scratch = yield* fs.makeTempDirectory({ prefix: "t3-cli-smoke-" });77 const scratch = yield* fs.makeTempDirectory({ prefix: "t3-cli-smoke-" });
78 // Windows can keep t3.exe locked (EBUSY) for a moment after the server78 // 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({...@@ -219,7 +219,7 @@ export default defineConfig({
219 },219 },
220 {220 {
221 // The one place that reads the host platform to seed the injected references.221 // 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"],
223 rules: { "t3code/no-global-process-runtime": "off" },223 rules: { "t3code/no-global-process-runtime": "off" },
224 },224 },
225 {225 {