diff --git a/apps/desktop/src/shell/DesktopOpenWith.test.ts b/apps/desktop/src/shell/DesktopOpenWith.test.ts
index 286a7f161a8..e98b202a025 100644
--- a/apps/desktop/src/shell/DesktopOpenWith.test.ts
+++ b/apps/desktop/src/shell/DesktopOpenWith.test.ts
@@ -9,7 +9,6 @@ import {
} from "@t3tools/contracts";
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 * as Layer from "effect/Layer";
import * as Option from "effect/Option";
@@ -144,35 +143,6 @@ describe("DesktopOpenWith launch resolution", () => {
}).pipe(Effect.provide(NodeServices.layer)),
);
- it.effect("resolves CFBundleExecutable and reports missing bundle executables", () =>
- Effect.gen(function* () {
- // oxlint-disable-next-line t3code/no-global-process-runtime -- Platform-gated native fixture.
- if (process.platform !== "darwin") return;
- const fileSystem = yield* FileSystem.FileSystem;
- const path = yield* Path.Path;
- const base = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3-open-with-test-" });
- const applicationPath = path.join(base, "Fixture.app");
- const contentsPath = path.join(applicationPath, "Contents");
- const executableDirectory = path.join(contentsPath, "MacOS");
- yield* fileSystem.makeDirectory(executableDirectory, { recursive: true });
- yield* fileSystem.writeFileString(
- path.join(contentsPath, "Info.plist"),
- `
- CFBundleExecutableFixture`,
- );
- const executablePath = path.join(executableDirectory, "Fixture");
- yield* fileSystem.writeFileString(executablePath, "#!/bin/sh\n");
-
- assert.equal(
- yield* DesktopOpenWith.resolveMacBundleExecutable(applicationPath),
- executablePath,
- );
- yield* fileSystem.remove(executablePath);
- const error = yield* Effect.flip(DesktopOpenWith.resolveMacBundleExecutable(applicationPath));
- assert.equal(error.reason, "missing-executable");
- }).pipe(Effect.provide(NodeServices.layer), Effect.scoped),
- );
-
it.effect("reports available and missing command presentations", () =>
Effect.gen(function* () {
const openWith = yield* DesktopOpenWith.DesktopOpenWith;
diff --git a/apps/desktop/src/shell/DesktopOpenWith.ts b/apps/desktop/src/shell/DesktopOpenWith.ts
index 464d71fce48..73452ba9610 100644
--- a/apps/desktop/src/shell/DesktopOpenWith.ts
+++ b/apps/desktop/src/shell/DesktopOpenWith.ts
@@ -1,6 +1,5 @@
// @effect-diagnostics nodeBuiltinImport:off - macOS bundle paths use the host path grammar.
import {
- OpenWithBundleResolutionError,
OpenWithEnvironmentError,
OpenWithInvalidTargetError,
OpenWithMissingEntryError,
@@ -70,65 +69,6 @@ const entryIsAvailable = Effect.fn("desktop.openWith.entryIsAvailable")(function
return Option.isSome(stat) && stat.value.type === "Directory";
});
-export const resolveMacBundleExecutable = Effect.fn("desktop.openWith.resolveMacBundleExecutable")(
- function* (applicationPath: string) {
- if (!isMacApplicationPath(applicationPath)) {
- return yield* new OpenWithBundleResolutionError({
- applicationPath,
- reason: "invalid-application-path",
- });
- }
- const infoPlistPath = NodePath.join(applicationPath, "Contents", "Info.plist");
- const plistStat = yield* statPath(infoPlistPath);
- if (Option.isNone(plistStat) || plistStat.value.type !== "File") {
- return yield* new OpenWithBundleResolutionError({
- applicationPath,
- reason: "missing-info-plist",
- });
- }
-
- const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
- const executableName = yield* spawner
- .string(
- ChildProcess.make(
- "/usr/bin/plutil",
- ["-extract", "CFBundleExecutable", "raw", "-o", "-", infoPlistPath],
- { stdin: "ignore", stdout: "pipe", stderr: "pipe" },
- ),
- )
- .pipe(
- Effect.map((output) => output.trim()),
- Effect.mapError(
- (cause) =>
- new OpenWithBundleResolutionError({
- applicationPath,
- reason: "malformed-info-plist",
- cause,
- }),
- ),
- );
- if (
- executableName.length === 0 ||
- executableName.includes("/") ||
- executableName.includes("\\")
- ) {
- return yield* new OpenWithBundleResolutionError({
- applicationPath,
- reason: "malformed-info-plist",
- });
- }
- const executablePath = NodePath.join(applicationPath, "Contents", "MacOS", executableName);
- const executableStat = yield* statPath(executablePath);
- if (Option.isNone(executableStat) || executableStat.value.type !== "File") {
- return yield* new OpenWithBundleResolutionError({
- applicationPath,
- reason: "missing-executable",
- });
- }
- return executablePath;
- },
-);
-
const expandDirectoryArguments = (args: readonly string[], directory: string): string[] =>
args.map((argument) => argument.replaceAll("{directory}", directory));
@@ -169,8 +109,8 @@ export const resolveOpenWithLaunch = Effect.fn("desktop.openWith.resolveLaunch")
if (entry.directoryMode === "working-directory") {
if (entry.invocation.type === "mac-application") {
return {
- command: yield* resolveMacBundleExecutable(entry.invocation.applicationPath),
- args: [...entry.arguments],
+ command: "/usr/bin/open",
+ args: ["-a", entry.invocation.applicationPath, "--args", ...entry.arguments],
cwd: directory,
};
}
@@ -187,8 +127,8 @@ export const resolveOpenWithLaunch = Effect.fn("desktop.openWith.resolveLaunch")
const args = expandDirectoryArguments(entry.arguments, directory);
if (entry.invocation.type === "mac-application") {
return {
- command: yield* resolveMacBundleExecutable(entry.invocation.applicationPath),
- args,
+ command: "/usr/bin/open",
+ args: ["-a", entry.invocation.applicationPath, "--args", ...args],
cwd: null,
};
}
diff --git a/packages/contracts/src/openWith.ts b/packages/contracts/src/openWith.ts
index 9df4e1db990..94e40032a51 100644
--- a/packages/contracts/src/openWith.ts
+++ b/packages/contracts/src/openWith.ts
@@ -132,27 +132,6 @@ export class OpenWithUnavailableApplicationError extends Schema.TaggedErrorClass
}
}
-export const OpenWithBundleResolutionReason = Schema.Literals([
- "invalid-application-path",
- "missing-info-plist",
- "malformed-info-plist",
- "missing-executable",
-]);
-export type OpenWithBundleResolutionReason = typeof OpenWithBundleResolutionReason.Type;
-
-export class OpenWithBundleResolutionError extends Schema.TaggedErrorClass()(
- "OpenWithBundleResolutionError",
- {
- applicationPath: Schema.String,
- reason: OpenWithBundleResolutionReason,
- cause: Schema.optional(Schema.Defect()),
- },
-) {
- override get message(): string {
- return `Unable to resolve the executable in macOS application '${this.applicationPath}' (${this.reason}).`;
- }
-}
-
export class OpenWithSpawnError extends Schema.TaggedErrorClass()(
"OpenWithSpawnError",
{
@@ -173,7 +152,6 @@ export const OpenWithLaunchError = Schema.Union([
OpenWithMissingEntryError,
OpenWithInvalidTargetError,
OpenWithUnavailableApplicationError,
- OpenWithBundleResolutionError,
OpenWithSpawnError,
]);
export type OpenWithLaunchError = typeof OpenWithLaunchError.Type;