From 51385989d6d7dc99d11e20f6fc66ee72f46e1e2d Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Fri, 9 Oct 2026 16:28:45 -0700 Subject: [PATCH] refactor(shared): host process references live in a HostProcess module The host references were named exports of a camelCase hostProcess module, imported by name (`HostProcessPlatform`, `HostProcessHomeDirectory`, ...). They are now short exports of `@t3tools/shared/HostProcess`, imported as a namespace like every other service module: `HostProcess.Platform`, `HostProcess.HomeDirectory`, `HostProcess.isWindows`. Reference keys follow the new module path. Co-Authored-By: Claude Opus 5.5 --- apps/desktop/src/app/DesktopApp.ts | 4 +- .../src/app/DesktopAppActivation.test.ts | 18 ++--- apps/desktop/src/app/DesktopAppActivation.ts | 4 +- apps/desktop/src/app/DesktopClerk.test.ts | 4 +- apps/desktop/src/app/DesktopClerk.ts | 4 +- .../src/app/DesktopPreReadyFileSystem.test.ts | 4 +- .../src/app/DesktopPreReadyPlatform.test.ts | 12 +-- .../src/app/DesktopPreReadyPlatform.ts | 6 +- .../backend/DesktopNetworkInterfaces.test.ts | 4 +- .../src/backend/DesktopNetworkInterfaces.ts | 4 +- .../desktop/src/electron/ElectronMenu.test.ts | 4 +- apps/desktop/src/electron/ElectronMenu.ts | 4 +- .../src/electron/ElectronSafeStorage.ts | 4 +- .../src/electron/ElectronWindow.test.ts | 4 +- apps/desktop/src/electron/ElectronWindow.ts | 4 +- .../src/ipc/methods/notificationBadge.test.ts | 4 +- .../src/ipc/methods/notificationBadge.ts | 4 +- apps/desktop/src/ipc/methods/window.test.ts | 8 +- apps/desktop/src/ipc/methods/window.ts | 7 +- apps/desktop/src/main.ts | 6 +- .../BrowserImport/BrowserImport.test.ts | 16 ++-- .../preview/BrowserImport/BrowserImport.ts | 6 +- .../preview/BrowserImport/ChromiumCookies.ts | 2 +- .../BrowserImport/ChromiumKeys.test.ts | 6 +- .../src/preview/BrowserImport/ChromiumKeys.ts | 6 +- .../BrowserImport/SafariPermission.test.ts | 10 +-- .../src/preview/BrowserImport/Sources.test.ts | 64 ++++++++-------- .../src/preview/BrowserImport/Sources.ts | 17 ++--- apps/desktop/src/preview/Manager.test.ts | 4 +- apps/desktop/src/preview/Manager.ts | 4 +- apps/desktop/src/snapShot/DesktopSnapShot.ts | 4 +- apps/desktop/src/snapShot/snapShot.test.ts | 4 +- .../record-codex-app-server-replay-fixture.ts | 5 +- .../scripts/record-grok-acp-replay-fixture.ts | 6 +- apps/server/scripts/t3-sqlite-state.test.ts | 4 +- apps/server/src/assets/AssetAccess.test.ts | 4 +- apps/server/src/assets/AssetAccess.ts | 4 +- .../src/assets/NativeAppIconResolver.test.ts | 4 +- .../src/assets/NativeAppIconResolver.ts | 4 +- apps/server/src/bootstrap.test.ts | 8 +- apps/server/src/bootstrap.ts | 4 +- .../src/checkpointing/CheckpointStore.test.ts | 4 +- apps/server/src/cli/app.test.ts | 35 ++++----- apps/server/src/cli/app.ts | 12 +-- apps/server/src/cli/browser.ts | 12 +-- apps/server/src/cli/connect.ts | 4 +- apps/server/src/cli/invocation.test.ts | 42 +++++------ apps/server/src/cli/invocation.ts | 26 +++---- apps/server/src/cli/pair.test.ts | 4 +- apps/server/src/cli/server.ts | 4 +- apps/server/src/cli/service.test.ts | 8 +- apps/server/src/cli/service.ts | 4 +- apps/server/src/cli/theme.test.ts | 4 +- apps/server/src/cli/triage.ts | 4 +- apps/server/src/cli/uninstall.test.ts | 4 +- apps/server/src/cli/uninstall.ts | 16 ++-- apps/server/src/cli/update.test.ts | 31 ++++---- apps/server/src/cli/update.ts | 31 +++----- apps/server/src/cloud/bootService.test.ts | 12 +-- apps/server/src/cloud/bootService.ts | 15 ++-- apps/server/src/cloud/selfUpdate.test.ts | 6 +- apps/server/src/cloud/selfUpdate.ts | 6 +- .../src/cloud/serviceLauncherClient.test.ts | 4 +- .../server/src/cloud/serviceLauncherClient.ts | 4 +- apps/server/src/device/AgentDeviceShim.ts | 4 +- .../src/device/AgentDeviceTarget.test.ts | 12 +-- .../server/src/device/LocalDeviceHost.test.ts | 25 +++---- apps/server/src/device/LocalDeviceHost.ts | 24 +++--- .../server/src/device/sshDeviceScript.test.ts | 8 +- .../src/environment/RemoteOpenTargets.test.ts | 4 +- .../src/environment/RemoteOpenTargets.ts | 4 +- .../src/environment/ServerEnvironment.test.ts | 15 ++-- .../src/environment/ServerEnvironment.ts | 6 +- .../ServerEnvironmentLabel.test.ts | 6 +- .../src/environment/ServerEnvironmentLabel.ts | 6 +- .../ServerEnvironmentMachine.test.ts | 4 +- .../environment/ServerEnvironmentMachine.ts | 4 +- apps/server/src/htmlRender/HtmlRender.test.ts | 10 +-- apps/server/src/htmlRender/HtmlRender.ts | 4 +- apps/server/src/keybindings.test.ts | 4 +- .../src/mcp/toolkits/device/handlers.ts | 4 +- apps/server/src/observability/HeapSnapshot.ts | 4 +- .../Adapters/AcpAdapterV2.test.ts | 18 ++--- .../Adapters/ClaudeAdapterV2.test.ts | 4 +- .../Adapters/ClaudeAdapterV2.testkit.ts | 4 +- .../Adapters/ClaudeAdapterV2.ts | 8 +- .../Adapters/CodexAdapterV2.test.ts | 12 +-- .../Adapters/CodexAdapterV2.ts | 8 +- .../Adapters/CursorAdapterV2.testkit.ts | 4 +- .../Adapters/GrokAdapterV2.test.ts | 4 +- .../Adapters/GrokAdapterV2.testkit.ts | 4 +- .../orchestration-v2/workflowScriptQuery.ts | 4 +- apps/server/src/os-jank.ts | 14 ++-- apps/server/src/preview/PortScanner.test.ts | 8 +- apps/server/src/preview/PortScanner.ts | 4 +- .../server/src/preview/PreviewBrowser.test.ts | 8 +- apps/server/src/preview/PreviewBrowser.ts | 6 +- .../src/preview/PreviewBrowserHost.test.ts | 4 +- apps/server/src/preview/PreviewBrowserHost.ts | 6 +- apps/server/src/preview/ServerBrowser.ts | 10 +-- .../src/process/externalLauncher.test.ts | 10 +-- apps/server/src/process/externalLauncher.ts | 10 +-- apps/server/src/processRunner.test.ts | 8 +- .../server/src/project/AgentSessionScanner.ts | 12 +-- .../src/project/ProjectSetupScriptRunner.ts | 6 +- .../provider/AntigravityInstallation.test.ts | 19 ++--- .../src/provider/AntigravityInstallation.ts | 14 ++-- .../src/provider/CodexInstallation.test.ts | 12 +-- apps/server/src/provider/CodexInstallation.ts | 16 ++-- apps/server/src/provider/CodexProvider.ts | 4 +- .../Drivers/AntigravityDriver.test.ts | 17 ++--- .../src/provider/Drivers/AntigravityDriver.ts | 6 +- .../src/provider/Drivers/AntigravityUsage.ts | 6 +- .../src/provider/Drivers/ClaudeDriver.ts | 4 +- .../provider/Drivers/ClaudeExecutable.test.ts | 6 +- .../src/provider/Drivers/ClaudeExecutable.ts | 4 +- .../server/src/provider/Drivers/ClaudeHome.ts | 4 +- .../src/provider/Drivers/ClaudeSkills.ts | 6 +- .../src/provider/Drivers/CodexDriver.test.ts | 4 +- .../src/provider/Drivers/CodexDriver.ts | 4 +- .../src/provider/Drivers/CodexHomeLayout.ts | 4 +- .../src/provider/Drivers/claudeUsage.ts | 4 +- .../provider/ProviderInstanceRegistry.test.ts | 14 ++-- .../acp/AcpSessionRuntime.processTree.test.ts | 10 +-- .../provider/antigravityAuthSupport.test.ts | 14 ++-- .../src/provider/antigravityAuthSupport.ts | 6 +- .../src/provider/claudeResetCredits.test.ts | 12 +-- .../server/src/provider/claudeResetCredits.ts | 6 +- .../src/provider/providerInstallation.test.ts | 4 +- .../providerMaintenanceRunner.test.ts | 8 +- .../src/resourceTelemetry/HostResources.ts | 4 +- .../ResourceMonitorBinary.test.ts | 44 +++++------ .../ResourceMonitorBinary.ts | 12 +-- apps/server/src/review/ReviewService.ts | 4 +- .../SourceControlRepositoryService.ts | 4 +- apps/server/src/storageCleanup.ts | 4 +- .../src/telemetry/AnalyticsService.test.ts | 14 ++-- apps/server/src/telemetry/AnalyticsService.ts | 6 +- apps/server/src/telemetry/Identify.ts | 4 +- apps/server/src/terminal/Manager.test.ts | 12 +-- apps/server/src/terminal/Manager.ts | 12 +-- .../src/terminal/NodePtyAdapter.test.ts | 10 +-- apps/server/src/terminal/NodePtyAdapter.ts | 16 ++-- .../ClaudeTextGeneration.test.ts | 6 +- .../src/textGeneration/CodexTextGeneration.ts | 4 +- apps/server/src/usage/UsageService.test.ts | 10 +-- apps/server/src/usage/UsageService.ts | 4 +- apps/server/src/vcs/GitVcsDriverCore.test.ts | 10 +-- apps/server/src/vcs/GitVcsDriverCore.ts | 8 +- apps/server/src/vcs/VcsProcess.test.ts | 4 +- .../src/workspace/WorkspaceEntries.test.ts | 6 +- apps/server/src/workspace/WorkspaceEntries.ts | 8 +- .../src/workspace/WorkspaceFileSystem.test.ts | 4 +- apps/server/src/workspace/WorkspacePaths.ts | 4 +- apps/server/src/ws.test.ts | 4 +- .../rules/no-global-process-runtime.test.ts | 12 +-- .../rules/no-global-process-runtime.ts | 2 +- .../src/server/AcpRegistrySupport.test.ts | 32 ++++---- .../src/server/AcpRegistrySupport.ts | 12 +-- .../src/server/adapter.ts | 4 +- .../src/server/driver.ts | 4 +- .../src/server/AcpSessionRuntime.ts | 6 +- .../src/server/instanceEnvironment.test.ts | 4 +- .../src/server/instanceEnvironment.ts | 4 +- .../src/server/maintenanceResolver.test.ts | 20 ++--- .../src/server/maintenanceResolver.ts | 8 +- .../provider-core/src/server/pathExpansion.ts | 2 +- .../src/server/processGroup.test.ts | 4 +- .../src/server/snapshotProbe.test.ts | 4 +- .../provider-core/src/server/snapshotProbe.ts | 4 +- .../src/server/CursorUsageAccounts.ts | 12 +-- .../provider-cursor/src/server/adapter.ts | 4 +- packages/provider-cursor/src/server/skills.ts | 4 +- .../src/server/textGeneration.ts | 4 +- .../src/server/usageLimits.test.ts | 12 +-- .../provider-cursor/src/server/usageLimits.ts | 6 +- .../provider-grok/src/server/acpSupport.ts | 4 +- packages/provider-grok/src/server/adapter.ts | 16 ++-- .../provider-grok/src/server/driver.test.ts | 4 +- packages/provider-grok/src/server/usage.ts | 4 +- .../provider-grok/src/server/usageLimits.ts | 4 +- packages/provider-muse/src/server/driver.ts | 6 +- .../OpenCodeRuntime.environment.test.ts | 12 +-- .../server/OpenCodeRuntime.inventory.test.ts | 14 ++-- .../src/server/OpenCodeRuntime.ts | 4 +- .../src/server/OpenCodeServerLedger.test.ts | 6 +- .../src/server/OpenCodeServerLedger.ts | 4 +- .../provider-opencode/src/server/adapter.ts | 6 +- .../src/server/driver.test.ts | 6 +- .../provider-opencode/src/server/usage.ts | 6 +- .../src/server/usageLimits.ts | 4 +- .../src/server/v2/OpenCode2Server.test.ts | 14 ++-- .../provider-pi/src/server/adapter.test.ts | 4 +- packages/provider-pi/src/server/adapter.ts | 6 +- packages/provider-pi/src/server/rpc.ts | 4 +- packages/provider-testing/src/fakeCli.ts | 6 +- packages/shared/package.json | 6 +- .../src/{hostProcess.ts => HostProcess.ts} | 75 ++++++++----------- packages/shared/src/editor.ts | 4 +- packages/shared/src/logging.test.ts | 4 +- packages/shared/src/nodeRuntime.test.ts | 61 +++++++-------- packages/shared/src/nodeRuntime.ts | 22 ++---- packages/shared/src/relayClient.test.ts | 8 +- packages/shared/src/relayClient.ts | 6 +- packages/shared/src/shell.test.ts | 26 +++---- packages/shared/src/shell.ts | 12 +-- packages/shared/src/testing/longTempDir.ts | 4 +- .../src/server/ForgejoCli.ts | 6 +- .../src/server/GitHubCredentials.ts | 6 +- .../GitHubSourceControlProvider.test.ts | 6 +- .../src/server/GitHubSourceControlProvider.ts | 6 +- packages/ssh/src/auth.test.ts | 6 +- packages/ssh/src/auth.ts | 8 +- packages/ssh/src/command.ts | 4 +- packages/ssh/src/runnerProcess.test.ts | 6 +- packages/ssh/src/tunnel.test.ts | 6 +- packages/tailscale/src/tailscale.test.ts | 4 +- packages/tailscale/src/tailscale.ts | 6 +- scripts/build-cli-archive.ts | 6 +- scripts/build-desktop-artifact.test.ts | 34 ++++----- scripts/build-desktop-artifact.ts | 14 ++-- scripts/build-npm-platform-packages.test.ts | 6 +- scripts/build-npm-platform-packages.ts | 6 +- scripts/dev-runner.test.ts | 36 ++++----- scripts/dev-runner.ts | 8 +- scripts/export-brand-icons.ts | 4 +- scripts/install.test.ts | 6 +- scripts/lib/build-target-arch.test.ts | 6 +- scripts/lib/build-target-arch.ts | 6 +- scripts/lib/cli-external-packages.test.ts | 2 +- scripts/mobile-native-client.ts | 18 ++--- scripts/mobile-native-static-check.test.ts | 4 +- scripts/smoke-cli-archive.ts | 4 +- vite.config.ts | 2 +- 234 files changed, 948 insertions(+), 1145 deletions(-) rename packages/shared/src/{hostProcess.ts => HostProcess.ts} (53%) diff --git a/apps/desktop/src/app/DesktopApp.ts b/apps/desktop/src/app/DesktopApp.ts index b76f6b4ba197..a6906099dbd5 100644 --- a/apps/desktop/src/app/DesktopApp.ts +++ b/apps/desktop/src/app/DesktopApp.ts @@ -35,7 +35,7 @@ import * as DesktopUpdates from "../updates/DesktopUpdates.ts"; import * as DesktopSnapShot from "../snapShot/DesktopSnapShot.ts"; import * as DesktopWslBackend from "../wsl/DesktopWslBackend.ts"; import * as DesktopRendererHistory from "../telemetry/DesktopRendererHistory.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const DEFAULT_DESKTOP_BACKEND_PORT = 3773; const MAX_TCP_PORT = 65_535; @@ -286,7 +286,7 @@ const startup = Effect.gen(function* () { const linuxElectronOptions = environment.platform === "linux" && !hasCommandLinePasswordStore ? DesktopPreReadyPlatform.resolveEarlyLinuxElectronOptionsFromProcess( - yield* HostProcessHomeDirectory, + yield* HostProcess.HomeDirectory, ) : preReadyElectronOptions.linux; if (linuxElectronOptions !== null && !hasCommandLinePasswordStore) { diff --git a/apps/desktop/src/app/DesktopAppActivation.test.ts b/apps/desktop/src/app/DesktopAppActivation.test.ts index 8ab165afce0a..dfe415644760 100644 --- a/apps/desktop/src/app/DesktopAppActivation.test.ts +++ b/apps/desktop/src/app/DesktopAppActivation.test.ts @@ -11,7 +11,7 @@ import { type DesktopAppActivationResponse, } from "@t3tools/contracts"; import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl"; -import { HostProcessPlatform, HostProcessUserId } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import { afterEach, describe, expect } from "vite-plus/test"; @@ -83,8 +83,8 @@ function exchange(address: string, payload: DesktopAppActivationRequest) { describe("desktop app control server", () => { it.effect("roundtrips a request and removes its socket on shutdown", () => Effect.gen(function* () { - const platform = yield* HostProcessPlatform; - const userId = yield* HostProcessUserId; + const platform = yield* HostProcess.Platform; + const userId = yield* HostProcess.UserId; yield* Effect.promise(async () => { const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-control-test-")); const target = makeTarget(NodePath.join(root, "userdata"), platform, userId); @@ -123,8 +123,8 @@ describe("desktop app control server", () => { it.effect("cancels a queued request when the client disconnects", () => Effect.gen(function* () { - const platform = yield* HostProcessPlatform; - const userId = yield* HostProcessUserId; + const platform = yield* HostProcess.Platform; + const userId = yield* HostProcess.UserId; yield* Effect.promise(async () => { const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-cancel-test-")); const target = makeTarget(NodePath.join(root, "userdata"), platform, userId); @@ -162,8 +162,8 @@ describe("desktop app control server", () => { // Two desktop apps can share one state dir, such as nightly and a preview build. it.effect("keeps a newer app's socket when an older app on the same state dir quits", () => Effect.gen(function* () { - const platform = yield* HostProcessPlatform; - const userId = yield* HostProcessUserId; + const platform = yield* HostProcess.Platform; + const userId = yield* HostProcess.UserId; if (platform === "win32") return; yield* Effect.promise(async () => { const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-takeover-test-")); @@ -183,8 +183,8 @@ describe("desktop app control server", () => { it.effect("binds its address again after the socket file is removed", () => Effect.gen(function* () { - const platform = yield* HostProcessPlatform; - const userId = yield* HostProcessUserId; + const platform = yield* HostProcess.Platform; + const userId = yield* HostProcess.UserId; if (platform === "win32") return; yield* Effect.promise(async () => { const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-app-reclaim-test-")); diff --git a/apps/desktop/src/app/DesktopAppActivation.ts b/apps/desktop/src/app/DesktopAppActivation.ts index 740799955da2..19f24460106e 100644 --- a/apps/desktop/src/app/DesktopAppActivation.ts +++ b/apps/desktop/src/app/DesktopAppActivation.ts @@ -12,7 +12,7 @@ import { type DesktopAppActivationResponse, } from "@t3tools/contracts"; import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl"; -import { HostProcessUserId } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -315,7 +315,7 @@ export const make = Effect.gen(function* () { const desktopWindow = yield* DesktopWindow.DesktopWindow; const electronWindow = yield* ElectronWindow.ElectronWindow; const path = yield* Path.Path; - const userId = yield* HostProcessUserId; + const userId = yield* HostProcess.UserId; const runPromise = Effect.runPromiseWith(yield* Effect.context()); const address = resolveDesktopAppControlAddress({ stateDir: path.resolve(desktopEnvironment.stateDir), diff --git a/apps/desktop/src/app/DesktopClerk.test.ts b/apps/desktop/src/app/DesktopClerk.test.ts index 4b4b90c29728..76306bfbf227 100644 --- a/apps/desktop/src/app/DesktopClerk.test.ts +++ b/apps/desktop/src/app/DesktopClerk.test.ts @@ -3,7 +3,7 @@ import * as NodeHttp from "node:http"; import * as NodePath from "@effect/platform-node/NodePath"; import { codexAuthHandoffUrl, readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff"; import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts"; -import { HostProcessArguments } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { assert, describe, it } from "@effect/vitest"; import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; @@ -375,7 +375,7 @@ it.effect.each(["startup", "open-url"] as const)( assert.strictEqual(delivery?.returnUrl, request.returnUrl); }).pipe( Effect.provide(layerDesktopClerk(true, [], "darwin", undefined, shell)), - Effect.provideService(HostProcessArguments, entry === "startup" ? ["t3", link] : ["t3"]), + Effect.provideService(HostProcess.Arguments, entry === "startup" ? ["t3", link] : ["t3"]), Effect.provideService(ElectronApp.ElectronApp, electronApp), Effect.provideService( ElectronWindow.ElectronWindow, diff --git a/apps/desktop/src/app/DesktopClerk.ts b/apps/desktop/src/app/DesktopClerk.ts index 1bc390ac3c62..f1a7f31174ab 100644 --- a/apps/desktop/src/app/DesktopClerk.ts +++ b/apps/desktop/src/app/DesktopClerk.ts @@ -11,7 +11,7 @@ import { codexAuthDeliveryUrl, readCodexAuthHandoff } from "@t3tools/shared/code import { receiveCodexAuthCallback, CodexAuthCallbackError } from "./CodexAuthCallback.ts"; import * as ElectronShell from "../electron/ElectronShell.ts"; import { providerAuthReturnUrl } from "@t3tools/shared/providerAuthReturnUrl"; -import { HostProcessArguments } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth"; import * as ElectronApp from "../electron/ElectronApp.ts"; import * as ElectronProtocol from "../electron/ElectronProtocol.ts"; @@ -182,7 +182,7 @@ export const make = Effect.gen(function* () { ); return true; }; - const args = yield* HostProcessArguments; + const args = yield* HostProcess.Arguments; args.some((value) => startProviderAuthHandoff(value)); yield* electronApp.on("open-url", (event: { preventDefault: () => void }, url: string) => { if (startProviderAuthHandoff(url) || resumeProviderAuth(url)) event.preventDefault(); diff --git a/apps/desktop/src/app/DesktopPreReadyFileSystem.test.ts b/apps/desktop/src/app/DesktopPreReadyFileSystem.test.ts index ab4c4f86cdf1..542f6b987594 100644 --- a/apps/desktop/src/app/DesktopPreReadyFileSystem.test.ts +++ b/apps/desktop/src/app/DesktopPreReadyFileSystem.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; import * as FileSystem from "effect/FileSystem"; @@ -32,7 +32,7 @@ it.layer(NodeServices.layer)("DesktopPreReadyFileSystem", (it) => { }), ); - it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32" || process.getuid?.() === 0)( + it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32" || process.getuid?.() === 0)( "fails instead of treating an unreadable profile as missing", () => Effect.gen(function* () { diff --git a/apps/desktop/src/app/DesktopPreReadyPlatform.test.ts b/apps/desktop/src/app/DesktopPreReadyPlatform.test.ts index 4fa5d417aa64..ecdc94d8254e 100644 --- a/apps/desktop/src/app/DesktopPreReadyPlatform.test.ts +++ b/apps/desktop/src/app/DesktopPreReadyPlatform.test.ts @@ -1,5 +1,5 @@ import { assert, describe, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -75,7 +75,7 @@ describe("DesktopPreReadyPlatform", () => { }).pipe( Effect.provide( DesktopPreReadyPlatform.layer.pipe( - Layer.provide(Layer.succeed(HostProcessPlatform, "linux")), + Layer.provide(Layer.succeed(HostProcess.Platform, "linux")), ), ), ); @@ -111,7 +111,7 @@ describe("DesktopPreReadyPlatform", () => { })); yield* Layer.build( DesktopPreReadyPlatform.layer.pipe( - Layer.provide(Layer.succeed(HostProcessPlatform, "linux")), + Layer.provide(Layer.succeed(HostProcess.Platform, "linux")), ), ); const identity = yield* Effect.promise(() => portalIdentity); @@ -135,7 +135,7 @@ describe("DesktopPreReadyPlatform", () => { }); return DesktopPreReadyPlatform.make.pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.asVoid, ); }); @@ -151,7 +151,7 @@ describe("DesktopPreReadyPlatform", () => { assert.include(contents, "MimeType=x-scheme-handler/t3code;"); assert.include(contents, "Icon="); assert.equal(setDesktopNameMock.mock.calls.length, 1); - }).pipe(Effect.provideService(HostProcessPlatform, "linux")); + }).pipe(Effect.provideService(HostProcess.Platform, "linux")); }); it.effect( @@ -168,7 +168,7 @@ describe("DesktopPreReadyPlatform", () => { }); const layerPreReady = DesktopPreReadyPlatform.layer.pipe( - Layer.provide(Layer.succeed(HostProcessPlatform, "darwin")), + Layer.provide(Layer.succeed(HostProcess.Platform, "darwin")), ); const layerClerkShaped = Layer.effect( diff --git a/apps/desktop/src/app/DesktopPreReadyPlatform.ts b/apps/desktop/src/app/DesktopPreReadyPlatform.ts index 2de132887aa2..378eb58f160c 100644 --- a/apps/desktop/src/app/DesktopPreReadyPlatform.ts +++ b/apps/desktop/src/app/DesktopPreReadyPlatform.ts @@ -6,7 +6,7 @@ import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Electron from "electron"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as DesktopEarlyElectronStartup from "./DesktopEarlyElectronStartup.ts"; import { resolveDesktopAppBranding } from "./DesktopEnvironment.ts"; @@ -50,8 +50,8 @@ export class DesktopPreReadyElectronOptions extends Context.Service< /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { - const platform = yield* HostProcessPlatform; - const homeDirectory = yield* HostProcessHomeDirectory; + const platform = yield* HostProcess.Platform; + const homeDirectory = yield* HostProcess.HomeDirectory; return yield* Effect.sync((): DesktopPreReadyElectronOptions["Service"] => { const linuxPasswordStoreCommandLine = platform === "linux" diff --git a/apps/desktop/src/backend/DesktopNetworkInterfaces.test.ts b/apps/desktop/src/backend/DesktopNetworkInterfaces.test.ts index ab6990ef1767..679d19a53d0a 100644 --- a/apps/desktop/src/backend/DesktopNetworkInterfaces.test.ts +++ b/apps/desktop/src/backend/DesktopNetworkInterfaces.test.ts @@ -1,5 +1,5 @@ import { assert, describe, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -16,7 +16,7 @@ vi.mock("node:os", () => ({ import * as DesktopNetworkInterfaces from "./DesktopNetworkInterfaces.ts"; const layerTest = DesktopNetworkInterfaces.layer.pipe( - Layer.provide(Layer.succeed(HostProcessPlatform, "linux")), + Layer.provide(Layer.succeed(HostProcess.Platform, "linux")), ); describe("DesktopNetworkInterfaces", () => { diff --git a/apps/desktop/src/backend/DesktopNetworkInterfaces.ts b/apps/desktop/src/backend/DesktopNetworkInterfaces.ts index de200f1b67b6..f2c32e1d0731 100644 --- a/apps/desktop/src/backend/DesktopNetworkInterfaces.ts +++ b/apps/desktop/src/backend/DesktopNetworkInterfaces.ts @@ -1,6 +1,6 @@ import * as NodeOS from "node:os"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -41,7 +41,7 @@ export class DesktopNetworkInterfaces extends Context.Service< /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; return DesktopNetworkInterfaces.of({ read: Effect.try({ try: () => NodeOS.networkInterfaces(), diff --git a/apps/desktop/src/electron/ElectronMenu.test.ts b/apps/desktop/src/electron/ElectronMenu.test.ts index 01b4fe080304..320988051e5f 100644 --- a/apps/desktop/src/electron/ElectronMenu.test.ts +++ b/apps/desktop/src/electron/ElectronMenu.test.ts @@ -1,5 +1,5 @@ import { assert, describe, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -28,7 +28,7 @@ vi.mock("electron", () => ({ import * as ElectronMenu from "./ElectronMenu.ts"; const layerTest = ElectronMenu.layer.pipe( - Layer.provide(Layer.succeed(HostProcessPlatform, "linux")), + Layer.provide(Layer.succeed(HostProcess.Platform, "linux")), ); const makeWindow = (zoomFactor = 1): Electron.BrowserWindow => diff --git a/apps/desktop/src/electron/ElectronMenu.ts b/apps/desktop/src/electron/ElectronMenu.ts index 401e0c27ccd8..352a5bc97a21 100644 --- a/apps/desktop/src/electron/ElectronMenu.ts +++ b/apps/desktop/src/electron/ElectronMenu.ts @@ -1,5 +1,5 @@ import type { ContextMenuItem } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -114,7 +114,7 @@ const normalizePosition = ( /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; let destructiveMenuIconCache: Option.Option | undefined; const getDestructiveMenuIcon = (): Option.Option => { diff --git a/apps/desktop/src/electron/ElectronSafeStorage.ts b/apps/desktop/src/electron/ElectronSafeStorage.ts index 57ae5d6dcb69..cd01613d92fd 100644 --- a/apps/desktop/src/electron/ElectronSafeStorage.ts +++ b/apps/desktop/src/electron/ElectronSafeStorage.ts @@ -5,7 +5,7 @@ import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import * as Electron from "electron"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const electronSafeStorageErrorFields = { cause: Schema.Defect(), @@ -67,7 +67,7 @@ export class ElectronSafeStorage extends Context.Service< /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; return ElectronSafeStorage.of({ isEncryptionAvailable: Effect.try({ diff --git a/apps/desktop/src/electron/ElectronWindow.test.ts b/apps/desktop/src/electron/ElectronWindow.test.ts index 50dd15ba6df1..ef94312ed6f0 100644 --- a/apps/desktop/src/electron/ElectronWindow.test.ts +++ b/apps/desktop/src/electron/ElectronWindow.test.ts @@ -1,5 +1,5 @@ import { assert, describe, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; @@ -58,7 +58,7 @@ vi.mock("electron", () => ({ import * as ElectronWindow from "./ElectronWindow.ts"; const layerTestFor = (platform: NodeJS.Platform) => - ElectronWindow.layer.pipe(Layer.provide(Layer.succeed(HostProcessPlatform, platform))); + ElectronWindow.layer.pipe(Layer.provide(Layer.succeed(HostProcess.Platform, platform))); const layerTest = layerTestFor("linux"); diff --git a/apps/desktop/src/electron/ElectronWindow.ts b/apps/desktop/src/electron/ElectronWindow.ts index 1c8d82eb2cf9..a5e74494c12f 100644 --- a/apps/desktop/src/electron/ElectronWindow.ts +++ b/apps/desktop/src/electron/ElectronWindow.ts @@ -2,7 +2,7 @@ import * as NodePath from "node:path"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import type * as Cause from "effect/Cause"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; @@ -129,7 +129,7 @@ export class ElectronWindow extends Context.Service< /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; // The focus worker loads a native accessibility module. Start it on the first // capture reveal so users who never capture pay nothing at launch. let windowsForegroundFocus: ReturnType | undefined; diff --git a/apps/desktop/src/ipc/methods/notificationBadge.test.ts b/apps/desktop/src/ipc/methods/notificationBadge.test.ts index a47732550f64..40d1df6a3366 100644 --- a/apps/desktop/src/ipc/methods/notificationBadge.test.ts +++ b/apps/desktop/src/ipc/methods/notificationBadge.test.ts @@ -1,7 +1,7 @@ import * as Effect from "effect/Effect"; import { beforeEach, expect, vi } from "vite-plus/test"; import { it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const native = vi.hoisted(() => ({ setBadgeCount: vi.fn(), @@ -122,7 +122,7 @@ it.effect("validates IPC and clears on native focus, quit, and disposal", () => expect(native.setBadgeCount).toHaveBeenLastCalledWith(0); }), ).pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provide([ ElectronApp.layer, DesktopIpc.layer({ diff --git a/apps/desktop/src/ipc/methods/notificationBadge.ts b/apps/desktop/src/ipc/methods/notificationBadge.ts index 40e4549138f2..952745b4b7c6 100644 --- a/apps/desktop/src/ipc/methods/notificationBadge.ts +++ b/apps/desktop/src/ipc/methods/notificationBadge.ts @@ -1,7 +1,7 @@ import * as Electron from "electron"; import * as Effect from "effect/Effect"; import * as Schema from "effect/Schema"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as ElectronApp from "../../electron/ElectronApp.ts"; import * as DesktopIpc from "../DesktopIpc.ts"; @@ -45,7 +45,7 @@ export const installNotificationBadge = Effect.fn("desktop.ipc.installNotificati function* () { const ipc = yield* DesktopIpc.DesktopIpc; const app = yield* ElectronApp.ElectronApp; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const clear = () => { applyNotificationBadge(platform, { count: 0, image: null }); for (const window of Electron.BrowserWindow.getAllWindows()) { diff --git a/apps/desktop/src/ipc/methods/window.test.ts b/apps/desktop/src/ipc/methods/window.test.ts index 72f631d162d1..a6913528653c 100644 --- a/apps/desktop/src/ipc/methods/window.test.ts +++ b/apps/desktop/src/ipc/methods/window.test.ts @@ -1,6 +1,6 @@ import { assert, describe, it } from "@effect/vitest"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import * as Effect from "effect/Effect"; @@ -314,7 +314,7 @@ describe("pickProjectFavicon", () => { ); }); -it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( +it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "finds remote editors installed without PATH launchers", () => Effect.gen(function* () { @@ -333,11 +333,11 @@ it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( yield* fs.chmod(executable, 0o755); } const editors = yield* probeRemoteEditors.handler(undefined).pipe( - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { HOME: home, PATH: path.join(home, "empty"), }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), ); assert.include(editors, "cursor"); assert.include(editors, "vscode"); diff --git a/apps/desktop/src/ipc/methods/window.ts b/apps/desktop/src/ipc/methods/window.ts index 8e4ffebfefe7..47e6c02ffe52 100644 --- a/apps/desktop/src/ipc/methods/window.ts +++ b/apps/desktop/src/ipc/methods/window.ts @@ -15,7 +15,7 @@ import { } from "@t3tools/contracts"; import { WORKSPACE_IMAGE_PREVIEW_EXTENSIONS } from "@t3tools/shared/filePreview"; import { resolveEditorCommand } from "@t3tools/shared/editor"; -import * as HostProcess from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import * as Effect from "effect/Effect"; @@ -45,7 +45,6 @@ import { resolveWslPickFolderDefaultPath, wslUncPathToLinuxPath, } from "../../wsl/wslPathParsing.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; const ContextMenuPosition = Schema.Struct({ x: Schema.Number, @@ -345,7 +344,7 @@ export const probeRemoteEditors = DesktopIpc.makeIpcMethod({ result: Schema.Array(EditorId), handler: Effect.fn("desktop.ipc.window.probeRemoteEditors")(function* () { const available: Array = []; - const env = yield* HostProcess.HostProcessEnvironment; + const env = yield* HostProcess.Environment; for (const editorId of REMOTE_CAPABLE_EDITOR_IDS) { const editor = EDITORS.find((editor) => editor.id === editorId); if (editor && Option.isSome(yield* resolveEditorCommand(editor, env))) { @@ -398,7 +397,7 @@ export const pickThemeFiles = DesktopIpc.makeIpcMethod({ // The VS Code extensions directory is the same dotfolder on Windows, // macOS, and Linux; when it is missing the picker opens wherever the // platform would by default. - const extensionsDir = path.join(yield* HostProcessHomeDirectory, ".vscode", "extensions"); + const extensionsDir = path.join(yield* HostProcess.HomeDirectory, ".vscode", "extensions"); const defaultPath = yield* fileSystem .exists(extensionsDir) .pipe(Effect.orElseSucceed(() => false)); diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 869961f955b7..806b038d7696 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -18,7 +18,7 @@ import * as Option from "effect/Option"; import * as Electron from "electron"; import * as NetService from "@t3tools/shared/Net"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import type { RemoteT3RunnerOptions } from "@t3tools/ssh/tunnel"; import serverPackageJson from "../../server/package.json" with { type: "json" }; @@ -90,8 +90,8 @@ const layerDesktopEnvironment = Layer.unwrap( const metadata = yield* Effect.service(ElectronApp.ElectronApp).pipe( Effect.flatMap((app) => app.metadata), ); - const platform = yield* HostProcessPlatform; - const processArch = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const processArch = yield* HostProcess.Architecture; return DesktopEnvironment.layer({ dirname: __dirname, homeDirectory: NodeOS.homedir(), diff --git a/apps/desktop/src/preview/BrowserImport/BrowserImport.test.ts b/apps/desktop/src/preview/BrowserImport/BrowserImport.test.ts index 0f1e2bd386ce..edd4e981dee5 100644 --- a/apps/desktop/src/preview/BrowserImport/BrowserImport.test.ts +++ b/apps/desktop/src/preview/BrowserImport/BrowserImport.test.ts @@ -1,10 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, describe, it } from "@effect/vitest"; -import { - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Fiber from "effect/Fiber"; @@ -52,10 +48,10 @@ const layerRejectedBeforeSession = Layer.succeed( const withImporter = Effect.fnUntraced(function* () { const fileSystem = yield* FileSystem.FileSystem; const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-import-" }); - const layerEnvironment = Layer.succeed(HostProcessEnvironment, { HOME: home }); + const layerEnvironment = Layer.succeed(HostProcess.Environment, { HOME: home }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), ); const root = helium.userDataDirectory(context); if (root === undefined) throw new Error("Helium has no macOS user-data directory"); @@ -69,8 +65,8 @@ const withImporter = Effect.fnUntraced(function* () { BrowserImport.layer.pipe( Layer.provide(layerRejectedBeforeSession), Layer.provide(layerEnvironment), - Layer.provide(Layer.succeed(HostProcessPlatform, "darwin")), - Layer.provide(Layer.succeed(HostProcessExecutablePath, "/Applications/T3 Code.app")), + Layer.provide(Layer.succeed(HostProcess.Platform, "darwin")), + Layer.provide(Layer.succeed(HostProcess.ExecutablePath, "/Applications/T3 Code.app")), Layer.provide(NodeServices.layer), ), ), diff --git a/apps/desktop/src/preview/BrowserImport/BrowserImport.ts b/apps/desktop/src/preview/BrowserImport/BrowserImport.ts index 8893f2322410..69fccc5b761d 100644 --- a/apps/desktop/src/preview/BrowserImport/BrowserImport.ts +++ b/apps/desktop/src/preview/BrowserImport/BrowserImport.ts @@ -21,7 +21,7 @@ import * as Schema from "effect/Schema"; import * as Scope from "effect/Scope"; import { ChildProcessSpawner } from "effect/process"; -import { HostProcessExecutablePath, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as BrowserSession from "../BrowserSession.ts"; import { ChromiumCookieReadError, readChromiumCookies } from "./ChromiumCookies.ts"; @@ -169,8 +169,8 @@ export const writeCookies = Effect.fn("BrowserImport.writeCookies")(function* ( /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* BrowserImportMake() { const browserSession = yield* BrowserSession.BrowserSession; - const platform = yield* HostProcessPlatform; - const executablePath = yield* HostProcessExecutablePath; + const platform = yield* HostProcess.Platform; + const executablePath = yield* HostProcess.ExecutablePath; // Captured here so the service's methods stay free of a requirements // channel: the layer is built where NodeServices is already in scope. const platformServices = yield* Effect.context< diff --git a/apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts b/apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts index 2c2fd425df56..d524bf0938fc 100644 --- a/apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts +++ b/apps/desktop/src/preview/BrowserImport/ChromiumCookies.ts @@ -315,7 +315,7 @@ export interface ChromiumCookieSource { readonly keychainAccount: string | undefined; readonly linuxSecretApplication: string | undefined; readonly windowsLocalStatePath?: string; - /** Supplied by the caller from `HostProcessPlatform` rather than read here. */ + /** Supplied by the caller from `HostProcess.Platform` rather than read here. */ readonly platform: NodeJS.Platform; } diff --git a/apps/desktop/src/preview/BrowserImport/ChromiumKeys.test.ts b/apps/desktop/src/preview/BrowserImport/ChromiumKeys.test.ts index 0466d6b4749c..cdeb67e0e8cc 100644 --- a/apps/desktop/src/preview/BrowserImport/ChromiumKeys.test.ts +++ b/apps/desktop/src/preview/BrowserImport/ChromiumKeys.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "@effect/vitest"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -232,7 +232,7 @@ describe("Linux Chromium secrets", () => { capture: (value) => (captured = value), }), ), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { PATH: "/synthetic/bin", SESSION_MARKER: "kept", LC_ALL: "localized", @@ -322,7 +322,7 @@ describe("Windows Chromium secrets", () => { Effect.provide( layerHelper({ stdout: key.toString("base64"), capture: (value) => (captured = value) }), ), - Effect.provideService(HostProcessEnvironment, { SystemRoot: "C:\\Windows" }), + Effect.provideService(HostProcess.Environment, { SystemRoot: "C:\\Windows" }), ); }); }); diff --git a/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts b/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts index 35e1e9c4b55e..ef7c8685b707 100644 --- a/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts +++ b/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts @@ -19,7 +19,7 @@ */ import * as NodeCrypto from "node:crypto"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Base64 from "effect/encoding/Base64"; @@ -138,7 +138,7 @@ export const readLinuxSecret = Effect.fn("ChromiumKeys.readLinuxSecret")(functio return yield* Effect.scoped( Effect.gen(function* () { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const helper = yield* LinuxBrowserSecretPath; if (helper === undefined) { return yield* new ChromiumKeyError({ reason: "keychainUnavailable" }); @@ -219,7 +219,7 @@ export const decodeWindowsWrappedKey = Effect.fn("ChromiumKeys.decodeWindowsWrap export const unwrapWindowsDpapiKey = Effect.fn("ChromiumKeys.unwrapWindowsDpapiKey")(function* ( wrapped: Buffer, ) { - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; return yield* Effect.scoped( Effect.gen(function* () { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; diff --git a/apps/desktop/src/preview/BrowserImport/SafariPermission.test.ts b/apps/desktop/src/preview/BrowserImport/SafariPermission.test.ts index cd41673a3f14..3b33f872d124 100644 --- a/apps/desktop/src/preview/BrowserImport/SafariPermission.test.ts +++ b/apps/desktop/src/preview/BrowserImport/SafariPermission.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as PlatformError from "effect/PlatformError"; @@ -30,8 +30,8 @@ it.effect("detects Safari access becoming available without reading or importing ), }); const check = yield* safariPermissionCheck.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService(FileSystem.FileSystem, guardedFs), ); assert.isFalse(yield* Effect.promise(check)); @@ -47,8 +47,8 @@ it.effect("recognizes access when cookies exist only in a named Safari profile", const fs = yield* FileSystem.FileSystem; const home = yield* fs.makeTempDirectoryScoped({ prefix: "t3-safari-named-access-" }); const check = yield* safariPermissionCheck.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), ); assert.isFalse(yield* Effect.promise(check)); const directory = `${home}/Library/Containers/com.apple.Safari/Data/Library/WebKit/WebsiteDataStore/12345678-1234-1234-1234-123456789abc/Cookies`; diff --git a/apps/desktop/src/preview/BrowserImport/Sources.test.ts b/apps/desktop/src/preview/BrowserImport/Sources.test.ts index 4a04e0498cb6..51bab02ce939 100644 --- a/apps/desktop/src/preview/BrowserImport/Sources.test.ts +++ b/apps/desktop/src/preview/BrowserImport/Sources.test.ts @@ -3,11 +3,7 @@ import * as NodePath from "node:path"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, describe, it } from "@effect/vitest"; -import { - HostProcessEnvironment, - HostProcessHostname, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; @@ -80,8 +76,8 @@ const withSourceHome = Effect.fnUntraced(function* () { const fileSystem = yield* FileSystem.FileSystem; const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-sources-" }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), ); yield* fileSystem.makeDirectory(userDataDirectory(context), { recursive: true }); return context; @@ -133,8 +129,8 @@ describe("Helium on Linux", () => { const fileSystem = yield* FileSystem.FileSystem; const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-helium-linux-" }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "linux"), ); const root = `${home}/.config/net.imput.helium`; yield* fileSystem.makeDirectory(`${root}/Default`, { recursive: true }); @@ -162,11 +158,11 @@ describe("Helium on Windows", () => { run( Effect.gen(function* () { const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { USERPROFILE: "C:\\Users\\browser-user", LOCALAPPDATA: "C:\\Users\\browser-user\\AppData\\Local", }), - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), ); assert.include(helium.platforms, "win32"); @@ -198,11 +194,11 @@ describe("isSourceRunning", () => { prefix: "t3code-helium-windows-lock-", }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { HOME: home, LOCALAPPDATA: home, }), - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), ); const profile = context.path.join(helium.userDataDirectory(context)!, "Default"); const database = context.path.join(profile, "Network", "Cookies"); @@ -259,12 +255,12 @@ describe("isSourceRunning", () => { assert.isTrue( yield* isSourceRunning(helium, paths).pipe( - Effect.provideService(HostProcessHostname, "another-host"), + Effect.provideService(HostProcess.Hostname, "another-host"), ), ); assert.isFalse( yield* isSourceRunning(helium, paths).pipe( - Effect.provideService(HostProcessHostname, "lock-owner"), + Effect.provideService(HostProcess.Hostname, "lock-owner"), ), ); }), @@ -656,8 +652,8 @@ describe("cookieDatabaseCandidatePaths", () => { Effect.gen(function* () { const path = yield* Path.Path; const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: "/tmp/test" }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: "/tmp/test" }), + Effect.provideService(HostProcess.Platform, "darwin"), ); const candidates = cookieDatabaseCandidatePaths(firefox, context, "Profiles/abc.default"); assert.deepEqual(candidates, [ @@ -684,8 +680,8 @@ describe("Firefox Snap profiles", () => { prefix: "t3code-firefox-snap-", }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "linux"), ); const root = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox"); const directory = context.path.join(root, "abcd.default"); @@ -724,8 +720,8 @@ describe("Firefox Snap profiles", () => { const fileSystem = yield* FileSystem.FileSystem; const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-snap-" }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "linux"), ); const native = context.path.join(home, ".mozilla", "firefox"); const snap = context.path.join(home, "snap", "firefox", "common", ".mozilla", "firefox"); @@ -775,11 +771,11 @@ describe("listSourceProfiles Firefox fallback", () => { }); const appData = path.join(home, "AppData", "Roaming"); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { HOME: home, APPDATA: appData, }), - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Platform, platform), ); const root = firefox.userDataDirectory(context)!; const scanRoot = platform === "linux" ? root : path.join(root, "Profiles"); @@ -812,8 +808,8 @@ describe("listSourceProfiles Firefox fallback", () => { prefix: "t3code-firefox-stale-ini-", }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), ); const root = firefox.userDataDirectory(context)!; // `profiles.ini` names a profile that was never launched (no cookie @@ -851,8 +847,8 @@ describe("listSourceProfiles Firefox fallback", () => { prefix: "t3code-firefox-counts-", }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), ); const root = firefox.userDataDirectory(context)!; const declaredDirectory = path.join(root, "Profiles", "declared.default"); @@ -902,8 +898,8 @@ describe("isSourceRunning for Firefox", () => { const fileSystem = yield* FileSystem.FileSystem; const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), ); const root = firefox.userDataDirectory(context)!; const profile = `${root}/Profiles/abcd.default-release`; @@ -952,7 +948,7 @@ describe("isSourceRunning for Firefox", () => { ); // Holds the lock with python3's fcntl, which does not exist on Windows. - it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "detects a live fcntl lock on .parentlock, as macOS Firefox leaves it", () => run( @@ -961,8 +957,8 @@ describe("isSourceRunning for Firefox", () => { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const home = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3code-firefox-" }); const context = yield* sourcePathContext.pipe( - Effect.provideService(HostProcessEnvironment, { HOME: home }), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Environment, { HOME: home }), + Effect.provideService(HostProcess.Platform, "darwin"), ); const root = firefox.userDataDirectory(context)!; const profile = `${root}/Profiles/abcd.default-release`; @@ -1033,11 +1029,11 @@ describe("isSourceRunning for Firefox", () => { const context = yield* sourcePathContext.pipe( // Firefox's win32 root hangs off %APPDATA%; without it the root is // undefined and the fixture would escape the sandbox into the repo. - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { HOME: home, APPDATA: `${home}/AppData/Roaming`, }), - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), ); const root = firefox.userDataDirectory(context)!; const profile = `${root}/Profiles/gx7x7fqx.default-release`; diff --git a/apps/desktop/src/preview/BrowserImport/Sources.ts b/apps/desktop/src/preview/BrowserImport/Sources.ts index fa8f79e1ccba..86baffbf1b2f 100644 --- a/apps/desktop/src/preview/BrowserImport/Sources.ts +++ b/apps/desktop/src/preview/BrowserImport/Sources.ts @@ -17,12 +17,7 @@ */ import type { BrowserImportSourceId, BrowserImportSourceProfile } from "@t3tools/contracts"; import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient"; -import { - HostProcessEnvironment, - HostProcessAddresses, - HostProcessHostname, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; @@ -335,8 +330,8 @@ export function parseFirefoxProfiles( */ export const sourcePathContext = Effect.gen(function* () { const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; - const environment = yield* HostProcessEnvironment; + const platform = yield* HostProcess.Platform; + const environment = yield* HostProcess.Environment; return { path, platform, @@ -782,7 +777,7 @@ export const posixLockIsHeld = Effect.fnUntraced(function* ( interpreters: ReadonlyArray = FCNTL_PROBE_INTERPRETERS, ) { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; for (const interpreter of interpreters) { const verdict = yield* Effect.scoped( Effect.gen(function* () { @@ -872,7 +867,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning") if (context.platform === "win32") { return yield* windowsChromiumCookiesAreHeld(definition, context); } - const currentHost = yield* HostProcessHostname; + const currentHost = yield* HostProcess.Hostname; const lock = context.path.join(root, "SingletonLock"); return yield* fileSystem.readLink(lock).pipe( Effect.flatMap((target) => chromiumSingletonLockIsHeld(target, currentHost, processIsAlive)), @@ -883,7 +878,7 @@ export const isSourceRunning = Effect.fn("BrowserImportSources.isSourceRunning") const profiles = yield* listSourceProfiles(definition, context); // Only the Linux `lock` symlink names an address, so Windows skips the lookup. const localAddresses: ReadonlySet = - context.platform === "win32" ? new Set() : yield* yield* HostProcessAddresses; + context.platform === "win32" ? new Set() : yield* yield* HostProcess.Addresses; const found = yield* Effect.forEach(profiles, (profile) => { const directory = context.path.isAbsolute(profile.directory) ? profile.directory diff --git a/apps/desktop/src/preview/Manager.test.ts b/apps/desktop/src/preview/Manager.test.ts index c13e2ce2868d..6d585a88641c 100644 --- a/apps/desktop/src/preview/Manager.test.ts +++ b/apps/desktop/src/preview/Manager.test.ts @@ -5,7 +5,7 @@ import type { DesktopPreviewRecordingFrame, DesktopPreviewRecordingInputEvent, } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { parseKeybindingShortcut } from "@t3tools/shared/keybindings"; import * as Cause from "effect/Cause"; import * as Deferred from "effect/Deferred"; @@ -313,7 +313,7 @@ const managerLayer = (platform: NodeJS.Platform = "darwin") => Layer.provideMerge(layerFileSystem), Layer.provideMerge(Path.layer), Layer.provideMerge(NodeCrypto.layer), - Layer.provideMerge(Layer.succeed(HostProcessPlatform, platform)), + Layer.provideMerge(Layer.succeed(HostProcess.Platform, platform)), ); const withManager = ( diff --git a/apps/desktop/src/preview/Manager.ts b/apps/desktop/src/preview/Manager.ts index 58a7413ede2c..aa36055452eb 100644 --- a/apps/desktop/src/preview/Manager.ts +++ b/apps/desktop/src/preview/Manager.ts @@ -25,7 +25,7 @@ import type { DesktopPreviewTabDefaults, PreviewForwardedShortcut, } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { matchesKeybindingShortcut } from "@t3tools/shared/keybindings"; import { normalizePreviewUrl } from "@t3tools/shared/preview"; import { @@ -544,7 +544,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function ) { const fileSystem = yield* FileSystem.FileSystem; const rendererHistory = yield* DesktopRendererHistory.DesktopRendererHistory; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const path = yield* Path.Path; const crypto = yield* Crypto.Crypto; const parentScope = yield* Scope.Scope; diff --git a/apps/desktop/src/snapShot/DesktopSnapShot.ts b/apps/desktop/src/snapShot/DesktopSnapShot.ts index 5718676f3b7a..71fe47d3f6ca 100644 --- a/apps/desktop/src/snapShot/DesktopSnapShot.ts +++ b/apps/desktop/src/snapShot/DesktopSnapShot.ts @@ -88,7 +88,7 @@ import { snapShotShortcutRegistrationFailureMessage, snapShotShortcutSystemConflict, } from "./snapShot.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const MAX_CAPTURE_WIDTH = 2_560; const MAX_CAPTURE_HEIGHT = 1_600; @@ -728,7 +728,7 @@ export const make = Effect.gen(function* () { const runPromise = Effect.runPromiseWith(context); const captureDirectory = path.join(environment.stateDir, "snap-shots"); const linuxAppId = environment.linuxDesktopEntryName.replace(/\.desktop$/, ""); - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; let shortcutVerified = false; const gnomeSetupPaths = { bundle: environment.isPackaged diff --git a/apps/desktop/src/snapShot/snapShot.test.ts b/apps/desktop/src/snapShot/snapShot.test.ts index 634c4653a5a6..ea52e877b93f 100644 --- a/apps/desktop/src/snapShot/snapShot.test.ts +++ b/apps/desktop/src/snapShot/snapShot.test.ts @@ -1,5 +1,5 @@ import { it as effectIt } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import { describe, expect, it, vi } from "vite-plus/test"; @@ -703,7 +703,7 @@ describe("isWaylandSession", () => { "falls back to a live runtime directory socket when session variables are stripped", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; yield* Effect.promise(async () => { const { mkdtemp, rm, writeFile } = await import("node:fs/promises"); const { createServer } = await import("node:net"); diff --git a/apps/server/scripts/record-codex-app-server-replay-fixture.ts b/apps/server/scripts/record-codex-app-server-replay-fixture.ts index 4343aec87ba1..0d18e917e031 100644 --- a/apps/server/scripts/record-codex-app-server-replay-fixture.ts +++ b/apps/server/scripts/record-codex-app-server-replay-fixture.ts @@ -5,7 +5,7 @@ import { revertCodexThread } from "../src/provider/CodexThreadRevert.ts"; import { buildCodexInitializeParams } from "../src/provider/CodexProvider.ts"; import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; import * as Console from "effect/Console"; import * as Deferred from "effect/Deferred"; @@ -1211,7 +1211,8 @@ function layerCodex({ recorder }: { readonly recorder: Recorder }) { Effect.gen(function* () { // The vp node shim marks its children with VP_TOOL_RECURSION, which makes every // `node` the agent runs through a shell fail. Codex must not inherit it. - const { VP_TOOL_RECURSION: _vpToolRecursion, ...environment } = yield* HostProcessEnvironment; + const { VP_TOOL_RECURSION: _vpToolRecursion, ...environment } = + yield* HostProcess.Environment; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const commandName = environment.T3_CODEX_BIN ?? environment.CODEX_BIN ?? "codex"; const spawnCommand = yield* resolveSpawnCommand(commandName, ["app-server"], { diff --git a/apps/server/scripts/record-grok-acp-replay-fixture.ts b/apps/server/scripts/record-grok-acp-replay-fixture.ts index f04b04cfe348..6415a145690d 100644 --- a/apps/server/scripts/record-grok-acp-replay-fixture.ts +++ b/apps/server/scripts/record-grok-acp-replay-fixture.ts @@ -12,7 +12,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { type ProviderReplayEntry } from "@t3tools/contracts"; import { GrokSettings } from "@t3tools/provider-grok/settings"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime"; import * as Clock from "effect/Clock"; import * as Console from "effect/Console"; @@ -442,12 +442,12 @@ const recordScenario = Effect.fn("recordGrokScenario")(function* (fixtureName: s const settings = { ...DEFAULT_GROK_SETTINGS, binaryPath: process.env.T3_GROK_BIN ?? "grok" }; const layerRegistry = ProviderAdapterRegistry.layerFromAdaptersEffect( Effect.gen(function* () { - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const adapter = yield* makeGrokAdapterV2({ instanceId: GROK_DEFAULT_INSTANCE_ID, settings, environment, - hostPlatform: yield* HostProcessPlatform, + hostPlatform: yield* HostProcess.Platform, selfInvocation: yield* resolveSelfInvocation(), continuationRequests: yield* ProviderContinuationRequests.ProviderContinuationRequests, // Production's runtime factory, with the protocol logger teeing raw lines. diff --git a/apps/server/scripts/t3-sqlite-state.test.ts b/apps/server/scripts/t3-sqlite-state.test.ts index 45bc78b30e0d..4946d1985639 100644 --- a/apps/server/scripts/t3-sqlite-state.test.ts +++ b/apps/server/scripts/t3-sqlite-state.test.ts @@ -7,7 +7,7 @@ import * as SqlClient from "effect/sql/SqlClient"; import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient"; import { runSqliteState } from "./t3-sqlite-state.ts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; const createFixtureDatabase = Effect.fn("createSqliteStateFixtureDatabase")(function* ( @@ -90,7 +90,7 @@ it.layer(NodeServices.layer)("t3-sqlite-state", (it) => { sql: "INSERT INTO fixtures (id, label) VALUES (2, 'seeded')", }); assert.equal(mutation.operation, "exec"); - if (mutation.operation === "exec" && (yield* HostProcessPlatform) !== "win32") { + if (mutation.operation === "exec" && (yield* HostProcess.Platform) !== "win32") { // NTFS has no POSIX mode bits to report. assert.equal((yield* fs.stat(mutation.backup)).mode & 0o777, 0o600); } diff --git a/apps/server/src/assets/AssetAccess.test.ts b/apps/server/src/assets/AssetAccess.test.ts index 6b6d4b2b95da..8a92b40aaea2 100644 --- a/apps/server/src/assets/AssetAccess.test.ts +++ b/apps/server/src/assets/AssetAccess.test.ts @@ -36,7 +36,7 @@ import { openMediaFile } from "./MediaFile.ts"; import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; import * as GitHubCredentials from "@t3tools/source-control-github/server/GitHubCredentials"; import { githubMediaResponse } from "./GitHubMediaFetch.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; vi.mock("node:fs/promises", async (importOriginal) => { const actual = await importOriginal(); @@ -326,7 +326,7 @@ describe("AssetAccess", () => { expect(yield* Effect.promise(() => response.text())).toBe("recording bytes"); } } - }).pipe(Effect.provideService(HostProcessHomeDirectory, home)); + }).pipe(Effect.provideService(HostProcess.HomeDirectory, home)); }).pipe(Effect.provide(layerTest)), ); diff --git a/apps/server/src/assets/AssetAccess.ts b/apps/server/src/assets/AssetAccess.ts index d2de3e555736..43d7d75f7864 100644 --- a/apps/server/src/assets/AssetAccess.ts +++ b/apps/server/src/assets/AssetAccess.ts @@ -58,7 +58,7 @@ import * as ProjectFaviconResolver from "../project/ProjectFaviconResolver.ts"; import * as WorkspacePaths from "../workspace/WorkspacePaths.ts"; import * as NativeAppIconResolver from "./NativeAppIconResolver.ts"; import { openMediaFile, readMediaFileHeader, type OpenMediaFile } from "./MediaFile.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; export const ASSET_ROUTE_PREFIX = "/api/assets"; @@ -470,7 +470,7 @@ export const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (i switch (input.resource._tag) { case "media-file": { - let requestedPath = expandHomePath(input.resource.path, yield* HostProcessHomeDirectory); + let requestedPath = expandHomePath(input.resource.path, yield* HostProcess.HomeDirectory); if (!path.isAbsolute(requestedPath)) { if (!input.workspaceRoot) { return yield* new AssetWorkspaceContextNotFoundError({ resource: input.resource }); diff --git a/apps/server/src/assets/NativeAppIconResolver.test.ts b/apps/server/src/assets/NativeAppIconResolver.test.ts index 753f7378285d..6c69eebceafc 100644 --- a/apps/server/src/assets/NativeAppIconResolver.test.ts +++ b/apps/server/src/assets/NativeAppIconResolver.test.ts @@ -5,7 +5,7 @@ import * as Layer from "effect/Layer"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import { ChildProcessSpawner } from "effect/process"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as ServerConfig from "../config.ts"; import * as NativeAppIconResolver from "./NativeAppIconResolver.ts"; @@ -44,7 +44,7 @@ describe("resolveNativeAppIcon", () => { }); const layerDependencies = Layer.mergeAll( layerConfig, - Layer.succeed(HostProcessPlatform, "darwin"), + Layer.succeed(HostProcess.Platform, "darwin"), Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner), ).pipe(Layer.provideMerge(NodeServices.layer)); const layerTest = NativeAppIconResolver.layer.pipe(Layer.provide(layerDependencies)); diff --git a/apps/server/src/assets/NativeAppIconResolver.ts b/apps/server/src/assets/NativeAppIconResolver.ts index df5c8a03f670..e25610e5223a 100644 --- a/apps/server/src/assets/NativeAppIconResolver.ts +++ b/apps/server/src/assets/NativeAppIconResolver.ts @@ -15,7 +15,7 @@ import * as PlatformError from "effect/PlatformError"; import * as Semaphore from "effect/Semaphore"; import * as Hex from "effect/encoding/Hex"; import { ChildProcess, ChildProcessSpawner } from "effect/process"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as ServerConfig from "../config.ts"; @@ -214,7 +214,7 @@ const resolveNativeAppIconUncached = Effect.fn("NativeAppIconResolver.resolveUnc /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const resolutionSemaphore = yield* Semaphore.make(2); const resolutionCache: Cache.Cache< string, diff --git a/apps/server/src/bootstrap.test.ts b/apps/server/src/bootstrap.test.ts index d532f71c9fb8..0b14c7dd1e23 100644 --- a/apps/server/src/bootstrap.test.ts +++ b/apps/server/src/bootstrap.test.ts @@ -11,7 +11,7 @@ import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as TestClock from "effect/testing/TestClock"; import { vi } from "vite-plus/test"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { BootstrapEnvelopeDecodeError, @@ -55,7 +55,7 @@ vi.mock("node:fs", async (importOriginal) => { }; }); -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; const nullDevice = windowsHost ? "\\\\.\\NUL" : "/dev/null"; const closeIfOpen = (fd: number) => { try { @@ -116,7 +116,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { try { const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { timeoutMs: 100, - }).pipe(Effect.provideService(HostProcessPlatform, "linux")); + }).pipe(Effect.provideService(HostProcess.Platform, "linux")); assertSome(payload, { mode: "desktop", }); @@ -141,7 +141,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { try { const error = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { timeoutMs: 100, - }).pipe(Effect.provideService(HostProcessPlatform, "linux"), Effect.flip); + }).pipe(Effect.provideService(HostProcess.Platform, "linux"), Effect.flip); assert.instanceOf(error, BootstrapInputStreamOpenError); assert.equal(error.fd, fd); diff --git a/apps/server/src/bootstrap.ts b/apps/server/src/bootstrap.ts index 71dae0dc3096..708a8fd9119b 100644 --- a/apps/server/src/bootstrap.ts +++ b/apps/server/src/bootstrap.ts @@ -10,7 +10,7 @@ import * as Predicate from "effect/Predicate"; import * as Result from "effect/Result"; import * as Schema from "effect/Schema"; import { decodeJsonResult } from "@t3tools/shared/schemaJson"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; export class BootstrapFdStatError extends Schema.TaggedError()( "BootstrapFdStatError", @@ -168,7 +168,7 @@ const isFdReady = (fd: number) => const makeBootstrapInputStream = (fd: number) => Effect.gen(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const fdPath = resolveFdPath(fd, platform); return yield* Effect.try({ try: () => { diff --git a/apps/server/src/checkpointing/CheckpointStore.test.ts b/apps/server/src/checkpointing/CheckpointStore.test.ts index c1ad293d40ab..2846b86e1b88 100644 --- a/apps/server/src/checkpointing/CheckpointStore.test.ts +++ b/apps/server/src/checkpointing/CheckpointStore.test.ts @@ -4,7 +4,7 @@ import * as NodePath from "node:path"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { it } from "@effect/vitest"; import { ThreadId, type VcsError } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; @@ -329,7 +329,7 @@ it.layer(layerTest)("CheckpointStore.layer", (it) => { const copiedText = Array.from({ length: 20 }, (_, index) => `copy line ${index}\n`).join( "", ); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const renamedPath = platform === "win32" ? "renamed café.txt" : "renamed\tcafé\nname.txt"; const addedPath = platform === "win32" ? "new café.txt" : "new\tfile\n名.txt"; for (const [path, contents] of Object.entries({ diff --git a/apps/server/src/cli/app.test.ts b/apps/server/src/cli/app.test.ts index 0c35ab9f6941..e785baa58f1c 100644 --- a/apps/server/src/cli/app.test.ts +++ b/apps/server/src/cli/app.test.ts @@ -8,12 +8,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { it } from "@effect/vitest"; import type { DesktopAppActivationRequest } from "@t3tools/contracts"; import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl"; -import { - HostProcessHomeDirectory, - HostProcessPlatform, - HostProcessUserId, - HostProcessWorkingDirectory, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as NetService from "@t3tools/shared/Net"; import * as ConfigProvider from "effect/ConfigProvider"; import * as Effect from "effect/Effect"; @@ -110,8 +105,8 @@ async function startFakeDesktop(input: { const fakeDesktop = Effect.fn(function* ( input: Omit[0], "platform" | "userId">, ) { - const platform = yield* HostProcessPlatform; - const userId = yield* HostProcessUserId; + const platform = yield* HostProcess.Platform; + const userId = yield* HostProcess.UserId; return yield* Effect.acquireRelease( Effect.promise(() => startFakeDesktop({ ...input, platform, userId })), (server) => Effect.promise(() => server.close()), @@ -142,7 +137,7 @@ describe("t3 server command safety", () => { "C:new-project", ]) { const error = yield* runCli([word, "--base-dir", baseDir]).pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.flip, ); expect(String(error)).toContain(`Unknown command "${word}"`); @@ -181,7 +176,7 @@ describe("t3 server command safety", () => { yield* Effect.promise(() => NodeFSP.mkdir(stateDir, { recursive: true })); yield* Effect.promise(() => NodeFSP.writeFile(statePath, record)); const newDirectory = NodePath.join(root, "new-project"); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; for (const args of [ [], ["start"], @@ -193,7 +188,7 @@ describe("t3 server command safety", () => { ]) { const error = yield* runCli(args, { T3CODE_HOME: baseDir }).pipe( Effect.provideService( - HostProcessPlatform, + HostProcess.Platform, args[0] === "C:new-project" ? "win32" : platform, ), Effect.flip, @@ -234,7 +229,7 @@ describe("t3 app", () => { Effect.gen(function* () { const baseDir = NodePath.join(root, "missing-t3-home"); const error = yield* runCli(["app", "--base-dir", baseDir]).pipe( - Effect.provideService(HostProcessPlatform, "freebsd"), + Effect.provideService(HostProcess.Platform, "freebsd"), Effect.flip, ); @@ -257,7 +252,7 @@ describe("t3 app", () => { expect(error).toMatchObject({ _tag: "DesktopAppUnreachableError", candidateAddresses: [expect.any(String)], - workspaceRoot: yield* HostProcessWorkingDirectory, + workspaceRoot: yield* HostProcess.WorkingDirectory, message: expect.stringContaining("Could not reach the T3 Code desktop app."), cause: { code: "ENOENT" }, }); @@ -271,8 +266,8 @@ describe("t3 app", () => { Effect.gen(function* () { const baseDir = NodePath.join(root, "t3-home"); const explicitPath = NodePath.join(root, "project"); - const platform = yield* HostProcessPlatform; - const workingDirectory = yield* HostProcessWorkingDirectory; + const platform = yield* HostProcess.Platform; + const workingDirectory = yield* HostProcess.WorkingDirectory; const desktop = yield* fakeDesktop({ baseDir }); yield* runCli(["app"], { T3CODE_HOME: baseDir }); @@ -298,7 +293,7 @@ describe("t3 app", () => { expect(desktop.received).toHaveLength(1); expect(development.received).toHaveLength(0); - }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped), + }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped), ), ); @@ -313,7 +308,7 @@ describe("t3 app", () => { expect(development.received).toHaveLength(2); expect(yield* pathExists(baseDir)).toBe(false); - }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped), + }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped), ), ); @@ -329,7 +324,7 @@ describe("t3 app", () => { expect(flagError).toMatchObject({ _tag: "DesktopAppUnreachableError" }); expect(envError).toMatchObject({ _tag: "DesktopAppUnreachableError" }); expect(development.received).toHaveLength(0); - }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped), + }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped), ), ); @@ -363,7 +358,7 @@ describe("t3 app", () => { _tag: "DesktopAppRequestFailedError", code: "project-create-failed", requestId: desktop.received[0]?.requestId, - workspaceRoot: yield* HostProcessWorkingDirectory, + workspaceRoot: yield* HostProcess.WorkingDirectory, message: expect.stringContaining("project-create-failed"), cause: { ok: false, @@ -377,7 +372,7 @@ describe("t3 app", () => { cause: { message: "The desktop app response is invalid." }, }); } - }).pipe(Effect.provideService(HostProcessHomeDirectory, root), Effect.scoped), + }).pipe(Effect.provideService(HostProcess.HomeDirectory, root), Effect.scoped), ), ); }); diff --git a/apps/server/src/cli/app.ts b/apps/server/src/cli/app.ts index d9ad57f5127d..eade5887c6c1 100644 --- a/apps/server/src/cli/app.ts +++ b/apps/server/src/cli/app.ts @@ -10,11 +10,7 @@ import { type DesktopAppActivationRequest, } from "@t3tools/contracts"; import { resolveDesktopAppControlAddress } from "@t3tools/shared/desktopAppControl"; -import { - HostProcessPlatform, - HostProcessUserId, - HostProcessWorkingDirectory, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Config from "effect/Config"; import * as Console from "effect/Console"; import * as Crypto from "effect/Crypto"; @@ -188,7 +184,7 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: { readonly workspaceRoot: Option.Option; }) { const environment = yield* appEnvironment; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; if (Option.isSome(environment.sshConnection) || Option.isSome(environment.sshTty)) { return yield* new DesktopAppSshUnsupportedError({}); } @@ -201,9 +197,9 @@ const runAppCommand = Effect.fn("cli.app")(function* (flags: { const baseDir = yield* resolveBaseDir(configuredBaseDir); const allowDevFallback = Option.isNone(flags.baseDir) && !environment.t3Home?.trim(); const rawWorkspaceRoot = - Option.getOrUndefined(flags.workspaceRoot) ?? (yield* HostProcessWorkingDirectory); + Option.getOrUndefined(flags.workspaceRoot) ?? (yield* HostProcess.WorkingDirectory); const workspaceRoot = path.resolve(yield* expandHomePath(rawWorkspaceRoot)); - const userId = yield* HostProcessUserId; + const userId = yield* HostProcess.UserId; const resolveAddress = (stateSubdirectory: "userdata" | "dev") => resolveDesktopAppControlAddress({ stateDir: path.join(baseDir, stateSubdirectory), diff --git a/apps/server/src/cli/browser.ts b/apps/server/src/cli/browser.ts index 12f74ba60d2d..9bff41cb4fed 100644 --- a/apps/server/src/cli/browser.ts +++ b/apps/server/src/cli/browser.ts @@ -10,11 +10,7 @@ * Both need root. Without it, the command prints what it would change and the * `sudo` line to run. It is safe to run again; it skips what is already done. */ -import { - HostProcessEnvironment, - HostProcessPlatform, - HostProcessUserId, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Console from "effect/Console"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -61,7 +57,7 @@ const runStep = Effect.fn("browserSetup.runStep")(function* ( * unspecified home falls back to the invoking user's `~/.t3`. */ const setupBaseDir = Effect.fn("browserSetup.baseDir")(function* (explicit: Option.Option) { - const env = yield* HostProcessEnvironment; + const env = yield* HostProcess.Environment; const raw = Option.getOrUndefined(explicit) ?? env.T3CODE_HOME; if (raw !== undefined || env.SUDO_USER === undefined) return yield* resolveBaseDir(raw); const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; @@ -109,11 +105,11 @@ const browserSetupCommand = Command.make("setup", { baseDir: baseDirFlag }).pipe ), Command.withHandler(({ baseDir }) => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") { + if ((yield* HostProcess.Platform) !== "linux") { return yield* Console.log("Nothing to set up: T3's browser runs as is on this system."); } const fs = yield* FileSystem.FileSystem; - const isRoot = (yield* HostProcessUserId) === 0; + const isRoot = (yield* HostProcess.UserId) === 0; const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND); const needsProfile = yield* PreviewBrowserHost.sandboxBlocked; diff --git a/apps/server/src/cli/connect.ts b/apps/server/src/cli/connect.ts index 83d384097ecc..866cc5ec8927 100644 --- a/apps/server/src/cli/connect.ts +++ b/apps/server/src/cli/connect.ts @@ -5,7 +5,7 @@ import { type RelayClientInstallProgressStage, } from "@t3tools/contracts"; import { RelayOkResponse } from "@t3tools/contracts/relay"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as RelayClient from "@t3tools/shared/relayClient"; import { withRelayClientTracing } from "@t3tools/shared/relayTracing"; import * as Cause from "effect/Cause"; @@ -686,7 +686,7 @@ export const connectCommand = Command.make("connect", { // show how to run the server manually. const background = yield* recoverServiceOnboardingOffer(offerServiceDuringOnboarding); if (background) { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; yield* Console.log( platform === "darwin" ? "\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." diff --git a/apps/server/src/cli/invocation.test.ts b/apps/server/src/cli/invocation.test.ts index bf2dcba2b9f4..5cd89a1457b2 100644 --- a/apps/server/src/cli/invocation.test.ts +++ b/apps/server/src/cli/invocation.test.ts @@ -1,12 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, expect, it } from "@effect/vitest"; -import { - HostProcessArguments, - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; @@ -113,11 +107,11 @@ it.layer(NodeServices.layer)("root CLI commands", (it) => { readonly executable?: boolean; }) => resolveRootCliCommand("browser setup").pipe( - Effect.provideService(HostProcessExecutablePath, input.node), - Effect.provideService(HostProcessArguments, [input.node, input.entry]), - Effect.provideService(HostProcessIsExecutable, input.executable ?? false), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessEnvironment, { PATH: input.path ?? "", ...input.env }), + Effect.provideService(HostProcess.ExecutablePath, input.node), + Effect.provideService(HostProcess.Arguments, [input.node, input.entry]), + Effect.provideService(HostProcess.IsExecutable, input.executable ?? false), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Environment, { PATH: input.path ?? "", ...input.env }), ); /** 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) => { yield* fs.makeDirectory(path.dirname(entry), { recursive: true }); yield* fs.writeFileString(entry, ""); const installation = yield* resolveServerInstallation.pipe( - Effect.provideService(HostProcessArguments, ["node", entry]), - Effect.provideService(HostProcessExecutablePath, entry), - Effect.provideService(HostProcessIsExecutable, entry.endsWith("/t3")), + Effect.provideService(HostProcess.Arguments, ["node", entry]), + Effect.provideService(HostProcess.ExecutablePath, entry), + Effect.provideService(HostProcess.IsExecutable, entry.endsWith("/t3")), ); expect(installation).toEqual({ kind }); } @@ -227,9 +221,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => { '{"name":"t3","version":"0.0.45","bin":{"t3":"./dist/bin.mjs"}}', ); const resolve = resolveServerInstallation.pipe( - Effect.provideService(HostProcessArguments, ["node", entry]), - Effect.provideService(HostProcessIsExecutable, false), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Arguments, ["node", entry]), + Effect.provideService(HostProcess.IsExecutable, false), + Effect.provideService(HostProcess.Platform, "linux"), ); expect(yield* resolve).toBeNull(); yield* fs.symlink(entry, globalBin); @@ -237,7 +231,7 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => { yield* fs.remove(globalBin); yield* fs.writeFileString(globalBin, "an unrelated t3 command"); expect(yield* resolve).toBeNull(); - expect(yield* resolve.pipe(Effect.provideService(HostProcessPlatform, "win32"))).toBeNull(); + expect(yield* resolve.pipe(Effect.provideService(HostProcess.Platform, "win32"))).toBeNull(); }), ); @@ -261,9 +255,9 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => { ); yield* fs.symlink(launcher, path.join(prefix, "bin/t3")); const resolve = resolveServerInstallation.pipe( - Effect.provideService(HostProcessExecutablePath, entry), - Effect.provideService(HostProcessIsExecutable, true), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.ExecutablePath, entry), + Effect.provideService(HostProcess.IsExecutable, true), + Effect.provideService(HostProcess.Platform, "linux"), ); for (const [version, expected] of [ ["0.0.44", null], @@ -296,8 +290,8 @@ it.layer(NodeServices.layer)("manual server installation ownership", (it) => { } expect( yield* resolveServerInstallation.pipe( - Effect.provideService(HostProcessArguments, ["node", entry]), - Effect.provideService(HostProcessIsExecutable, false), + Effect.provideService(HostProcess.Arguments, ["node", entry]), + Effect.provideService(HostProcess.IsExecutable, false), ), ).toBeNull(); } diff --git a/apps/server/src/cli/invocation.ts b/apps/server/src/cli/invocation.ts index 59843abd7289..ff5cb9d8f9c8 100644 --- a/apps/server/src/cli/invocation.ts +++ b/apps/server/src/cli/invocation.ts @@ -5,13 +5,7 @@ import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import type { ServerInstallation } from "@t3tools/contracts"; -import { - HostProcessArguments, - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { isCommandAvailable } from "@t3tools/shared/shell"; import packageJson from "../../package.json" with { type: "json" }; @@ -60,10 +54,10 @@ const decodeInstallManifest = Schema.decodeUnknownEffect(Schema.fromJsonString(I export const resolveServerInstallation = Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const args = yield* HostProcessArguments; - const executable = yield* HostProcessIsExecutable; - const executablePath = yield* HostProcessExecutablePath; - const platform = yield* HostProcessPlatform; + const args = yield* HostProcess.Arguments; + const executable = yield* HostProcess.IsExecutable; + const executablePath = yield* HostProcess.ExecutablePath; + const platform = yield* HostProcess.Platform; const entry = yield* fs.realPath(executable ? executablePath : (args[1] ?? "")); const match = /^(.*)\/lib\/node_modules\/t3\/(?:dist\/bin\.mjs|bin\/t3\.js|node_modules\/@t3code\/t3-[^/]+\/t3)$/.exec( @@ -141,7 +135,7 @@ export function formatCliCommand(input: { /** `formatCliCommand` against this process's real entry path and version. */ export const resolveCliCommand = (subcommand: string) => - Effect.map(HostProcessArguments, (processArguments) => + Effect.map(HostProcess.Arguments, (processArguments) => formatCliCommand({ subcommand, entryPath: processArguments[1] ?? "", @@ -161,12 +155,12 @@ const shellWord = (value: string) => */ const resolveInstallLauncher = Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; - const shim = (yield* HostProcessEnvironment).T3CODE_CLI_PATH?.trim(); + const shim = (yield* HostProcess.Environment).T3CODE_CLI_PATH?.trim(); if (shim && (yield* fs.exists(shim).pipe(Effect.orElseSucceed(() => false)))) { return Option.some(shim); } - return (yield* HostProcessIsExecutable) - ? Option.some(yield* HostProcessExecutablePath) + return (yield* HostProcess.IsExecutable) + ? Option.some(yield* HostProcess.ExecutablePath) : Option.none(); }); @@ -197,7 +191,7 @@ export const resolveRootCliCommand = (subcommand: string) => Effect.gen(function* () { const { command, launcher } = yield* resolveHostCliCommand(subcommand); if (launcher) return `sudo ${command}`; - const executablePath = yield* HostProcessExecutablePath; + const executablePath = yield* HostProcess.ExecutablePath; const systemNode = ROOT_PATH_DIRECTORIES.some((directory) => executablePath.startsWith(`${directory}/`), ); diff --git a/apps/server/src/cli/pair.test.ts b/apps/server/src/cli/pair.test.ts index fa7c6b7588fd..56a84bba7177 100644 --- a/apps/server/src/cli/pair.test.ts +++ b/apps/server/src/cli/pair.test.ts @@ -7,7 +7,7 @@ import * as NodePath from "node:path"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { AuthStandardClientScopes } from "@t3tools/contracts"; import * as NetService from "@t3tools/shared/Net"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { assert, describe, expect, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -184,7 +184,7 @@ describe("t3 pair", () => { }), ).pipe( Effect.provide(NodeServices.layer), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { ...process.env, [SERVICE_LAUNCHER_CONTEXT_ENV]: JSON.stringify({ protocol: SERVICE_LAUNCHER_PROTOCOL, diff --git a/apps/server/src/cli/server.ts b/apps/server/src/cli/server.ts index 3062a840e59e..8c8dd9237cb9 100644 --- a/apps/server/src/cli/server.ts +++ b/apps/server/src/cli/server.ts @@ -1,4 +1,4 @@ -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Option from "effect/Option"; @@ -32,7 +32,7 @@ export const runDefaultServerCommand = (flags: CliServerFlags) => if (Option.isSome(flags.cwd)) { const cwd = flags.cwd.value.trim(); const fs = yield* FileSystem.FileSystem; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const explicitPath = cwd === "." || cwd === ".." || diff --git a/apps/server/src/cli/service.test.ts b/apps/server/src/cli/service.test.ts index f58fe4a17815..077274fc2159 100644 --- a/apps/server/src/cli/service.test.ts +++ b/apps/server/src/cli/service.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, expect, it } from "@effect/vitest"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as NetService from "@t3tools/shared/Net"; import * as ConfigProvider from "effect/ConfigProvider"; import * as Effect from "effect/Effect"; @@ -136,7 +136,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands "--base-dir", baseDir, ]).pipe( - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Environment, {}), Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))), ); @@ -161,7 +161,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands "--base-dir", baseDir, ]).pipe( - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Environment, {}), Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))), Effect.flip, ); @@ -190,7 +190,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, NetService.layer))("service commands baseDir, "--allow-downgrade", ]).pipe( - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Environment, {}), Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))), ); diff --git a/apps/server/src/cli/service.ts b/apps/server/src/cli/service.ts index 6b799f58e23e..7a5dd7337478 100644 --- a/apps/server/src/cli/service.ts +++ b/apps/server/src/cli/service.ts @@ -1,4 +1,4 @@ -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Console from "effect/Console"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -241,7 +241,7 @@ export const offerServiceDuringOnboarding = Effect.gen(function* () { } // A LaunchAgent starts at login and dies at logout; there is no // enable-linger equivalent on macOS. Do not promise more than that. - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const wanted = yield* Prompt.run( Prompt.Confirm({ message: installed diff --git a/apps/server/src/cli/theme.test.ts b/apps/server/src/cli/theme.test.ts index edf309ccc33b..5dd350043dbe 100644 --- a/apps/server/src/cli/theme.test.ts +++ b/apps/server/src/cli/theme.test.ts @@ -14,11 +14,11 @@ import { Command } from "effect/cli"; import { cli } from "../binCli.ts"; import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; // These force a failure with chmod, which Windows ignores for directories and // cannot use to make a file unreadable, so the failure never happens there. -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; const runCli = (args: ReadonlyArray) => Command.runWith(cli, { version: "0.0.0" })(args).pipe( diff --git a/apps/server/src/cli/triage.ts b/apps/server/src/cli/triage.ts index a7bd06fab678..7bce1c0251ca 100644 --- a/apps/server/src/cli/triage.ts +++ b/apps/server/src/cli/triage.ts @@ -14,7 +14,7 @@ import * as NodeChildProcess from "node:child_process"; import * as NodeOS from "node:os"; import * as NodeReadlinePromises from "node:readline/promises"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell"; import * as Config from "effect/Config"; import * as Console from "effect/Console"; @@ -193,7 +193,7 @@ export const triageCommand = Command.make("triage", { releaseTag: /^[^-+]+-(?:nightly|preview)\./.test(version) ? `v${version} (prerelease build; if this tag does not exist, clone main)` : `v${version}`, - os: `${yield* HostProcessPlatform} ${yield* HostProcessArchitecture} (${NodeOS.release()})`, + os: `${yield* HostProcess.Platform} ${yield* HostProcess.Architecture} (${NodeOS.release()})`, nodeVersion: process.version, launchedAs: yield* resolveCliCommand("triage"), server: yield* describeServerProcess(paths.serverRuntimeStatePath), diff --git a/apps/server/src/cli/uninstall.test.ts b/apps/server/src/cli/uninstall.test.ts index 02860f529440..1e81e8b8c7a9 100644 --- a/apps/server/src/cli/uninstall.test.ts +++ b/apps/server/src/cli/uninstall.test.ts @@ -3,7 +3,7 @@ import { assert, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { findOwnedLauncher } from "./uninstall.ts"; @@ -32,6 +32,6 @@ it.layer(NodeServices.layer)("t3 uninstall launcher", (it) => { assert.isUndefined(yield* findOwnedLauncher({ launchedAs: theirs, versionsDir })); assert.isUndefined(yield* findOwnedLauncher({ launchedAs: copy, versionsDir })); assert.isUndefined(yield* findOwnedLauncher({ launchedAs: undefined, versionsDir })); - }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")), + }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")), ); }); diff --git a/apps/server/src/cli/uninstall.ts b/apps/server/src/cli/uninstall.ts index 4b977bc24951..deec288ef6e8 100644 --- a/apps/server/src/cli/uninstall.ts +++ b/apps/server/src/cli/uninstall.ts @@ -4,11 +4,7 @@ // cannot express: it kills the child when the scope closes. import * as NodeChildProcess from "node:child_process"; -import { - HostProcessEnvironment, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Console from "effect/Console"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -58,7 +54,7 @@ export const findOwnedLauncher = Effect.fn("cli.uninstall.find_launcher")(functi }) { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (input.launchedAs === undefined) return undefined; if (platform === "win32") { const shimPath = yield* findWindowsShim(input.launchedAs); @@ -87,7 +83,7 @@ const planUninstall = Effect.fn("cli.uninstall.plan")(function* (input: { path.resolve(status.installedBaseDir) === path.resolve(input.baseDir); const versionsDir = pinnedRuntimeVersionsDir(path, input.baseDir); const runtimeDir = path.dirname(versionsDir); - const launchedAs = (yield* HostProcessIsExecutable) ? yield* resolveLauncherPath : undefined; + const launchedAs = (yield* HostProcess.IsExecutable) ? yield* resolveLauncherPath : undefined; const plan: UninstallPlan = { service: status.supported && status.installed && servesThisHome, launcher: yield* findOwnedLauncher({ launchedAs, versionsDir }), @@ -128,14 +124,14 @@ const runUninstall = Effect.fn("cli.uninstall.run")(function* (input: { readonly assumeYes: boolean; }) { const fs = yield* FileSystem.FileSystem; - const platform = yield* HostProcessPlatform; - const environment = yield* HostProcessEnvironment; + const platform = yield* HostProcess.Platform; + const environment = yield* HostProcess.Environment; const service = yield* BootService.BootService; const plan = yield* planUninstall({ baseDir: input.baseDir }); if (!plan.service && plan.launcher === undefined && plan.runtimeDir === undefined) { yield* Console.log(`Nothing to remove: t3 is not installed for ${input.baseDir}.`); - if (!(yield* HostProcessIsExecutable)) { + if (!(yield* HostProcess.IsExecutable)) { yield* Console.log( " 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).", ); diff --git a/apps/server/src/cli/update.test.ts b/apps/server/src/cli/update.test.ts index 1a9c66428da9..8664e4ba5b45 100644 --- a/apps/server/src/cli/update.test.ts +++ b/apps/server/src/cli/update.test.ts @@ -4,12 +4,7 @@ import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Option from "effect/Option"; import * as Path from "effect/Path"; -import { - HostProcessEnvironment, - HostProcessInvokedAs, - HostProcessPlatform, - HostProcessWorkingDirectory, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { repointLauncher, resolveLauncherPath } from "./update.ts"; @@ -37,7 +32,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => { assert.deepStrictEqual(Option.getOrUndefined(repointed), launcher); assert.equal(yield* fs.readLink(launcher), newExe); - }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")), + }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")), ); it.effect("leaves a plain copy or a foreign symlink alone", () => @@ -71,7 +66,7 @@ it.layer(NodeServices.layer)("t3 update launcher", (it) => { } assert.equal(yield* fs.readLink(foreign), elsewhere); assert.equal(yield* fs.readLink(otherLauncher), otherHome); - }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")), + }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")), ); 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) => { yield* fs.writeFileString(launcher, ""); const bare = yield* resolveLauncherPath.pipe( - Effect.provideService(HostProcessInvokedAs, "t3"), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.InvokedAs, "t3"), + Effect.provideService(HostProcess.Environment, { PATH: `${path.join(root, "missing")}:${path.join(root, "bin")}`, }), - Effect.provideService(HostProcessWorkingDirectory, root), + Effect.provideService(HostProcess.WorkingDirectory, root), ); const relative = yield* resolveLauncherPath.pipe( - Effect.provideService(HostProcessInvokedAs, "./bin/t3"), - Effect.provideService(HostProcessEnvironment, { PATH: "" }), - Effect.provideService(HostProcessWorkingDirectory, root), + Effect.provideService(HostProcess.InvokedAs, "./bin/t3"), + Effect.provideService(HostProcess.Environment, { PATH: "" }), + Effect.provideService(HostProcess.WorkingDirectory, root), ); const absent = yield* resolveLauncherPath.pipe( - Effect.provideService(HostProcessInvokedAs, "t3"), - Effect.provideService(HostProcessEnvironment, { PATH: path.join(root, "missing") }), - Effect.provideService(HostProcessWorkingDirectory, root), + Effect.provideService(HostProcess.InvokedAs, "t3"), + Effect.provideService(HostProcess.Environment, { PATH: path.join(root, "missing") }), + Effect.provideService(HostProcess.WorkingDirectory, root), ); assert.equal(bare, launcher); assert.equal(relative, launcher); assert.equal(absent, undefined); - }).pipe(Effect.scoped, Effect.provideService(HostProcessPlatform, "linux")), + }).pipe(Effect.scoped, Effect.provideService(HostProcess.Platform, "linux")), ); }); diff --git a/apps/server/src/cli/update.ts b/apps/server/src/cli/update.ts index 576158e316bc..073217d505cb 100644 --- a/apps/server/src/cli/update.ts +++ b/apps/server/src/cli/update.ts @@ -1,11 +1,4 @@ -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessInvokedAs, - HostProcessIsExecutable, - HostProcessPlatform, - HostProcessWorkingDirectory, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { CLI_RELEASE_BASE_URL_ENV, CLI_RELEASE_CHANNELS, @@ -121,7 +114,7 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function }) { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (input.launchedAs === undefined) return Option.none(); const ownsTarget = (candidate: string) => launcherOwnsVersionsDir(path, input.versionsDir, candidate); @@ -170,10 +163,10 @@ export const repointLauncher = Effect.fn("cli.update.repoint_launcher")(function export const resolveLauncherPath = Effect.gen(function* () { const path = yield* Path.Path; const fs = yield* FileSystem.FileSystem; - const invokedAs = yield* HostProcessInvokedAs; - const cwd = yield* HostProcessWorkingDirectory; - const environment = yield* HostProcessEnvironment; - const platform = yield* HostProcessPlatform; + const invokedAs = yield* HostProcess.InvokedAs; + const cwd = yield* HostProcess.WorkingDirectory; + const environment = yield* HostProcess.Environment; + const platform = yield* HostProcess.Platform; if (invokedAs.includes("/") || invokedAs.includes("\\")) { return path.resolve(cwd, invokedAs); } @@ -198,7 +191,7 @@ export const findWindowsShim = Effect.fn("cli.update.find_windows_shim")(functio ) { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const candidates = [ ...(environment["T3CODE_INSTALL_BIN_DIR"] ? [environment["T3CODE_INSTALL_BIN_DIR"]] : []), ...(environment["PATH"] ?? environment["Path"] ?? "").split(";"), @@ -299,7 +292,7 @@ const findForegroundServer = Effect.fn("cli.update.find_foreground_server")(func const belongsToBootService = Effect.fn("cli.update.belongs_to_boot_service")(function* ( pid: number, ) { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const fs = yield* FileSystem.FileSystem; const runner = yield* ProcessRunner.ProcessRunner; if (platform === "linux") { @@ -340,9 +333,9 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const runner = yield* ProcessRunner.ProcessRunner; - const platform = yield* HostProcessPlatform; - const arch = yield* HostProcessArchitecture; - const environment = yield* HostProcessEnvironment; + const platform = yield* HostProcess.Platform; + const arch = yield* HostProcess.Architecture; + const environment = yield* HostProcess.Environment; const httpClient = yield* HttpClient.HttpClient; const service = yield* BootService.BootService; @@ -531,7 +524,7 @@ const runUpdate = Effect.fn("cli.update.run")(function* (input: { ), ); - const launchedAs = (yield* HostProcessIsExecutable) ? yield* resolveLauncherPath : undefined; + const launchedAs = (yield* HostProcess.IsExecutable) ? yield* resolveLauncherPath : undefined; const repointed = yield* repointLauncher({ launchedAs, versionsDir: path.dirname(runtime.versionDir), diff --git a/apps/server/src/cloud/bootService.test.ts b/apps/server/src/cloud/bootService.test.ts index 85de4a7bd437..65bf0818a970 100644 --- a/apps/server/src/cloud/bootService.test.ts +++ b/apps/server/src/cloud/bootService.test.ts @@ -1,10 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { expect, it } from "@effect/vitest"; -import { - HostProcessExecutablePath, - HostProcessPlatform, - HostProcessUserId, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as ConfigProvider from "effect/ConfigProvider"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; @@ -226,9 +222,9 @@ const makeHarness = Effect.fn("test.make_boot_service_harness")(function* ( Effect.provideService(ProcessRunner.ProcessRunner, runner), Effect.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, platform), - Layer.succeed(HostProcessUserId, 501), - Layer.succeed(HostProcessExecutablePath, "/usr/bin/t3"), + Layer.succeed(HostProcess.Platform, platform), + Layer.succeed(HostProcess.UserId, 501), + Layer.succeed(HostProcess.ExecutablePath, "/usr/bin/t3"), Layer.succeed( HttpClient.HttpClient, HttpClient.make(() => Effect.die("no release download expected")), diff --git a/apps/server/src/cloud/bootService.ts b/apps/server/src/cloud/bootService.ts index 0b102579887a..294f229affa9 100644 --- a/apps/server/src/cloud/bootService.ts +++ b/apps/server/src/cloud/bootService.ts @@ -1,9 +1,4 @@ -import { - HostProcessArchitecture, - HostProcessExecutablePath, - HostProcessPlatform, - HostProcessUserId, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Config from "effect/Config"; import * as Context from "effect/Context"; import * as DateTime from "effect/DateTime"; @@ -558,10 +553,10 @@ export const make = Effect.fn("cloud.boot_service.make")(function* (input: { readonly cliVersion: string; readonly host?: BootServiceHost; }) { - const hostExecPath = yield* HostProcessExecutablePath; - const platform = yield* HostProcessPlatform; - const arch = yield* HostProcessArchitecture; - const uid = yield* HostProcessUserId; + const hostExecPath = yield* HostProcess.ExecutablePath; + const platform = yield* HostProcess.Platform; + const arch = yield* HostProcess.Architecture; + const uid = yield* HostProcess.UserId; const httpClient = yield* HttpClient.HttpClient; const releaseBaseUrl = Option.getOrUndefined( yield* Config.String(CLI_RELEASE_BASE_URL_ENV).pipe(Config.option), diff --git a/apps/server/src/cloud/selfUpdate.test.ts b/apps/server/src/cloud/selfUpdate.test.ts index 111b62c8a481..443fad607fb8 100644 --- a/apps/server/src/cloud/selfUpdate.test.ts +++ b/apps/server/src/cloud/selfUpdate.test.ts @@ -1,7 +1,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { expect, it } from "@effect/vitest"; import { ServerSelfUpdateError, ThreadId } from "@t3tools/contracts"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; @@ -120,8 +120,8 @@ const makeHarness = Effect.fn("test.make_self_update_harness")(function* ( }, ), Effect.provideService(HttpClient.HttpClient, releaseHttpClient(order)), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessArchitecture, "x64"), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Architecture, "x64"), Effect.provide(ServerConfig.layer({ ...config, mode: options.mode ?? "web" })), ); return { selfUpdate, order }; diff --git a/apps/server/src/cloud/selfUpdate.ts b/apps/server/src/cloud/selfUpdate.ts index 47c4949de739..615351c4395e 100644 --- a/apps/server/src/cloud/selfUpdate.ts +++ b/apps/server/src/cloud/selfUpdate.ts @@ -6,7 +6,7 @@ import { type ServerSelfUpdateResult, type ThreadId, } from "@t3tools/contracts"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Config from "effect/Config"; import * as Context from "effect/Context"; @@ -176,8 +176,8 @@ export const make = Effect.fn("cloud.server_self_update.make")(function* () { const runner = yield* ProcessRunner.ProcessRunner; const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; - const arch = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const arch = yield* HostProcess.Architecture; // Archive-distributed targets download from GitHub Releases. The client is // optional so callers without one (tests, npm-only hosts) still construct. const httpClient = yield* HttpClient.HttpClient; diff --git a/apps/server/src/cloud/serviceLauncherClient.test.ts b/apps/server/src/cloud/serviceLauncherClient.test.ts index eab0935419a0..dee00b0b203c 100644 --- a/apps/server/src/cloud/serviceLauncherClient.test.ts +++ b/apps/server/src/cloud/serviceLauncherClient.test.ts @@ -1,5 +1,5 @@ import { expect, it } from "@effect/vitest"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; @@ -45,7 +45,7 @@ class FakeLauncherProcess { const makeClient = (host: FakeLauncherProcess, currentVersion: string) => ServiceLauncherClient.make({ currentVersion }).pipe( Effect.provideService(ServiceLauncherClient.ServiceLauncherHostProcess, host), - Effect.provideService(HostProcessEnvironment, host.env), + Effect.provideService(HostProcess.Environment, host.env), ); it.effect("waits for the launcher to durably commit the trial update ID", () => diff --git a/apps/server/src/cloud/serviceLauncherClient.ts b/apps/server/src/cloud/serviceLauncherClient.ts index 2d644157211f..b58d133494cb 100644 --- a/apps/server/src/cloud/serviceLauncherClient.ts +++ b/apps/server/src/cloud/serviceLauncherClient.ts @@ -1,5 +1,5 @@ import type { ServerSelfUpdateOutcome } from "@t3tools/contracts"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -114,7 +114,7 @@ export class ServiceLauncherClient extends Context.Service< const resolveStartup = Effect.fn("cloud.service_launcher_client.resolve_startup")( function* (options?: { readonly currentVersion?: string }) { const host = yield* ServiceLauncherHostProcess; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const currentVersion = options?.currentVersion ?? packageJson.version; const rawContext = environment[SERVICE_LAUNCHER_CONTEXT_ENV]; const context = rawContext === undefined ? undefined : decodeServiceLauncherContext(rawContext); diff --git a/apps/server/src/device/AgentDeviceShim.ts b/apps/server/src/device/AgentDeviceShim.ts index a5a669d1d8ba..f3a21fe9b362 100644 --- a/apps/server/src/device/AgentDeviceShim.ts +++ b/apps/server/src/device/AgentDeviceShim.ts @@ -5,7 +5,7 @@ * types `agent-device …` and gets the version the injected instructions were * written for, regardless of what is or is not globally installed. */ -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveNodeExecutable } from "@t3tools/shared/nodeRuntime"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -20,7 +20,7 @@ export const ensureAgentDeviceShim = Effect.fn("AgentDeviceShim.ensure")(functio const { entryPath } = input; const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const node = yield* resolveNodeExecutable("Device automation"); const shimDir = path.join(input.stateDir, SHIM_DIR); yield* fs.makeDirectory(shimDir, { recursive: true }); diff --git a/apps/server/src/device/AgentDeviceTarget.test.ts b/apps/server/src/device/AgentDeviceTarget.test.ts index 4dfd5e20d1c8..2cedbe1e8bed 100644 --- a/apps/server/src/device/AgentDeviceTarget.test.ts +++ b/apps/server/src/device/AgentDeviceTarget.test.ts @@ -1,9 +1,5 @@ // @effect-diagnostics nodeBuiltinImport:off - exercises concurrent real CLI subprocesses. -import { - HostProcessExecutablePath, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { describe, expect, it } from "@effect/vitest"; import * as NodeChildProcess from "node:child_process"; import * as NodeUtil from "node:util"; @@ -26,7 +22,7 @@ describe("host-bound agent commands", () => { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const temp = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-target-" }); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const dir = path.join( temp, platform === "win32" ? "paths with spaces" : "quotes '\" $HOME `literal`", @@ -92,8 +88,8 @@ if (process.env.AGENT_DEVICE_DAEMON_BASE_URL) process.exit(2);`, } }).pipe( Effect.scoped, - Effect.provideService(HostProcessIsExecutable, true), - Effect.provideService(HostProcessExecutablePath, "/packaged/t3"), + Effect.provideService(HostProcess.IsExecutable, true), + Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"), Effect.provide(NodeServices.layer), ), ); diff --git a/apps/server/src/device/LocalDeviceHost.test.ts b/apps/server/src/device/LocalDeviceHost.test.ts index 7dde6263defd..9b404099e1dd 100644 --- a/apps/server/src/device/LocalDeviceHost.test.ts +++ b/apps/server/src/device/LocalDeviceHost.test.ts @@ -1,11 +1,6 @@ import { describe, expect, it } from "@effect/vitest"; import * as NodePath from "@effect/platform-node/NodePath"; -import { - HostProcessEnvironment, - HostProcessPlatform, - HostProcessIsExecutable, - HostProcessUserId, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; @@ -26,8 +21,8 @@ const diagnose = ( platform: NodeJS.Platform = "darwin", ) => LocalDeviceHost.__testing.platformReason("android").pipe( - Effect.provideService(HostProcessEnvironment, environment), - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Environment, environment), + Effect.provideService(HostProcess.Platform, platform), Effect.provideService( FileSystem.FileSystem, FileSystem.makeNoop({ @@ -155,8 +150,8 @@ it.effect( ] as const) { const environment = { PATH: "/usr/bin", XDG_RUNTIME_DIR: runtimeDir }; const result = yield* LocalDeviceHost.__testing.hubEnvironment(environment).pipe( - Effect.provideService(HostProcessPlatform, platform), - Effect.provideService(HostProcessUserId, uid), + Effect.provideService(HostProcess.Platform, platform), + Effect.provideService(HostProcess.UserId, uid), Effect.provideService( FileSystem.FileSystem, FileSystem.makeNoop({ @@ -176,8 +171,8 @@ it.effect( const missing = yield* LocalDeviceHost.__testing .hubEnvironment({}) .pipe( - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessUserId, 1000), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.UserId, 1000), Effect.provideService(FileSystem.FileSystem, FileSystem.makeNoop({})), ); expect(missing.XDG_RUNTIME_DIR).toBeUndefined(); @@ -192,8 +187,8 @@ it.effect( const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-consent-" }); const host = yield* LocalDeviceHost.make().pipe( Effect.provide(Layer.mergeAll(ServerConfig.layerTest(baseDir, baseDir), NetService.layer)), - Effect.provideService(HostProcessEnvironment, { HOME: baseDir, PATH: "" }), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Environment, { HOME: baseDir, PATH: "" }), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provideService( ChildProcessSpawner.ChildProcessSpawner, ChildProcessSpawner.make(() => @@ -213,7 +208,7 @@ it.effect( expect(yield* host.current).toBeNull(); const error = yield* host .ensureReady(() => Effect.die("Must not install without Node")) - .pipe(Effect.flip, Effect.provideService(HostProcessIsExecutable, true)); + .pipe(Effect.flip, Effect.provideService(HostProcess.IsExecutable, true)); expect(error.message).toContain("Local device support requires Node.js"); expect(error.message).toContain("Install Node.js"); yield* host.stop; diff --git a/apps/server/src/device/LocalDeviceHost.ts b/apps/server/src/device/LocalDeviceHost.ts index 58179151877c..779221ab93cf 100644 --- a/apps/server/src/device/LocalDeviceHost.ts +++ b/apps/server/src/device/LocalDeviceHost.ts @@ -19,11 +19,7 @@ import { LOCAL_DEVICE_HOST_ID, } from "@t3tools/contracts"; import { waitForHttpReady } from "@t3tools/shared/httpReadiness"; -import { - HostProcessEnvironment, - HostProcessPlatform, - HostProcessUserId, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveNodeExecutable, type NodeRuntimeUnavailableError, @@ -107,7 +103,7 @@ interface RunningHost { const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* ( platform: DevicePlatform, ): Effect.fn.Return { - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; if (platform === "ios") { if (hostPlatform !== "darwin") return "iOS Simulators need macOS with Xcode."; if (!(yield* isCommandAvailable("xcrun"))) return "Xcode command line tools were not found."; @@ -132,8 +128,8 @@ const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* ( const androidSdk = Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const environment = yield* HostProcessEnvironment; - const platform = yield* HostProcessPlatform; + const environment = yield* HostProcess.Environment; + const platform = yield* HostProcess.Platform; const home = environment.HOME ?? environment.USERPROFILE ?? ""; const explicit = environment.ANDROID_HOME?.trim() || environment.ANDROID_SDK_ROOT?.trim(); const candidates = explicit @@ -208,8 +204,8 @@ const hubEnvironment = Effect.fn("LocalDeviceHost.hubEnvironment")(function* ( environment: NodeJS.ProcessEnv, ) { const env: NodeJS.ProcessEnv = { ...environment, FORCE_COLOR: "0", NO_COLOR: "1" }; - const platform = yield* HostProcessPlatform; - const uid = yield* HostProcessUserId; + const platform = yield* HostProcess.Platform; + const uid = yield* HostProcess.UserId; if (platform === "linux" && env.XDG_RUNTIME_DIR === undefined && uid !== undefined) { // SSH sessions may omit the directory where the emulator publishes its gRPC token. const runtimeDir = `/run/user/${uid}`; @@ -234,8 +230,8 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () { const net = yield* NetService.NetService; const runner = yield* ProcessRunner.ProcessRunner; const httpClient = yield* HttpClient.HttpClient; - const environment = yield* HostProcessEnvironment; - const hostPlatform = yield* HostProcessPlatform; + const environment = yield* HostProcess.Environment; + const hostPlatform = yield* HostProcess.Platform; const sdk = yield* androidSdk; const hostEnvironment = deviceHostEnvironment(environment, sdk.root, hostPlatform, path); const startLock = yield* Semaphore.make(1); @@ -406,7 +402,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () { stderr: "pipe", env: yield* hubEnvironment(hostEnvironment).pipe( Effect.provideService(FileSystem.FileSystem, fs), - Effect.provideService(HostProcessPlatform, hostPlatform), + Effect.provideService(HostProcess.Platform, hostPlatform), ), }, ), @@ -598,7 +594,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () { const nodePath = yield* resolveNodeExecutable("Local device support", hostEnvironment).pipe( Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path), - Effect.provideService(HostProcessPlatform, hostPlatform), + Effect.provideService(HostProcess.Platform, hostPlatform), ); const installed = yield* isDeviceHubInstalled(config.baseDir).pipe( Effect.provideService(FileSystem.FileSystem, fs), diff --git a/apps/server/src/device/sshDeviceScript.test.ts b/apps/server/src/device/sshDeviceScript.test.ts index f1f56c715e60..97f124721bb0 100644 --- a/apps/server/src/device/sshDeviceScript.test.ts +++ b/apps/server/src/device/sshDeviceScript.test.ts @@ -1,6 +1,6 @@ // @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - verifies generated remote scripts using real shell and Node processes. import * as Effect from "effect/Effect"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { describe, expect, it } from "@effect/vitest"; import * as NodeChildProcess from "node:child_process"; import * as NodeFSP from "node:fs/promises"; @@ -14,7 +14,7 @@ const exec = NodeUtil.promisify(NodeChildProcess.execFile); it.effect("finds Android Studio Java for a non-interactive SSH session", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) === "win32") return; + if ((yield* HostProcess.Platform) === "win32") return; yield* Effect.promise(async () => { const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-ssh-java-")); try { @@ -38,7 +38,7 @@ it.effect("finds Android Studio Java for a non-interactive SSH session", () => it.effect("preserves shell metacharacters and newlines in remote arguments", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) === "win32") return; + if ((yield* HostProcess.Platform) === "win32") return; yield* Effect.promise(async () => { const value = "quotes ' \" ; $(echo expanded) $HOME\nnext line"; const result = await exec("sh", ["-c", `printf %s ${quoteRemoteArg(value)}`]); @@ -50,7 +50,7 @@ it.effect("preserves shell metacharacters and newlines in remote arguments", () describe("remote helper lifecycle", () => { it.effect("reuses its own healthy helpers and stops only its own runtime", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) === "win32") return; + if ((yield* HostProcess.Platform) === "win32") return; yield* Effect.promise(async () => { const home = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-remote-script-")); const bin = NodePath.join(home, "bin"); diff --git a/apps/server/src/environment/RemoteOpenTargets.test.ts b/apps/server/src/environment/RemoteOpenTargets.test.ts index 1e222abb867e..8a90a9345df3 100644 --- a/apps/server/src/environment/RemoteOpenTargets.test.ts +++ b/apps/server/src/environment/RemoteOpenTargets.test.ts @@ -1,5 +1,5 @@ import { it } from "@effect/vitest"; -import { HostProcessHostname } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as NetService from "@t3tools/shared/Net"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -54,7 +54,7 @@ const resolveTargets = (input: { readonly hostname: string; }) => Effect.flatMap(RemoteOpenTargets.RemoteOpenTargets, (service) => service.resolveTargets()).pipe( - Effect.provideService(HostProcessHostname, input.hostname), + Effect.provideService(HostProcess.Hostname, input.hostname), Effect.provide( RemoteOpenTargets.layer.pipe( Layer.provide(Layer.mergeAll(layerNet(input.sshd), layerSpawner(input.tailscale))), diff --git a/apps/server/src/environment/RemoteOpenTargets.ts b/apps/server/src/environment/RemoteOpenTargets.ts index e0acfaee2f48..1cd5751bc2d4 100644 --- a/apps/server/src/environment/RemoteOpenTargets.ts +++ b/apps/server/src/environment/RemoteOpenTargets.ts @@ -9,7 +9,7 @@ * on the tailnet; `.local` only on the same LAN). */ import { type RemoteOpenTarget } from "@t3tools/contracts"; -import { HostProcessHostname } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as NetService from "@t3tools/shared/Net"; import { readTailscaleStatus } from "@t3tools/tailscale"; import * as Context from "effect/Context"; @@ -58,7 +58,7 @@ export const make = Effect.gen(function* () { // os.hostname() may already be an FQDN (macOS often reports // "Name.local"); mDNS names are always `.local`. - const hostname = yield* HostProcessHostname; + const hostname = yield* HostProcess.Hostname; const shortHostname = hostname.split(".")[0]?.trim(); if (shortHostname !== undefined && shortHostname.length > 0) { targets.push({ kind: "mdns", host: `${shortHostname}.local` }); diff --git a/apps/server/src/environment/ServerEnvironment.test.ts b/apps/server/src/environment/ServerEnvironment.test.ts index 41c18b907437..f9e13212252f 100644 --- a/apps/server/src/environment/ServerEnvironment.test.ts +++ b/apps/server/src/environment/ServerEnvironment.test.ts @@ -10,12 +10,7 @@ import * as PlatformError from "effect/PlatformError"; import * as Schema from "effect/Schema"; import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability"; -import { - HostProcessArguments, - HostProcessEnvironment, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as OtelEnvironment from "@t3tools/shared/otelEnvironment"; import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; @@ -112,10 +107,10 @@ it.layer(NodeServices.layer)("ServerEnvironmentLive", (it) => { Layer.provide(ServerConfig.layer({ ...config, mode })), ), ), - Effect.provideService(HostProcessArguments, ["node", entry]), - Effect.provideService(HostProcessIsExecutable, false), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Arguments, ["node", entry]), + Effect.provideService(HostProcess.IsExecutable, false), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Environment, {}), ); expect(descriptor.capabilities.serverInstallation).toEqual( mode === "web" ? { kind: "npm-global", prefix } : undefined, diff --git a/apps/server/src/environment/ServerEnvironment.ts b/apps/server/src/environment/ServerEnvironment.ts index 6381547468ae..7fc4a66464e9 100644 --- a/apps/server/src/environment/ServerEnvironment.ts +++ b/apps/server/src/environment/ServerEnvironment.ts @@ -4,7 +4,7 @@ import { PROVIDER_SEND_TURN_MAX_FILE_BYTES, type ExecutionEnvironmentDescriptor, } from "@t3tools/contracts"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Crypto from "effect/Crypto"; import * as Effect from "effect/Effect"; @@ -186,8 +186,8 @@ export const make = Effect.gen(function* () { const serverConfig = yield* ServerConfig.ServerConfig; const secrets = yield* ServerSecretStore.ServerSecretStore; const identity = yield* ServerEnvironmentIdentity; - const hostPlatform = yield* HostProcessPlatform; - const hostArchitecture = yield* HostProcessArchitecture; + const hostPlatform = yield* HostProcess.Platform; + const hostArchitecture = yield* HostProcess.Architecture; const environmentId = yield* identity.getEnvironmentId; const cwdBaseName = path.basename(serverConfig.cwd).trim(); const label = yield* resolveServerEnvironmentLabel({ cwdBaseName }); diff --git a/apps/server/src/environment/ServerEnvironmentLabel.test.ts b/apps/server/src/environment/ServerEnvironmentLabel.test.ts index fd7f8ccb3726..7fd418e2821e 100644 --- a/apps/server/src/environment/ServerEnvironmentLabel.test.ts +++ b/apps/server/src/environment/ServerEnvironmentLabel.test.ts @@ -7,7 +7,7 @@ import * as PlatformError from "effect/PlatformError"; import * as References from "effect/References"; import * as Schema from "effect/Schema"; import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"; -import { HostProcessHostname, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { vi } from "vite-plus/test"; import * as ProcessRunner from "../processRunner.ts"; @@ -52,8 +52,8 @@ const withHostPlatform = ( ) => Layer.mergeAll( layer, - Layer.succeed(HostProcessPlatform, platform), - Layer.succeed(HostProcessHostname, hostname), + Layer.succeed(HostProcess.Platform, platform), + Layer.succeed(HostProcess.Hostname, hostname), ); afterEach(() => { diff --git a/apps/server/src/environment/ServerEnvironmentLabel.ts b/apps/server/src/environment/ServerEnvironmentLabel.ts index 4a5d0a009b9a..73ff4a763910 100644 --- a/apps/server/src/environment/ServerEnvironmentLabel.ts +++ b/apps/server/src/environment/ServerEnvironmentLabel.ts @@ -1,4 +1,4 @@ -import { HostProcessHostname, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Option from "effect/Option"; @@ -151,7 +151,7 @@ const runFriendlyLabelCommand = Effect.fn("runFriendlyLabelCommand")(function* ( }); const resolveFriendlyHostLabel = Effect.fn("resolveFriendlyHostLabel")(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (platform === "darwin") { return yield* runFriendlyLabelCommand({ probe: "macos-computer-name", @@ -187,7 +187,7 @@ export const resolveServerEnvironmentLabel = Effect.fn("resolveServerEnvironment return friendlyHostLabel; } - const hostname = normalizeLabel(yield* HostProcessHostname); + const hostname = normalizeLabel(yield* HostProcess.Hostname); if (hostname) { return hostname; } diff --git a/apps/server/src/environment/ServerEnvironmentMachine.test.ts b/apps/server/src/environment/ServerEnvironmentMachine.test.ts index 3c2ab52a7083..198aa4ed5583 100644 --- a/apps/server/src/environment/ServerEnvironmentMachine.test.ts +++ b/apps/server/src/environment/ServerEnvironmentMachine.test.ts @@ -4,7 +4,7 @@ import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as PlatformError from "effect/PlatformError"; import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { vi } from "vite-plus/test"; import * as ProcessRunner from "../processRunner.ts"; @@ -52,7 +52,7 @@ const layerDmiFileSystem = (files: Readonly>) => }); const withPlatform = (platform: NodeJS.Platform, fileSystem = FileSystem.layerNoop({})) => - Layer.mergeAll(layerProcessRunnerTest, fileSystem, Layer.succeed(HostProcessPlatform, platform)); + Layer.mergeAll(layerProcessRunnerTest, fileSystem, Layer.succeed(HostProcess.Platform, platform)); afterEach(() => { runMock.mockReset(); diff --git a/apps/server/src/environment/ServerEnvironmentMachine.ts b/apps/server/src/environment/ServerEnvironmentMachine.ts index e9f5e51af600..267dd42a532c 100644 --- a/apps/server/src/environment/ServerEnvironmentMachine.ts +++ b/apps/server/src/environment/ServerEnvironmentMachine.ts @@ -1,5 +1,5 @@ import type { EnvironmentMachineKind } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -161,7 +161,7 @@ const detectLinuxMachineKind = Effect.fn("detectLinuxMachineKind")(function* () export const detectServerEnvironmentMachineKind = Effect.fn("detectServerEnvironmentMachineKind")( function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; switch (platform) { case "darwin": return yield* detectDarwinMachineKind(); diff --git a/apps/server/src/htmlRender/HtmlRender.test.ts b/apps/server/src/htmlRender/HtmlRender.test.ts index a6a3e56564dc..930fe11c0a8c 100644 --- a/apps/server/src/htmlRender/HtmlRender.test.ts +++ b/apps/server/src/htmlRender/HtmlRender.test.ts @@ -2,7 +2,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { describe, expect, it } from "@effect/vitest"; import { ThreadId } from "@t3tools/contracts"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { HTML_RENDER_MEASURE_FONTS, HTML_RENDER_MEASURE_WIDTHS, @@ -238,7 +238,7 @@ describe("HtmlRender", () => { "screenshots the page in headless Chrome with the requested theme and every console level", (ctx) => Effect.gen(function* () { - const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV]; + const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV]; if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`); yield* Effect.gen(function* () { const htmlRender = yield* HtmlRender.HtmlRender; @@ -292,7 +292,7 @@ describe("HtmlRender", () => { "keeps every local file but the page itself out of the browser", (ctx) => Effect.gen(function* () { - const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV]; + const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV]; if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`); yield* Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; @@ -323,7 +323,7 @@ describe("HtmlRender", () => { "keeps the page off this machine's local network", (ctx) => Effect.gen(function* () { - const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV]; + const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV]; if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`); // The page's connections go through a proxy that only reaches public // addresses, and WebRTC is gone. Each line below is a way out that @@ -381,7 +381,7 @@ describe("HtmlRender", () => { "measures a published page at every client width with a fresh load each", (ctx) => Effect.gen(function* () { - const executable = (yield* HostProcessEnvironment)[TEST_BROWSER_ENV]; + const executable = (yield* HostProcess.Environment)[TEST_BROWSER_ENV]; if (!executable) return ctx.skip(`Set ${TEST_BROWSER_ENV} to run this test.`); yield* Effect.gen(function* () { const htmlRender = yield* HtmlRender.HtmlRender; diff --git a/apps/server/src/htmlRender/HtmlRender.ts b/apps/server/src/htmlRender/HtmlRender.ts index cfbf6c206ffb..47c7238fb476 100644 --- a/apps/server/src/htmlRender/HtmlRender.ts +++ b/apps/server/src/htmlRender/HtmlRender.ts @@ -1,5 +1,5 @@ import type { ThreadId } from "@t3tools/contracts"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { clampHtmlRenderHeight, HTML_RENDER_COLUMN_WIDTH, @@ -341,7 +341,7 @@ const make = Effect.gen(function* () { const browsers = yield* Semaphore.make(MAX_CONCURRENT_BROWSERS); // Chrome's sandbox stays on unless the operator explicitly turns it off. // Chrome also refuses it as root, where that opt-out is the only way to run. - const noSandbox = PreviewBrowserHost.sandboxDisabled(yield* HostProcessEnvironment); + const noSandbox = PreviewBrowserHost.sandboxDisabled(yield* HostProcess.Environment); const setupCommand = yield* resolveRootCliCommand(PreviewBrowserHost.SETUP_SUBCOMMAND); /** Runs one browser launch; a host that cannot start it gets setup steps instead. */ diff --git a/apps/server/src/keybindings.test.ts b/apps/server/src/keybindings.test.ts index f6c3cb9e8843..0ea44fb3ca07 100644 --- a/apps/server/src/keybindings.test.ts +++ b/apps/server/src/keybindings.test.ts @@ -12,7 +12,7 @@ import * as Schema from "effect/Schema"; import * as ServerConfig from "./config.ts"; import * as Keybindings from "./keybindings.ts"; import { KeybindingsConfigError, MAX_KEYBINDINGS_COUNT } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const KeybindingsConfigJson = Schema.fromJsonString(KeybindingsConfig); const encodeKeybindingsConfigJson = Schema.encodeEffect(KeybindingsConfigJson); @@ -564,7 +564,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => { ); // chmod cannot make a directory unwritable on Windows, so the write succeeds. - it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "fails when config directory is not writable", () => Effect.gen(function* () { diff --git a/apps/server/src/mcp/toolkits/device/handlers.ts b/apps/server/src/mcp/toolkits/device/handlers.ts index 1543bbc87100..669d90f23ac5 100644 --- a/apps/server/src/mcp/toolkits/device/handlers.ts +++ b/apps/server/src/mcp/toolkits/device/handlers.ts @@ -9,7 +9,7 @@ import { } from "@t3tools/contracts"; import * as Effect from "effect/Effect"; import * as Path from "effect/Path"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as ServerConfig from "../../../config.ts"; import { ensureAgentDeviceShim } from "../../../device/AgentDeviceShim.ts"; import { nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime"; @@ -179,7 +179,7 @@ const handlers = { const targetArgs = [...agentDeviceTargetArgs(device), ...agentArgs]; const config = yield* ServerConfig.ServerConfig; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const shimDir = yield* ensureAgentDeviceShim({ entryPath: yield* devices.agentCli, stateDir: config.stateDir, diff --git a/apps/server/src/observability/HeapSnapshot.ts b/apps/server/src/observability/HeapSnapshot.ts index 827dfab2c6d6..6359c1628c58 100644 --- a/apps/server/src/observability/HeapSnapshot.ts +++ b/apps/server/src/observability/HeapSnapshot.ts @@ -2,7 +2,7 @@ import * as NodePath from "node:path"; import * as NodeV8 from "node:v8"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -40,7 +40,7 @@ export const writeHeapSnapshot = Effect.fn("server.heapSnapshot", { root: true } */ export const layer = Layer.effectDiscard( Effect.gen(function* () { - if ((yield* HostProcessPlatform) === "win32") return; + if ((yield* HostProcess.Platform) === "win32") return; const { logsDir } = yield* ServerConfig.ServerConfig; const runFork = Effect.runForkWith(yield* Effect.context()); const onSignal = () => void runFork(writeHeapSnapshot(logsDir)); diff --git a/apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts b/apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts index 0802fef78f9e..8651890a2052 100644 --- a/apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts +++ b/apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts @@ -27,7 +27,7 @@ import { type OrchestrationV2ProviderThread, } from "@t3tools/contracts"; import { GrokSettings } from "@t3tools/provider-grok/settings"; -import { HostProcessIsExecutable, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime"; import * as DateTime from "effect/DateTime"; import * as Deferred from "effect/Deferred"; @@ -705,7 +705,7 @@ describe("AcpAdapterV2", () => { const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner; const path = yield* Path.Path; const selfInvocation = yield* resolveSelfInvocation().pipe( - Effect.provideService(HostProcessIsExecutable, true), + Effect.provideService(HostProcess.IsExecutable, true), ); const mockAgentPath = yield* path.fromFileUrl( new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), @@ -1833,7 +1833,7 @@ describe("AcpAdapterV2", () => { it.live("cleans detached fixtures when an assertion aborts the test scope", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const fileSystem = yield* FileSystem.FileSystem; let published: ReadonlyArray = []; const failed = yield* Effect.scoped( @@ -1947,7 +1947,7 @@ describe("AcpAdapterV2", () => { it.live("reaps detached native work when the provider exits before explicit teardown", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner; const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; @@ -2026,7 +2026,7 @@ describe("AcpAdapterV2", () => { it.live("surfaces reduced guarantee when delegated cgroup containment is unavailable", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner; const path = yield* Path.Path; const selfInvocation = yield* resolveSelfInvocation(); @@ -3100,7 +3100,7 @@ describe("AcpAdapterV2", () => { instanceId, settings: DEFAULT_GROK_SETTINGS, environment: {}, - hostPlatform: yield* HostProcessPlatform, + hostPlatform: yield* HostProcess.Platform, selfInvocation: yield* resolveSelfInvocation(), // Production Grok runtimes are wrapped by the x.ai prompt runtime. makeRuntime: (input) => @@ -3147,7 +3147,7 @@ describe("AcpAdapterV2", () => { instanceId, settings: DEFAULT_GROK_SETTINGS, environment: {}, - hostPlatform: yield* HostProcessPlatform, + hostPlatform: yield* HostProcess.Platform, selfInvocation: yield* resolveSelfInvocation(), // Production Grok runtimes are wrapped by the x.ai prompt runtime. makeRuntime: (input) => @@ -13147,7 +13147,7 @@ describe("AcpAdapterV2", () => { it.live("direct Stop skips uninterruptible ACP cancel and recovers after native teardown", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner; const fileSystem = yield* FileSystem.FileSystem; const idAllocator = yield* IdAllocator.IdAllocatorV2; @@ -13567,7 +13567,7 @@ describe("AcpAdapterV2", () => { it.live("restart_active terminates native work and reloads a clean runtime", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner; const fileSystem = yield* FileSystem.FileSystem; const idAllocator = yield* IdAllocator.IdAllocatorV2; diff --git a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts index 9c4e336815f7..6777f0a2902a 100644 --- a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts +++ b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts @@ -47,7 +47,7 @@ import * as Stream from "effect/Stream"; import * as TestClock from "effect/testing/TestClock"; import { Tool } from "effect/ai"; import { formatClaudeResumeCompactionQuestion } from "@t3tools/shared/claudeCompaction"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import { attachmentRelativePath } from "../../attachmentStore.ts"; @@ -1171,7 +1171,7 @@ describe("ClaudeAdapterV2 executable path", () => { const npmDir = "C:\\Users\\dev\\AppData\\Roaming\\npm"; const packageExe = `${npmDir}\\node_modules\\@anthropic-ai\\claude-code\\bin\\claude.exe`; const executablePaths = yield* captureSdkExecutablePaths("claude").pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(SpawnExecutableResolution, () => `${npmDir}\\claude.cmd`), Effect.provideService(ClaudeExecutableFileCheck, (filePath) => filePath === packageExe), ); diff --git a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts index cc8a5bef6f5a..730ed8a575f2 100644 --- a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts +++ b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts @@ -8,7 +8,7 @@ import { type SDKUserMessage, } from "@anthropic-ai/claude-agent-sdk"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import { ProviderReplayEntry, @@ -1440,7 +1440,7 @@ async function recordMessagesUntilToolUse(input: { const resolveClaudeRecordingExecutablePath = Effect.fn("resolveClaudeRecordingExecutablePath")( function* (environment: NodeJS.ProcessEnv) { const resolveExecutable = yield* SpawnExecutableResolution; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const resolved = resolveExecutable("claude", platform, environment); if (resolved === undefined) { return undefined; diff --git a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts index 33db150ec689..79d7bdd7e115 100644 --- a/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts +++ b/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts @@ -31,7 +31,7 @@ import type { WebSearchOutput, } from "@anthropic-ai/claude-agent-sdk/sdk-tools"; import { parseCliArgs } from "@t3tools/shared/cliArgs"; -import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { applyClaudePromptEffortPrefix } from "@t3tools/shared/model"; import { CLAUDE_RESUME_COMPACTION_NEVER_ANSWER, @@ -8176,7 +8176,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")( ) { const { instanceId, environment, enabled, config } = input; const fileSystem = yield* FileSystem.FileSystem; - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const idAllocator = yield* IdAllocator.IdAllocatorV2; const queryRunner = yield* ClaudeAgentSdkQueryRunner; const serverConfig = yield* ServerConfig.ServerConfig; @@ -8186,7 +8186,7 @@ export const createClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2Driver.create")( const path = yield* Path.Path; const crypto = yield* Crypto.Crypto; const binaryPath = yield* resolveClaudeSdkExecutablePath( - expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory), + expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory), claudeEnvironment, ); return yield* makeClaudeAdapterV2({ @@ -8231,7 +8231,7 @@ const makeDefaultClaudeAdapterV2 = Effect.fn("ClaudeAdapterV2.layer")(function* const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; const crypto = yield* Crypto.Crypto; - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const idAllocator = yield* IdAllocator.IdAllocatorV2; const queryRunner = yield* ClaudeAgentSdkQueryRunner; const serverConfig = yield* ServerConfig.ServerConfig; diff --git a/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts b/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts index 5b18f436c26e..9a1c8f6c900f 100644 --- a/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts +++ b/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts @@ -29,7 +29,7 @@ import { TurnItemId, } from "@t3tools/contracts"; import { assert, describe, it } from "@effect/vitest"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import * as CodexClient from "effect-codex-app-server/client"; import * as CodexError from "effect-codex-app-server/errors"; @@ -698,8 +698,8 @@ describe("CodexAdapterV2 process spawning", () => { assert.deepEqual(command.options.env, { CUSTOM: "1" }); assert.equal(command.options.extendEnv, true); }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Platform, "win32"), + Effect.provideService(HostProcess.Environment, { PATH: "C:\\Windows\\System32", HOST_ONLY: "1", }), @@ -726,7 +726,7 @@ describe("CodexAdapterV2 process spawning", () => { assert.deepEqual(command.args, ["app-server"]); assert.equal(command.options.shell, false); }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(SpawnExecutableResolution, () => "C:\\bin\\codex.exe"), ), ); @@ -774,7 +774,7 @@ describe("CodexAdapterV2 process spawning", () => { ["app-server", "--strict-config", "-c", "model_reasoning_summary=detailed"], ["app-server", "--enable", "env-feature"], ]); - }).pipe(Effect.provideService(HostProcessPlatform, "linux")), + }).pipe(Effect.provideService(HostProcess.Platform, "linux")), ); it.effect("expands ~ in the configured binary path before spawning", () => @@ -821,7 +821,7 @@ describe("CodexAdapterV2 process spawning", () => { Effect.provide( Layer.mergeAll(IdAllocator.layer, McpProviderSessions.layer, NodeServices.layer), ), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), ), ); }); diff --git a/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts b/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts index 69eb0aa7f38e..87c116250c5b 100644 --- a/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts +++ b/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts @@ -30,7 +30,7 @@ import { type ProviderSetupError, } from "@t3tools/contracts"; import { SKILL_MENTION_PATTERN } from "@t3tools/shared/composerInlineTokens"; -import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { dynamicToolTitle } from "@t3tools/shared/toolActivity"; import { getModelSelectionStringOptionValue, modelSelectionsEqual } from "@t3tools/shared/model"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; @@ -1562,7 +1562,7 @@ export const createCodexAdapterV2 = ( const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests; const crypto = yield* Crypto.Crypto; const fileSystem = yield* FileSystem.FileSystem; - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const idAllocator = yield* IdAllocator.IdAllocatorV2; const serverConfig = yield* ServerConfig; const homeLayout = yield* resolveCodexHomeLayout(config); @@ -1582,7 +1582,7 @@ export const createCodexAdapterV2 = ( const settings = { ...config, enabled, - binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory), + binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory), homePath: homeLayout.effectiveHomePath ?? "", } satisfies CodexSettings; @@ -1623,7 +1623,7 @@ const layer: Layer.Layer< const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests; const crypto = yield* Crypto.Crypto; const fileSystem = yield* FileSystem.FileSystem; - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const idAllocator = yield* IdAllocator.IdAllocatorV2; const serverConfig = yield* ServerConfig; diff --git a/apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.testkit.ts b/apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.testkit.ts index daf906ec92cc..4b6b68861c51 100644 --- a/apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.testkit.ts +++ b/apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.testkit.ts @@ -1,4 +1,4 @@ -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import type { InteractionUpdate, RunResult } from "@cursor/sdk"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { @@ -519,7 +519,7 @@ export function layer( // Skill discovery also scans user roots under HOME; an empty HOME keeps // replays from picking up the host's own skills. const layerHostEnvironment = Layer.effect( - HostProcessEnvironment, + HostProcess.Environment, Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const home = yield* fs.makeTempDirectoryScoped({ prefix: "t3-cursor-replay-home-" }); diff --git a/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.test.ts b/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.test.ts index bdfc883aeb93..1a1391ca9363 100644 --- a/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.test.ts +++ b/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.test.ts @@ -7,7 +7,7 @@ import { ThreadId, } from "@t3tools/contracts"; import { GrokSettings } from "@t3tools/provider-grok/settings"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime"; import * as EffectAcpErrors from "effect-acp/errors"; import { xAiRateLimitedErrorCode } from "@t3tools/provider-grok/testing"; @@ -364,7 +364,7 @@ describe("Grok launch permission mode", () => { return launches; }).pipe( // Keep the launch argv unwrapped by the Linux cgroup shim. - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provide(layerTest), ); diff --git a/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.testkit.ts b/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.testkit.ts index b6b67c7a0d56..8d3e86d1ae2a 100644 --- a/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.testkit.ts +++ b/apps/server/src/orchestration-v2/Adapters/GrokAdapterV2.testkit.ts @@ -6,7 +6,7 @@ import * as Layer from "effect/Layer"; import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime"; import * as TestProviderHost from "@t3tools/provider-testing/TestProviderHost"; @@ -43,7 +43,7 @@ function layerGrokProviderAdapterRegistryReplay( const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; // Same queue the continuation worker drains when the fixture runs it. const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests; const replayGate = options.replayGate; diff --git a/apps/server/src/orchestration-v2/workflowScriptQuery.ts b/apps/server/src/orchestration-v2/workflowScriptQuery.ts index a4aa736c669b..ef2ea88c574a 100644 --- a/apps/server/src/orchestration-v2/workflowScriptQuery.ts +++ b/apps/server/src/orchestration-v2/workflowScriptQuery.ts @@ -18,7 +18,7 @@ import * as NodePath from "node:path"; import { OrchestrationGetWorkflowScriptError } from "@t3tools/contracts"; import * as Effect from "effect/Effect"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const SCRIPT_BYTE_CAP = 256 * 1024; @@ -38,7 +38,7 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")( }); } - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const root = yield* Effect.tryPromise({ try: () => NodeFSP.realpath(scriptsRoot(home)), catch: (cause) => diff --git a/apps/server/src/os-jank.ts b/apps/server/src/os-jank.ts index 25c7dfdcb973..38bbcde011cb 100644 --- a/apps/server/src/os-jank.ts +++ b/apps/server/src/os-jank.ts @@ -1,8 +1,4 @@ -import { - HostProcessEnvironment, - HostProcessHomeDirectory, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { listLoginShellCandidates, mergePathEntries, @@ -57,8 +53,8 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return< never, FileSystem.FileSystem | Path.Path > { - const platform = yield* HostProcessPlatform; - const env = yield* HostProcessEnvironment; + const platform = yield* HostProcess.Platform; + const env = yield* HostProcess.Environment; if (platform === "win32") { const repairedEnvironment = yield* resolveWindowsEnvironment(env).pipe( @@ -97,7 +93,7 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return< export const expandHomePath = Effect.fn(function* (input: string) { const { join } = yield* Path.Path; - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; if (input === "~") { return home; } @@ -110,7 +106,7 @@ export const expandHomePath = Effect.fn(function* (input: string) { export const resolveBaseDir = Effect.fn(function* (raw: string | undefined) { const { join, resolve } = yield* Path.Path; if (!raw || raw.trim().length === 0) { - return join(yield* HostProcessHomeDirectory, ".t3"); + return join(yield* HostProcess.HomeDirectory, ".t3"); } return resolve(yield* expandHomePath(raw.trim())); }); diff --git a/apps/server/src/preview/PortScanner.test.ts b/apps/server/src/preview/PortScanner.test.ts index fa4fd4402e93..8a6bf87d4699 100644 --- a/apps/server/src/preview/PortScanner.test.ts +++ b/apps/server/src/preview/PortScanner.test.ts @@ -6,7 +6,7 @@ import { PREVIEW_URL_MAX_LENGTH, type DiscoveredLocalServer, } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Net from "@t3tools/shared/Net"; import * as Cause from "effect/Cause"; import * as Clock from "effect/Clock"; @@ -74,7 +74,7 @@ const layerProbeFailure = ( reserveLoopbackPort: () => Effect.succeed(40_000), findAvailablePort: (preferred) => Effect.succeed(preferred), }), - Layer.succeed(HostProcessPlatform, "linux"), + Layer.succeed(HostProcess.Platform, "linux"), FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.Fetch, fetch))), ), ), @@ -86,7 +86,7 @@ const layerTestPortDiscovery = PortScanner.layer.pipe( layerNoProc, layerTestProcessRunner, layerTestIntegrationNet, - Layer.succeed(HostProcessPlatform, "win32"), + Layer.succeed(HostProcess.Platform, "win32"), FetchHttpClient.layer, ), ), @@ -122,7 +122,7 @@ const layerLsofScanner = (input: { reserveLoopbackPort: () => Effect.succeed(40_000), findAvailablePort: (preferred) => Effect.succeed(preferred), }), - Layer.succeed(HostProcessPlatform, "linux"), + Layer.succeed(HostProcess.Platform, "linux"), FetchHttpClient.layer.pipe( Layer.provide(Layer.succeed(FetchHttpClient.Fetch, input.fetch)), ), diff --git a/apps/server/src/preview/PortScanner.ts b/apps/server/src/preview/PortScanner.ts index eb573def97e0..9b1d9e966333 100644 --- a/apps/server/src/preview/PortScanner.ts +++ b/apps/server/src/preview/PortScanner.ts @@ -25,7 +25,7 @@ import { ThreadId, type DiscoveredLocalServer, } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Net from "@t3tools/shared/Net"; import { isLoopbackHost, LSOF_LOCAL_HOST_TOKENS } from "@t3tools/shared/preview"; import * as Cause from "effect/Cause"; @@ -342,7 +342,7 @@ export const make = Effect.gen(function* PortDiscoveryMake() { const net = yield* Net.NetService; const processRunner = yield* ProcessRunner.ProcessRunner; const fileSystem = yield* FileSystem.FileSystem; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.withScope); const stateRef = yield* Ref.make({ listeners: new Map(), diff --git a/apps/server/src/preview/PreviewBrowser.test.ts b/apps/server/src/preview/PreviewBrowser.test.ts index 6e984c2301e8..32c46fe24ab1 100644 --- a/apps/server/src/preview/PreviewBrowser.test.ts +++ b/apps/server/src/preview/PreviewBrowser.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { expect, it } from "@effect/vitest"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Deferred from "effect/Deferred"; import * as Crypto from "effect/Crypto"; import type * as Duration from "effect/Duration"; @@ -20,7 +20,7 @@ import * as PreviewBrowser from "./PreviewBrowser.ts"; // POSIX modes cannot be checked on NTFS, so follow the host like the Antigravity suite. const hostPlatform: NodeJS.Platform = - HostProcessPlatform.defaultValue() === "win32" ? "win32" : "linux"; + HostProcess.Platform.defaultValue() === "win32" ? "win32" : "linux"; const executableName = hostPlatform === "win32" ? "chrome-headless-shell.exe" : "chrome-headless-shell"; const ROOT = "chrome-headless-shell-fixture/"; @@ -105,8 +105,8 @@ const makeHarness = Effect.fn("test.makePreviewBrowser")(function* ( }, ...(options.wait === undefined ? {} : { wait: options.wait }), }).pipe( - Effect.provideService(HostProcessPlatform, hostPlatform), - Effect.provideService(HostProcessArchitecture, "x64"), + Effect.provideService(HostProcess.Platform, hostPlatform), + Effect.provideService(HostProcess.Architecture, "x64"), Effect.provideService( HttpClient.HttpClient, HttpClient.make((request) => diff --git a/apps/server/src/preview/PreviewBrowser.ts b/apps/server/src/preview/PreviewBrowser.ts index 8b64861ecbbb..1525bcde44cf 100644 --- a/apps/server/src/preview/PreviewBrowser.ts +++ b/apps/server/src/preview/PreviewBrowser.ts @@ -1,6 +1,6 @@ // @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest. import * as EffectNodeStream from "@effect/platform-node/NodeStream"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Clock from "effect/Clock"; import * as Context from "effect/Context"; @@ -175,8 +175,8 @@ export const makePreviewBrowser = Effect.fn("PreviewBrowser.make")(function* ( const http = yield* HttpClient.HttpClient; // Installs belong to the service, so they finish even when no caller is still waiting. const serviceScope = yield* Effect.scope; - const platform = yield* HostProcessPlatform; - const arch = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const arch = yield* HostProcess.Architecture; const release = options.release === undefined ? previewBrowserRelease(platform, arch) : options.release; const wait = options.wait ?? "45 seconds"; diff --git a/apps/server/src/preview/PreviewBrowserHost.test.ts b/apps/server/src/preview/PreviewBrowserHost.test.ts index 8fcfddff5cb5..5ae0a70752ca 100644 --- a/apps/server/src/preview/PreviewBrowserHost.test.ts +++ b/apps/server/src/preview/PreviewBrowserHost.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; @@ -67,7 +67,7 @@ const diagnose = (input: { setupCommand: "sudo t3 browser setup", }).pipe( Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), - Effect.provideService(HostProcessPlatform, input.platform), + Effect.provideService(HostProcess.Platform, input.platform), Effect.map((error) => ({ error, commands })), ); }; diff --git a/apps/server/src/preview/PreviewBrowserHost.ts b/apps/server/src/preview/PreviewBrowserHost.ts index 9ea56c4fa18b..de136cf41dad 100644 --- a/apps/server/src/preview/PreviewBrowserHost.ts +++ b/apps/server/src/preview/PreviewBrowserHost.ts @@ -7,7 +7,7 @@ * gets the command instead, and only the operator's explicit * `T3CODE_SERVER_BROWSER_SANDBOX=0` launches without it. */ -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Schema from "effect/Schema"; @@ -108,7 +108,7 @@ export const diagnoseLaunchFailure = Effect.fn("PreviewBrowserHost.diagnoseLaunc if (input.output.includes(NO_SANDBOX_SIGNATURE)) { return new PreviewBrowserSandboxError({ setupCommand }); } - if ((yield* HostProcessPlatform) !== "linux") return undefined; + if ((yield* HostProcess.Platform) !== "linux") return undefined; const libraries = yield* missingLibraries(input.executable); return libraries.length === 0 ? undefined @@ -147,7 +147,7 @@ export const missingLibraries = Effect.fn("PreviewBrowserHost.missingLibraries") * root, so the server checks it at startup. */ export const sandboxBlocked = Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return false; + if ((yield* HostProcess.Platform) !== "linux") return false; const fs = yield* FileSystem.FileSystem; const restricted = yield* fs.readFileString(USERNS_RESTRICTION).pipe( Effect.map((value) => value.trim() === "1"), diff --git a/apps/server/src/preview/ServerBrowser.ts b/apps/server/src/preview/ServerBrowser.ts index f3d9bea8b40f..072a022f90c0 100644 --- a/apps/server/src/preview/ServerBrowser.ts +++ b/apps/server/src/preview/ServerBrowser.ts @@ -42,11 +42,7 @@ import { SERVER_BROWSER_AUTOMATION_CLIENT_ID, type PreviewAppearancePreference, } from "@t3tools/contracts"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { normalizePreviewUrl } from "@t3tools/shared/preview"; import { resolvePreviewViewport } from "@t3tools/shared/previewViewport"; import * as NodeCrypto from "node:crypto"; @@ -476,7 +472,7 @@ const CLIPBOARD_SCRIPT = `(() => { const make = Effect.gen(function* () { const config = yield* ServerConfig.ServerConfig; - const host = { platform: yield* HostProcessPlatform, arch: yield* HostProcessArchitecture }; + const host = { platform: yield* HostProcess.Platform, arch: yield* HostProcess.Architecture }; const manager = yield* PreviewManager.PreviewManager; const broker = yield* PreviewAutomationBroker.PreviewAutomationBroker; const environment = yield* ServerEnvironment.ServerEnvironment; @@ -2367,7 +2363,7 @@ const make = Effect.gen(function* () { yield* manager.events.pipe(Stream.runForEach(mirrorManagerEvent), Effect.forkScoped); // Whoever runs the server learns the fix before anyone opens a tab. if ( - !PreviewBrowserHost.sandboxDisabled(yield* HostProcessEnvironment) && + !PreviewBrowserHost.sandboxDisabled(yield* HostProcess.Environment) && (yield* PreviewBrowserHost.sandboxBlocked) ) { yield* Effect.logWarning( diff --git a/apps/server/src/process/externalLauncher.test.ts b/apps/server/src/process/externalLauncher.test.ts index cd83cad6e968..6df4ea16db88 100644 --- a/apps/server/src/process/externalLauncher.test.ts +++ b/apps/server/src/process/externalLauncher.test.ts @@ -17,7 +17,7 @@ import * as Stream from "effect/Stream"; import * as TestClock from "effect/testing/TestClock"; import { ChildProcess, ChildProcessSpawner } from "effect/process"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import * as ExternalLauncher from "./externalLauncher.ts"; @@ -25,7 +25,7 @@ import * as ExternalLauncher from "./externalLauncher.ts"; // directory to a posix-mocked resolver as PATH. On a Windows host the temp // path carries a drive letter, so the posix `:` split shatters it; there is // no posix executable to find there anyway. -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; interface MockSpawnResult { readonly exitCode?: number; @@ -85,7 +85,7 @@ const layerTest = (input: { return Layer.mergeAll( ExternalLauncher.layer.pipe(Layer.provide(Layer.merge(NodeServices.layer, layerSpawner))), - Layer.succeed(HostProcessPlatform, input.platform), + Layer.succeed(HostProcess.Platform, input.platform), Layer.succeed( SpawnExecutableResolution, (command) => input.resolveExecutable?.(command) ?? command, @@ -1302,7 +1302,7 @@ it.effect("memoizes editor discovery and refreshes after the cache window", () = Effect.provide( Layer.mergeAll( layerLauncher, - Layer.succeed(HostProcessPlatform, "win32"), + Layer.succeed(HostProcess.Platform, "win32"), ConfigProvider.layer( ConfigProvider.fromEnv({ env: { @@ -1367,7 +1367,7 @@ it.effect("keeps scanning after the caller is interrupted and shares that scan", Effect.provide( Layer.mergeAll( layerLauncher, - Layer.succeed(HostProcessPlatform, "win32"), + Layer.succeed(HostProcess.Platform, "win32"), ConfigProvider.layer( ConfigProvider.fromEnv({ env: { diff --git a/apps/server/src/process/externalLauncher.ts b/apps/server/src/process/externalLauncher.ts index 6215f8653ffc..74e95b9ddcc4 100644 --- a/apps/server/src/process/externalLauncher.ts +++ b/apps/server/src/process/externalLauncher.ts @@ -19,7 +19,7 @@ import { type LaunchEditorInput, } from "@t3tools/contracts"; import { resolveEditorCommand } from "@t3tools/shared/editor"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { isCommandAvailable, resolveSpawnCommand, @@ -441,20 +441,20 @@ const buildAvailableEditors = Effect.fn("externalLauncher.buildAvailableEditors" const resolveBrowserLaunch = Effect.fn("externalLauncher.resolveBrowserLaunch")(function* ( target: string, ) { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const env = yield* readBrowserLaunchEnv; return buildBrowserLaunch(target, platform, env); }); const resolveAvailableEditors = Effect.fn("externalLauncher.resolveAvailableEditors")(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) }; return yield* buildAvailableEditors(platform, env).pipe(withPathDirectoryListings); }); const resolveFileManagerRevealKind = Effect.fn("externalLauncher.resolveFileManagerRevealKind")( function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) }; return yield* fileManagerRevealKindForPlatform(platform, env); }, @@ -519,7 +519,7 @@ const resolveEditorLaunch = Effect.fn("resolveEditorLaunch")(function* ( ExternalLauncherError, FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner > { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const env = { ...(yield* readBrowserLaunchEnv), ...(yield* readCommandLookupEnv) }; yield* Effect.annotateCurrentSpan({ "externalLauncher.editor": input.editor, diff --git a/apps/server/src/processRunner.test.ts b/apps/server/src/processRunner.test.ts index d241b3b3a4d4..3bec75351baf 100644 --- a/apps/server/src/processRunner.test.ts +++ b/apps/server/src/processRunner.test.ts @@ -9,7 +9,7 @@ import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import { TestClock } from "effect/testing"; import { ChildProcessSpawner } from "effect/process"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import * as ProcessRunner from "./processRunner.ts"; @@ -145,8 +145,8 @@ describe("runProcess", () => { args: ["repos", "pr", "list", "--source-branch", "feature & release"], env: { AZURE_CONFIG_DIR: "C:\\Users\\tester\\.azure" }, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Platform, "win32"), + Effect.provideService(HostProcess.Environment, { PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm", PATHEXT: ".COM;.EXE;.BAT;.CMD", }), @@ -407,7 +407,7 @@ describe("isWindowsCommandNotFound", () => { const isCommandNotFound = yield* ProcessRunner.isWindowsCommandNotFound( 1, "wird nicht als interner oder externer Befehl, betriebsfahiges Programm oder Batch-Datei erkannt", - ).pipe(Effect.provideService(HostProcessPlatform, "win32")); + ).pipe(Effect.provideService(HostProcess.Platform, "win32")); expect(isCommandNotFound).toBe(true); }), ); diff --git a/apps/server/src/project/AgentSessionScanner.ts b/apps/server/src/project/AgentSessionScanner.ts index 5177a948d945..454971a75ab8 100644 --- a/apps/server/src/project/AgentSessionScanner.ts +++ b/apps/server/src/project/AgentSessionScanner.ts @@ -44,11 +44,7 @@ import { parseGitHubRepositoryNameWithOwnerFromRemoteUrl, parseOriginUrlFromGitConfig, } from "@t3tools/shared/git"; -import { - HostProcessEnvironment, - HostProcessHomeDirectory, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { normalizeProjectPathForComparison } from "@t3tools/shared/path"; import * as ServerConfig from "../config.ts"; @@ -633,9 +629,9 @@ export const make = Effect.gen(function* () { const worktreesDir = path.resolve(serverConfig.worktreesDir); // Windows filesystems are case-insensitive, so path prefix checks there // must case fold. - const foldWorktreeCase = (yield* HostProcessPlatform) === "win32"; - const hostEnvironment = yield* HostProcessEnvironment; - const homeDir = yield* HostProcessHomeDirectory; + const foldWorktreeCase = (yield* HostProcess.Platform) === "win32"; + const hostEnvironment = yield* HostProcess.Environment; + const homeDir = yield* HostProcess.HomeDirectory; // `/private/tmp` is what macOS reports for sessions started in `/tmp`. const excludedProjectRoots = new Set( [homeDir, NodeOS.tmpdir(), "/tmp", "/private/tmp"].map((directory) => diff --git a/apps/server/src/project/ProjectSetupScriptRunner.ts b/apps/server/src/project/ProjectSetupScriptRunner.ts index 973617156277..c96f88087865 100644 --- a/apps/server/src/project/ProjectSetupScriptRunner.ts +++ b/apps/server/src/project/ProjectSetupScriptRunner.ts @@ -1,5 +1,5 @@ import { ProjectId, type ProjectScript } from "@t3tools/contracts"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { projectScriptRuntimeEnv, resolveProjectScripts, @@ -206,8 +206,8 @@ export const make = Effect.gen(function* () { const serverSettings = yield* ServerSettings.ServerSettingsService; const crypto = yield* Crypto.Crypto; const completionShell = resolveCompletionShell( - yield* HostProcessPlatform, - yield* HostProcessEnvironment, + yield* HostProcess.Platform, + yield* HostProcess.Environment, ); /** diff --git a/apps/server/src/provider/AntigravityInstallation.test.ts b/apps/server/src/provider/AntigravityInstallation.test.ts index ac256ef3dcd0..e99c2f684954 100644 --- a/apps/server/src/provider/AntigravityInstallation.test.ts +++ b/apps/server/src/provider/AntigravityInstallation.test.ts @@ -1,11 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { expect, it } from "@effect/vitest"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Crypto from "effect/Crypto"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; @@ -62,7 +57,7 @@ const zipFixtures = { // the host and let the fixture names follow; the suite is about install // mechanics, which are the same on every platform. const hostPlatform: NodeJS.Platform = - HostProcessPlatform.defaultValue() === "win32" ? "win32" : "linux"; + HostProcess.Platform.defaultValue() === "win32" ? "win32" : "linux"; const completeArchive = Buffer.from( hostPlatform === "win32" ? zipFixtures.windows : zipFixtures.complete, "base64", @@ -189,9 +184,9 @@ const makeHarness = Effect.fn("test.makeAntigravityInstallation")(function* ( }), }).pipe( Effect.provideService(FileSystem.FileSystem, trackedFs), - Effect.provideService(HostProcessPlatform, platform), - Effect.provideService(HostProcessArchitecture, "x64"), - Effect.provideService(HostProcessEnvironment, { PATH: options.path ?? "" }), + Effect.provideService(HostProcess.Platform, platform), + Effect.provideService(HostProcess.Architecture, "x64"), + Effect.provideService(HostProcess.Environment, { PATH: options.path ?? "" }), Effect.provideService( HttpClient.HttpClient, HttpClient.make((request) => @@ -259,7 +254,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => { }); expect(requests).toEqual([]); expect(validations).toEqual([]); - }).pipe(Effect.provideService(HostProcessIsExecutable, true)), + }).pipe(Effect.provideService(HostProcess.IsExecutable, true)), ); it.effect("verifies both files before activating a streamed download", () => @@ -734,7 +729,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => { // Real posix executables in a real temp dir, resolved by a linux-mocked // PATH walk; a Windows temp path cannot be split on `:`. - it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "honors explicit paths and reports invalid overrides without falling back", () => Effect.gen(function* () { diff --git a/apps/server/src/provider/AntigravityInstallation.ts b/apps/server/src/provider/AntigravityInstallation.ts index 4f78ee8ebb33..c57200f4afda 100644 --- a/apps/server/src/provider/AntigravityInstallation.ts +++ b/apps/server/src/provider/AntigravityInstallation.ts @@ -1,11 +1,7 @@ // @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest or free-space query. import * as EffectNodeStream from "@effect/platform-node/NodeStream"; import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime"; import * as Clock from "effect/Clock"; import * as Cause from "effect/Cause"; @@ -156,9 +152,9 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma const http = yield* HttpClient.HttpClient; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const serviceScope = yield* Effect.scope; - const platform = yield* HostProcessPlatform; - const arch = yield* HostProcessArchitecture; - const environment = yield* HostProcessEnvironment; + const platform = yield* HostProcess.Platform; + const arch = yield* HostProcess.Architecture; + const environment = yield* HostProcess.Environment; const releaseAsset = options.releaseAsset === undefined ? resolveAntigravityReleaseAsset(platform, arch) @@ -410,7 +406,7 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma yield* resolveNodeExecutable("Antigravity", environment).pipe( Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path), - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Platform, platform), Effect.mapError((cause) => installationError("verify", nodeRuntimeUnavailableMessage("Antigravity"), cause), ), diff --git a/apps/server/src/provider/CodexInstallation.test.ts b/apps/server/src/provider/CodexInstallation.test.ts index 88bc67690125..abc67ad55ea1 100644 --- a/apps/server/src/provider/CodexInstallation.test.ts +++ b/apps/server/src/provider/CodexInstallation.test.ts @@ -1,11 +1,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import * as ModelManifest from "./ModelManifest.ts"; import { expect, it } from "@effect/vitest"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Crypto from "effect/Crypto"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; @@ -66,9 +62,9 @@ const makeHarness = Effect.fn("test.makeCodexInstallation")(function* ( forceRefresh: Effect.succeed(ModelManifest.BUNDLED_MODEL_MANIFEST), refreshInBackground: Effect.void, }), - Effect.provideService(HostProcessPlatform, "darwin"), - Effect.provideService(HostProcessArchitecture, "arm64"), - Effect.provideService(HostProcessEnvironment, { PATH: input.local ? localDirectory : "" }), + Effect.provideService(HostProcess.Platform, "darwin"), + Effect.provideService(HostProcess.Architecture, "arm64"), + Effect.provideService(HostProcess.Environment, { PATH: input.local ? localDirectory : "" }), Effect.provideService( HttpClient.HttpClient, HttpClient.make((request) => diff --git a/apps/server/src/provider/CodexInstallation.ts b/apps/server/src/provider/CodexInstallation.ts index 7dfce2bba433..fa7876b1e92a 100644 --- a/apps/server/src/provider/CodexInstallation.ts +++ b/apps/server/src/provider/CodexInstallation.ts @@ -1,10 +1,6 @@ // @effect-diagnostics nodeBuiltinImport:off - Effect has no incremental digest. import { ProviderDriverKind, type ProviderInstallState } from "@t3tools/contracts"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveCommandPath, resolveSpawnCommand } from "@t3tools/shared/shell"; import * as Clock from "effect/Clock"; import * as Cause from "effect/Cause"; @@ -169,9 +165,9 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function const http = yield* HttpClient.HttpClient; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const serviceScope = yield* Effect.scope; - const platform = yield* HostProcessPlatform; - const environment = yield* HostProcessEnvironment; - const arch = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const environment = yield* HostProcess.Environment; + const arch = yield* HostProcess.Architecture; const asset = options.releaseAsset === undefined ? resolveCodexReleaseAsset(platform, arch) @@ -311,7 +307,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function args: ReadonlyArray, ) { const resolved = yield* resolveSpawnCommand(command, args).pipe( - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Platform, platform), ); const child = yield* spawner.spawn( ChildProcess.make(resolved.command, resolved.args, { shell: resolved.shell }), @@ -335,7 +331,7 @@ export const makeCodexInstallation = Effect.fn("makeCodexInstallation")(function const resolveLocal = Effect.fn("CodexInstallation.resolveLocal")( function* () { const executablePath = yield* resolveCommandPath("codex", { env: environment }).pipe( - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Platform, platform), Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path), ); diff --git a/apps/server/src/provider/CodexProvider.ts b/apps/server/src/provider/CodexProvider.ts index a8895e21ae32..cb1a5513cd01 100644 --- a/apps/server/src/provider/CodexProvider.ts +++ b/apps/server/src/provider/CodexProvider.ts @@ -47,7 +47,7 @@ import { type CodexRateLimitSnapshot, type CodexResetCreditsSummary, } from "./codexUsageLimits.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import packageJson from "../../package.json" with { type: "json" }; const isCodexAppServerSpawnError = Schema.is(CodexErrors.CodexAppServerSpawnError); const RATE_LIMITS_PROBE_TIMEOUT_MS = 3_000; @@ -376,7 +376,7 @@ export const withCodexAppServerClient = Effect.fn("withCodexAppServerClient")(fu // "CODEX_HOME points to '~/.codex_work', but that path does not exist". // Expand here for parity with `CodexTextGeneration`. const resolvedHomePath = input.homePath - ? expandHomePath(input.homePath, yield* HostProcessHomeDirectory) + ? expandHomePath(input.homePath, yield* HostProcess.HomeDirectory) : undefined; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const environment = { diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.test.ts b/apps/server/src/provider/Drivers/AntigravityDriver.test.ts index dc0bdd4d756f..f15cdfeff676 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.test.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.test.ts @@ -5,12 +5,7 @@ import { ProviderInstanceId, type AntigravitySettings, } from "@t3tools/contracts"; -import { - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Deferred from "effect/Deferred"; import * as Fiber from "effect/Fiber"; @@ -37,7 +32,7 @@ import { AntigravityDriver } from "./AntigravityDriver.ts"; import * as ProviderHostLive from "../ProviderHostLive.ts"; import * as ServerSecretStore from "../../auth/ServerSecretStore.ts"; -const hostPlatform = HostProcessPlatform.defaultValue(); +const hostPlatform = HostProcess.Platform.defaultValue(); const windowsHost = hostPlatform === "win32"; const decodeRequest = Schema.decodeEffect( Schema.fromJsonString( @@ -65,8 +60,8 @@ const makeHarness = Effect.fn("makeAntigravityDriverHarness")(function* ( const path = yield* Path.Path; const config = yield* ServerConfig.ServerConfig; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const nodePath = yield* HostProcessExecutablePath; - const baseEnv = yield* HostProcessEnvironment; + const nodePath = yield* HostProcess.ExecutablePath; + const baseEnv = yield* HostProcess.Environment; const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-antigravity-driver-" }); const instanceId = ProviderInstanceId.make(path.basename(root)); const mockAgentPath = yield* path.fromFileUrl( @@ -283,8 +278,8 @@ it.layer(layerTest)("AntigravityDriver", (it) => { expect(h.launches).toEqual([]); }).pipe( Effect.scoped, - Effect.provideService(HostProcessIsExecutable, true), - Effect.provideService(HostProcessEnvironment, { PATH: "" }), + Effect.provideService(HostProcess.IsExecutable, true), + Effect.provideService(HostProcess.Environment, { PATH: "" }), ), ); diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.ts b/apps/server/src/provider/Drivers/AntigravityDriver.ts index cdf938dbb4d0..c82565e8f2fe 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.ts @@ -1,7 +1,7 @@ import { withAgentDeviceEnvironment } from "@t3tools/provider-core/server/mcpSession"; import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions"; import { AntigravitySettings, ProviderDriverKind, ProviderSetupError } from "@t3tools/contracts"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSelfInvocation } from "@t3tools/shared/nodeRuntime"; import { NodeRuntimeUnavailableError, @@ -115,9 +115,9 @@ export const AntigravityDriver: ProviderDriver< const authConfigIssue = antigravityAuthConfigIssue(auth); const processEnvironment = yield* mergeProviderInstanceEnvironment(environment); const userHome = resolveAntigravityUserHome( - yield* HostProcessPlatform, + yield* HostProcess.Platform, processEnvironment, - yield* HostProcessHomeDirectory, + yield* HostProcess.HomeDirectory, ); const directories = yield* resolveAntigravityInstanceDirectories( host.paths.stateDir, diff --git a/apps/server/src/provider/Drivers/AntigravityUsage.ts b/apps/server/src/provider/Drivers/AntigravityUsage.ts index d99539b555c1..ee5369b21716 100644 --- a/apps/server/src/provider/Drivers/AntigravityUsage.ts +++ b/apps/server/src/provider/Drivers/AntigravityUsage.ts @@ -17,7 +17,7 @@ import type { ProviderUsageReader, ProviderUsageScan, } from "@t3tools/provider-core/server/usage"; -import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Crypto from "effect/Crypto"; import * as Effect from "effect/Effect"; @@ -44,12 +44,12 @@ const make = Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; const host = yield* ProviderHost.ProviderHost; - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const cache = makeAntigravityUsageCache(); /** `ANTIGRAVITY_DATA_DIR` (comma-separated) or the defaults, canonicalized. */ const dataRoots = Effect.gen(function* () { - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const configured = hostEnvironment["ANTIGRAVITY_DATA_DIR"] ?.split(",") .map((value) => value.trim()) diff --git a/apps/server/src/provider/Drivers/ClaudeDriver.ts b/apps/server/src/provider/Drivers/ClaudeDriver.ts index 9a43be65aac4..be7872a7df28 100644 --- a/apps/server/src/provider/Drivers/ClaudeDriver.ts +++ b/apps/server/src/provider/Drivers/ClaudeDriver.ts @@ -71,7 +71,7 @@ import { makeClaudeContinuationGroupKey, resolveClaudeHomePath, } from "./ClaudeHome.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const decodeClaudeSettings = Schema.decodeSync(ClaudeSettings); const DRIVER_KIND = ProviderDriverKind.make("claudeAgent"); @@ -139,7 +139,7 @@ export const ClaudeDriver: ProviderDriver(effect: Effect.Effect) => effect.pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(SpawnExecutableResolution, () => input.resolvedCommand), Effect.provideService(ClaudeExecutableFileCheck, (filePath) => existing.has(filePath)), ); @@ -28,7 +28,7 @@ describe("resolveClaudeSdkExecutablePath", () => { Effect.gen(function* () { expect( yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService(SpawnExecutableResolution, () => { throw new Error("must not resolve on non-Windows platforms"); }), diff --git a/apps/server/src/provider/Drivers/ClaudeExecutable.ts b/apps/server/src/provider/Drivers/ClaudeExecutable.ts index fe1192d1df47..a7d409b84d9b 100644 --- a/apps/server/src/provider/Drivers/ClaudeExecutable.ts +++ b/apps/server/src/provider/Drivers/ClaudeExecutable.ts @@ -2,7 +2,7 @@ import * as NodeFS from "node:fs"; import * as NodePath from "node:path"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; @@ -67,7 +67,7 @@ export const ClaudeExecutableFileCheck = Context.Reference( */ export const resolveClaudeSdkExecutablePath = Effect.fn("resolveClaudeSdkExecutablePath")( function* (binaryPath: string, environment: NodeJS.ProcessEnv): Effect.fn.Return { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (platform !== "win32") { return binaryPath; } diff --git a/apps/server/src/provider/Drivers/ClaudeHome.ts b/apps/server/src/provider/Drivers/ClaudeHome.ts index 7ebfffa3fddb..78bb34c2fd9e 100644 --- a/apps/server/src/provider/Drivers/ClaudeHome.ts +++ b/apps/server/src/provider/Drivers/ClaudeHome.ts @@ -4,7 +4,7 @@ import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const quotePath = Schema.encodeSync(Schema.fromJsonString(Schema.String)); @@ -20,7 +20,7 @@ export const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function environment?: NodeJS.ProcessEnv, ): Effect.fn.Return { const path = yield* Path.Path; - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const homePath = config.homePath.trim(); if (homePath.length > 0) { return path.resolve(expandHomePath(homePath, home)); diff --git a/apps/server/src/provider/Drivers/ClaudeSkills.ts b/apps/server/src/provider/Drivers/ClaudeSkills.ts index 3082f53b0280..40ab84d65ed6 100644 --- a/apps/server/src/provider/Drivers/ClaudeSkills.ts +++ b/apps/server/src/provider/Drivers/ClaudeSkills.ts @@ -19,7 +19,7 @@ import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { fromLenientJson } from "@t3tools/shared/schemaJson"; import { parse as parseYamlDocument } from "yaml"; @@ -242,7 +242,7 @@ const readSkillOverrides = Effect.fn("readSkillOverrides")(function* ( ): Effect.fn.Return, never, FileSystem.FileSystem | Path.Path> { const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const overridesByName = new Map(); const repositoryRoot = cwd === undefined ? undefined : yield* findRepositoryRoot(cwd); @@ -295,7 +295,7 @@ const resolveClaudeConfigDirPath = Effect.fn("resolveClaudeConfigDirPath")(funct cwd?: string, ): Effect.fn.Return { const path = yield* Path.Path; - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const homePath = config.homePath.trim(); if (homePath.length > 0) { return path.resolve(expandHomePath(homePath, home)); diff --git a/apps/server/src/provider/Drivers/CodexDriver.test.ts b/apps/server/src/provider/Drivers/CodexDriver.test.ts index 54053e1dc9b8..7ac25a2e6bc1 100644 --- a/apps/server/src/provider/Drivers/CodexDriver.test.ts +++ b/apps/server/src/provider/Drivers/CodexDriver.test.ts @@ -7,7 +7,7 @@ import * as NodeOS from "node:os"; import * as NodePath from "node:path"; import { expect, it } from "@effect/vitest"; import { EnvironmentId, ProviderInstanceId, ProviderSessionId, ThreadId } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Deferred from "effect/Deferred"; import * as Fiber from "effect/Fiber"; @@ -88,7 +88,7 @@ const layerDeps = ServerConfig.layerTest(process.cwd(), { const layerTest = ProviderHostLive.layer.pipe(Layer.provideMerge(layerDeps)); // The `#!/bin/sh` stub below cannot be resolved as an executable on Windows. -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; const noSpawn = ChildProcessSpawner.make(() => Effect.die("Disabled Codex must not spawn a process"), diff --git a/apps/server/src/provider/Drivers/CodexDriver.ts b/apps/server/src/provider/Drivers/CodexDriver.ts index e1fadbcd175e..8aa546d103e1 100644 --- a/apps/server/src/provider/Drivers/CodexDriver.ts +++ b/apps/server/src/provider/Drivers/CodexDriver.ts @@ -77,7 +77,7 @@ import { codexUsageReader } from "./codexUsage.ts"; import * as CodexInstallation from "../CodexInstallation.ts"; import * as ServerSecretStore from "../../auth/ServerSecretStore.ts"; import * as ServerEnvironment from "../../environment/ServerEnvironment.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const decodeCodexSettings = Schema.decodeSync(CodexSettings); const DRIVER_KIND = ProviderDriverKind.make("codex"); @@ -179,7 +179,7 @@ export const CodexDriver: ProviderDriver { const path = yield* Path.Path; - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const sharedHomePath = resolveHomePath(path, home, config.homePath); const shadowHomePath = config.shadowHomePath.trim(); if (shadowHomePath.length === 0) { diff --git a/apps/server/src/provider/Drivers/claudeUsage.ts b/apps/server/src/provider/Drivers/claudeUsage.ts index 38df3146e097..2bab4f5e92b6 100644 --- a/apps/server/src/provider/Drivers/claudeUsage.ts +++ b/apps/server/src/provider/Drivers/claudeUsage.ts @@ -17,7 +17,7 @@ import { type TranscriptUsageFormat, type UsageRecord, } from "@t3tools/provider-core/server/usage"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; /** * Parses one line of a Claude Code transcript. @@ -111,7 +111,7 @@ export const claudeUsageReader: ProviderUsageReader = // An undecodable config has no trustworthy home to read. if (config === undefined) return []; const path = yield* Path.Path; - const homeDirectory = yield* HostProcessHomeDirectory; + const homeDirectory = yield* HostProcess.HomeDirectory; const configured = config.homePath.trim(); const home = configured ? expandHomePath(configured, homeDirectory) diff --git a/apps/server/src/provider/ProviderInstanceRegistry.test.ts b/apps/server/src/provider/ProviderInstanceRegistry.test.ts index 7c6b191a8b84..49d575f7eb66 100644 --- a/apps/server/src/provider/ProviderInstanceRegistry.test.ts +++ b/apps/server/src/provider/ProviderInstanceRegistry.test.ts @@ -39,11 +39,7 @@ import * as ProviderLatestVersions from "@t3tools/provider-core/server/ProviderL import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderSessions"; import type { GrokSettings } from "@t3tools/provider-grok/settings"; import type { CursorSettings } from "@t3tools/provider-cursor/settings"; -import { - HostProcessHomeDirectory, - HostProcessPlatform, - isHostWindows, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -156,7 +152,7 @@ const makeTildeProviderFixtures = Effect.fn( )(function* () { const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const homePath = yield* HostProcessHomeDirectory; + const homePath = yield* HostProcess.HomeDirectory; const fixtureDir = yield* fileSystem.makeTempDirectoryScoped({ directory: homePath, prefix: ".t3-provider-path-test-", @@ -349,7 +345,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => { it.live("reports Codex's answer when a redemption changed nothing", () => Effect.gen(function* () { - if (yield* isHostWindows) return; + if (yield* HostProcess.isWindows) return; const fileSystem = yield* FileSystem.FileSystem; const fixtures = yield* makeTildeProviderFixtures(); yield* fileSystem.writeFileString( @@ -386,7 +382,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => { it.live("runs Codex and Claude readiness probes from configured tilde paths", () => Effect.gen(function* () { - if (yield* isHostWindows) return; + if (yield* HostProcess.isWindows) return; const fixtures = yield* makeTildeProviderFixtures(); @@ -503,7 +499,7 @@ describe("ProviderInstanceRegistry — multi-instance codex slice", () => { return { outcome, after: yield* instance!.snapshot.getSnapshot }; }).pipe( // macOS logins live in the Keychain, where resets are never read. - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provide(layerTest), ); diff --git a/apps/server/src/provider/acp/AcpSessionRuntime.processTree.test.ts b/apps/server/src/provider/acp/AcpSessionRuntime.processTree.test.ts index 13a7dd6c2c81..81d499733caf 100644 --- a/apps/server/src/provider/acp/AcpSessionRuntime.processTree.test.ts +++ b/apps/server/src/provider/acp/AcpSessionRuntime.processTree.test.ts @@ -5,7 +5,7 @@ import * as NodePath from "node:path"; import * as NodeURL from "node:url"; import { describe, expect, it, vi } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Clock from "effect/Clock"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; @@ -155,7 +155,7 @@ describe("terminatePosixOwnedProcessTree", () => { it.live("preserves exact argv and strips wrapper-only environment before exec", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const lease = AcpSessionRuntime.makeLinuxCgroupController().create(); if (lease === undefined) return; const scratchRoot = NodePath.join(process.cwd(), "tmp"); @@ -235,7 +235,7 @@ describe("terminatePosixOwnedProcessTree", () => { ); it("contains a packaged-runtime command without requiring cgroup delegation", () => { - if (HostProcessPlatform.defaultValue() !== "linux") return; + if (HostProcess.Platform.defaultValue() !== "linux") return; const scratchRoot = NodePath.join(process.cwd(), "tmp"); NodeFS.mkdirSync(scratchRoot, { recursive: true }); const scratch = NodeFS.mkdtempSync(NodePath.join(scratchRoot, "acp-cgroup-wrapper-fake-")); @@ -316,7 +316,7 @@ describe("terminatePosixOwnedProcessTree", () => { it.live("kills a post-TERM detached double fork without touching an unrelated sentinel", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const controller = AcpSessionRuntime.makeLinuxCgroupController(); const lease = controller.create(); if (lease === undefined) return; @@ -531,7 +531,7 @@ describe("terminatePosixOwnedProcessTree", () => { it.live("finds a child forked by a non-leader pthread", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) !== "linux") return; + if ((yield* HostProcess.Platform) !== "linux") return; const scratchRoot = NodePath.join(process.cwd(), "tmp"); NodeFS.mkdirSync(scratchRoot, { recursive: true }); const scratch = NodeFS.mkdtempSync(NodePath.join(scratchRoot, "acp-pthread-spawn-")); diff --git a/apps/server/src/provider/antigravityAuthSupport.test.ts b/apps/server/src/provider/antigravityAuthSupport.test.ts index 8f794b59a1af..a1be101b1436 100644 --- a/apps/server/src/provider/antigravityAuthSupport.test.ts +++ b/apps/server/src/provider/antigravityAuthSupport.test.ts @@ -5,11 +5,7 @@ import * as NodeCrypto from "@effect/platform-node/NodeCrypto"; import * as NodePath from "@effect/platform-node/NodePath"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { ProviderInstanceId } from "@t3tools/contracts"; -import { - HostProcessExecutablePath, - HostProcessIsExecutable, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { describe, expect, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -574,8 +570,8 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => { expect(profile.browserCommand).not.toContain("/packaged/t3"); expect(yield* fs.exists(profile.acpDirectory)).toBe(true); }).pipe( - Effect.provideService(HostProcessIsExecutable, true), - Effect.provideService(HostProcessExecutablePath, "/packaged/t3"), + Effect.provideService(HostProcess.IsExecutable, true), + Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"), ), ); @@ -601,7 +597,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => { }); } expect(yield* fs.exists(profileDirectory)).toBe(false); - }).pipe(Effect.provideService(HostProcessIsExecutable, true)), + }).pipe(Effect.provideService(HostProcess.IsExecutable, true)), ); it.effect("preflights the no-browser helper and creates private directories only", () => @@ -616,7 +612,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => { expect(profile.geminiHome).toBe(path.join(temporaryDirectory, "profile")); expect(yield* fs.exists(profile.acpDirectory)).toBe(true); expect(yield* fs.exists(profile.tokenPath)).toBe(false); - if ((yield* HostProcessPlatform) !== "win32") { + if ((yield* HostProcess.Platform) !== "win32") { expect((yield* fs.stat(profile.geminiHome)).mode & 0o777).toBe(0o700); expect((yield* fs.stat(profile.acpDirectory)).mode & 0o777).toBe(0o700); } diff --git a/apps/server/src/provider/antigravityAuthSupport.ts b/apps/server/src/provider/antigravityAuthSupport.ts index 4b0e769cde1d..a78ba04aa360 100644 --- a/apps/server/src/provider/antigravityAuthSupport.ts +++ b/apps/server/src/provider/antigravityAuthSupport.ts @@ -2,7 +2,7 @@ import * as NodeFSP from "node:fs/promises"; import type { AntigravityAuthMethod, ProviderInstanceId } from "@t3tools/contracts"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveNodeExecutable, nodeRuntimeUnavailableMessage } from "@t3tools/shared/nodeRuntime"; import * as Crypto from "effect/Crypto"; import * as Effect from "effect/Effect"; @@ -315,13 +315,13 @@ export const prepareAntigravityProfile = Effect.fn("prepareAntigravityProfile")( const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const platform = input.platform ?? (yield* HostProcessPlatform); + const platform = input.platform ?? (yield* HostProcess.Platform); const userHome = input.userHome ?? resolveAntigravityUserHome( platform, input.baseEnv ?? process.env, - yield* HostProcessHomeDirectory, + yield* HostProcess.HomeDirectory, ); const runtimeExecutablePath = input.runtimeExecutablePath ?? diff --git a/apps/server/src/provider/claudeResetCredits.test.ts b/apps/server/src/provider/claudeResetCredits.test.ts index 0dcb409ffa3c..a928e64c9fd5 100644 --- a/apps/server/src/provider/claudeResetCredits.test.ts +++ b/apps/server/src/provider/claudeResetCredits.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { it as effectIt } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -111,7 +111,7 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => { ); }); const credits = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provideService(HttpClient.HttpClient, client), ); expect(credits).toEqual({ availableCount: 1, nextCreditId: "grant_a" }); @@ -122,11 +122,11 @@ effectIt.layer(NodeServices.layer)("readClaudeResetCredits", (it) => { Effect.gen(function* () { const { configDir } = yield* writeLogin; const darwin = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService(HttpClient.HttpClient, refuseRequests), ); const limited = yield* ClaudeResetCredits.readClaudeResetCredits(configDir, "2.1.0").pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provideService(HttpClient.HttpClient, respond(429, {})), ); expect([darwin, limited]).toEqual([undefined, undefined]); @@ -147,7 +147,7 @@ const consume = (client: HttpClient.HttpClient, ids = { grantId: "grant_a", requ version: "2.1.0", ...ids, }).pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provideService(HttpClient.HttpClient, client), Effect.result, ); @@ -228,7 +228,7 @@ effectIt.layer(NodeServices.layer)("consumeClaudeResetCredit", (it) => { grantId: "grant_a", requestId: "r-1", }).pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provideService(HttpClient.HttpClient, client), Effect.result, Effect.forkChild, diff --git a/apps/server/src/provider/claudeResetCredits.ts b/apps/server/src/provider/claudeResetCredits.ts index c37a0dfb2d8d..e381fa7cabe2 100644 --- a/apps/server/src/provider/claudeResetCredits.ts +++ b/apps/server/src/provider/claudeResetCredits.ts @@ -11,7 +11,7 @@ import type { ProviderConsumeResetCreditOutcome, ServerProviderResetCredits, } from "@t3tools/contracts"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -149,7 +149,7 @@ const readJson = (schema: S, file: string) => const readAccessToken = (configDir: string) => Effect.gen(function* () { - if ((yield* HostProcessPlatform) === "darwin") return undefined; + if ((yield* HostProcess.Platform) === "darwin") return undefined; const path = yield* Path.Path; const credentials = yield* readJson(Credentials, path.join(configDir, ".credentials.json")); return credentials.claudeAiOauth?.accessToken?.trim() || undefined; @@ -195,7 +195,7 @@ export const claudeAccountConfigPath = Effect.fn("claudeAccountConfigPath")(func const path = yield* Path.Path; return configDir ? path.join(configDir, ".claude.json") - : path.join(yield* HostProcessHomeDirectory, ".claude.json"); + : path.join(yield* HostProcess.HomeDirectory, ".claude.json"); }); const CLAIM_OUTCOMES = { diff --git a/apps/server/src/provider/providerInstallation.test.ts b/apps/server/src/provider/providerInstallation.test.ts index ae2064fc85fa..f71f7c1ecfd8 100644 --- a/apps/server/src/provider/providerInstallation.test.ts +++ b/apps/server/src/provider/providerInstallation.test.ts @@ -5,7 +5,7 @@ import { ProviderInstanceId, type ProviderInstallState, } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; @@ -215,7 +215,7 @@ describe("provider installation routing", () => { Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-provider-install-route-" }); const binary = platform === "win32" ? "agy-test.exe" : "agy-test"; const executable = path.join(directory, binary); diff --git a/apps/server/src/provider/providerMaintenanceRunner.test.ts b/apps/server/src/provider/providerMaintenanceRunner.test.ts index 3b820093542c..26b33a35f4a2 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.test.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.test.ts @@ -20,7 +20,7 @@ import * as Stream from "effect/Stream"; import * as TestClock from "effect/testing/TestClock"; import { HttpClient, HttpClientResponse } from "effect/http"; import { ChildProcessSpawner } from "effect/process"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import * as ProviderRegistry from "./ProviderRegistry.ts"; @@ -45,7 +45,7 @@ const encoder = new TextEncoder(); // `{ command, args }` assertions below hold deterministically on any host // (including Windows). Windows-specific resolution is covered by the dedicated // win32 case at the end of this suite. -const layerNonWindowsPlatform = Layer.succeed(HostProcessPlatform, "linux"); +const layerNonWindowsPlatform = Layer.succeed(HostProcess.Platform, "linux"); function lifecycleFor(provider: ProviderDriverKind): ProviderMaintenanceCapabilities { if (provider === NATIVE_CLI_DRIVER) { @@ -962,8 +962,8 @@ describe("providerMaintenanceRunner", () => { }).pipe( Effect.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, "win32"), - Layer.succeed(HostProcessEnvironment, { + Layer.succeed(HostProcess.Platform, "win32"), + Layer.succeed(HostProcess.Environment, { PATH: "C:\\fake\\npm", PATHEXT: ".COM;.EXE;.BAT;.CMD", }), diff --git a/apps/server/src/resourceTelemetry/HostResources.ts b/apps/server/src/resourceTelemetry/HostResources.ts index 607172b0f109..c3bb1a1894bc 100644 --- a/apps/server/src/resourceTelemetry/HostResources.ts +++ b/apps/server/src/resourceTelemetry/HostResources.ts @@ -1,6 +1,6 @@ import * as NodeOS from "node:os"; import type { HostResourcesSnapshot } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cache from "effect/Cache"; import * as Context from "effect/Context"; import * as DateTime from "effect/DateTime"; @@ -40,7 +40,7 @@ function darwinAvailableMemory(output: string): number | null { const make = Effect.fn("makeHostResources")(function* () { const fs = yield* FileSystem.FileSystem; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const sample = Effect.fn("HostResources.sample")(function* () { diff --git a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts index 7032691f0dd0..d53e1a091f47 100644 --- a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts +++ b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts @@ -1,9 +1,5 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { afterEach, assert, describe, expect, it, vi } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -13,7 +9,7 @@ import * as ResourceMonitorBinary from "./ResourceMonitorBinary.ts"; // The override checks POSIX exec bits on a real file under a linux platform // mock; NTFS never reports those bits, so the check cannot be satisfied there. -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; describe("ResourceMonitorBinary", () => { afterEach(() => { @@ -34,9 +30,9 @@ describe("ResourceMonitorBinary", () => { const service = yield* ResourceMonitorBinary.make().pipe( Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), - Effect.provideService(HostProcessPlatform, "win32"), - Effect.provideService(HostProcessArchitecture, "arm64"), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Platform, "win32"), + Effect.provideService(HostProcess.Architecture, "arm64"), + Effect.provideService(HostProcess.Environment, { T3CODE_RESOURCE_MONITOR_PATH: binaryPath, }), ); @@ -58,10 +54,10 @@ describe("ResourceMonitorBinary", () => { const service = yield* ResourceMonitorBinary.make().pipe( Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessArchitecture, "x64"), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Architecture, "x64"), Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { T3CODE_RESOURCE_MONITOR_PATH: binaryPath, }), ); @@ -82,9 +78,9 @@ describe("ResourceMonitorBinary", () => { const service = yield* ResourceMonitorBinary.make().pipe( Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), - Effect.provideService(HostProcessPlatform, "freebsd"), - Effect.provideService(HostProcessArchitecture, "ia32"), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Platform, "freebsd"), + Effect.provideService(HostProcess.Architecture, "ia32"), + Effect.provideService(HostProcess.Environment, { T3CODE_RESOURCE_MONITOR_PATH: binaryPath, }), ); @@ -105,10 +101,10 @@ describe("ResourceMonitorBinary", () => { const service = yield* ResourceMonitorBinary.make().pipe( Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessArchitecture, "x64"), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Architecture, "x64"), Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "gnu"), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { T3CODE_RESOURCE_MONITOR_PATH: binaryPath, }), ); @@ -127,9 +123,9 @@ describe("ResourceMonitorBinary", () => { }); const service = yield* ResourceMonitorBinary.make().pipe( Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), - Effect.provideService(HostProcessPlatform, "freebsd"), - Effect.provideService(HostProcessArchitecture, "ia32"), - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Platform, "freebsd"), + Effect.provideService(HostProcess.Architecture, "ia32"), + Effect.provideService(HostProcess.Environment, {}), ); const error = yield* Effect.flip(service.resolve); @@ -145,10 +141,10 @@ describe("ResourceMonitorBinary", () => { }); const service = yield* ResourceMonitorBinary.make().pipe( Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessArchitecture, "x64"), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Architecture, "x64"), Effect.provideService(ResourceMonitorBinary.ResourceMonitorHostLinuxLibc, "musl"), - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Environment, {}), ); const error = yield* Effect.flip(service.resolve); diff --git a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts index c4b9d6a85149..035a9364a497 100644 --- a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts +++ b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts @@ -1,8 +1,4 @@ -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -139,9 +135,9 @@ export const make = Effect.fn("resourceTelemetry.resourceMonitorBinary.make")(fu const config = yield* ServerConfig.ServerConfig; const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; - const architecture = yield* HostProcessArchitecture; - const environment = yield* HostProcessEnvironment; + const platform = yield* HostProcess.Platform; + const architecture = yield* HostProcess.Architecture; + const environment = yield* HostProcess.Environment; const linuxLibc = platform === "linux" ? yield* ResourceMonitorHostLinuxLibc : undefined; const executableName = binaryName(platform); const platformKey = resourceMonitorPlatformKey(platform, architecture); diff --git a/apps/server/src/review/ReviewService.ts b/apps/server/src/review/ReviewService.ts index ef7a0e31590f..d8e27c9d6dd7 100644 --- a/apps/server/src/review/ReviewService.ts +++ b/apps/server/src/review/ReviewService.ts @@ -20,7 +20,7 @@ import * as GitVcsDriver from "../vcs/GitVcsDriver.ts"; import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts"; import * as ServerSettings from "../serverSettings.ts"; import { isFilesystemRoot, managedWorktreesDirectories } from "../worktreesDirectory.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; export class ReviewService extends Context.Service< ReviewService, @@ -74,7 +74,7 @@ export const make = Effect.gen(function* () { const worktreesDirectories = yield* settings.getSettings.pipe( Effect.orElseSucceed(() => ({ worktreesDirectory: "", previousWorktreesDirectories: [] })), ); - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const [candidate, workspaceRoot, worktreesRoots] = yield* Effect.all([ canonicalizePath(cwd), canonicalizePath(config.cwd), diff --git a/apps/server/src/sourceControl/SourceControlRepositoryService.ts b/apps/server/src/sourceControl/SourceControlRepositoryService.ts index e595b4028cee..d17f860050bb 100644 --- a/apps/server/src/sourceControl/SourceControlRepositoryService.ts +++ b/apps/server/src/sourceControl/SourceControlRepositoryService.ts @@ -29,7 +29,7 @@ import { import * as GitVcsDriver from "../vcs/GitVcsDriver.ts"; import * as BitbucketApi from "@t3tools/source-control-bitbucket/server/BitbucketApi"; import * as SourceControlProviderRegistry from "./SourceControlProviderRegistry.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const isSourceControlRepositoryError = Schema.is(SourceControlRepositoryError); const isSourceControlProviderError = Schema.is(SourceControlProviderError); const isBitbucketRepositoryLocatorError = Schema.is(BitbucketApi.BitbucketRepositoryLocatorError); @@ -214,7 +214,7 @@ export const make = Effect.gen(function* () { }); } - return path.resolve(expandHomePath(trimmed, yield* HostProcessHomeDirectory)); + return path.resolve(expandHomePath(trimmed, yield* HostProcess.HomeDirectory)); }, ); diff --git a/apps/server/src/storageCleanup.ts b/apps/server/src/storageCleanup.ts index c0ad95a63c61..7804ed42ef10 100644 --- a/apps/server/src/storageCleanup.ts +++ b/apps/server/src/storageCleanup.ts @@ -38,7 +38,7 @@ import * as TerminalManager from "./terminal/Manager.ts"; import { isFilesystemRoot, managedWorktreesDirectories } from "./worktreesDirectory.ts"; import * as GitVcsDriver from "./vcs/GitVcsDriver.ts"; import { withWorkspaceLease } from "./workspace/workspaceLease.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const decodeCleanupThread = Schema.decodeUnknownEffect( Schema.fromJsonString(OrchestrationV2AppThreadJson), @@ -214,7 +214,7 @@ export const make = Effect.gen(function* () { serverSettings, config.worktreesDir, path, - yield* HostProcessHomeDirectory, + yield* HostProcess.HomeDirectory, )) { // An unmounted drive only skips its own worktrees. const root = yield* fs.exists(directory).pipe( diff --git a/apps/server/src/telemetry/AnalyticsService.test.ts b/apps/server/src/telemetry/AnalyticsService.test.ts index e0a4786ece6f..73f844e4017c 100644 --- a/apps/server/src/telemetry/AnalyticsService.test.ts +++ b/apps/server/src/telemetry/AnalyticsService.test.ts @@ -11,7 +11,7 @@ import * as HttpClientError from "effect/http/HttpClientError"; import * as HttpServer from "effect/http/HttpServer"; import * as HttpServerRequest from "effect/http/HttpServerRequest"; import * as HttpServerResponse from "effect/http/HttpServerResponse"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as ServerConfig from "../config.ts"; import { getTelemetryIdentifier } from "./Identify.ts"; @@ -105,8 +105,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => { ), Layer.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, "win32"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, "win32"), + Layer.succeed(HostProcess.Architecture, "x64"), layerAcceptThenFailClient(batches), ), ), @@ -167,8 +167,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => { Layer.provide(layerConfig), Layer.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, "linux"), - Layer.succeed(HostProcessArchitecture, "arm64"), + Layer.succeed(HostProcess.Platform, "linux"), + Layer.succeed(HostProcess.Architecture, "arm64"), ), ), Layer.provideMerge(NodeHttpServer.layerTest), @@ -257,8 +257,8 @@ it.layer(NodeServices.layer)("AnalyticsService test", (it) => { Layer.provide(layerConfig), Layer.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, "linux"), - Layer.succeed(HostProcessArchitecture, "arm64"), + Layer.succeed(HostProcess.Platform, "linux"), + Layer.succeed(HostProcess.Architecture, "arm64"), ), ), Layer.provideMerge(NodeHttpServer.layerTest), diff --git a/apps/server/src/telemetry/AnalyticsService.ts b/apps/server/src/telemetry/AnalyticsService.ts index 3d10e93a26d6..864979759588 100644 --- a/apps/server/src/telemetry/AnalyticsService.ts +++ b/apps/server/src/telemetry/AnalyticsService.ts @@ -8,7 +8,7 @@ * * @module AnalyticsService */ -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import type { ClientOs } from "@t3tools/contracts"; import * as Clock from "effect/Clock"; import * as Config from "effect/Config"; @@ -136,8 +136,8 @@ export const make = Effect.gen(function* () { // The background flush and the shutdown flush must not send the same batch at once. const flushLock = yield* Semaphore.make(1); const clientType = serverConfig.mode === "desktop" ? "desktop-app" : "cli-web-client"; - const hostPlatform = yield* HostProcessPlatform; - const hostArchitecture = yield* HostProcessArchitecture; + const hostPlatform = yield* HostProcess.Platform; + const hostArchitecture = yield* HostProcess.Architecture; const enqueueBufferedEvent = ( uuid: string, diff --git a/apps/server/src/telemetry/Identify.ts b/apps/server/src/telemetry/Identify.ts index a0e6c1c7ecfd..6704300f87a4 100644 --- a/apps/server/src/telemetry/Identify.ts +++ b/apps/server/src/telemetry/Identify.ts @@ -9,7 +9,7 @@ import * as Schema from "effect/Schema"; import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite"; import * as ServerConfig from "../config.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; /** * Codex writes `tokens` only for ChatGPT logins and omits the key for API-key, @@ -312,6 +312,6 @@ export const getTelemetryIdentifierForHome = Effect.fn("getTelemetryIdentifierFo ); export const getTelemetryIdentifier = Effect.flatMap( - HostProcessHomeDirectory, + HostProcess.HomeDirectory, getTelemetryIdentifierForHome, ); diff --git a/apps/server/src/terminal/Manager.test.ts b/apps/server/src/terminal/Manager.test.ts index 5a40f7bbb933..9889f33d4a8f 100644 --- a/apps/server/src/terminal/Manager.test.ts +++ b/apps/server/src/terminal/Manager.test.ts @@ -12,7 +12,7 @@ import { ServerSettingsError, TerminalProviderInstanceNotFoundError, } from "@t3tools/contracts"; -import { HostProcessPlatform, HostProcessArchitecture } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Data from "effect/Data"; import * as Clock from "effect/Clock"; import * as Deferred from "effect/Deferred"; @@ -315,7 +315,7 @@ const createManager = ( ); const layerWithHostPlatform = (platform: NodeJS.Platform) => - Layer.succeed(HostProcessPlatform, platform); + Layer.succeed(HostProcess.Platform, platform); // Apply the existing line policy, then find the longest code-point-aligned byte tail. function retainedHistory(text: string, maxLines: number, maxBytes = Infinity): string { @@ -619,7 +619,7 @@ it.layer( it.effect("preserves non-notFound cwd stat failures", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) === "win32") return; + if ((yield* HostProcess.Platform) === "win32") return; const path = yield* Path.Path; @@ -1826,7 +1826,7 @@ it.layer( it.effect("retries with fallback shells when preferred shell spawn fails", () => Effect.gen(function* () { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const missingShell = platform === "win32" ? "C:\\definitely\\missing-shell.exe" : "/definitely/missing-shell -l"; const { manager, ptyAdapter } = yield* createManager(5, { @@ -1933,7 +1933,7 @@ it.layer( Effect.provide( Layer.merge( layerWithHostPlatform("win32"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Architecture, "x64"), ), ), ); @@ -2513,7 +2513,7 @@ it.layer( it.effect("starts zsh with prompt spacer disabled to avoid `%` end markers", () => Effect.gen(function* () { - if ((yield* HostProcessPlatform) === "win32") return; + if ((yield* HostProcess.Platform) === "win32") return; const { manager, ptyAdapter } = yield* createManager(5, { shellResolver: () => "/bin/zsh", }); diff --git a/apps/server/src/terminal/Manager.ts b/apps/server/src/terminal/Manager.ts index 2a16b9d44f75..d8b2cf3e0553 100644 --- a/apps/server/src/terminal/Manager.ts +++ b/apps/server/src/terminal/Manager.ts @@ -42,11 +42,7 @@ import { } from "@t3tools/contracts"; import { makeKeyedCoalescingWorker } from "@t3tools/shared/KeyedCoalescingWorker"; import * as KeyedLock from "@t3tools/shared/KeyedLock"; -import { - HostProcessArchitecture, - HostProcessHomeDirectory, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { mergePathEntries } from "@t3tools/shared/shell"; import { acpRegistryManagedBinaryDirectories } from "@t3tools/provider-acp-registry/server"; @@ -1482,8 +1478,8 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func const logsDir = options.logsDir; const historyLineLimit = options.historyLineLimit ?? DEFAULT_HISTORY_LINE_LIMIT; const historyByteLimit = options.historyByteLimit ?? DEFAULT_HISTORY_BYTE_LIMIT; - const platform = yield* HostProcessPlatform; - const architecture = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const architecture = yield* HostProcess.Architecture; // Terminals must inherit the user's full environment (minus the blocklist // applied in createTerminalSpawnEnv) — an allowlist here silently strips // things like PSModulePath, DISPLAY, proxies, and toolchain variables. @@ -2253,7 +2249,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func baseEnv, session.runtimeEnv, platform, - yield* HostProcessHomeDirectory, + yield* HostProcess.HomeDirectory, ); // Append (never prepend) managed ACP agent install directories so // `kimi login` and friends resolve by name without shadowing any diff --git a/apps/server/src/terminal/NodePtyAdapter.test.ts b/apps/server/src/terminal/NodePtyAdapter.test.ts index e8c2e4d75ff7..79f73c2e9060 100644 --- a/apps/server/src/terminal/NodePtyAdapter.test.ts +++ b/apps/server/src/terminal/NodePtyAdapter.test.ts @@ -3,7 +3,7 @@ import * as NodeNet from "node:net"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; @@ -66,8 +66,8 @@ const layerTestFor = (platform: NodeJS.Platform = "win32") => Layer.provide( Layer.mergeAll( NodeServices.layer, - Layer.succeed(HostProcessPlatform, platform), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, platform), + Layer.succeed(HostProcess.Architecture, "x64"), Layer.succeed(NodePtyAdapter.NodePtyModuleLoaderRef, () => Promise.resolve(fakeNodePty)), ), ), @@ -272,8 +272,8 @@ it.effect("reports native module load failures as structured startup defects", ( Effect.provide( Layer.mergeAll( NodeServices.layer, - Layer.succeed(HostProcessPlatform, "win32"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, "win32"), + Layer.succeed(HostProcess.Architecture, "x64"), ), ), ), diff --git a/apps/server/src/terminal/NodePtyAdapter.ts b/apps/server/src/terminal/NodePtyAdapter.ts index ed4aee84006e..e865c3020a80 100644 --- a/apps/server/src/terminal/NodePtyAdapter.ts +++ b/apps/server/src/terminal/NodePtyAdapter.ts @@ -7,7 +7,7 @@ import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as PtyAdapter from "@t3tools/shared/PtyAdapter"; @@ -46,8 +46,8 @@ let didEnsureSpawnHelperExecutable = false; const resolveNodePtySpawnHelperPath = Effect.gen(function* () { const path = yield* Path.Path; const fs = yield* FileSystem.FileSystem; - const platform = yield* HostProcessPlatform; - const architecture = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const architecture = yield* HostProcess.Architecture; const packageJsonPath = requireForNodePty.resolve("node-pty/package.json"); const packageDir = path.dirname(packageJsonPath); @@ -67,7 +67,7 @@ const resolveNodePtySpawnHelperPath = Effect.gen(function* () { const ensureNodePtySpawnHelperExecutable = Effect.fn(function* () { const fs = yield* FileSystem.FileSystem; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (platform === "win32") return; if (didEnsureSpawnHelperExecutable) return; @@ -236,8 +236,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () { const loadNodePtyModule = yield* NodePtyModuleLoaderRef; const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; - const architecture = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const architecture = yield* HostProcess.Architecture; const nodePty = yield* Effect.tryPromise({ try: loadNodePtyModule, @@ -253,8 +253,8 @@ export const make = Effect.fn("NodePtyAdapter.make")(function* () { ensureNodePtySpawnHelperExecutable().pipe( Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path), - Effect.provideService(HostProcessPlatform, platform), - Effect.provideService(HostProcessArchitecture, architecture), + Effect.provideService(HostProcess.Platform, platform), + Effect.provideService(HostProcess.Architecture, architecture), Effect.orElseSucceed(() => undefined), ), ); diff --git a/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts b/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts index 29c0f950f7c8..577c122f65e0 100644 --- a/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts +++ b/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts @@ -1,7 +1,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { it } from "@effect/vitest"; import { ClaudeSettings, ProviderInstanceId } from "@t3tools/contracts"; -import { HostProcessPlatform, isHostWindows } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { createModelSelection } from "@t3tools/shared/model"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -35,7 +35,7 @@ function makeFakeClaudeBinary(dir: string) { return Effect.gen(function* () { const path = yield* Path.Path; const fs = yield* FileSystem.FileSystem; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const binDir = path.join(dir, "bin"); const fixturePath = yield* path.fromFileUrl( new URL("./testing/ClaudeTextGeneration.fixture.mjs", import.meta.url), @@ -69,7 +69,7 @@ function withFakeClaudeEnv( const fs = yield* FileSystem.FileSystem; const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3code-claude-text-" }); const binDir = yield* makeFakeClaudeBinary(tempDir); - const pathDelimiter = (yield* isHostWindows) ? ";" : ":"; + const pathDelimiter = (yield* HostProcess.isWindows) ? ";" : ":"; const previousPath = process.env.PATH; const previousOutput = process.env.T3_FAKE_CLAUDE_OUTPUT; const previousExitCode = process.env.T3_FAKE_CLAUDE_EXIT_CODE; diff --git a/apps/server/src/textGeneration/CodexTextGeneration.ts b/apps/server/src/textGeneration/CodexTextGeneration.ts index c11fed75814d..3902b0c74d78 100644 --- a/apps/server/src/textGeneration/CodexTextGeneration.ts +++ b/apps/server/src/textGeneration/CodexTextGeneration.ts @@ -26,7 +26,7 @@ import { } from "@t3tools/provider-core/server/textGenerationUtils"; import { codexModelFamily, getModelSelectionStringOptionValue } from "@t3tools/shared/model"; import { getCodexServiceTierOptionValue } from "../codexModelOptions.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const CODEX_TIMEOUT_MS = 180_000; const encodeJsonString = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown)); @@ -218,7 +218,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func ? { CODEX_HOME: expandHomePath( effectiveConfig.homePath, - yield* HostProcessHomeDirectory, + yield* HostProcess.HomeDirectory, ), } : {}), diff --git a/apps/server/src/usage/UsageService.test.ts b/apps/server/src/usage/UsageService.test.ts index 9c1e62fe1a7d..cb9270a7ed3b 100644 --- a/apps/server/src/usage/UsageService.test.ts +++ b/apps/server/src/usage/UsageService.test.ts @@ -8,7 +8,7 @@ import * as NodeSqlite from "node:sqlite"; import { assert, describe, it } from "@effect/vitest"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { mergeUsage } from "@t3tools/shared/usageMerge"; import { EnvironmentId, @@ -134,7 +134,7 @@ const layerService = (input: { Layer.provideMerge(Layer.mock(ServerSecretStore.ServerSecretStore)({})), Layer.provideMerge(ServerConfig.layerTest(process.cwd(), { prefix: input.prefix })), Layer.provideMerge(NodeServices.layer), - Layer.provideMerge(Layer.succeed(HostProcessPlatform, input.platform ?? "linux")), + Layer.provideMerge(Layer.succeed(HostProcess.Platform, input.platform ?? "linux")), Layer.provideMerge(ServerSettings.layerTest(input.settings)), Layer.provideMerge( Layer.succeed( @@ -150,7 +150,7 @@ const layerService = (input: { ), ), Layer.provideMerge( - Layer.succeed(HostProcessEnvironment, { + Layer.succeed(HostProcess.Environment, { HOME: input.home, GROK_HOME: NodePath.join(input.home, "grok"), OPENCODE_DATA_DIR: NodePath.join(input.home, "opencode"), @@ -1356,7 +1356,7 @@ describe("UsageService", () => { }).pipe(Effect.scoped), ); - it.live.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.live.skipIf(HostProcess.Platform.defaultValue() === "win32")( "keeps a newer cached read when a slower scan of another window finishes later", () => Effect.gen(function* () { @@ -1387,7 +1387,7 @@ describe("UsageService", () => { }).pipe(Effect.scoped), ); - it.live.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.live.skipIf(HostProcess.Platform.defaultValue() === "win32")( "keeps the later read when a scan that read earlier finishes first", () => Effect.gen(function* () { diff --git a/apps/server/src/usage/UsageService.ts b/apps/server/src/usage/UsageService.ts index 2ceeb8750001..3b496d8f4498 100644 --- a/apps/server/src/usage/UsageService.ts +++ b/apps/server/src/usage/UsageService.ts @@ -31,7 +31,7 @@ import { type UsageSummaryInput, UsageReadError, } from "@t3tools/contracts"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Cause from "effect/Cause"; import * as Clock from "effect/Clock"; import * as Context from "effect/Context"; @@ -227,7 +227,7 @@ export const make = Effect.gen(function* () { const config = yield* ServerConfig.ServerConfig; const settingsService = yield* ServerSettings.ServerSettingsService; const httpClient = yield* HttpClient.HttpClient; - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; // The readers yield their own services; scans run them against this context. const readerContext = yield* Effect.context(); diff --git a/apps/server/src/vcs/GitVcsDriverCore.test.ts b/apps/server/src/vcs/GitVcsDriverCore.test.ts index a71226c06aee..fc0cdef01e5b 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.test.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.test.ts @@ -1,7 +1,7 @@ // @effect-diagnostics nodeBuiltinImport:off - realpathSync.native resolves Windows 8.3 short names, which the Effect realPath does not. import * as NodeFS from "node:fs"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { assert, it, describe } from "@effect/vitest"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; @@ -1864,7 +1864,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => { yield* writeTextFile(cwd, " leading.txt", "whitespace path\n"); yield* writeTextFile(cwd, "l.txt", "other\n"); yield* writeTextFile(cwd, "binary.dat", "binary\0data"); - if ((yield* HostProcessPlatform) !== "win32") { + if ((yield* HostProcess.Platform) !== "win32") { yield* writeTextFile(cwd, "tab\tand\nnewline.txt", "unusual path\n"); } yield* git(cwd, ["add", "."]); @@ -1906,7 +1906,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => { additions: 0, deletions: 0, }); - if ((yield* HostProcessPlatform) !== "win32") { + if ((yield* HostProcess.Platform) !== "win32") { assert.deepInclude(branch.files ?? [], { path: "tab\tand\nnewline.txt", previousPath: null, @@ -2890,7 +2890,7 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => { }); // NTFS rejects a newline in a file name, so there is nothing to preserve there. - it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "preserves newline characters in worktree paths when listing refs", () => Effect.gen(function* () { @@ -3965,7 +3965,7 @@ describe("Windows long path configuration", () => { const layer = GitVcsDriver.layer.pipe( Layer.provide(layerServerConfig), Layer.provideMerge(NodeServices.layer), - Layer.provide(Layer.succeed(HostProcessPlatform, platform)), + Layer.provide(Layer.succeed(HostProcess.Platform, platform)), ); return yield* Effect.gen(function* () { const driver = yield* GitVcsDriver.GitVcsDriver; diff --git a/apps/server/src/vcs/GitVcsDriverCore.ts b/apps/server/src/vcs/GitVcsDriverCore.ts index b273e9eff52f..51c1f7b29468 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.ts @@ -29,7 +29,7 @@ import { type VcsRef, } from "@t3tools/contracts"; import { dedupeRemoteBranchesWithLocalMatches, normalizeGitRemoteUrl } from "@t3tools/shared/git"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { compactTraceAttributes } from "@t3tools/shared/observability"; import { decodeJsonResult } from "@t3tools/shared/schemaJson"; import { parseT3ProjectFile } from "@t3tools/shared/t3ProjectFile"; @@ -944,7 +944,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner; const { worktreesDir } = yield* ServerConfig.ServerConfig; const crypto = yield* Crypto.Crypto; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const executeRaw: GitVcsDriver.GitVcsDriver["Service"]["execute"] = Effect.fnUntraced( function* (input) { @@ -2657,7 +2657,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* "hash-object", "-t", "tree", - (yield* HostProcessPlatform) === "win32" ? "NUL" : "/dev/null", + (yield* HostProcess.Platform) === "win32" ? "NUL" : "/dev/null", ]); return stdout.trim(); }); @@ -3403,7 +3403,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* options?.worktreesDirectory ?? "", worktreesDir, path, - yield* HostProcessHomeDirectory, + yield* HostProcess.HomeDirectory, ); if (parentDir === null) { return yield* new GitCommandError({ diff --git a/apps/server/src/vcs/VcsProcess.test.ts b/apps/server/src/vcs/VcsProcess.test.ts index 9962044fc905..bbe95780a1f4 100644 --- a/apps/server/src/vcs/VcsProcess.test.ts +++ b/apps/server/src/vcs/VcsProcess.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, describe, expect, it } from "@effect/vitest"; -import { HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Duration from "effect/Duration"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; @@ -535,7 +535,7 @@ describe("VcsProcess.run", () => { operation: "test.output-limit", command: "node", args: ["-e", "process.stdout.write('x'.repeat(2048))"], - cwd: yield* HostProcessWorkingDirectory, + cwd: yield* HostProcess.WorkingDirectory, maxOutputBytes: 128, outputMode: "error", }).pipe(Effect.flip); diff --git a/apps/server/src/workspace/WorkspaceEntries.test.ts b/apps/server/src/workspace/WorkspaceEntries.test.ts index 31c806b8e78e..e827ae920985 100644 --- a/apps/server/src/workspace/WorkspaceEntries.test.ts +++ b/apps/server/src/workspace/WorkspaceEntries.test.ts @@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError"; import { vi } from "vite-plus/test"; import * as ServerConfig from "../config.ts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as VcsProcess from "../vcs/VcsProcess.ts"; import * as WorkspaceEntries from "./WorkspaceEntries.ts"; import * as WorkspacePaths from "./WorkspacePaths.ts"; @@ -84,7 +84,7 @@ const searchWorkspaceEntries = (input: { }); const appendSeparator = (input: string) => - Effect.map(HostProcessPlatform, (platform) => + Effect.map(HostProcess.Platform, (platform) => input.endsWith("/") || input.endsWith("\\") ? input : `${input}${platform === "win32" ? "\\" : "/"}`, @@ -143,7 +143,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceEntries", (it) => { const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; yield* writeTextFile(cwd, ".git/HEAD"); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (platform !== "win32") yield* fileSystem.symlink(outside, path.join(cwd, "external")); const workspaceEntries = yield* WorkspaceEntries.WorkspaceEntries; for (const directoryPath of [ diff --git a/apps/server/src/workspace/WorkspaceEntries.ts b/apps/server/src/workspace/WorkspaceEntries.ts index 153360443338..8f312223dae1 100644 --- a/apps/server/src/workspace/WorkspaceEntries.ts +++ b/apps/server/src/workspace/WorkspaceEntries.ts @@ -19,7 +19,7 @@ import type { ProjectSearchEntriesInput, ProjectSearchEntriesResult, } from "@t3tools/contracts"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { isExplicitRelativePath, isWindowsAbsolutePath } from "@t3tools/shared/path"; import { normalizeSearchQuery } from "@t3tools/shared/searchRanking"; @@ -110,7 +110,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu input: FilesystemBrowseInput, path: Path.Path, ): Effect.fn.Return { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (platform !== "win32" && isWindowsAbsolutePath(input.partialPath)) { return yield* new WorkspaceEntriesWindowsPathUnsupportedError({ cwd: input.cwd, @@ -120,7 +120,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu } if (!isExplicitRelativePath(input.partialPath)) { - return path.resolve(expandHomePath(input.partialPath, yield* HostProcessHomeDirectory)); + return path.resolve(expandHomePath(input.partialPath, yield* HostProcess.HomeDirectory)); } if (!input.cwd) { @@ -129,7 +129,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu }); } return path.resolve( - expandHomePath(input.cwd, yield* HostProcessHomeDirectory), + expandHomePath(input.cwd, yield* HostProcess.HomeDirectory), input.partialPath, ); }); diff --git a/apps/server/src/workspace/WorkspaceFileSystem.test.ts b/apps/server/src/workspace/WorkspaceFileSystem.test.ts index 9a22a27bd37c..885b0eabb4ad 100644 --- a/apps/server/src/workspace/WorkspaceFileSystem.test.ts +++ b/apps/server/src/workspace/WorkspaceFileSystem.test.ts @@ -14,7 +14,7 @@ import * as VcsProcess from "../vcs/VcsProcess.ts"; import * as WorkspaceEntries from "./WorkspaceEntries.ts"; import * as WorkspaceFileSystem from "./WorkspaceFileSystem.ts"; import * as WorkspacePaths from "./WorkspacePaths.ts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; const layerProject = WorkspaceFileSystem.layer.pipe( @@ -102,7 +102,7 @@ it.layer(layerTest, { excludeTestServices: true })("WorkspaceFileSystemLive", (i ); // Needs mkfifo; Windows has no FIFOs to reject. - it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "rejects a FIFO without blocking on open", () => Effect.gen(function* () { diff --git a/apps/server/src/workspace/WorkspacePaths.ts b/apps/server/src/workspace/WorkspacePaths.ts index 748689330072..097c757a18e8 100644 --- a/apps/server/src/workspace/WorkspacePaths.ts +++ b/apps/server/src/workspace/WorkspacePaths.ts @@ -15,7 +15,7 @@ import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; export class WorkspaceRootNotExistsError extends Schema.TaggedError()( "WorkspaceRootNotExistsError", @@ -154,7 +154,7 @@ export const make = Effect.gen(function* () { "WorkspacePaths.normalizeWorkspaceRoot", )(function* (workspaceRoot, options) { const normalizedWorkspaceRoot = path.resolve( - expandHomePath(workspaceRoot.trim(), yield* HostProcessHomeDirectory), + expandHomePath(workspaceRoot.trim(), yield* HostProcess.HomeDirectory), ); let workspaceStat = yield* statWorkspaceRoot( workspaceRoot, diff --git a/apps/server/src/ws.test.ts b/apps/server/src/ws.test.ts index ae263ac15fd3..0f735efd31c7 100644 --- a/apps/server/src/ws.test.ts +++ b/apps/server/src/ws.test.ts @@ -4,7 +4,7 @@ import { type ServerConfig, type ServerConfigStreamEvent, } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as ConfigProvider from "effect/ConfigProvider"; import * as Deferred from "effect/Deferred"; import * as Duration from "effect/Duration"; @@ -164,7 +164,7 @@ const makeParkedWindowsLauncher = Effect.gen(function* () { ); const onWindows = (effect: Effect.Effect) => effect.pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provide( ConfigProvider.layer( ConfigProvider.fromEnv({ diff --git a/oxlint-plugin-t3code/rules/no-global-process-runtime.test.ts b/oxlint-plugin-t3code/rules/no-global-process-runtime.test.ts index dc9cf6979a70..8a4a8816b25f 100644 --- a/oxlint-plugin-t3code/rules/no-global-process-runtime.test.ts +++ b/oxlint-plugin-t3code/rules/no-global-process-runtime.test.ts @@ -8,10 +8,10 @@ describe("t3code/no-global-process-runtime", () => { rule.valid( "allows injected host process references", ` - import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; + import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; - export const isWindows = Effect.map(HostProcessPlatform, (platform) => platform === "win32"); + export const isWindows = Effect.map(HostProcess.Platform, (platform) => platform === "win32"); `, ); @@ -38,7 +38,7 @@ describe("t3code/no-global-process-runtime", () => { export const isWindows = process.platform === "win32"; `, (output) => { - assert.match(output, /Use HostProcessPlatform/); + assert.match(output, /Use HostProcess\.Platform/); }, ); @@ -48,7 +48,7 @@ describe("t3code/no-global-process-runtime", () => { export const isArm = process.arch === "arm64"; `, (output) => { - assert.match(output, /Use HostProcessArchitecture/); + assert.match(output, /Use HostProcess\.Architecture/); }, ); @@ -67,7 +67,7 @@ describe("t3code/no-global-process-runtime", () => { export const isWindows = NodeOS.platform() === "win32"; `, (output) => { - assert.match(output, /Use HostProcessPlatform/); + assert.match(output, /Use HostProcess\.Platform/); }, ); @@ -79,7 +79,7 @@ describe("t3code/no-global-process-runtime", () => { export const isArm = hostArch() === "arm64"; `, (output) => { - assert.match(output, /Use HostProcessArchitecture/); + assert.match(output, /Use HostProcess\.Architecture/); }, ); diff --git a/oxlint-plugin-t3code/rules/no-global-process-runtime.ts b/oxlint-plugin-t3code/rules/no-global-process-runtime.ts index f122d16db29a..822094e922f2 100644 --- a/oxlint-plugin-t3code/rules/no-global-process-runtime.ts +++ b/oxlint-plugin-t3code/rules/no-global-process-runtime.ts @@ -19,7 +19,7 @@ const isGlobalProcessObject = (node: unknown): boolean => { }; const message = (property: string) => - `Use HostProcess${property === "arch" ? "Architecture" : "Platform"} instead of process.${property}; inject the runtime reference in Effect code and provide it explicitly in tests.`; + `Use HostProcess.${property === "arch" ? "Architecture" : "Platform"} instead of process.${property}; inject the runtime reference in Effect code and provide it explicitly in tests.`; const getLiteralStringValue = (node: unknown): Option.Option => { if (typeof node !== "object" || node === null) return Option.none(); diff --git a/packages/provider-acp-registry/src/server/AcpRegistrySupport.test.ts b/packages/provider-acp-registry/src/server/AcpRegistrySupport.test.ts index 62fd6274e64d..f95286d004af 100644 --- a/packages/provider-acp-registry/src/server/AcpRegistrySupport.test.ts +++ b/packages/provider-acp-registry/src/server/AcpRegistrySupport.test.ts @@ -6,11 +6,7 @@ import { ProviderInstanceId, } from "@t3tools/contracts"; import { AcpRegistrySettings } from "../settings.ts"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { SpawnExecutableResolution } from "@t3tools/shared/shell"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; @@ -63,9 +59,9 @@ function layerResolver( return Layer.mergeAll( NodeServices.layer, TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)), - Layer.succeed(HostProcessPlatform, "linux"), - Layer.succeed(HostProcessArchitecture, "x64"), - Layer.succeed(HostProcessEnvironment, environment), + Layer.succeed(HostProcess.Platform, "linux"), + Layer.succeed(HostProcess.Architecture, "x64"), + Layer.succeed(HostProcess.Environment, environment), Layer.succeed(HttpClient.HttpClient, HttpClient.make(execute)), ); } @@ -229,7 +225,7 @@ describe("AcpRegistrySupport", () => { cacheDir, toolsDir: `${cacheDir}/tools`, registryUrl, - }).pipe(Effect.provideService(HostProcessEnvironment, hostEnvironment)); + }).pipe(Effect.provideService(HostProcess.Environment, hostEnvironment)); const localSettings = decodeAcpRegistrySettings({ source: "local", commandPath: "dsh", @@ -279,7 +275,7 @@ describe("AcpRegistrySupport", () => { cacheDir, toolsDir: `${cacheDir}/tools`, registryUrl, - }).pipe(Effect.provideService(HostProcessEnvironment, environment)); + }).pipe(Effect.provideService(HostProcess.Environment, environment)); const resolved = yield* resolver.resolve( decodeAcpRegistrySettings({ source: "local", commandPath }), "/workspace", @@ -300,7 +296,7 @@ describe("AcpRegistrySupport", () => { toolsDir: `${cacheDir}/tools`, registryUrl, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(SpawnExecutableResolution, () => `C:\\bin\\dsh${extension}`), ); const localSettings = decodeAcpRegistrySettings({ source: "local", commandPath: "dsh" }); @@ -432,7 +428,7 @@ describe("AcpRegistrySupport", () => { cacheDir, toolsDir: `${cacheDir}/tools`, registryUrl, - }).pipe(Effect.provideService(HostProcessEnvironment, toolchain.environment)); + }).pipe(Effect.provideService(HostProcess.Environment, toolchain.environment)); const first = yield* resolver.resolve(settings(), "/workspace", toolchain.environment); const second = yield* resolver.resolve(settings(), "/workspace", toolchain.environment); @@ -478,7 +474,7 @@ describe("AcpRegistrySupport", () => { cacheDir, toolsDir: `${cacheDir}/tools`, registryUrl, - }).pipe(Effect.provideService(HostProcessEnvironment, environment)); + }).pipe(Effect.provideService(HostProcess.Environment, environment)); const resolved = yield* resolver.resolve(settings(), "/workspace", environment); const userGlobalBin = toolchain.globalBin; @@ -559,7 +555,7 @@ describe("AcpRegistrySupport", () => { toolsDir: `${cacheDir}/tools`, registryUrl, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(SpawnExecutableResolution, (command) => { if (command === "uv") return toolchain.uvPath; if (command === "fast-agent") return toolchain.executablePath; @@ -677,7 +673,7 @@ describe("AcpRegistrySupport", () => { cacheDir, toolsDir: `${cacheDir}/tools`, registryUrl, - }).pipe(Effect.provideService(HostProcessEnvironment, environment)); + }).pipe(Effect.provideService(HostProcess.Environment, environment)); yield* resolver.search({ query: "example" }); expect(yield* resolver.inspect(settings(), environment)).toMatchObject({ status: "unprepared", @@ -781,8 +777,8 @@ describe("AcpRegistrySupport", () => { TestProviderHost.layer().pipe(Layer.provide(NodeServices.layer)), ), ), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessArchitecture, "x64"), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Architecture, "x64"), ); }); @@ -1097,7 +1093,7 @@ describe("AcpRegistrySupport", () => { cacheDir, toolsDir: `${cacheDir}/tools`, registryUrl, - }).pipe(Effect.provideService(HostProcessEnvironment, toolchain.environment)); + }).pipe(Effect.provideService(HostProcess.Environment, toolchain.environment)); const prepared = yield* resolver.prepare({ agentId: agent.id }); expect(prepared).toEqual({ agentId: "example-agent", diff --git a/packages/provider-acp-registry/src/server/AcpRegistrySupport.ts b/packages/provider-acp-registry/src/server/AcpRegistrySupport.ts index fba8e656e615..aeb792b08ca8 100644 --- a/packages/provider-acp-registry/src/server/AcpRegistrySupport.ts +++ b/packages/provider-acp-registry/src/server/AcpRegistrySupport.ts @@ -12,11 +12,7 @@ import { } from "@t3tools/contracts"; import type { AcpRegistryDistributionPreference } from "../settings.ts"; import type { AcpRegistrySettings } from "../settings.ts"; -import { - HostProcessArchitecture, - HostProcessEnvironment, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { mergePathEntries, resolveSpawnCommand, @@ -637,9 +633,9 @@ export const makeAcpRegistryCatalog = Effect.fn("AcpRegistryCatalog.make")(funct const httpClient = yield* HttpClient.HttpClient; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const { settings: hostSettings } = yield* ProviderHost.ProviderHost; - const platform = yield* HostProcessPlatform; - const architecture = yield* HostProcessArchitecture; - const hostEnvironment = yield* HostProcessEnvironment; + const platform = yield* HostProcess.Platform; + const architecture = yield* HostProcess.Architecture; + const hostEnvironment = yield* HostProcess.Environment; const resolveExecutable = yield* SpawnExecutableResolution; const platformTarget = resolveAcpRegistryPlatformTarget(platform, architecture); const registryUrl = input.registryUrl ?? ACP_REGISTRY_URL; diff --git a/packages/provider-acp-registry/src/server/adapter.ts b/packages/provider-acp-registry/src/server/adapter.ts index 4827ca4e4c56..d5fb3279f405 100644 --- a/packages/provider-acp-registry/src/server/adapter.ts +++ b/packages/provider-acp-registry/src/server/adapter.ts @@ -5,7 +5,7 @@ import { } from "./devinAcp.ts"; import { defaultInstanceIdForDriver, ProviderDriverKind } from "@t3tools/contracts"; import { AcpRegistrySettings } from "../settings.ts"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime"; import * as Crypto from "effect/Crypto"; import * as Effect from "effect/Effect"; @@ -271,7 +271,7 @@ export const AcpRegistryAdapterV2Driver: ProviderAdapterDriver< defaultConfig: (): AcpRegistrySettings => DEFAULT_ACP_REGISTRY_SETTINGS, create: Effect.fn("AcpRegistryAdapterV2Driver.create")( function* (input: ProviderAdapterDriverCreateInput) { - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const selfInvocation = yield* resolveSelfInvocation(); const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers; const makeNativeLogger = yield* makeAcpNativeLoggerFactory(); diff --git a/packages/provider-acp-registry/src/server/driver.ts b/packages/provider-acp-registry/src/server/driver.ts index 4468aa70af39..8ddf7ad9ce23 100644 --- a/packages/provider-acp-registry/src/server/driver.ts +++ b/packages/provider-acp-registry/src/server/driver.ts @@ -8,7 +8,7 @@ import { type ServerProviderModel, } from "@t3tools/contracts"; import { AcpRegistrySettings } from "../settings.ts"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { createModelCapabilities } from "@t3tools/shared/model"; import * as Clock from "effect/Clock"; import * as Crypto from "effect/Crypto"; @@ -484,7 +484,7 @@ export const AcpRegistryDriver: ProviderDriver(); const stderrTailRef = yield* Ref.make(""); - const homeDirectory = yield* HostProcessHomeDirectory; + const homeDirectory = yield* HostProcess.HomeDirectory; const stderrDrained = yield* Deferred.make(); const runtimeClosed = yield* Deferred.make(); const promptSerializationSemaphore = yield* Semaphore.make(1); @@ -1729,7 +1729,7 @@ export const make = ( Effect.uninterruptible(terminateOwnedProcessGroupImpl), ); if (options.ownDetachedProcessGroup === true) { - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const forceTerminateOwnedProcessGroup = hostPlatform === "win32" ? terminateWindowsProcessTreeWithTaskkill(Number(child.pid)).pipe( diff --git a/packages/provider-core/src/server/instanceEnvironment.test.ts b/packages/provider-core/src/server/instanceEnvironment.test.ts index e64cd31650f5..1899d1f9d5c3 100644 --- a/packages/provider-core/src/server/instanceEnvironment.test.ts +++ b/packages/provider-core/src/server/instanceEnvironment.test.ts @@ -2,7 +2,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { describe, expect, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Path from "effect/Path"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { mergeProviderInstanceEnvironment } from "./instanceEnvironment.ts"; @@ -36,7 +36,7 @@ describe("mergeProviderInstanceEnvironment", () => { CLAUDE_CONFIG_DIR: "~/.inherited-claude", }); }).pipe( - Effect.provideService(HostProcessHomeDirectory, "/home/ada"), + Effect.provideService(HostProcess.HomeDirectory, "/home/ada"), Effect.provide(NodeServices.layer), ), ); diff --git a/packages/provider-core/src/server/instanceEnvironment.ts b/packages/provider-core/src/server/instanceEnvironment.ts index 0ddb61af4b5c..c4dfe37cbb8c 100644 --- a/packages/provider-core/src/server/instanceEnvironment.ts +++ b/packages/provider-core/src/server/instanceEnvironment.ts @@ -1,5 +1,5 @@ import type { ProviderInstanceEnvironment } from "@t3tools/contracts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import { expandHomePath } from "./pathExpansion.ts"; @@ -12,7 +12,7 @@ export const mergeProviderInstanceEnvironment = Effect.fn(function* ( return baseEnv; } - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const next: NodeJS.ProcessEnv = { ...baseEnv }; for (const variable of environment) { // Child processes do not apply shell expansion to environment values. diff --git a/packages/provider-core/src/server/maintenanceResolver.test.ts b/packages/provider-core/src/server/maintenanceResolver.test.ts index 23f0707a4a51..b0b1be74ee88 100644 --- a/packages/provider-core/src/server/maintenanceResolver.test.ts +++ b/packages/provider-core/src/server/maintenanceResolver.test.ts @@ -6,7 +6,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import * as NodeOS from "node:os"; import * as NodePath from "node:path"; import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Crypto from "effect/Crypto"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; @@ -37,7 +37,7 @@ import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; const driver = (value: string) => ProviderDriverKind.make(value); // These write `#!/bin/sh` stubs and evaluate them with darwin/linux path // semantics; a Windows temp path cannot be split on `:`. -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; const makeTempDir = (name: string) => Crypto.Crypto.pipe( Effect.flatMap((crypto) => crypto.randomUUIDv4), @@ -332,7 +332,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { env: {}, platform: "win32", }, - ).pipe(Effect.provideService(HostProcessPlatform, "win32")); + ).pipe(Effect.provideService(HostProcess.Platform, "win32")); expect(capabilities.update).toMatchObject({ executable: visiblePath, @@ -360,7 +360,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { binaryPath: shim, env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" }, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), ); @@ -376,7 +376,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { binaryPath: script, env: { PATH: "" }, }).pipe( - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), ); expect(posix.update).toBeNull(); @@ -429,7 +429,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { env: { PATH: bunBinDir }, }, ).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), ); @@ -454,7 +454,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { env: { PATH: nativeBinDir }, }, ).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, noSpawn), ); @@ -659,7 +659,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { env: { PATH: brewBinDir }, }, ).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService( ChildProcessSpawner.ChildProcessSpawner, stdoutSpawner((command, args) => { @@ -725,7 +725,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { env: { PATH: brewBinDir }, }, ).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService( ChildProcessSpawner.ChildProcessSpawner, stdoutSpawner(() => "/opt/homebrew\n"), @@ -864,7 +864,7 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { binaryPath: kegBinary, env: { PATH: "" }, }).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService( ChildProcessSpawner.ChildProcessSpawner, stdoutSpawner((_command, args) => (args[0] === "--prefix" ? `${tempDir}\n` : "{}")), diff --git a/packages/provider-core/src/server/maintenanceResolver.ts b/packages/provider-core/src/server/maintenanceResolver.ts index fb985bd2011a..c625f067bd45 100644 --- a/packages/provider-core/src/server/maintenanceResolver.ts +++ b/packages/provider-core/src/server/maintenanceResolver.ts @@ -12,7 +12,7 @@ import { type ServerProviderVersionAdvisory, } from "@t3tools/contracts"; import { compareSemverVersions } from "@t3tools/shared/semver"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { causeErrorTag } from "@t3tools/shared/observability"; import { resolveCommandPath } from "@t3tools/shared/shell"; import * as Cache from "effect/Cache"; @@ -141,7 +141,7 @@ export function makeProviderMaintenanceCapabilities(input: { readonly env?: NodeJS.ProcessEnv; readonly latestVersion?: string | null; }): ProviderMaintenanceCapabilities { - const platform = input.platform ?? HostProcessPlatform.defaultValue(); + const platform = input.platform ?? HostProcess.Platform.defaultValue(); const update = input.updateExecutable === null || input.updateLockKey === null ? null @@ -587,7 +587,7 @@ const resolveNpmGlobalPrefix = Effect.fn("resolveNpmGlobalPrefix")(function* ( if (fromRealPath) { return fromRealPath; } - if ((yield* HostProcessPlatform) !== "win32") { + if ((yield* HostProcess.Platform) !== "win32") { return null; } const fileSystem = yield* FileSystem.FileSystem; @@ -667,7 +667,7 @@ export const resolveProviderMaintenanceCapabilitiesEffect = Effect.fn( resolvedCommandPath, realCommandPath, env, - platform: yield* HostProcessPlatform, + platform: yield* HostProcess.Platform, }); }); diff --git a/packages/provider-core/src/server/pathExpansion.ts b/packages/provider-core/src/server/pathExpansion.ts index d486b2988d47..1cc52dd0e9d7 100644 --- a/packages/provider-core/src/server/pathExpansion.ts +++ b/packages/provider-core/src/server/pathExpansion.ts @@ -3,7 +3,7 @@ import * as NodePath from "node:path"; /** * Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to `home`, - * the current user's home directory (`HostProcessHomeDirectory`). Spawned + * the current user's home directory (`HostProcess.HomeDirectory`). Spawned * processes don't get shell expansion, so env vars like * `CODEX_HOME=~/.codex-work` would be passed verbatim and treated as relative * paths by the receiver. diff --git a/packages/provider-core/src/server/processGroup.test.ts b/packages/provider-core/src/server/processGroup.test.ts index 9694d9b7ab94..b2b39abe4320 100644 --- a/packages/provider-core/src/server/processGroup.test.ts +++ b/packages/provider-core/src/server/processGroup.test.ts @@ -2,7 +2,7 @@ import * as NodeChildProcess from "node:child_process"; import { describe, expect, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { signalProcessGroup } from "./processGroup.ts"; @@ -15,7 +15,7 @@ const errorCode = (run: () => void) => { } }; -describe.skipIf(HostProcessPlatform.defaultValue() === "win32")("signalProcessGroup", () => { +describe.skipIf(HostProcess.Platform.defaultValue() === "win32")("signalProcessGroup", () => { // Signal 0 only probes, so this is safe to run unguarded: `kill(-1, 0)` and // `kill(0, 0)` succeed, which is how a fake spawner's pid 1 became // `kill(-1, SIGKILL)` and took down every process the user owned. diff --git a/packages/provider-core/src/server/snapshotProbe.test.ts b/packages/provider-core/src/server/snapshotProbe.test.ts index 8ee272cee394..fc207f90f340 100644 --- a/packages/provider-core/src/server/snapshotProbe.test.ts +++ b/packages/provider-core/src/server/snapshotProbe.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "@effect/vitest"; import type { ModelCapabilities } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { createModelCapabilities } from "@t3tools/shared/model"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; @@ -158,7 +158,7 @@ describe("ProviderCommandNotFoundError", () => { ChildProcess.make("codex", ["--version"]), ).pipe( Effect.provide(Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner)), - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.flip, ); diff --git a/packages/provider-core/src/server/snapshotProbe.ts b/packages/provider-core/src/server/snapshotProbe.ts index f61881ba0806..071d9fd5ae07 100644 --- a/packages/provider-core/src/server/snapshotProbe.ts +++ b/packages/provider-core/src/server/snapshotProbe.ts @@ -19,7 +19,7 @@ import * as Stream from "effect/Stream"; import * as ChildProcess from "effect/process/ChildProcess"; import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"; import { readCustomModelEntries } from "@t3tools/shared/model"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { createProviderVersionAdvisory } from "./maintenanceResolver.ts"; import { collectUint8StreamText } from "./collectStreamText.ts"; @@ -38,7 +38,7 @@ export const isWindowsCommandNotFound = Effect.fn("isWindowsCommandNotFound")(fu code: number | null, stderr: string, ) { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (platform !== "win32") return false; if (code === 9009) return true; return WINDOWS_COMMAND_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(stderr)); diff --git a/packages/provider-cursor/src/server/CursorUsageAccounts.ts b/packages/provider-cursor/src/server/CursorUsageAccounts.ts index 56f64104a449..24f4ff87afff 100644 --- a/packages/provider-cursor/src/server/CursorUsageAccounts.ts +++ b/packages/provider-cursor/src/server/CursorUsageAccounts.ts @@ -14,11 +14,7 @@ import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost"; import type { ProviderUsageScan } from "@t3tools/provider-core/server/usage"; import { writeFileStringAtomically } from "@t3tools/shared/atomicWrite"; -import { - HostProcessEnvironment, - HostProcessHomeDirectory, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Clock from "effect/Clock"; import * as Context from "effect/Context"; import * as Deferred from "effect/Deferred"; @@ -71,8 +67,8 @@ const make = Effect.gen(function* () { const path = yield* Path.Path; const host = yield* ProviderHost.ProviderHost; const accountReader = yield* CursorAccountReader.CursorAccountReader; - const hostEnvironment = yield* HostProcessEnvironment; - const platform = yield* HostProcessPlatform; + const hostEnvironment = yield* HostProcess.Environment; + const platform = yield* HostProcess.Platform; const cachePath = path.join(host.paths.stateDir, CURSOR_ACCOUNT_CACHE_FILE_NAME); /** Account caches by credential source. */ @@ -286,7 +282,7 @@ const make = Effect.gen(function* () { const scan: CursorUsageAccounts["Service"]["scan"] = Effect.fn("CursorUsageAccounts.scan")( function* ({ keychainUsageEnabled, windowStartMs, retentionCutoffMs, awaitRefresh }) { - const home = yield* HostProcessHomeDirectory; + const home = yield* HostProcess.HomeDirectory; const userHome = (platform === "win32" ? hostEnvironment["USERPROFILE"] : hostEnvironment["HOME"]) || home; const configHome = hostEnvironment["XDG_CONFIG_HOME"]?.trim(); diff --git a/packages/provider-cursor/src/server/adapter.ts b/packages/provider-cursor/src/server/adapter.ts index fa557d6d8bc1..f7cd8005eef5 100644 --- a/packages/provider-cursor/src/server/adapter.ts +++ b/packages/provider-cursor/src/server/adapter.ts @@ -9,7 +9,7 @@ import type { ToolCall, } from "@cursor/sdk"; import { formatReadToolLabel, formatSearchToolLabel } from "@t3tools/shared/toolActivity"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { isOrchestrationV2WorkActive, defaultInstanceIdForDriver, @@ -2620,7 +2620,7 @@ export const CursorAdapterV2Driver: ProviderAdapterDriver< defaultConfig: (): CursorSettings => DEFAULT_CURSOR_SETTINGS, create: Effect.fn("CursorAdapterV2Driver.create")( function* (input: ProviderAdapterDriverCreateInput) { - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; return yield* makeCursorAdapterV2({ instanceId: input.instanceId, settings: { diff --git a/packages/provider-cursor/src/server/skills.ts b/packages/provider-cursor/src/server/skills.ts index 4c7b0bbea985..371aa75352d6 100644 --- a/packages/provider-cursor/src/server/skills.ts +++ b/packages/provider-cursor/src/server/skills.ts @@ -17,7 +17,7 @@ import * as Path from "effect/Path"; import * as PlatformError from "effect/PlatformError"; import * as Schema from "effect/Schema"; import { parse as parseYamlDocument } from "yaml"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/; const SKILL_MENTION_PATTERN = @@ -224,7 +224,7 @@ const inspectCursorSkills = Effect.fn("inspectCursorSkills")(function* ( const userHome = environment.HOME?.trim() || environment.USERPROFILE?.trim() || - (yield* HostProcessHomeDirectory); + (yield* HostProcess.HomeDirectory); const rootsBelow = (base: string, scope: "user" | "project") => [ { directory: path.join(base, ".cursor", "skills"), scope }, { directory: path.join(base, ".agents", "skills"), scope }, diff --git a/packages/provider-cursor/src/server/textGeneration.ts b/packages/provider-cursor/src/server/textGeneration.ts index 6a6b8ae989cf..ff1325d648d3 100644 --- a/packages/provider-cursor/src/server/textGeneration.ts +++ b/packages/provider-cursor/src/server/textGeneration.ts @@ -12,7 +12,7 @@ import * as TextGenerationOperations from "@t3tools/provider-core/server/textGen import { cursorSdkModelSelection } from "./sdkModel.ts"; import type { CursorAuth } from "./auth.ts"; import * as CursorSdk from "./CursorSdk.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const CURSOR_TIMEOUT_MS = 180_000; @@ -90,7 +90,7 @@ export const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(fu const apiKey = yield* resolveCursorApiKey(operation); // The SDK loads sandbox.json independently of settingSources and lets it // expand the writable paths. Its public API cannot override that policy. - if (yield* fs.exists(`${yield* HostProcessHomeDirectory}/.cursor/sandbox.json`)) { + if (yield* fs.exists(`${yield* HostProcess.HomeDirectory}/.cursor/sandbox.json`)) { return yield* new TextGenerationError({ operation, detail: diff --git a/packages/provider-cursor/src/server/usageLimits.test.ts b/packages/provider-cursor/src/server/usageLimits.test.ts index bb3e38703037..ce8a2cbc27cf 100644 --- a/packages/provider-cursor/src/server/usageLimits.test.ts +++ b/packages/provider-cursor/src/server/usageLimits.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "@effect/vitest"; import { NodeServices } from "@effect/platform-node"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; @@ -106,7 +106,7 @@ describe("Cursor usage limits", () => { { apiEndpoint: "https://cursor.example/" }, { XDG_CONFIG_HOME: directory, HOME: directory, AGENT_CLI_CREDENTIAL_STORE: "file" }, ).pipe( - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Platform, platform), Effect.provideService(HttpClient.HttpClient, client), ); expect(limits.windows[0]?.usedPercent).toBe(42); @@ -131,7 +131,7 @@ describe("Cursor usage limits", () => { }, false, ).pipe( - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Platform, platform), Effect.provideService( FileSystem.FileSystem, FileSystem.makeNoop({ @@ -202,7 +202,7 @@ describe("Cursor usage limits", () => { Effect.gen(function* () { const limits = yield* withNodeServices( readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService( FileSystem.FileSystem, FileSystem.makeNoop({ @@ -232,7 +232,7 @@ describe("Cursor usage limits", () => { Effect.gen(function* () { const limits = yield* withNodeServices( readCursorUsageLimits({ apiEndpoint: "" }, {}, true).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService( HttpClient.HttpClient, HttpClient.make(() => Effect.die("must not request limits without a login")), @@ -258,7 +258,7 @@ describe("Cursor usage limits", () => { ] as const) { const limits = yield* withNodeServices( readCursorUsageLimits({ apiEndpoint }, environment, true).pipe( - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcess.Platform, "darwin"), Effect.provideService( HttpClient.HttpClient, HttpClient.make(() => Effect.die("must not send a Keychain credential to a proxy")), diff --git a/packages/provider-cursor/src/server/usageLimits.ts b/packages/provider-cursor/src/server/usageLimits.ts index dd29a443cd3a..049e646d2c49 100644 --- a/packages/provider-cursor/src/server/usageLimits.ts +++ b/packages/provider-cursor/src/server/usageLimits.ts @@ -1,6 +1,6 @@ import type { ServerProviderUsageWindow } from "@t3tools/contracts"; import type { CursorSettings } from "../settings.ts"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { CURSOR_USAGE_WINDOWS } from "@t3tools/shared/usageLimits"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; @@ -70,7 +70,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function return yield* Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const endpoint = ( settings.apiEndpoint?.trim() || environment.CURSOR_API_ENDPOINT?.trim() || @@ -109,7 +109,7 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function } else if (!token) { const home = (platform === "win32" ? environment.USERPROFILE : environment.HOME) || - (yield* HostProcessHomeDirectory); + (yield* HostProcess.HomeDirectory); const directory = platform === "win32" ? path.join(environment.APPDATA || path.join(home, "AppData", "Roaming"), "Cursor") diff --git a/packages/provider-grok/src/server/acpSupport.ts b/packages/provider-grok/src/server/acpSupport.ts index 53f5ae3ffb2b..60d395284648 100644 --- a/packages/provider-grok/src/server/acpSupport.ts +++ b/packages/provider-grok/src/server/acpSupport.ts @@ -12,7 +12,7 @@ import * as Layer from "effect/Layer"; import * as Scope from "effect/Scope"; import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"; import * as EffectAcpErrors from "effect-acp/errors"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { normalizeModelSlug } from "@t3tools/shared/model"; import * as AcpSessionRuntime from "@t3tools/provider-acp/server/AcpSessionRuntime"; @@ -159,7 +159,7 @@ export const makeGrokAcpRuntime = ( ChildProcessSpawner.ChildProcessSpawner | Crypto.Crypto | Scope.Scope > => Effect.gen(function* () { - const processGroupPlatform = yield* HostProcessPlatform.pipe( + const processGroupPlatform = yield* HostProcess.Platform.pipe( Effect.provide(NodeServices.layer), ); const acpContext = yield* Layer.build( diff --git a/packages/provider-grok/src/server/adapter.ts b/packages/provider-grok/src/server/adapter.ts index cca040e81698..224654585625 100644 --- a/packages/provider-grok/src/server/adapter.ts +++ b/packages/provider-grok/src/server/adapter.ts @@ -4,11 +4,7 @@ import { isXAiTaskCompletedWakeNotification, xAiRateLimitedErrorCode, } from "./xaiAcpExtension.ts"; -import { - HostProcessEnvironment, - HostProcessHomeDirectory, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSelfInvocation, type SelfInvocation } from "@t3tools/shared/nodeRuntime"; import { defaultInstanceIdForDriver, @@ -339,7 +335,7 @@ export const makeGrokAdapterV2 = Effect.fn("makeGrokAdapterV2")(function* ( ) { return yield* makeAcpAdapterV2({ instanceId: options.instanceId, - flavor: makeGrokAcpAdapterFlavor(options, yield* HostProcessHomeDirectory), + flavor: makeGrokAcpAdapterFlavor(options, yield* HostProcess.HomeDirectory), selfInvocation: options.selfInvocation, ...(options.nativeLogging === undefined ? {} : { nativeLogging: options.nativeLogging }), ...(options.continuationRequests === undefined @@ -365,8 +361,8 @@ export const GrokAdapterV2Driver: ProviderAdapterDriver DEFAULT_GROK_SETTINGS, create: Effect.fn("GrokAdapterV2Driver.create")( function* (input: ProviderAdapterDriverCreateInput) { - const hostEnvironment = yield* HostProcessEnvironment; - const hostPlatform = yield* HostProcessPlatform; + const hostEnvironment = yield* HostProcess.Environment; + const hostPlatform = yield* HostProcess.Platform; const selfInvocation = yield* resolveSelfInvocation(); const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers; const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests; @@ -415,8 +411,8 @@ const layer: Layer.Layer< > = Layer.effect( ProviderAdapter.ProviderAdapterV2, Effect.gen(function* () { - const hostEnvironment = yield* HostProcessEnvironment; - const hostPlatform = yield* HostProcessPlatform; + const hostEnvironment = yield* HostProcess.Environment; + const hostPlatform = yield* HostProcess.Platform; const selfInvocation = yield* resolveSelfInvocation(); const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers; const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests; diff --git a/packages/provider-grok/src/server/driver.test.ts b/packages/provider-grok/src/server/driver.test.ts index 22b2c64aa0b8..b3e96bad0d04 100644 --- a/packages/provider-grok/src/server/driver.test.ts +++ b/packages/provider-grok/src/server/driver.test.ts @@ -1,7 +1,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { expect, it } from "@effect/vitest"; import { ProviderInstanceId } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; @@ -41,7 +41,7 @@ const noSpawner = ChildProcessSpawner.make(() => ); // The `#!/bin/sh` stub below cannot be resolved as an executable on Windows. -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; it.layer(layerTest)("GrokDriver", (it) => { it.effect.skipIf(windowsHost)("updates through the configured executable's own updater", () => diff --git a/packages/provider-grok/src/server/usage.ts b/packages/provider-grok/src/server/usage.ts index 8b5c0db45ea6..4359cd11959c 100644 --- a/packages/provider-grok/src/server/usage.ts +++ b/packages/provider-grok/src/server/usage.ts @@ -19,7 +19,7 @@ import { } from "@t3tools/provider-core/server/usage"; import type { GrokSettings } from "../settings.ts"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; /** * Grok reports cost in integer ticks where `1 USD = 10^10` ticks. See Grok @@ -229,7 +229,7 @@ export const grokUsageReader: ProviderUsageReader = { format: grokUsageFormat, directories: Effect.fn("grokUsageReader.directories")(function* ({ environment }) { const path = yield* Path.Path; - const homeDirectory = yield* HostProcessHomeDirectory; + const homeDirectory = yield* HostProcess.HomeDirectory; const home = expandHomePath( environment.GROK_HOME?.trim() || path.join(homeDirectory, ".grok"), homeDirectory, diff --git a/packages/provider-grok/src/server/usageLimits.ts b/packages/provider-grok/src/server/usageLimits.ts index b7db7f6fd79a..d4a855883a6c 100644 --- a/packages/provider-grok/src/server/usageLimits.ts +++ b/packages/provider-grok/src/server/usageLimits.ts @@ -13,7 +13,7 @@ import { makeUnavailableUsageLimits, makeUsageLimits, } from "@t3tools/provider-core/server/usageLimits"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const GrokCredentials = Schema.Record( Schema.String, @@ -101,7 +101,7 @@ const readGrokCredential = Effect.fn("readGrokCredential")(function* ( const home = environment.GROK_HOME?.trim() || path.join( - environment.HOME || environment.USERPROFILE || (yield* HostProcessHomeDirectory), + environment.HOME || environment.USERPROFILE || (yield* HostProcess.HomeDirectory), ".grok", ); for (const configPath of [ diff --git a/packages/provider-muse/src/server/driver.ts b/packages/provider-muse/src/server/driver.ts index 3b9df42100a6..9a70f74eed83 100644 --- a/packages/provider-muse/src/server/driver.ts +++ b/packages/provider-muse/src/server/driver.ts @@ -1,6 +1,6 @@ import { ProviderDriverKind } from "@t3tools/contracts"; import { MuseSettings } from "../settings.ts"; -import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; @@ -69,7 +69,7 @@ export const MuseDriver: ProviderDriver = { const eventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers; const { cwd } = host.paths; const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests; - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; // Drop an inherited META_API_KEY so Muse uses its login; an instance value still wins. const processEnvironment = yield* mergeProviderInstanceEnvironment( environment, @@ -78,7 +78,7 @@ export const MuseDriver: ProviderDriver = { const effectiveConfig = { ...config, enabled, - binaryPath: expandHomePath(config.binaryPath, yield* HostProcessHomeDirectory), + binaryPath: expandHomePath(config.binaryPath, yield* HostProcess.HomeDirectory), } satisfies MuseSettings; const continuationIdentity = defaultProviderContinuationIdentity({ driverKind: DRIVER_KIND, diff --git a/packages/provider-opencode/src/server/OpenCodeRuntime.environment.test.ts b/packages/provider-opencode/src/server/OpenCodeRuntime.environment.test.ts index 6476c7a7c3ce..5e2746d0f82c 100644 --- a/packages/provider-opencode/src/server/OpenCodeRuntime.environment.test.ts +++ b/packages/provider-opencode/src/server/OpenCodeRuntime.environment.test.ts @@ -1,11 +1,7 @@ import type { OpencodeClient } from "@opencode-ai/sdk/v2"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { it as effectIt } from "@effect/vitest"; -import { - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as FileSystem from "effect/FileSystem"; @@ -168,9 +164,9 @@ describe("OpenCode server output", () => { Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const environment = yield* HostProcessEnvironment; - const executablePath = yield* HostProcessExecutablePath; - const platform = yield* HostProcessPlatform; + const environment = yield* HostProcess.Environment; + const executablePath = yield* HostProcess.ExecutablePath; + const platform = yield* HostProcess.Platform; const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-output-" }); const isWindows = platform === "win32"; const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode"); diff --git a/packages/provider-opencode/src/server/OpenCodeRuntime.inventory.test.ts b/packages/provider-opencode/src/server/OpenCodeRuntime.inventory.test.ts index 29e302c134f1..d9cdfa9e6441 100644 --- a/packages/provider-opencode/src/server/OpenCodeRuntime.inventory.test.ts +++ b/packages/provider-opencode/src/server/OpenCodeRuntime.inventory.test.ts @@ -9,11 +9,7 @@ import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as Path from "effect/Path"; import * as Queue from "effect/Queue"; -import { - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as OpenCodeRuntime from "./OpenCodeRuntime.ts"; import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts"; @@ -217,9 +213,9 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => { Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const hostEnvironment = yield* HostProcessEnvironment; - const executablePath = yield* HostProcessExecutablePath; - const hostPlatform = yield* HostProcessPlatform; + const hostEnvironment = yield* HostProcess.Environment; + const executablePath = yield* HostProcess.ExecutablePath; + const hostPlatform = yield* HostProcess.Platform; const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-inventory-" }); const isWindows = hostPlatform === "win32"; const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode"); @@ -271,7 +267,7 @@ it.layer(layerTest)("OpenCodeRuntime inventory", (it) => { it.effect("caps and drains command stdout and stderr when requested", () => Effect.gen(function* () { const runtime = yield* OpenCodeRuntime.OpenCodeRuntime; - const executablePath = yield* HostProcessExecutablePath; + const executablePath = yield* HostProcess.ExecutablePath; const outputBytes = 2 * 1024 * 1024; const result = yield* runtime.runOpenCodeCommand({ binaryPath: executablePath, diff --git a/packages/provider-opencode/src/server/OpenCodeRuntime.ts b/packages/provider-opencode/src/server/OpenCodeRuntime.ts index 4637ec831b21..c91da0326228 100644 --- a/packages/provider-opencode/src/server/OpenCodeRuntime.ts +++ b/packages/provider-opencode/src/server/OpenCodeRuntime.ts @@ -36,7 +36,7 @@ import { isWindowsCommandNotFound } from "@t3tools/provider-core/server/snapshot import * as OpenCodeServerLedger from "./OpenCodeServerLedger.ts"; import { collectStreamAsString } from "@t3tools/provider-core/server/snapshotProbe"; import * as NetService from "@t3tools/shared/Net"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { compareSemverVersions, parseSemver } from "@t3tools/shared/semver"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; const encodeUnknownJsonStringExit = Schema.encodeUnknownExit(Schema.fromJsonString(Schema.Unknown)); @@ -595,7 +595,7 @@ function ensureRuntimeError( const makeOpenCodeRuntime = Effect.gen(function* () { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const netService = yield* NetService.NetService; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const serverLedger = yield* OpenCodeServerLedger.OpenCodeServerLedger; const resolveCommand = (command: string, args: ReadonlyArray, env?: NodeJS.ProcessEnv) => resolveSpawnCommand(command, args, env ? { env } : {}); diff --git a/packages/provider-opencode/src/server/OpenCodeServerLedger.test.ts b/packages/provider-opencode/src/server/OpenCodeServerLedger.test.ts index 90b0c55c157f..45bb5bb5d7c1 100644 --- a/packages/provider-opencode/src/server/OpenCodeServerLedger.test.ts +++ b/packages/provider-opencode/src/server/OpenCodeServerLedger.test.ts @@ -3,7 +3,7 @@ import * as NodeChildProcess from "node:child_process"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { describe, expect, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; @@ -67,7 +67,7 @@ const recordFromDeadServer = (stateDir: string, server: { readonly pid: number } yield* previousServer.exited; }); -const hostPlatform = HostProcessPlatform.defaultValue(); +const hostPlatform = HostProcess.Platform.defaultValue(); // procps accepts the same `ps` flags as macOS, so Linux also covers the macOS path. const observedPlatforms: ReadonlyArray = hostPlatform === "linux" ? ["linux", "darwin"] : hostPlatform === "darwin" ? ["darwin"] : []; @@ -75,7 +75,7 @@ const observedPlatforms: ReadonlyArray = describe.each(observedPlatforms)("OpenCodeServerLedger observing as %s", (platform) => { const provideHost = (effect: Effect.Effect) => effect.pipe( - Effect.provideService(HostProcessPlatform, platform), + Effect.provideService(HostProcess.Platform, platform), Effect.provide(NodeServices.layer), ); diff --git a/packages/provider-opencode/src/server/OpenCodeServerLedger.ts b/packages/provider-opencode/src/server/OpenCodeServerLedger.ts index 43774e245232..cb6b2f92da41 100644 --- a/packages/provider-opencode/src/server/OpenCodeServerLedger.ts +++ b/packages/provider-opencode/src/server/OpenCodeServerLedger.ts @@ -1,4 +1,4 @@ -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -119,7 +119,7 @@ export const make = Effect.fn("OpenCodeServerLedger.make")(function* (input: { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const directory = path.join(input.stateDir, ENTRY_DIRECTORY); // Windows servers are not detached and are never recorded. const recordable = platform === "linux" || platform === "darwin"; diff --git a/packages/provider-opencode/src/server/adapter.ts b/packages/provider-opencode/src/server/adapter.ts index c7020b8ff45a..327d4d8cef4f 100644 --- a/packages/provider-opencode/src/server/adapter.ts +++ b/packages/provider-opencode/src/server/adapter.ts @@ -9,7 +9,7 @@ import type { Todo as OpenCodeTodo, ToolPart, } from "@opencode-ai/sdk/v2"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { getModelSelectionStringOptionValue } from "@t3tools/shared/model"; import { causeErrorTag } from "@t3tools/shared/observability"; import { @@ -3739,7 +3739,7 @@ export const OpenCodeAdapterV2Driver: ProviderAdapterDriver< defaultConfig: (): OpenCodeSettings => DEFAULT_OPENCODE_SETTINGS, create: Effect.fn("OpenCodeAdapterV2Driver.create")( function* (input: ProviderAdapterDriverCreateInput) { - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const providerEventLoggers = yield* ProviderEventLoggers.ProviderEventLoggers; return yield* makeOpenCodeAdapterV2({ instanceId: input.instanceId, @@ -3769,7 +3769,7 @@ const layer: Layer.Layer Effect.provide(NodeServices.layer), ); -it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( +it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "updates an npm-global OpenCode 2 install as @opencode/cli and a 1.x one as opencode-ai", () => Effect.gen(function* () { @@ -243,7 +243,7 @@ it.layer(layerUpdate)("OpenCodeDriver updates", (it) => { }).pipe(Effect.scoped), ); - it.effect.skipIf(HostProcessPlatform.defaultValue() === "win32")( + it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")( "offers no package update for an unknown version and follows a changed one on a fresh read", () => Effect.gen(function* () { diff --git a/packages/provider-opencode/src/server/usage.ts b/packages/provider-opencode/src/server/usage.ts index 65897f85d98e..9d09266118eb 100644 --- a/packages/provider-opencode/src/server/usage.ts +++ b/packages/provider-opencode/src/server/usage.ts @@ -11,7 +11,7 @@ import { type ProviderUsageReader, type UsageRecord, } from "@t3tools/provider-core/server/usage"; -import { HostProcessEnvironment, HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; @@ -257,8 +257,8 @@ export const readOpenCodeUsage = Effect.fn("readOpenCodeUsage")(function* ( const resolveOpenCodeDataDirs = Effect.fn("resolveOpenCodeDataDirs")(function* () { const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const environment = yield* HostProcessEnvironment; - const homeDirectory = yield* HostProcessHomeDirectory; + const environment = yield* HostProcess.Environment; + const homeDirectory = yield* HostProcess.HomeDirectory; const roots = environment["OPENCODE_DATA_DIR"] ?.split(",") .map((value) => value.trim()) diff --git a/packages/provider-opencode/src/server/usageLimits.ts b/packages/provider-opencode/src/server/usageLimits.ts index 05c3b79d411a..6472bb71039c 100644 --- a/packages/provider-opencode/src/server/usageLimits.ts +++ b/packages/provider-opencode/src/server/usageLimits.ts @@ -16,7 +16,7 @@ import { makeUnavailableUsageLimits, makeUsageLimits, } from "@t3tools/provider-core/server/usageLimits"; -import { HostProcessHomeDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; const AuthFile = Schema.Struct({ "opencode-go": Schema.optionalKey(Schema.Unknown) }); const ApiAuth = Schema.Struct({ type: Schema.Literal("api"), key: Schema.String }); @@ -47,7 +47,7 @@ export const readOpenCodeGoUsageLimits = Effect.fn("readOpenCodeGoUsageLimits")( const dataHome = env.XDG_DATA_HOME || path.join( - env.HOME || env.USERPROFILE || (yield* HostProcessHomeDirectory), + env.HOME || env.USERPROFILE || (yield* HostProcess.HomeDirectory), ".local", "share", ); diff --git a/packages/provider-opencode/src/server/v2/OpenCode2Server.test.ts b/packages/provider-opencode/src/server/v2/OpenCode2Server.test.ts index 340e03f8d7d5..9fab7f63420d 100644 --- a/packages/provider-opencode/src/server/v2/OpenCode2Server.test.ts +++ b/packages/provider-opencode/src/server/v2/OpenCode2Server.test.ts @@ -1,10 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; -import { - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as FileSystem from "effect/FileSystem"; @@ -221,7 +217,7 @@ describe("OpenCode2Server spawned server", () => { Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode2-fake-" }); const isWindows = platform === "win32"; const binaryPath = path.join(directory, isWindows ? "opencode.cmd" : "opencode"); @@ -230,8 +226,8 @@ describe("OpenCode2Server spawned server", () => { yield* fs.writeFileString( binaryPath, isWindows - ? `@echo off\r\n"${yield* HostProcessExecutablePath}" "${scriptPath}" %*\r\n` - : `#!/bin/sh\nexec "${yield* HostProcessExecutablePath}" "${scriptPath}" "$@"\n`, + ? `@echo off\r\n"${yield* HostProcess.ExecutablePath}" "${scriptPath}" %*\r\n` + : `#!/bin/sh\nexec "${yield* HostProcess.ExecutablePath}" "${scriptPath}" "$@"\n`, ); if (!isWindows) yield* fs.chmod(binaryPath, 0o755); @@ -240,7 +236,7 @@ describe("OpenCode2Server spawned server", () => { serverUrl: "", serverPassword: "", directory, - environment: { ...(yield* HostProcessEnvironment), OPENCODE_SERVER_PASSWORD: "ambient" }, + environment: { ...(yield* HostProcess.Environment), OPENCODE_SERVER_PASSWORD: "ambient" }, }); const first = yield* server.withConnection((connection) => Effect.succeed(connection)); const second = yield* server.withConnection((connection) => Effect.succeed(connection)); diff --git a/packages/provider-pi/src/server/adapter.test.ts b/packages/provider-pi/src/server/adapter.test.ts index 8508fb064837..e13f8213077f 100644 --- a/packages/provider-pi/src/server/adapter.test.ts +++ b/packages/provider-pi/src/server/adapter.test.ts @@ -38,7 +38,7 @@ import * as McpProviderSessions from "@t3tools/provider-core/server/McpProviderS import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator"; import * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter"; import { handoffBudget } from "@t3tools/provider-core/server/handoffBudget"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { makePiAdapterV2, PiAdapterV2Driver, @@ -336,7 +336,7 @@ const makeAdapter = Effect.fnUntraced(function* ( config: { enabled: true, binaryPath: "pi", launchArgs, customModels: [] }, }).pipe( Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Environment, {}), Effect.provideService(ProviderContinuationRequests.ProviderContinuationRequests, { ...continuationRequests, take: Effect.never, diff --git a/packages/provider-pi/src/server/adapter.ts b/packages/provider-pi/src/server/adapter.ts index c6bdc4338ab3..c650a444daf9 100644 --- a/packages/provider-pi/src/server/adapter.ts +++ b/packages/provider-pi/src/server/adapter.ts @@ -23,7 +23,7 @@ * Terminal-only decoration such as status, widget, title, and editor-text * updates has no matching T3 surface and is ignored. */ -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { getModelSelectionStringOptionValue } from "@t3tools/shared/model"; import { defaultInstanceIdForDriver, @@ -3271,7 +3271,7 @@ export const PiAdapterV2Driver: ProviderAdapterDriver DEFAULT_PI_SETTINGS, create: Effect.fn("PiAdapterV2Driver.create")( function* (input: ProviderAdapterDriverCreateInput) { - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const continuationRequests = yield* ProviderContinuationRequests.ProviderContinuationRequests; return yield* makePiAdapterV2({ instanceId: input.instanceId, @@ -3299,7 +3299,7 @@ const layer: Layer.Layer boolean, hasExited export const makePiRpcConnection = Effect.fnUntraced(function* (options: PiRpcSpawnOptions) { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const scope = yield* Effect.scope; const spawnCommand = yield* resolveSpawnCommand(options.command, [...options.args], { diff --git a/packages/provider-testing/src/fakeCli.ts b/packages/provider-testing/src/fakeCli.ts index 68ab157aed7a..650f2fd0d5e2 100644 --- a/packages/provider-testing/src/fakeCli.ts +++ b/packages/provider-testing/src/fakeCli.ts @@ -2,7 +2,7 @@ import * as NodeFS from "node:fs"; import * as NodePath from "node:path"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; export interface FakeCliOptions { /** Directory the launcher and its stub are written into. */ @@ -15,7 +15,7 @@ export interface FakeCliOptions { readonly env?: Readonly>; /** * Platform the launcher is shaped for. Effect callers should pass the value - * they read from `HostProcessPlatform` so an injected override is honoured; + * they read from `HostProcess.Platform` so an injected override is honoured; * defaults to the real host for plain tests. */ readonly platform?: NodeJS.Platform; @@ -45,7 +45,7 @@ export function writeFakeCli(options: FakeCliOptions): string { "utf8", ); - if ((options.platform ?? HostProcessPlatform.defaultValue()) === "win32") { + if ((options.platform ?? HostProcess.Platform.defaultValue()) === "win32") { const launcherPath = NodePath.join(options.directory, `${options.name}.cmd`); NodeFS.writeFileSync( launcherPath, diff --git a/packages/shared/package.json b/packages/shared/package.json index fdc368b6c399..fd68e8dada27 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -311,9 +311,9 @@ "types": "./src/nodeRuntime.ts", "import": "./src/nodeRuntime.ts" }, - "./hostProcess": { - "types": "./src/hostProcess.ts", - "import": "./src/hostProcess.ts" + "./HostProcess": { + "types": "./src/HostProcess.ts", + "import": "./src/HostProcess.ts" }, "./testing/longTempDir": { "types": "./src/testing/longTempDir.ts", diff --git a/packages/shared/src/hostProcess.ts b/packages/shared/src/HostProcess.ts similarity index 53% rename from packages/shared/src/hostProcess.ts rename to packages/shared/src/HostProcess.ts index d729624b7630..f30b83234d69 100644 --- a/packages/shared/src/hostProcess.ts +++ b/packages/shared/src/HostProcess.ts @@ -4,57 +4,51 @@ import * as NodeDns from "node:dns"; import * as NodeOS from "node:os"; import * as NodeSea from "node:sea"; -export const HostProcessPlatform = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessPlatform", - { - defaultValue: () => process.platform, - }, -); +export const Platform = Context.Reference("@t3tools/shared/HostProcess/Platform", { + defaultValue: () => process.platform, +}); -export const HostProcessArchitecture = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessArchitecture", +export const Architecture = Context.Reference( + "@t3tools/shared/HostProcess/Architecture", { defaultValue: () => process.arch, }, ); -export const HostProcessHostname = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessHostname", - { - defaultValue: () => NodeOS.hostname(), - }, -); +export const Hostname = Context.Reference("@t3tools/shared/HostProcess/Hostname", { + defaultValue: () => NodeOS.hostname(), +}); -export const HostProcessHomeDirectory = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessHomeDirectory", +export const HomeDirectory = Context.Reference( + "@t3tools/shared/HostProcess/HomeDirectory", { defaultValue: () => NodeOS.homedir(), }, ); -export const HostProcessEnvironment = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessEnvironment", +export const Environment = Context.Reference( + "@t3tools/shared/HostProcess/Environment", { defaultValue: () => process.env, }, ); -export const HostProcessWorkingDirectory = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessWorkingDirectory", +export const WorkingDirectory = Context.Reference( + "@t3tools/shared/HostProcess/WorkingDirectory", { defaultValue: () => process.cwd(), }, ); -export const HostProcessExecutablePath = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessExecutablePath", +export const ExecutablePath = Context.Reference( + "@t3tools/shared/HostProcess/ExecutablePath", { defaultValue: () => process.execPath, }, ); -export const HostProcessArguments = Context.Reference>( - "@t3tools/shared/hostProcess/HostProcessArguments", +export const Arguments = Context.Reference>( + "@t3tools/shared/HostProcess/Arguments", { defaultValue: () => process.argv, }, @@ -65,12 +59,9 @@ export const HostProcessArguments = Context.Reference>( * `t3` for a PATH lookup, `./t3` or the launcher symlink for an explicit * path. `process.argv[0]` and `execPath` are always the resolved binary. */ -export const HostProcessInvokedAs = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessInvokedAs", - { - defaultValue: () => process.argv0, - }, -); +export const InvokedAs = Context.Reference("@t3tools/shared/HostProcess/InvokedAs", { + defaultValue: () => process.argv0, +}); /** * Whether this process is a Node single-executable rather than a script run @@ -78,12 +69,9 @@ export const HostProcessInvokedAs = Context.Reference( * one branches on this: an executable hosts such things as hidden * subcommands of itself. */ -export const HostProcessIsExecutable = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessIsExecutable", - { - defaultValue: () => NodeSea.isSea(), - }, -); +export const IsExecutable = Context.Reference("@t3tools/shared/HostProcess/IsExecutable", { + defaultValue: () => NodeSea.isSea(), +}); /** * Every IP address this machine answers to: the interface addresses, plus @@ -95,8 +83,8 @@ export const HostProcessIsExecutable = Context.Reference( * * Best effort: a failed lookup just leaves the interface set. */ -export const HostProcessAddresses = Context.Reference>>( - "@t3tools/shared/hostProcess/HostProcessAddresses", +export const Addresses = Context.Reference>>( + "@t3tools/shared/HostProcess/Addresses", { defaultValue: () => Effect.gen(function* () { @@ -115,11 +103,8 @@ export const HostProcessAddresses = Context.Reference( - "@t3tools/shared/hostProcess/HostProcessUserId", - { - defaultValue: () => process.getuid?.(), - }, -); +export const UserId = Context.Reference("@t3tools/shared/HostProcess/UserId", { + defaultValue: () => process.getuid?.(), +}); -export const isHostWindows = Effect.map(HostProcessPlatform, (platform) => platform === "win32"); +export const isWindows = Effect.map(Platform, (platform) => platform === "win32"); diff --git a/packages/shared/src/editor.ts b/packages/shared/src/editor.ts index b996b6d12c14..3017e5bb8a30 100644 --- a/packages/shared/src/editor.ts +++ b/packages/shared/src/editor.ts @@ -4,7 +4,7 @@ import * as FileSystem from "effect/FileSystem"; import * as Option from "effect/Option"; import * as Path from "effect/Path"; -import * as HostProcess from "./hostProcess.ts"; +import * as HostProcess from "./HostProcess.ts"; import { isCommandAvailable } from "./shell.ts"; type Editor = (typeof EDITORS)[number]; @@ -37,7 +37,7 @@ export const resolveEditorCommand = Effect.fn("editor.resolveEditorCommand")(fun if (yield* isCommandAvailable(command, { env })) return Option.some({ command, baseArgs }); } - const platform = yield* HostProcess.HostProcessPlatform; + const platform = yield* HostProcess.Platform; const path = yield* Path.Path; const fs = yield* FileSystem.FileSystem; const home = env.HOME; diff --git a/packages/shared/src/logging.test.ts b/packages/shared/src/logging.test.ts index 0e294bbe29bf..7317cb4f7b49 100644 --- a/packages/shared/src/logging.test.ts +++ b/packages/shared/src/logging.test.ts @@ -3,7 +3,7 @@ import * as NodeFS from "node:fs"; import * as NodeOS from "node:os"; import * as NodePath from "node:path"; import { afterEach, describe, expect, it } from "vite-plus/test"; -import { HostProcessPlatform } from "./hostProcess.ts"; +import * as HostProcess from "./HostProcess.ts"; import { RotatingFileSink, @@ -11,7 +11,7 @@ import { RotatingFileSinkError, } from "./logging.ts"; -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; const tempDirectories: string[] = []; const makeTempDirectory = (): string => { diff --git a/packages/shared/src/nodeRuntime.test.ts b/packages/shared/src/nodeRuntime.test.ts index 31c73ac732f6..c298ad405b2e 100644 --- a/packages/shared/src/nodeRuntime.test.ts +++ b/packages/shared/src/nodeRuntime.test.ts @@ -5,12 +5,7 @@ import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import * as Result from "effect/Result"; -import { - HostProcessArguments, - HostProcessExecutablePath, - HostProcessIsExecutable, - HostProcessPlatform, -} from "./hostProcess.ts"; +import * as HostProcess from "./HostProcess.ts"; import { resolveNodeExecutable, resolveSelfInvocation, selfInvocationArgs } from "./nodeRuntime.ts"; import { symlinksSupported } from "./testing/symlinks.ts"; @@ -19,9 +14,9 @@ describe("Self invocation", () => { Effect.gen(function* () { const path = yield* Path.Path; const invocation = yield* resolveSelfInvocation().pipe( - Effect.provideService(HostProcessExecutablePath, "/runtime/node"), - Effect.provideService(HostProcessIsExecutable, false), - Effect.provideService(HostProcessArguments, ["/runtime/node", "dist/bin.mjs", "serve"]), + Effect.provideService(HostProcess.ExecutablePath, "/runtime/node"), + Effect.provideService(HostProcess.IsExecutable, false), + Effect.provideService(HostProcess.Arguments, ["/runtime/node", "dist/bin.mjs", "serve"]), ); expect(invocation.command).toBe("/runtime/node"); expect(invocation.entrypoint).toBe(path.resolve("dist/bin.mjs")); @@ -36,9 +31,9 @@ describe("Self invocation", () => { Effect.gen(function* () { // Node repeats the binary at argv[1] for a single-executable; it is not a script. const invocation = yield* resolveSelfInvocation().pipe( - Effect.provideService(HostProcessExecutablePath, "/packaged/t3"), - Effect.provideService(HostProcessIsExecutable, true), - Effect.provideService(HostProcessArguments, ["/packaged/t3", "/packaged/t3", "serve"]), + Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"), + Effect.provideService(HostProcess.IsExecutable, true), + Effect.provideService(HostProcess.Arguments, ["/packaged/t3", "/packaged/t3", "serve"]), ); expect(invocation).toEqual({ command: "/packaged/t3", entrypoint: undefined }); expect(selfInvocationArgs(invocation, ["acp-mcp-bridge"])).toEqual(["acp-mcp-bridge"]); @@ -52,8 +47,8 @@ describe("Node runtime selection", () => { for (const executable of ["/runtime/node", "/Applications/T3 Code.app/Electron"]) { expect( yield* resolveNodeExecutable("Local device support", { PATH: "" }).pipe( - Effect.provideService(HostProcessExecutablePath, executable), - Effect.provideService(HostProcessIsExecutable, false), + Effect.provideService(HostProcess.ExecutablePath, executable), + Effect.provideService(HostProcess.IsExecutable, false), ), ).toBe(executable); } @@ -69,8 +64,8 @@ describe("Node runtime selection", () => { }), ).toBe(process.execPath); }).pipe( - Effect.provideService(HostProcessExecutablePath, "/packaged/t3"), - Effect.provideService(HostProcessIsExecutable, true), + Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"), + Effect.provideService(HostProcess.IsExecutable, true), Effect.provide(NodeServices.layer), ), ); @@ -84,7 +79,7 @@ describe("Node runtime selection", () => { expect(error.message).toContain("Local device support requires Node.js"); expect(error.message).toContain("Install Node.js"); }).pipe( - Effect.provideService(HostProcessIsExecutable, true), + Effect.provideService(HostProcess.IsExecutable, true), Effect.provide(NodeServices.layer), ), ); @@ -94,7 +89,7 @@ describe("Node runtime selection", () => { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const directory = yield* fs.makeTempDirectoryScoped(); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const node = path.join(directory, platform === "win32" ? "node.exe" : "node"); const env = { PATH: directory }; expect( @@ -107,8 +102,8 @@ describe("Node runtime selection", () => { expect(yield* resolveNodeExecutable("Local device support", env)).toBe(node); }).pipe( Effect.scoped, - Effect.provideService(HostProcessExecutablePath, "/packaged/t3"), - Effect.provideService(HostProcessIsExecutable, true), + Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"), + Effect.provideService(HostProcess.IsExecutable, true), Effect.provide(NodeServices.layer), ), ); @@ -134,9 +129,9 @@ describe("Node runtime selection", () => { ).toBe(node); }).pipe( Effect.scoped, - Effect.provideService(HostProcessExecutablePath, "/packaged/t3"), - Effect.provideService(HostProcessIsExecutable, true), - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"), + Effect.provideService(HostProcess.IsExecutable, true), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provide(NodeServices.layer), ), ); @@ -156,8 +151,8 @@ describe("Node runtime selection", () => { expect(error.message).toContain("Install Node.js"); }).pipe( Effect.scoped, - Effect.provideService(HostProcessIsExecutable, true), - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.IsExecutable, true), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provide(NodeServices.layer), ), ); @@ -167,21 +162,21 @@ describe("Node runtime selection", () => { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const directory = yield* fs.makeTempDirectoryScoped(); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const executable = path.join(directory, platform === "win32" ? "t3.exe" : "t3"); const node = path.join(directory, platform === "win32" ? "node.exe" : "node"); yield* fs.writeFileString(executable, "standalone executable fixture"); yield* fs.chmod(executable, 0o755); yield* fs.link(executable, node); const error = yield* resolveNodeExecutable("Local device support", { PATH: directory }).pipe( - Effect.provideService(HostProcessExecutablePath, executable), + Effect.provideService(HostProcess.ExecutablePath, executable), Effect.flip, ); expect(error._tag).toBe("NodeRuntimeUnavailableError"); expect(error.message).toContain("Install Node.js"); }).pipe( Effect.scoped, - Effect.provideService(HostProcessIsExecutable, true), + Effect.provideService(HostProcess.IsExecutable, true), Effect.provide(NodeServices.layer), ), ); @@ -191,14 +186,14 @@ describe("Node runtime selection", () => { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const directory = yield* fs.makeTempDirectoryScoped(); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const node = path.join(directory, platform === "win32" ? "node.exe" : "node"); yield* fs.symlink(process.execPath, node); expect(yield* resolveNodeExecutable("Local device support", { PATH: directory })).toBe(node); }).pipe( Effect.scoped, - Effect.provideService(HostProcessExecutablePath, "/packaged/t3"), - Effect.provideService(HostProcessIsExecutable, true), + Effect.provideService(HostProcess.ExecutablePath, "/packaged/t3"), + Effect.provideService(HostProcess.IsExecutable, true), Effect.provide(NodeServices.layer), ), ); @@ -210,7 +205,7 @@ describe("Node runtime selection", () => { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const directory = yield* fs.makeTempDirectoryScoped(); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const node = path.join(directory, platform === "win32" ? "node.exe" : "node"); yield* fs.symlink(process.execPath, node); const error = yield* resolveNodeExecutable("Local device support", { @@ -219,7 +214,7 @@ describe("Node runtime selection", () => { expect(error.message).toContain("Install Node.js"); }).pipe( Effect.scoped, - Effect.provideService(HostProcessIsExecutable, true), + Effect.provideService(HostProcess.IsExecutable, true), Effect.provide(NodeServices.layer), ), ); diff --git a/packages/shared/src/nodeRuntime.ts b/packages/shared/src/nodeRuntime.ts index baa4d9dc610c..4ad752f43d0d 100644 --- a/packages/shared/src/nodeRuntime.ts +++ b/packages/shared/src/nodeRuntime.ts @@ -4,13 +4,7 @@ import * as Path from "effect/Path"; import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; -import { - HostProcessArguments, - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessIsExecutable, - HostProcessPlatform, -} from "./hostProcess.ts"; +import * as HostProcess from "./HostProcess.ts"; import { CommandResolutionCache, resolveCommandPath } from "./shell.ts"; const NodeRuntimeFeature = Schema.Literals([ @@ -51,11 +45,11 @@ export interface SelfInvocation { * assemble the pair themselves. */ export const resolveSelfInvocation = Effect.fn("nodeRuntime.resolveSelfInvocation")(function* () { - const command = yield* HostProcessExecutablePath; - if (yield* HostProcessIsExecutable) + const command = yield* HostProcess.ExecutablePath; + if (yield* HostProcess.IsExecutable) return { command, entrypoint: undefined } satisfies SelfInvocation; const path = yield* Path.Path; - const entry = (yield* HostProcessArguments)[1]; + const entry = (yield* HostProcess.Arguments)[1]; // Children spawn from their own working directory, so the script path must be absolute. return { command, @@ -75,13 +69,13 @@ export const resolveNodeExecutable = Effect.fn("nodeRuntime.resolveNodeExecutabl feature: typeof NodeRuntimeFeature.Type, environment?: NodeJS.ProcessEnv, ) { - const executablePath = yield* HostProcessExecutablePath; - if (!(yield* HostProcessIsExecutable)) return executablePath; + const executablePath = yield* HostProcess.ExecutablePath; + if (!(yield* HostProcess.IsExecutable)) return executablePath; const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; - const env = environment ?? (yield* HostProcessEnvironment); + const platform = yield* HostProcess.Platform; + const env = environment ?? (yield* HostProcess.Environment); const nodePath = yield* resolveCommandPath(platform === "win32" ? "node.exe" : "node", { // Batch wrappers require a shell; helper callers launch the runtime directly. env: platform === "win32" ? { ...env, PATHEXT: ".EXE" } : env, diff --git a/packages/shared/src/relayClient.test.ts b/packages/shared/src/relayClient.test.ts index a96f3f8d864b..d743067b6209 100644 --- a/packages/shared/src/relayClient.test.ts +++ b/packages/shared/src/relayClient.test.ts @@ -14,18 +14,18 @@ import * as Stream from "effect/Stream"; import * as TestClock from "effect/testing/TestClock"; import { HttpClient, HttpClientResponse } from "effect/http"; import { ChildProcess, ChildProcessSpawner } from "effect/process"; -import { HostProcessArchitecture, HostProcessPlatform } from "./hostProcess.ts"; +import * as HostProcess from "./HostProcess.ts"; import * as RelayClient from "./relayClient.ts"; // The suite runs the linux code path against the real filesystem, checking // POSIX exec bits that NTFS never reports; the win32 branch skips that check. -const windowsHost = HostProcessPlatform.defaultValue() === "win32"; +const windowsHost = HostProcess.Platform.defaultValue() === "win32"; const layerHostRuntime = (env: Record = {}, platform: NodeJS.Platform = "linux") => Layer.mergeAll( - Layer.succeed(HostProcessPlatform, platform), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, platform), + Layer.succeed(HostProcess.Architecture, "x64"), ConfigProvider.layer(ConfigProvider.fromEnv({ env })), ); diff --git a/packages/shared/src/relayClient.ts b/packages/shared/src/relayClient.ts index 3705e7677cdd..44a2429d4231 100644 --- a/packages/shared/src/relayClient.ts +++ b/packages/shared/src/relayClient.ts @@ -21,7 +21,7 @@ import * as Schedule from "effect/Schedule"; import * as Semaphore from "effect/Semaphore"; import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"; import { ChildProcess, ChildProcessSpawner } from "effect/process"; -import { HostProcessArchitecture, HostProcessPlatform } from "./hostProcess.ts"; +import * as HostProcess from "./HostProcess.ts"; export const CLOUDFLARED_VERSION = "2026.10.0"; // The oldest release that accepts every flag the connector is started with @@ -257,8 +257,8 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function const path = yield* Path.Path; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const installSemaphore = yield* Semaphore.make(1); - const platform = yield* HostProcessPlatform; - const arch = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const arch = yield* HostProcess.Architecture; const releaseAsset = options.releaseAsset ?? resolveReleaseAsset(platform, arch); const loadCloudflaredConfig = Effect.suspend(() => CloudflaredConfig).pipe(Effect.orDie); const managedRoot = path.join(options.baseDir, "tools", "cloudflared"); diff --git a/packages/shared/src/shell.test.ts b/packages/shared/src/shell.test.ts index 4e27aa49fcfc..428d0d5951f5 100644 --- a/packages/shared/src/shell.test.ts +++ b/packages/shared/src/shell.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { it as effectIt } from "@effect/vitest"; -import { HostProcessEnvironment, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; @@ -342,7 +342,7 @@ effectIt.layer(NodeServices.layer)("isCommandAvailable", (it) => { expect( yield* isCommandAvailable("definitely-not-installed", { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" }, - }).pipe(Effect.provideService(HostProcessPlatform, "win32")), + }).pipe(Effect.provideService(HostProcess.Platform, "win32")), ).toBe(false); }), ); @@ -353,7 +353,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => { Effect.gen(function* () { const result = yield* resolveCommandPath("definitely-not-installed", { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" }, - }).pipe(Effect.provideService(HostProcessPlatform, "win32"), Effect.result); + }).pipe(Effect.provideService(HostProcess.Platform, "win32"), Effect.result); expect(result._tag).toBe("Failure"); }), @@ -367,7 +367,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => { Effect.gen(function* () { const probed: Array = []; const result = yield* resolveCommandPath("definitely-not-installed", { env }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), Effect.provide( FileSystem.layerNoop({ @@ -425,7 +425,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => { const resolved = yield* resolveCommandPath(command, { env: { PATH: cwd, PATHEXT: ".CMD" }, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), Effect.provideService(FileSystem.FileSystem, { ...fs, @@ -458,7 +458,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => { yield* TestClock.adjust("30 seconds"); expect(yield* resolveCommandPath("appeared", options)).toBe(executable); }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), ), ); @@ -505,7 +505,7 @@ effectIt.layer(NodeServices.layer)("resolveCommandPath", (it) => { ); expect(probed).toEqual([path.join(first, "cursor.CMD"), path.join(second, "late.EXE")]); }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), ), ); @@ -517,7 +517,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => { const command = yield* resolveSpawnCommand("node.exe", ["script.js", "hello & goodbye"], { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" }, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), ); @@ -536,7 +536,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => { ["run", "value & calc", "%PATH%", 'quote"value'], { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" } }, ).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), Effect.provideService( SpawnExecutableResolution, @@ -563,9 +563,9 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => { env: { CODEX_HOME: "C:\\Users\\tester\\.codex" }, extendEnv: true, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), - Effect.provideService(HostProcessEnvironment, { + Effect.provideService(HostProcess.Environment, { PATH: "C:\\Users\\tester\\AppData\\Roaming\\npm", PATHEXT: ".COM;.EXE;.BAT;.CMD", }), @@ -592,7 +592,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => { }; const resolve = (command: string, path: string, resolver = scan) => resolveSpawnCommand(command, [], { env: { PATH: path, PATHEXT: ".EXE" } }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(SpawnExecutableResolution, resolver), ); @@ -632,7 +632,7 @@ effectIt.layer(NodeServices.layer)("resolveSpawnCommand", (it) => { const command = yield* resolveSpawnCommand("missing & calc", ["unsafe & value"], { env: { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD" }, }).pipe( - Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(HostProcess.Platform, "win32"), Effect.provideService(CommandResolutionCache, new Map()), ); diff --git a/packages/shared/src/shell.ts b/packages/shared/src/shell.ts index 1742aa33065b..b24c998b1785 100644 --- a/packages/shared/src/shell.ts +++ b/packages/shared/src/shell.ts @@ -11,7 +11,7 @@ import * as FileSystem from "effect/FileSystem"; import * as Option from "effect/Option"; import * as Path from "effect/Path"; -import { HostProcessEnvironment, HostProcessPlatform } from "./hostProcess.ts"; +import * as HostProcess from "./HostProcess.ts"; import * as Context from "effect/Context"; const SHELL_ENV_NAME_PATTERN = /^[A-Z0-9_]+$/; const WINDOWS_PATH_DELIMITER = ";"; @@ -503,7 +503,7 @@ interface CommandResolutionCacheEntry { readonly expiresAtNanos: bigint; } -// The cache lives in the Effect environment (like HostProcessPlatform above) +// The cache lives in the Effect environment (like HostProcess.Platform above) // so tests and embedders can provide an isolated instance; the default is a // single process-wide map shared by all consumers. export const CommandResolutionCache = Context.Reference>( @@ -688,8 +688,8 @@ export const resolveCommandPath = Effect.fn("shell.resolveCommandPath")(function options: CommandAvailabilityOptions = {}, ) { return yield* resolveCommandPathForPlatform(command, { - env: options.env ?? (yield* HostProcessEnvironment), - platform: yield* HostProcessPlatform, + env: options.env ?? (yield* HostProcess.Environment), + platform: yield* HostProcess.Platform, }); }); @@ -699,12 +699,12 @@ export const resolveSpawnCommand = Effect.fnUntraced(function* ( args: ReadonlyArray, options: CommandAvailabilityOptions = {}, ): Effect.fn.Return { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (platform !== "win32") { return { command, args: [...args], shell: false }; } - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; const env = options.env === undefined ? hostEnvironment diff --git a/packages/shared/src/testing/longTempDir.ts b/packages/shared/src/testing/longTempDir.ts index 8a18abb8ce42..669d6da36971 100644 --- a/packages/shared/src/testing/longTempDir.ts +++ b/packages/shared/src/testing/longTempDir.ts @@ -1,14 +1,14 @@ // @effect-diagnostics nodeBuiltinImport:off - runs once at test setup, outside any Effect runtime. import * as NodeFS from "node:fs"; import * as NodeOS from "node:os"; -import { HostProcessPlatform } from "../hostProcess.ts"; +import * as HostProcess from "../HostProcess.ts"; // GitHub's Windows runners hand out the temp directory by its 8.3 short name // (C:\Users\RUNNER~1\...). Anything that canonicalises a path, such as git or // realpath, reports the long form, so equality checks between a temp path and // its canonical form fail. Node reads TEMP/TMP on every os.tmpdir() call, so // pointing them at the long form fixes every temp directory the suite makes. -if (HostProcessPlatform.defaultValue() === "win32") { +if (HostProcess.Platform.defaultValue() === "win32") { try { const longForm = NodeFS.realpathSync.native(NodeOS.tmpdir()); process.env.TEMP = longForm; diff --git a/packages/source-control-forgejo/src/server/ForgejoCli.ts b/packages/source-control-forgejo/src/server/ForgejoCli.ts index 46afc4522b45..90501a4591ca 100644 --- a/packages/source-control-forgejo/src/server/ForgejoCli.ts +++ b/packages/source-control-forgejo/src/server/ForgejoCli.ts @@ -11,7 +11,7 @@ import * as NodePath from "node:path"; import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http"; import { ChildProcessSpawner } from "effect/process"; import { decodeJsonResult } from "@t3tools/shared/schemaJson"; -import { HostProcessHomeDirectory, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost"; import { collectUint8StreamText } from "@t3tools/provider-core/server/collectStreamText"; import type { SourceControlProviderContext } from "@t3tools/source-control-core/server/SourceControlProvider"; @@ -248,8 +248,8 @@ export const make = Effect.gen(function* () { const readKeys = Effect.fn("ForgejoCli.readKeys")(function* (cwd: string) { for (const path of forgejoKeysPaths({ - platform: yield* HostProcessPlatform, - home: yield* HostProcessHomeDirectory, + platform: yield* HostProcess.Platform, + home: yield* HostProcess.HomeDirectory, ...(globalThis.process.env.XDG_DATA_HOME ? { dataHome: globalThis.process.env.XDG_DATA_HOME } : {}), diff --git a/packages/source-control-github/src/server/GitHubCredentials.ts b/packages/source-control-github/src/server/GitHubCredentials.ts index 7483d7e02a52..9eaa52301c04 100644 --- a/packages/source-control-github/src/server/GitHubCredentials.ts +++ b/packages/source-control-github/src/server/GitHubCredentials.ts @@ -11,7 +11,7 @@ import * as PlatformError from "effect/PlatformError"; import * as Redacted from "effect/Redacted"; import * as Schema from "effect/Schema"; -import { HostProcessEnvironment, HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost"; @@ -130,8 +130,8 @@ export const make = Effect.gen(function* () { const sourceControlHost = yield* SourceControlHost.SourceControlHost; const process = sourceControlHost.process; const crypto = yield* Crypto.Crypto; - const environment = yield* HostProcessEnvironment; - const workingDirectory = yield* HostProcessWorkingDirectory; + const environment = yield* HostProcess.Environment; + const workingDirectory = yield* HostProcess.WorkingDirectory; /** `host:sha256(token)`, safe for cache keys and rate-limit scopes. */ const fingerprintOf = (host: string, token: string) => diff --git a/packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts b/packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts index fee5d5e9546c..3f17db9bb302 100644 --- a/packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts +++ b/packages/source-control-github/src/server/GitHubSourceControlProvider.test.ts @@ -1,4 +1,4 @@ -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { assert, describe, it } from "@effect/vitest"; import * as NodeServices from "@effect/platform-node/NodeServices"; import * as Effect from "effect/Effect"; @@ -1075,7 +1075,7 @@ it.live.each([ remoteName: "enterprise", remoteBranch: "feature", }); - }).pipe(Effect.provide(layer), Effect.provideService(HostProcessEnvironment, {}), Effect.scoped); + }).pipe(Effect.provide(layer), Effect.provideService(HostProcess.Environment, {}), Effect.scoped); }); it.effect.each([ @@ -1162,7 +1162,7 @@ it.effect.each([ ]); }).pipe( Effect.provide(layer), - Effect.provideService(HostProcessEnvironment, { GH_REPO: envRepository }), + Effect.provideService(HostProcess.Environment, { GH_REPO: envRepository }), Effect.scoped, ); }, diff --git a/packages/source-control-github/src/server/GitHubSourceControlProvider.ts b/packages/source-control-github/src/server/GitHubSourceControlProvider.ts index 0f442f65d712..e96db27a3e0c 100644 --- a/packages/source-control-github/src/server/GitHubSourceControlProvider.ts +++ b/packages/source-control-github/src/server/GitHubSourceControlProvider.ts @@ -18,7 +18,7 @@ import { type SourceControlRepositoryCloneUrls, } from "@t3tools/contracts"; import { normalizeGitRemoteUrl } from "@t3tools/shared/git"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { decodeJsonResult } from "@t3tools/shared/schemaJson"; import { isSshRemoteUrl } from "@t3tools/shared/sourceControl"; @@ -192,7 +192,7 @@ export const makeDiscovery = Effect.gen(function* () { const api = yield* GitHubApi.GitHubApi; const sourceControlHost = yield* SourceControlHost.SourceControlHost; const process = sourceControlHost.process; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; return { type: "managed-cli", @@ -477,7 +477,7 @@ export const make = Effect.gen(function* () { const api = yield* GitHubApi.GitHubApi; const sourceControlHost = yield* SourceControlHost.SourceControlHost; const process = sourceControlHost.process; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const git = sourceControlHost.git; const fileSystem = yield* FileSystem.FileSystem; diff --git a/packages/ssh/src/auth.test.ts b/packages/ssh/src/auth.test.ts index 3cd42ad43825..2c507db668e7 100644 --- a/packages/ssh/src/auth.test.ts +++ b/packages/ssh/src/auth.test.ts @@ -5,7 +5,7 @@ import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as Path from "effect/Path"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { buildSshAskpassHelperDescriptor, @@ -50,7 +50,7 @@ describe("ssh auth", () => { assert.equal(yield* fs.exists(askpassPath), true); assert.include(yield* fs.readFileString(askpassPath), 'printf "%s\\n" "$T3_SSH_AUTH_SECRET"'); }).pipe( - Effect.provide(Layer.merge(NodeServices.layer, Layer.succeed(HostProcessPlatform, "linux"))), + Effect.provide(Layer.merge(NodeServices.layer, Layer.succeed(HostProcess.Platform, "linux"))), Effect.scoped, ), ); @@ -61,7 +61,7 @@ describe("ssh auth", () => { directory: "C:\\temp\\t3code-ssh-askpass", }).pipe( Effect.provide( - Layer.merge(NodeServices.layer, Layer.succeed(HostProcessPlatform, "win32")), + Layer.merge(NodeServices.layer, Layer.succeed(HostProcess.Platform, "win32")), ), ); diff --git a/packages/ssh/src/auth.ts b/packages/ssh/src/auth.ts index fd4ec9dbc01e..a8bf22bf7e14 100644 --- a/packages/ssh/src/auth.ts +++ b/packages/ssh/src/auth.ts @@ -1,4 +1,4 @@ -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Config from "effect/Config"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; @@ -113,7 +113,7 @@ export const buildSshAskpassHelperDescriptor = Effect.fn( )(function* (input: { readonly directory: string; }): Effect.fn.Return { - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const path = yield* Path.Path; const directory = input.directory; @@ -152,7 +152,7 @@ const ensureSshAskpassHelpers = Effect.fn("ssh/auth.ensureSshAskpassHelpers")(fu const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const descriptor = yield* buildSshAskpassHelperDescriptor(input); - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; yield* fs.makeDirectory(path.dirname(descriptor.launcherPath), { recursive: true }); @@ -182,7 +182,7 @@ export const buildSshChildEnvironment = Effect.fn("ssh/auth.buildSshChildEnviron return baseEnv; } - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const hostDisplay = input.baseEnv ? input.baseEnv.DISPLAY : yield* Config.String("DISPLAY").pipe( diff --git a/packages/ssh/src/command.ts b/packages/ssh/src/command.ts index 8c9e2d304618..b4b42598e382 100644 --- a/packages/ssh/src/command.ts +++ b/packages/ssh/src/command.ts @@ -1,5 +1,5 @@ import type { DesktopSshEnvironmentTarget } from "@t3tools/contracts"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Crypto from "effect/Crypto"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; @@ -25,7 +25,7 @@ const MAX_SSH_ERROR_OUTPUT_LENGTH = 4_000; const sshCommandForPlatform = (platform: NodeJS.Platform): string => platform === "win32" ? "ssh.exe" : "ssh"; -export const resolveSshCommand = Effect.map(HostProcessPlatform, sshCommandForPlatform); +export const resolveSshCommand = Effect.map(HostProcess.Platform, sshCommandForPlatform); const encoder = new TextEncoder(); diff --git a/packages/ssh/src/runnerProcess.test.ts b/packages/ssh/src/runnerProcess.test.ts index bc6064628843..78bac0aac93f 100644 --- a/packages/ssh/src/runnerProcess.test.ts +++ b/packages/ssh/src/runnerProcess.test.ts @@ -1,6 +1,6 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, describe, it } from "@effect/vitest"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; @@ -21,7 +21,7 @@ const Started = Schema.Struct({ }); const decodeStarted = Schema.decodeUnknownSync(Schema.fromJsonString(Started)); -describe.skipIf(HostProcessPlatform.defaultValue() === "win32")( +describe.skipIf(HostProcess.Platform.defaultValue() === "win32")( "remote runner process ownership", () => { 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", () => { }, ); -describe.skipIf(HostProcessPlatform.defaultValue() === "win32")( +describe.skipIf(HostProcess.Platform.defaultValue() === "win32")( "remote stop process ownership", () => { it.live.each(["graceful", "timeout", "external"] as const)( diff --git a/packages/ssh/src/tunnel.test.ts b/packages/ssh/src/tunnel.test.ts index d0943d1e382f..f7f46926ddf9 100644 --- a/packages/ssh/src/tunnel.test.ts +++ b/packages/ssh/src/tunnel.test.ts @@ -1,7 +1,7 @@ import { assert, describe, it } from "@effect/vitest"; import * as NodeServices from "@effect/platform-node/NodeServices"; import * as NetService from "@t3tools/shared/Net"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Deferred from "effect/Deferred"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; @@ -691,8 +691,8 @@ describe("ssh tunnel scripts", () => { // lock excludes concurrent installers. Run the real script against a tiny // fake archive served from a file:// mirror. describe("archive runner script", () => { - const hostPlatform = HostProcessPlatform.defaultValue(); - const hostArch = HostProcessArchitecture.defaultValue(); + const hostPlatform = HostProcess.Platform.defaultValue(); + const hostArch = HostProcess.Architecture.defaultValue(); const windowsHost = hostPlatform === "win32"; const archiveVersion = "1.2.3-preview.20260911.4"; diff --git a/packages/tailscale/src/tailscale.test.ts b/packages/tailscale/src/tailscale.test.ts index cf297d570107..c800bf72defc 100644 --- a/packages/tailscale/src/tailscale.test.ts +++ b/packages/tailscale/src/tailscale.test.ts @@ -8,7 +8,7 @@ import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import * as TestClock from "effect/testing/TestClock"; import { ChildProcessSpawner } from "effect/process"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { buildTailscaleHttpsBaseUrl, @@ -104,7 +104,7 @@ function neverFinishingMockHandle() { function layerSpawner(spawner: ChildProcessSpawner.ChildProcessSpawner["Service"]) { return Layer.merge( Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner), - Layer.succeed(HostProcessPlatform, "linux"), + Layer.succeed(HostProcess.Platform, "linux"), ); } diff --git a/packages/tailscale/src/tailscale.ts b/packages/tailscale/src/tailscale.ts index c1da6fe2b2d4..e3579891b4c6 100644 --- a/packages/tailscale/src/tailscale.ts +++ b/packages/tailscale/src/tailscale.ts @@ -1,4 +1,4 @@ -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; @@ -217,7 +217,7 @@ export const parseTailscaleStatus = ( export const readTailscaleStatus = Effect.gen(function* () { const args = ["status", "--json"]; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const executable = tailscaleCommandForPlatform(hostPlatform); const commandContext = { executable, @@ -291,7 +291,7 @@ const runTailscaleCommand = ( ): Effect.Effect => Effect.gen(function* () { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const executable = tailscaleCommandForPlatform(hostPlatform); const commandContext = { executable, diff --git a/scripts/build-cli-archive.ts b/scripts/build-cli-archive.ts index 65835de83019..85f7ea8da5fe 100644 --- a/scripts/build-cli-archive.ts +++ b/scripts/build-cli-archive.ts @@ -28,7 +28,7 @@ import * as Schema from "effect/Schema"; import { Command, Flag } from "effect/cli"; import { ChildProcess, ChildProcessSpawner } from "effect/process"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { fromYaml } from "@t3tools/shared/schemaYaml"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; import rootPackageJson from "../package.json" with { type: "json" }; @@ -478,8 +478,8 @@ const buildCliArchive = Effect.fn("buildCliArchive")(function* (input: { ); // The unsuffixed host build is only a valid stand-in when it was built for // this platform and architecture; otherwise a missing target must fail. - const hostPlatform = yield* HostProcessPlatform; - const hostKey = `${hostPlatform === "win32" ? "win" : hostPlatform}-${yield* HostProcessArchitecture}`; + const hostPlatform = yield* HostProcess.Platform; + const hostKey = `${hostPlatform === "win32" ? "win" : hostPlatform}-${yield* HostProcess.Architecture}`; const builtExecutable = (yield* fs.exists(targetExecutable)) ? targetExecutable : targetKey === hostKey diff --git a/scripts/build-desktop-artifact.test.ts b/scripts/build-desktop-artifact.test.ts index 2fc9adf94526..8d27a55266fb 100644 --- a/scripts/build-desktop-artifact.test.ts +++ b/scripts/build-desktop-artifact.test.ts @@ -93,7 +93,7 @@ import { wslRuntimeArchiveStem, } from "./build-desktop-artifact.ts"; import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; // 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) => { assert.isBelow(result.fileCount, WINDOWS_PACKAGED_PAYLOAD_FILE_LIMIT); assert.deepStrictEqual(secondAsar, firstAsar); }), - ).pipe(Effect.provideService(HostProcessPlatform, "linux")), + ).pipe(Effect.provideService(HostProcess.Platform, "linux")), ); 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) => { assert.equal(result.packagedAppDir, fixture.packagedAppDir); }), - ).pipe(Effect.provideService(HostProcessPlatform, "linux")), + ).pipe(Effect.provideService(HostProcess.Platform, "linux")), ); it.effect.each(["x64", "arm64"] as const)( @@ -1307,7 +1307,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { assert.equal(result.packagedAppDir, fixture.packagedAppDir); }), - ).pipe(Effect.provideService(HostProcessPlatform, "linux")), + ).pipe(Effect.provideService(HostProcess.Platform, "linux")), ); it.effect.each(["x64", "arm64"] as const)( @@ -1498,8 +1498,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { Effect.provide( Layer.mergeAll( spawnerLayer, - Layer.succeed(HostProcessPlatform, "win32"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, "win32"), + Layer.succeed(HostProcess.Architecture, "x64"), ), ), ); @@ -1541,8 +1541,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { Effect.provide( Layer.mergeAll( spawnerLayer, - Layer.succeed(HostProcessPlatform, "linux"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, "linux"), + Layer.succeed(HostProcess.Architecture, "x64"), ), ), ); @@ -1577,8 +1577,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { Effect.provide( Layer.mergeAll( spawnerLayer, - Layer.succeed(HostProcessPlatform, "darwin"), - Layer.succeed(HostProcessArchitecture, "arm64"), + Layer.succeed(HostProcess.Platform, "darwin"), + Layer.succeed(HostProcess.Architecture, "arm64"), ), ), ); @@ -1623,8 +1623,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { Effect.provide( Layer.mergeAll( spawnerLayer, - Layer.succeed(HostProcessPlatform, "win32"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, "win32"), + Layer.succeed(HostProcess.Architecture, "x64"), ), ), ); @@ -1652,8 +1652,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { ).pipe( Effect.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, "win32"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, "win32"), + Layer.succeed(HostProcess.Architecture, "x64"), ), ), ), @@ -1764,7 +1764,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { assert.instanceOf(error, BundleNotSelfContainedError); assert.include(error.output, "t3code-deliberately-missing-package"); }), - ).pipe(Effect.provideService(HostProcessPlatform, "linux")), + ).pipe(Effect.provideService(HostProcess.Platform, "linux")), ); it.effect("preserves both Linux icon resize failures with structural context", () => { @@ -2333,8 +2333,8 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { }).pipe( Effect.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, "win32"), - Layer.succeed(HostProcessArchitecture, "x64"), + Layer.succeed(HostProcess.Platform, "win32"), + Layer.succeed(HostProcess.Architecture, "x64"), ConfigProvider.layer( ConfigProvider.fromEnv({ env: { diff --git a/scripts/build-desktop-artifact.ts b/scripts/build-desktop-artifact.ts index ed14f57b61a4..374e37830662 100644 --- a/scripts/build-desktop-artifact.ts +++ b/scripts/build-desktop-artifact.ts @@ -16,7 +16,7 @@ import { } from "@electron/asar"; import { fromYaml } from "@t3tools/shared/schemaYaml"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; import rootPackageJson from "../package.json" with { type: "json" }; @@ -869,7 +869,7 @@ const resolveGitCommitHash = Effect.fn("resolveGitCommitHash")(function* (repoRo const resolvePythonForNodeGyp = Effect.fn("resolvePythonForNodeGyp")(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const env = yield* Config.all({ configuredPython: Config.String("npm_config_python").pipe( Config.orElse(() => Config.String("PYTHON")), @@ -1716,7 +1716,7 @@ export const resolveBuildOptions = Effect.fn("resolveBuildOptions")(function* ( const path = yield* Path.Path; const repoRoot = yield* RepoRoot; const env = yield* BuildEnvConfig; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; const platform = mergeOptions( input.platform, @@ -2404,7 +2404,7 @@ export const stageBrowserSecret = Effect.fn("stageBrowserSecret")(function* (inp // silently. `universal` is a mac-only arch the option type still admits; // the helper script rejects it, so it maps to the concrete x64 the Linux // resource monitor uses for the same request. - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; if (hostPlatform !== "linux") { return yield* new LinuxBrowserSecretHostError({ hostPlatform }); } @@ -3165,8 +3165,8 @@ export const verifyWindowsPrimaryFffNativeLoad = Effect.fn( readonly targetArch: typeof BuildArch.Type; readonly verbose: boolean; }) { - const hostPlatform = yield* HostProcessPlatform; - const hostArchitecture = yield* HostProcessArchitecture; + const hostPlatform = yield* HostProcess.Platform; + const hostArchitecture = yield* HostProcess.Architecture; const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const executablePath = path.join(input.packagedAppDir, input.appExecutableName); @@ -3485,7 +3485,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( const repoRoot = yield* RepoRoot; const path = yield* Path.Path; const fs = yield* FileSystem.FileSystem; - const hostPlatform = yield* HostProcessPlatform; + const hostPlatform = yield* HostProcess.Platform; if (hostPlatform === "linux" && options.platform === "linux") { yield* preflightLinuxDesktopBuild(options.arch); } diff --git a/scripts/build-npm-platform-packages.test.ts b/scripts/build-npm-platform-packages.test.ts index cd813ae742b7..6ba620528bfe 100644 --- a/scripts/build-npm-platform-packages.test.ts +++ b/scripts/build-npm-platform-packages.test.ts @@ -1,4 +1,4 @@ -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; @@ -203,8 +203,8 @@ it.layer(NodeServices.layer)("build-npm-platform-packages", (it) => { // NODE_PATH stands in for node_modules: require.resolve finds the // platform package there exactly as it would after `npm install`. - const hostPlatform = yield* HostProcessPlatform; - const hostArch = yield* HostProcessArchitecture; + const hostPlatform = yield* HostProcess.Platform; + const hostArch = yield* HostProcess.Architecture; const env = { ...process.env, NODE_PATH: fixture.outputDir } as Record; if (KEYS.some((key) => key === `${hostPlatform}-${hostArch}`)) { const passthrough = yield* run(process.execPath, ["bin/t3.js", "serve", "--port", "1234"], { diff --git a/scripts/build-npm-platform-packages.ts b/scripts/build-npm-platform-packages.ts index 26ac80b1a3d9..289a6b32522f 100644 --- a/scripts/build-npm-platform-packages.ts +++ b/scripts/build-npm-platform-packages.ts @@ -36,7 +36,7 @@ import { cliArchiveFileName, type CliArchivePlatformKey, } from "@t3tools/shared/cliRelease"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { fromJsonStringPretty } from "@t3tools/shared/schemaJson"; import { isCommandAvailable } from "@t3tools/shared/shell"; import serverPackageJson from "../apps/server/package.json" with { type: "json" }; @@ -253,7 +253,7 @@ const runCommand = Effect.fn("runCommand")(function* ( const extractArchive = Effect.fn("extractArchive")(function* (archive: string, into: string) { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; if (!archive.endsWith(".zip")) { yield* runCommand(ChildProcess.make("tar", ["-xf", archive, "-C", into]), "tar -xf"); } else if (platform === "win32") { @@ -282,7 +282,7 @@ const extractArchive = Effect.fn("extractArchive")(function* (archive: string, i }); /** Tar to build npm tarballs with; see build-cli-archive.ts for why Windows names bsdtar by path. */ -const hostTar = Effect.map(HostProcessPlatform, (platform) => +const hostTar = Effect.map(HostProcess.Platform, (platform) => platform === "win32" ? windowsSystemTar() : "tar", ); diff --git a/scripts/dev-runner.test.ts b/scripts/dev-runner.test.ts index c8363c181976..950d0214c491 100644 --- a/scripts/dev-runner.test.ts +++ b/scripts/dev-runner.test.ts @@ -4,11 +4,7 @@ import * as NodeFS from "node:fs"; import * as NodeOS from "node:os"; import * as NodePath from "node:path"; import * as NetService from "@t3tools/shared/Net"; -import { - HostProcessEnvironment, - HostProcessPlatform, - HostProcessWorkingDirectory, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { assert, describe, it } from "@effect/vitest"; import * as ConfigProvider from "effect/ConfigProvider"; import * as Effect from "effect/Effect"; @@ -887,7 +883,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { return Effect.gen(function* () { const error = yield* runDevRunnerWithInput(devServerInput).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.flip, ); @@ -953,7 +949,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { share: true, }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), ); assert.equal(spawnCount, 1); @@ -977,7 +973,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { host: "192.168.1.10", }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.flip, ); @@ -1012,7 +1008,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { host: "0.0.0.0", }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), ); assert.equal(spawnCount, 1); @@ -1037,7 +1033,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { host: "192.168.1.10", }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), ); assert.equal(spawnCount, 1); @@ -1097,9 +1093,9 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { share: true, }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.provideService( - HostProcessEnvironment, + HostProcess.Environment, input.ambientBundledDev === undefined ? {} : { T3CODE_BUNDLED_DEV: input.ambientBundledDev }, @@ -1144,8 +1140,8 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { port: undefined, }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessEnvironment, {}), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.Environment, {}), ); assert.equal(captured?.T3CODE_BUNDLED_DEV, undefined); @@ -1172,7 +1168,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { share: true, }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), ); assert.equal(spawnCount, 0); @@ -1188,7 +1184,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { return Effect.gen(function* () { const error = yield* runDevRunnerWithInput(devServerInput).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.flip, ); @@ -1221,7 +1217,7 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { return Effect.gen(function* () { const error = yield* runDevRunnerWithInput(devServerInput).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), Effect.flip, ); @@ -1274,10 +1270,10 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { yield* runDevRunnerWithInput({ ...devServerInput, t3Home: input.t3Home }).pipe( Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)), - Effect.provideService(HostProcessPlatform, "linux"), - Effect.provideService(HostProcessWorkingDirectory, input.cwd), + Effect.provideService(HostProcess.Platform, "linux"), + Effect.provideService(HostProcess.WorkingDirectory, input.cwd), Effect.provideService( - HostProcessEnvironment, + HostProcess.Environment, input.ambientHome === undefined ? {} : { T3CODE_HOME: input.ambientHome }, ), ); diff --git a/scripts/dev-runner.ts b/scripts/dev-runner.ts index f026e2507e59..c8531d034c8f 100644 --- a/scripts/dev-runner.ts +++ b/scripts/dev-runner.ts @@ -6,7 +6,7 @@ import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as NodeServices from "@effect/platform-node/NodeServices"; import * as NetService from "@t3tools/shared/Net"; import { resolveGitWorktreePath, resolveWorktreeT3Home } from "@t3tools/shared/devHome"; -import { HostProcessEnvironment, HostProcessWorkingDirectory } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; import * as Config from "effect/Config"; import * as Effect from "effect/Effect"; @@ -645,7 +645,7 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) { return yield* new DevRunnerHostNotProxiableError({ mode: input.mode, host: input.host }); } - const worktreePath = yield* resolveGitWorktreePath(yield* HostProcessWorkingDirectory); + const worktreePath = yield* resolveGitWorktreePath(yield* HostProcess.WorkingDirectory); const { offset, source } = yield* resolveOffset({ portOffset, @@ -663,11 +663,11 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) { checkPortAvailability: makeDefaultCheckPortAvailability(input.host), }); - const hostEnvironment = yield* HostProcessEnvironment; + const hostEnvironment = yield* HostProcess.Environment; // A dev server started inside a worktree defaults to that worktree's own // (gitignored) `.t3` — see @t3tools/shared/devHome for why this must // outrank an ambient T3CODE_HOME. `--home-dir` still wins. - const worktreeHome = yield* resolveWorktreeT3Home(yield* HostProcessWorkingDirectory); + const worktreeHome = yield* resolveWorktreeT3Home(yield* HostProcess.WorkingDirectory); // Trim before choosing: `--home-dir ""` is not a selection, and treating it // as one would skip the worktree default and land on the shared home — // exactly the outcome this precedence exists to prevent. diff --git a/scripts/export-brand-icons.ts b/scripts/export-brand-icons.ts index 6ae7cf3802ea..70cc0949e75c 100644 --- a/scripts/export-brand-icons.ts +++ b/scripts/export-brand-icons.ts @@ -2,7 +2,7 @@ import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Console from "effect/Console"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -408,7 +408,7 @@ const probeIconComposerTool = Effect.fn("iconExport.probeIconComposerTool")(func const resolveIconComposerTool = Effect.fn("iconExport.resolveIconComposerTool")(function* () { const path = yield* Path.Path; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const configuredTool = environment.ICON_COMPOSER_TOOL?.trim(); if (configuredTool) { const tool = yield* probeIconComposerTool(configuredTool); diff --git a/scripts/install.test.ts b/scripts/install.test.ts index 9ded5cb51166..e0fb60517e4a 100644 --- a/scripts/install.test.ts +++ b/scripts/install.test.ts @@ -1,5 +1,5 @@ // @effect-diagnostics nodeBuiltinImport:off - Drives the real shell installer through a PTY and a gated HTTP fixture. -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as NodeChildProcess from "node:child_process"; import * as NodeCrypto from "node:crypto"; import * as NodeFSP from "node:fs/promises"; @@ -9,13 +9,13 @@ import * as NodePath from "node:path"; import { describe, expect, it } from "vite-plus/test"; // util-linux's script gives the real installer a terminal without a browser or extra packages. -describe.skipIf(HostProcessPlatform.defaultValue() !== "linux")("installer terminal", () => { +describe.skipIf(HostProcess.Platform.defaultValue() !== "linux")("installer terminal", () => { it.each([false, true])( "preserves download and install behavior (HTTP failure: %s)", async (fail) => { const root = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-install-progress-")); const version = "1.2.3"; - const stem = `t3-${version}-linux-${HostProcessArchitecture.defaultValue()}`; + const stem = `t3-${version}-linux-${HostProcess.Architecture.defaultValue()}`; const archiveName = `${stem}.tar.gz`; let resumeDownload: (() => void) | undefined; let sawPartialProgress = false; diff --git a/scripts/lib/build-target-arch.test.ts b/scripts/lib/build-target-arch.test.ts index 5da97047570b..d86573dca5a9 100644 --- a/scripts/lib/build-target-arch.test.ts +++ b/scripts/lib/build-target-arch.test.ts @@ -2,7 +2,7 @@ import { assert, describe, it } from "@effect/vitest"; import * as ConfigProvider from "effect/ConfigProvider"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { getDefaultBuildArch } from "./build-target-arch.ts"; @@ -18,8 +18,8 @@ const withHostRuntime = ( ) => Effect.provide( Layer.mergeAll( - Layer.succeed(HostProcessPlatform, platform), - Layer.succeed(HostProcessArchitecture, arch), + Layer.succeed(HostProcess.Platform, platform), + Layer.succeed(HostProcess.Architecture, arch), ConfigProvider.layer(ConfigProvider.fromEnv({ env: compactEnv(env) })), ), ); diff --git a/scripts/lib/build-target-arch.ts b/scripts/lib/build-target-arch.ts index b79c1746f88f..67e379c202ab 100644 --- a/scripts/lib/build-target-arch.ts +++ b/scripts/lib/build-target-arch.ts @@ -1,4 +1,4 @@ -import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import * as Config from "effect/Config"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; @@ -27,8 +27,8 @@ const optionToUndefined = (value: Option.Option): A | undefined => Option.getOrUndefined(value); const resolveHostProcessArch = Effect.fn("resolveHostProcessArch")(function* () { - const platform = yield* HostProcessPlatform; - const processArch = yield* HostProcessArchitecture; + const platform = yield* HostProcess.Platform; + const processArch = yield* HostProcess.Architecture; if (processArch === "arm64") return "arm64"; if (processArch === "x64") { if (platform !== "win32") return "x64"; diff --git a/scripts/lib/cli-external-packages.test.ts b/scripts/lib/cli-external-packages.test.ts index 33c2e897b047..b66545c941fb 100644 --- a/scripts/lib/cli-external-packages.test.ts +++ b/scripts/lib/cli-external-packages.test.ts @@ -34,7 +34,7 @@ const decodeManifest = Schema.decodeUnknownSync(Schema.fromJsonString(PackageMan describe("shouldBundleCliDependency", () => { it("bundles ordinary runtime dependencies", () => { - for (const id of ["effect", "@effect/platform", "hono", "@t3tools/shared/hostProcess"]) { + for (const id of ["effect", "@effect/platform", "hono", "@t3tools/shared/HostProcess"]) { assert.strictEqual(shouldBundleCliDependency(id), true, id); } }); diff --git a/scripts/mobile-native-client.ts b/scripts/mobile-native-client.ts index 6d9f1c762a63..9d33fe2eb293 100644 --- a/scripts/mobile-native-client.ts +++ b/scripts/mobile-native-client.ts @@ -1,10 +1,6 @@ import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { - HostProcessEnvironment, - HostProcessExecutablePath, - HostProcessPlatform, -} from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell"; import * as Console from "effect/Console"; import * as Crypto from "effect/Crypto"; @@ -155,9 +151,9 @@ const collect = (stream: Stream.Stream) => ); export const resolveAdb = Effect.gen(function* () { if (yield* isCommandAvailable("adb")) return "adb"; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const path = yield* Path.Path; - const executable = (yield* HostProcessPlatform) === "win32" ? "adb.exe" : "adb"; + const executable = (yield* HostProcess.Platform) === "win32" ? "adb.exe" : "adb"; for (const sdk of [environment.ANDROID_SDK_ROOT, environment.ANDROID_HOME]) { if (!sdk) continue; const candidate = path.join(sdk, "platform-tools", executable); @@ -176,7 +172,7 @@ const command = Effect.fn("nativeClient.command")(function* ( cwd?: string, ) { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const spawn = yield* resolveSpawnCommand(program === "adb" ? yield* resolveAdb : program, args); const child = yield* spawner.spawn( ChildProcess.make(spawn.command, spawn.args, { @@ -207,7 +203,7 @@ const command = Effect.fn("nativeClient.command")(function* ( }, Effect.scoped); const fingerprint = Effect.fn("nativeClient.fingerprint")(function* (platform: NativePlatform) { - const output = yield* command(yield* HostProcessExecutablePath, [ + const output = yield* command(yield* HostProcess.ExecutablePath, [ "--eval", `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; });`, platform, @@ -226,7 +222,7 @@ const validateDevice = Effect.fn("nativeClient.validateDevice")(function* ( device: string, ) { if (platform === "ios") { - if ((yield* HostProcessPlatform) !== "darwin") + if ((yield* HostProcess.Platform) !== "darwin") return yield* new NativeClientError({ message: "Run iOS check/ensure on the Mac that hosts the simulator.", }); @@ -299,7 +295,7 @@ const main = Command.make( yield* validateDevice(platform, device); const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const environment = yield* HostProcessEnvironment; + const environment = yield* HostProcess.Environment; const home = environment.HOME ?? environment.USERPROFILE; if (!home) return yield* new NativeClientError({ diff --git a/scripts/mobile-native-static-check.test.ts b/scripts/mobile-native-static-check.test.ts index a3e4b183b3ac..32a90c85d51b 100644 --- a/scripts/mobile-native-static-check.test.ts +++ b/scripts/mobile-native-static-check.test.ts @@ -1,5 +1,5 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; -import * as HostProcess from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { assert, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; @@ -33,7 +33,7 @@ const provideSpawner = (spawn: ChildProcessSpawner.ChildProcessSpawner["Service" Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, ChildProcessSpawner.make(spawn)); const runSwiftLint = runCommand("swiftlint", ["lint", "--strict"], "/repo/apps/mobile").pipe( - Effect.provideService(HostProcess.HostProcessPlatform, "linux"), + Effect.provideService(HostProcess.Platform, "linux"), ); it.layer(NodeServices.layer)("mobile native source discovery", (it) => { diff --git a/scripts/smoke-cli-archive.ts b/scripts/smoke-cli-archive.ts index 179c268b909a..9780680cd9e1 100644 --- a/scripts/smoke-cli-archive.ts +++ b/scripts/smoke-cli-archive.ts @@ -22,7 +22,7 @@ import { Command, Flag } from "effect/cli"; import { ChildProcess, ChildProcessSpawner } from "effect/process"; import * as NetService from "@t3tools/shared/Net"; -import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import * as HostProcess from "@t3tools/shared/HostProcess"; import { windowsSystemTar } from "./build-cli-archive.ts"; import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http"; @@ -72,7 +72,7 @@ const smokeCliArchive = Effect.fn("smokeCliArchive")(function* (input: { }) { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const platform = yield* HostProcessPlatform; + const platform = yield* HostProcess.Platform; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const scratch = yield* fs.makeTempDirectory({ prefix: "t3-cli-smoke-" }); // Windows can keep t3.exe locked (EBUSY) for a moment after the server diff --git a/vite.config.ts b/vite.config.ts index 46d61de5e963..b5d906697a6d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -219,7 +219,7 @@ export default defineConfig({ }, { // The one place that reads the host platform to seed the injected references. - files: ["packages/shared/src/hostProcess.ts"], + files: ["packages/shared/src/HostProcess.ts"], rules: { "t3code/no-global-process-runtime": "off" }, }, {