Files
reverse-engineering-anything/src/application/binary/BinarySessionPort.ts
T
morlutoandCursor Agent 88cf498036 fix!: preserve results when source publication fails (#8444)
* fix: retain address context cleanup failures

* fix!: preserve address context input errors

BREAKING CHANGE: Strict clients that cached the previous full inspect_address_context output schema must refresh tools/list and accept the typed error field on unavailable facets.

* test: use session contract for address context

* fix!: preserve address context resource recovery

BREAKING CHANGE: Clients validating unavailable context facets against a cached strict full output schema must refresh tools/list to accept resource_constraint errors.

* fix: expose authenticated records refused by the evidence ledger (#8426)

* fix: preserve completed evidence on retention refusal

* fix: preserve context when unretained evidence exceeds delivery limits

* fix(mcp): recover oversized context from session evidence

* fix(evidence): preserve completed atomic write results

* fix: retain completed results when source publication fails

* test: cover bounded recovery with unknown retention

* fix(evidence): preserve recovery identity and finalization facts

* fix(evidence): clarify retention of omitted observations

* test(evidence): compare omission guidance with its owner

* fix(evidence): preserve completed composed workflows

* fix(evidence): clarify unretained recovery export

* test(evidence): cover mixed recovery guidance

* fix(evidence): preserve caller scope in secondary failures

* refactor(evidence): remove superseded cleanup projection

* test(evidence): align recovery checks with owners

* fix: preserve cleanup on partial recovery limits

* test: use owners for diagnostic wording

* fix: admit completed analysis before evidence construction

* fix: preserve selected paths when reusing evidence

* fix(cli): preserve caller path in unretained evidence

* fix(evidence): preserve recovery metadata and admission bounds

* refactor: consolidate evidence closure imports

* style(test): format CLI help default annotations (#9280)

* test(mcp): keep recovery checks focused on contract facts

* fix(evidence): preserve feature trace replay revision

* test: align evidence recovery checks with ownership

* test: align partial recovery and cleanup diagnostics

* fix(evidence): preserve nested partials during cleanup

* fix(evidence): respect outer recovery ownership

* fix(capture): discard rejected nested observations

* test(frida): assert inline evidence recovery

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-09 02:41:54 +08:00

170 lines
7.4 KiB
TypeScript

import type { EspFlashSelection } from "../../domain/firmware/espFlashLocation.js";
import type { InvestigationRecordPort } from "../investigation/InvestigationRecordPort.js";
import type { RecoveryAdmission } from "../investigation/InvestigationRetention.js";
import type { ResetInvestigationReceipt } from "../../domain/investigationLifecycle.js";
import type { ExecutableFormatHint } from "../../domain/dosCom.js";
import type {
BinaryArchitecture,
BinaryTarget,
} from "../../domain/binaryTargetTypes.js";
import type { JsonValue } from "../../domain/jsonValue.js";
import type { AnalysisSnapshot } from "../../domain/analysisSnapshot.js";
import type { AnalysisProfileCommitment } from "../../domain/analysisProfile.js";
import type { AnalysisProviderSelector } from "../../domain/providerSelection.js";
import type { BinarySessionDetail } from "../../contracts/sessionStatusContract.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisCleanupRetry } from "../../domain/analysisErrorRecovery.js";
import type { Result } from "../../domain/result.js";
import type { EvidenceIntegrityError } from "../../domain/evidenceErrors.js";
import type { AnalysisSnapshotLoader } from "./BinarySessionOpen.js";
import type { WorkflowSnapshotRecordInput } from "./BinarySessionRecords.js";
import type { ResolvedAppBundleResourceRoot } from "../AppBundleExecutable.js";
import type { binaryTargetSummary } from "./BinaryTargetSummary.js";
import type {
AnalysisExecution,
AnalysisOperation,
AnalysisOperationPort,
ExecutionOptions,
ProviderIdentity,
} from "../AnalysisProvider.js";
import type { SavedAnalysisSnapshot } from "../../domain/savedAnalysisSnapshot.js";
export type { SavedAnalysisSnapshot } from "../../domain/savedAnalysisSnapshot.js";
/** Selection observed at the end of one serialized open attempt. */
export type OpenSelectionReceipt =
| { readonly kind: "binary"; readonly path: string; readonly sha256: string }
| {
readonly kind: "resources";
readonly path: string;
readonly caller_path: string;
}
| { readonly kind: "none" };
/** A failure retains its original error and both selection receipts. */
export type BinaryOpenResult =
| { readonly ok: true; readonly value: BinaryTarget }
| {
readonly ok: false;
readonly error: AnalysisError;
readonly selection: OpenSelectionReceipt;
readonly targetAtCompletion: ReturnType<
typeof binaryTargetSummary
> | null;
readonly providerIdAtCompletion: string | null;
};
/** Target lifecycle used by CLI and MCP without exposing a concrete provider. */
export interface BinarySessionPort
extends AnalysisOperationPort, InvestigationRecordPort {
readonly admitRecoveryObservation: RecoveryAdmission;
/** Execute only against a positively ready, already-created provider client. */
executeIfProviderReady(
operation: AnalysisOperation,
parameters: Readonly<Record<string, JsonValue>>,
options?: Pick<ExecutionOptions, "signal" | "selectorOrigin">,
): Promise<Result<AnalysisExecution, AnalysisError> | undefined>;
/** Hold the active target binding through a complete composed operation. */
withAdmittedAnalysis<Value>(
operationName: string,
signal: AbortSignal | undefined,
operation: (analysis: AnalysisOperationPort) => Promise<Value>,
): Promise<Result<Value, AnalysisError>>;
/** Serialize an external mutation and retire any active target afterward. */
withAdmittedExternalMutation<Value>(
_path: string | undefined,
signal: AbortSignal | undefined,
operation: () => Promise<Result<Value, AnalysisError>>,
completionFailure: (
value: Result<Value, AnalysisError>,
error: AnalysisError,
) => AnalysisError,
operationName?: string,
cleanupRecovery?: (
failure: AnalysisError | undefined,
) => Promise<Result<null, AnalysisError>>,
): Promise<Result<Result<Value, AnalysisError>, AnalysisError>>;
open(
path: string,
options?: {
readonly signal?: AbortSignal;
readonly targetKind?: BinaryTarget["kind"];
readonly formatHint?: ExecutableFormatHint;
readonly architecture?: BinaryArchitecture;
readonly entryPoint?: string;
readonly espFlash?: EspFlashSelection;
readonly snapshot?: AnalysisSnapshot;
readonly loadSnapshot?: AnalysisSnapshotLoader;
readonly providerId?: AnalysisProviderSelector;
},
): Promise<BinaryOpenResult>;
/** Open a resource-only app root without selecting or inventing an executable target. */
openBundleResources(
path: string,
options?: Pick<ExecutionOptions, "signal">,
): Promise<Result<ResolvedAppBundleResourceRoot, AnalysisError>>;
/**
* `cleanupRetry` names the caller's same-session retry; the session binds it
* to a failed close only while it retains that cleanup for the next close.
*/
close(
options?: Pick<ExecutionOptions, "progress"> & {
readonly retainProviderDocuments?: boolean;
readonly cleanupRetry?: AnalysisCleanupRetry;
},
): Promise<Result<null, AnalysisError>>;
/** Seal runtime acquisition and release investigation state after successful cleanup. */
dispose(
options?: Pick<ExecutionOptions, "progress"> & {
readonly retainProviderDocuments?: boolean;
},
): Promise<Result<null, AnalysisError>>;
/** Seal future acquisition/admission while previously admitted work drains. */
beginShutdown(): void;
/** Drain work, optionally checkpoint, and clear records without closing the active engine. */
resetInvestigation(options?: {
readonly savePath?: string;
readonly overwrite?: boolean;
readonly signal?: AbortSignal;
/** Adapter-owned cleanup joins the drained transaction before clearing records. */
readonly retryCleanup?: () => Promise<Result<null, AnalysisError>>;
}): Promise<Result<ResetInvestigationReceipt, AnalysisError>>;
/** Save a snapshot and close while excluding later provider requests. */
closeWithSnapshot(
path: string,
overwrite: boolean,
options?: Pick<ExecutionOptions, "progress"> & {
readonly cleanupRetry?: AnalysisCleanupRetry;
},
): Promise<Result<SavedAnalysisSnapshot, AnalysisError>>;
/** Default complete detail; summary omits provider diagnostics and candidate capabilities. */
status(options?: {
readonly signal?: AbortSignal;
readonly detail?: BinarySessionDetail;
readonly refreshCandidates?: boolean;
}): Promise<JsonValue>;
activeTarget(): BinaryTarget | undefined;
/** Read a snapshot with failed descriptors retained for session cleanup retry. */
readAnalysisSnapshot(
path: string,
signal?: AbortSignal,
): Promise<Result<AnalysisSnapshot, AnalysisError>>;
exportAnalysisSnapshot(): Result<AnalysisSnapshot, AnalysisError>;
importAnalysisSnapshot(
snapshot: AnalysisSnapshot,
): Result<number, AnalysisError>;
providerIdentity(operation?: AnalysisOperation): ProviderIdentity;
analysisProfile(
operation?: AnalysisOperation,
): AnalysisProfileCommitment | undefined;
allowsSnapshotReplay(operation: AnalysisOperation): boolean;
/** Invalidate cached Evidence before an external command may mutate the target. */
invalidateSnapshotForExternalMutation(): void;
recordWorkflowSnapshot(
input: WorkflowSnapshotRecordInput,
): Result<null, EvidenceIntegrityError>;
onAvailabilityChanged?(listener: () => void | Promise<void>): () => void;
onAnalysisSnapshotChanged?(listener: () => void | Promise<void>): () => void;
}