mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 16:57:19 +00:00
* fix(hopper): keep macOS and Linux launcher paths POSIX * fix(hopper): keep Linux and macOS bundle paths POSIX Linux package archives and macOS app-bundle launcher paths describe the target host, not the host running the test. Build them with path.posix so exercising these installers from Windows produces the same paths as the target platform. * fix(electron): follow Windows symlink targets with native separators readlink returns backslash-separated targets on Windows. Splitting only on '/' kept a whole relative target as one component, so nested links were not followed and a relative target could pass the framework-root check without being walked. Split on both separators on Windows and add a regression for an escaping target. * test(windows): align host-specific path and lifecycle expectations Compare generated skill and provider-command paths with native joins, bind ADB device-path validation to an explicit platform, and prepare simulated POSIX Ghidra install roots on Windows. Skip POSIX-only Hopper lease, permission-bit, and symlink-parent cases, assert Windows' unsupported Hopper state instead, and cover the Windows Ghidra native-source admission step before snapshot replay. Launch Node child seams with SystemRoot available and expect Windows close-failure resource retention. * test(windows): close review coverage gaps --------- Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import { readdirSync } from "node:fs";
|
|
import { posix } from "node:path";
|
|
|
|
export const MAC_HOPPER_APPLICATION_DIRECTORY = "/Applications";
|
|
export const MAC_HOPPER_APPLICATION_NAME = "Hopper Disassembler.app";
|
|
export const MAC_HOPPER_USER_APPLICATIONS_DIRECTORY = "Applications";
|
|
|
|
export const MAC_HOPPER_SYSTEM_LAUNCHER = posix.join(
|
|
MAC_HOPPER_APPLICATION_DIRECTORY,
|
|
MAC_HOPPER_APPLICATION_NAME,
|
|
"Contents/MacOS/hopper",
|
|
);
|
|
|
|
export const macHopperUserApplicationPath = (homeDirectory: string): string =>
|
|
posix.join(
|
|
homeDirectory,
|
|
MAC_HOPPER_USER_APPLICATIONS_DIRECTORY,
|
|
MAC_HOPPER_APPLICATION_NAME,
|
|
);
|
|
|
|
export const macHopperApplicationRoots = (
|
|
homeDirectory: string,
|
|
): readonly string[] => [
|
|
MAC_HOPPER_APPLICATION_DIRECTORY,
|
|
posix.join(homeDirectory, MAC_HOPPER_USER_APPLICATIONS_DIRECTORY),
|
|
];
|
|
|
|
export const macHopperCanonicalLauncherCandidates = (
|
|
homeDirectory: string,
|
|
): readonly string[] => [
|
|
MAC_HOPPER_SYSTEM_LAUNCHER,
|
|
posix.join(
|
|
macHopperUserApplicationPath(homeDirectory),
|
|
"Contents/MacOS/hopper",
|
|
),
|
|
];
|
|
|
|
/** Build deterministic candidates from the discovered app bundle names. */
|
|
export const macHopperRenamedLauncherCandidates = (
|
|
homeDirectory: string,
|
|
bundleNamesByRoot: ReadonlyMap<string, readonly string[]>,
|
|
): readonly string[] =>
|
|
macHopperApplicationRoots(homeDirectory).flatMap((root) =>
|
|
[...new Set(bundleNamesByRoot.get(root) ?? [])]
|
|
.filter(
|
|
(name) =>
|
|
/^Hopper.*\.app$/iu.test(name) &&
|
|
name.toLocaleLowerCase("en-US") !==
|
|
MAC_HOPPER_APPLICATION_NAME.toLocaleLowerCase("en-US"),
|
|
)
|
|
.sort()
|
|
.map((name) => posix.join(root, name, "Contents/MacOS/hopper")),
|
|
);
|
|
|
|
const localBundleNames = (root: string): readonly string[] => {
|
|
try {
|
|
return readdirSync(root, { withFileTypes: true })
|
|
.filter(
|
|
(entry) => entry.isDirectory() && /^Hopper.*\.app$/iu.test(entry.name),
|
|
)
|
|
.map(({ name }) => name);
|
|
} catch (cause: unknown) {
|
|
// Missing or unreadable optional app directories contain no candidates.
|
|
void cause;
|
|
return [];
|
|
}
|
|
};
|
|
|
|
/** Yield canonical paths first; enumerate renamed bundles only if needed. */
|
|
export function* macHopperLauncherCandidates(
|
|
homeDirectory: string,
|
|
): Generator<string> {
|
|
yield* macHopperCanonicalLauncherCandidates(homeDirectory);
|
|
for (const root of macHopperApplicationRoots(homeDirectory))
|
|
yield* macHopperRenamedLauncherCandidates(
|
|
homeDirectory,
|
|
new Map([[root, localBundleNames(root)]]),
|
|
);
|
|
}
|