mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
refactor: preserve provider-neutral runtime seams
This commit is contained in:
1 parent
513d9b1555
commit
a8161f0e55
6 files changed
+100
-44
No files matched your search
@@ -0,0 +1,62 @@
|
||||
import type {
|
||||
AnalysisClientFactory,
|
||||
AnalysisProfileResolution,
|
||||
AnalysisProfileResolutionOptions,
|
||||
AnalysisProvider,
|
||||
} from "./AnalysisProvider.js";
|
||||
import { AnalysisProviderRegistry } from "./AnalysisProviderRegistry.js";
|
||||
import { BinarySession } from "./BinarySession.js";
|
||||
import { SessionProviderRouter } from "./SessionProviderRouter.js";
|
||||
import type { BinaryTarget } from "../domain/binaryTarget.js";
|
||||
import type { AnalysisError } from "../domain/errors.js";
|
||||
import type { Result } from "../domain/result.js";
|
||||
|
||||
type BinarySessionOptions = {
|
||||
readonly resolveAnalysisProfile?: (
|
||||
target: BinaryTarget,
|
||||
options?: AnalysisProfileResolutionOptions,
|
||||
) => Promise<Result<AnalysisProfileResolution, AnalysisError>>;
|
||||
};
|
||||
|
||||
type BinarySessionOptionsOrResolver =
|
||||
| BinarySessionOptions
|
||||
| BinarySessionOptions["resolveAnalysisProfile"];
|
||||
|
||||
const normalizeBinarySessionOptions = (
|
||||
optionsOrResolver?: BinarySessionOptionsOrResolver,
|
||||
): BinarySessionOptions =>
|
||||
typeof optionsOrResolver === "function"
|
||||
? { resolveAnalysisProfile: optionsOrResolver }
|
||||
: (optionsOrResolver ?? {});
|
||||
|
||||
/**
|
||||
* Compose one provider-neutral session from deep-provider selection and
|
||||
* disjoint auxiliary operation families.
|
||||
*/
|
||||
export const composeBinarySession = (
|
||||
registry: AnalysisProviderRegistry | SessionProviderRouter,
|
||||
auxiliaryProviders: readonly AnalysisProvider[] = [],
|
||||
): BinarySession =>
|
||||
new BinarySession(
|
||||
registry instanceof SessionProviderRouter
|
||||
? registry
|
||||
: SessionProviderRouter.selectable(registry, auxiliaryProviders),
|
||||
);
|
||||
|
||||
/**
|
||||
* Compose a session through the same internal seam for focused adapter tests.
|
||||
* The constructor remains private to this composition module, so callers test
|
||||
* provider behavior without coupling to BinarySession construction.
|
||||
*/
|
||||
export const composeBinarySessionFromFactory = (
|
||||
provider: AnalysisProvider | AnalysisClientFactory | SessionProviderRouter,
|
||||
optionsOrResolver?: BinarySessionOptionsOrResolver,
|
||||
): BinarySession =>
|
||||
new BinarySession(provider, normalizeBinarySessionOptions(optionsOrResolver));
|
||||
|
||||
/** Compose a focused session from any provider-shaped test seam. */
|
||||
export const composeBinarySessionFromProvider = (
|
||||
provider: AnalysisProvider | AnalysisClientFactory | SessionProviderRouter,
|
||||
optionsOrResolver?: BinarySessionOptionsOrResolver,
|
||||
): BinarySession =>
|
||||
new BinarySession(provider, normalizeBinarySessionOptions(optionsOrResolver));
|
||||
@@ -500,12 +500,12 @@ export const startLoopbackReplay = async (
|
||||
async close() {
|
||||
closePromise ??= (async () => {
|
||||
recorder.stopMachineAdmission();
|
||||
await recorder.drainMachine();
|
||||
for (const client of websocket.clients) client.terminate();
|
||||
await new Promise<void>((resolveClose) =>
|
||||
websocket.close(() => resolveClose()),
|
||||
);
|
||||
await closeReplayServer(server);
|
||||
await recorder.drainMachine();
|
||||
})();
|
||||
await closePromise;
|
||||
},
|
||||
|
||||
@@ -49,8 +49,8 @@ export interface SessionProviderRoute {
|
||||
): AnalysisClient;
|
||||
}
|
||||
|
||||
interface LegacyProviderRuntime {
|
||||
readonly kind: "legacy";
|
||||
interface SingleProviderRuntime {
|
||||
readonly kind: "single";
|
||||
readonly provider: AnalysisProvider | AnalysisClientFactory;
|
||||
readonly identity: ProviderIdentity;
|
||||
readonly capabilities: ReadonlyMap<string, CapabilityDescriptor> | undefined;
|
||||
@@ -71,7 +71,7 @@ interface SelectableProviderRuntime {
|
||||
/** Resolve either the compatibility single-provider seam or a selectable set. */
|
||||
export class SessionProviderRouter {
|
||||
private constructor(
|
||||
private readonly runtime: LegacyProviderRuntime | SelectableProviderRuntime,
|
||||
private readonly runtime: SingleProviderRuntime | SelectableProviderRuntime,
|
||||
) {}
|
||||
|
||||
/** Preserve the existing provider/factory seam used by focused embedders. */
|
||||
@@ -104,7 +104,7 @@ export class SessionProviderRouter {
|
||||
provider.resolveAnalysisProfile?.(target, resolutionOptions) ??
|
||||
Promise.resolve(ok({ profile: null, compatibility: {} })));
|
||||
return new SessionProviderRouter({
|
||||
kind: "legacy",
|
||||
kind: "single",
|
||||
provider,
|
||||
identity,
|
||||
capabilities,
|
||||
@@ -148,7 +148,7 @@ export class SessionProviderRouter {
|
||||
|
||||
/** Provider identities exposed through the flat 1.x compatibility field. */
|
||||
providerIdentities(route: SessionProviderRoute): readonly ProviderIdentity[] {
|
||||
if (this.runtime.kind === "legacy") {
|
||||
if (this.runtime.kind === "single") {
|
||||
if (route.capabilities === undefined) return [route.identity];
|
||||
return uniqueProviderIdentities(
|
||||
[...route.capabilities.values()].map(({ provider }) => provider),
|
||||
@@ -177,7 +177,7 @@ export class SessionProviderRouter {
|
||||
binding: null,
|
||||
selection: undefined,
|
||||
createClient: (target, context) =>
|
||||
createLegacyClient(runtime, target, undefined, context),
|
||||
createSingleProviderClient(runtime, target, undefined, context),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ export class SessionProviderRouter {
|
||||
binding: null,
|
||||
selection: undefined,
|
||||
createClient: (openedTarget, context) =>
|
||||
createLegacyClient(
|
||||
createSingleProviderClient(
|
||||
runtime,
|
||||
openedTarget,
|
||||
normalized.value.profile ?? undefined,
|
||||
@@ -244,7 +244,7 @@ export class SessionProviderRouter {
|
||||
candidateStatuses(
|
||||
route: SessionProviderRoute,
|
||||
): readonly AnalysisProviderCandidateStatus[] {
|
||||
if (this.runtime.kind === "legacy") return [];
|
||||
if (this.runtime.kind === "single") return [];
|
||||
return route.selection?.candidates ?? this.runtime.registry.candidates();
|
||||
}
|
||||
|
||||
@@ -292,8 +292,8 @@ const selectableRoute = (
|
||||
};
|
||||
};
|
||||
|
||||
const createLegacyClient = (
|
||||
runtime: LegacyProviderRuntime,
|
||||
const createSingleProviderClient = (
|
||||
runtime: SingleProviderRuntime,
|
||||
target: BinaryTarget,
|
||||
profile: AnalysisProfileCommitment | undefined,
|
||||
context: AnalysisClientContext,
|
||||
|
||||
+27
-29
@@ -1,12 +1,12 @@
|
||||
import type { AppConfig } from "../config.js";
|
||||
import { BinarySession } from "./BinarySession.js";
|
||||
import type { BinarySession } from "./BinarySession.js";
|
||||
import { HopperProvider } from "../hopper/HopperProvider.js";
|
||||
import { GhidraProvider } from "../ghidra/GhidraProvider.js";
|
||||
import { silentLogger, type Logger } from "../logger.js";
|
||||
import { GENERATED_AUXILIARY_PROVIDERS } from "../generatedMcpToolCatalog.js";
|
||||
import { AnalysisProviderRegistry } from "./AnalysisProviderRegistry.js";
|
||||
import { composeBinarySession } from "./BinarySessionComposition.js";
|
||||
import { LazyAnalysisProvider } from "./LazyAnalysisProvider.js";
|
||||
import { SessionProviderRouter } from "./SessionProviderRouter.js";
|
||||
|
||||
/**
|
||||
* Compose the target-switching runtime shared directly by CLI and MCP adapters.
|
||||
@@ -34,32 +34,30 @@ export const createBinarySession = (
|
||||
throw new TypeError(`Missing generated provider metadata for ${id}`);
|
||||
return new LazyAnalysisProvider({ ...generated, load });
|
||||
};
|
||||
return new BinarySession(
|
||||
SessionProviderRouter.selectable(
|
||||
new AnalysisProviderRegistry([hopper, ghidra], config.analysisProvider),
|
||||
[
|
||||
lazyProvider("rea-artifact-graph", async () => {
|
||||
const { ArtifactProvider } = await import(
|
||||
"../artifacts/ArtifactProvider.js"
|
||||
);
|
||||
return new ArtifactProvider(
|
||||
config.artifactNativeMountEnabled,
|
||||
config.artifactIntegrityContinueEnabled,
|
||||
);
|
||||
}),
|
||||
lazyProvider("native-macos", async () => {
|
||||
const { NativeMacOSProvider } = await import(
|
||||
"../native/NativeMacOSProvider.js"
|
||||
);
|
||||
return new NativeMacOSProvider();
|
||||
}),
|
||||
lazyProvider("rea-dotnet-static", async () => {
|
||||
const { ManagedStaticProvider } = await import(
|
||||
"../dotnet/ManagedStaticProvider.js"
|
||||
);
|
||||
return new ManagedStaticProvider();
|
||||
}),
|
||||
],
|
||||
),
|
||||
return composeBinarySession(
|
||||
new AnalysisProviderRegistry([hopper, ghidra], config.analysisProvider),
|
||||
[
|
||||
lazyProvider("rea-artifact-graph", async () => {
|
||||
const { ArtifactProvider } = await import(
|
||||
"../artifacts/ArtifactProvider.js"
|
||||
);
|
||||
return new ArtifactProvider(
|
||||
config.artifactNativeMountEnabled,
|
||||
config.artifactIntegrityContinueEnabled,
|
||||
);
|
||||
}),
|
||||
lazyProvider("native-macos", async () => {
|
||||
const { NativeMacOSProvider } = await import(
|
||||
"../native/NativeMacOSProvider.js"
|
||||
);
|
||||
return new NativeMacOSProvider();
|
||||
}),
|
||||
lazyProvider("rea-dotnet-static", async () => {
|
||||
const { ManagedStaticProvider } = await import(
|
||||
"../dotnet/ManagedStaticProvider.js"
|
||||
);
|
||||
return new ManagedStaticProvider();
|
||||
}),
|
||||
],
|
||||
);
|
||||
};
|
||||
@@ -43,8 +43,6 @@ export const iosManifestSchema = z.strictObject({
|
||||
ui_required_device_capabilities: z.array(z.string()).default([]),
|
||||
app_permissions: z.array(z.string()).default([]),
|
||||
});
|
||||
export type IosManifest = z.infer<typeof iosManifestSchema>;
|
||||
|
||||
/** Signing information. */
|
||||
export const signingInfoSchema = z.strictObject({
|
||||
is_signed: z.boolean().default(false),
|
||||
|
||||
@@ -85,8 +85,6 @@ export const swiftAccessLevelSchema = z.enum([
|
||||
"public",
|
||||
"open",
|
||||
]);
|
||||
export type SwiftAccessLevel = z.infer<typeof swiftAccessLevelSchema>;
|
||||
|
||||
/** Swift declaration metadata. */
|
||||
export const swiftDeclSchema = z.strictObject({
|
||||
kind: swiftDeclKindSchema,
|
||||
|
||||
Reference in new issue
Block a user