fix(mcp): admit composed analysis through result bookkeeping

This commit is contained in:
morluto committed 2026-10-10 00:35:17 +08:00
1 parent e64678e8f9
commit e11f4d371a
80 files changed
+774 -471

No files matched your search

+27
View File
@@ -507,6 +507,33 @@ export class BinarySession
return call.finally(() => this.#calls.delete(call));
}
/** Admit one composed request until its result and session bookkeeping settle. */
withAdmittedAnalysis<Value>(
operationName: string,
signal: AbortSignal | undefined,
operation: (analysis: AnalysisOperationPort) => Promise<Value>,
): Promise<Result<Value, AnalysisError>> {
const generation = this.#transitionGeneration;
const transition = this.#transition;
const call = (async (): Promise<Result<Value, AnalysisError>> => {
const admission = await this.#waitForTransition(
operationName,
signal,
transition,
);
if (!admission.ok) return admission;
return ok(
await operation({
execute: (name, arguments_, options) =>
this.#execute(name, arguments_, options, Promise.resolve()),
}),
);
})();
// Register synchronously before a lifecycle transition can snapshot calls.
this.#calls.set(call, generation);
return call.finally(() => this.#calls.delete(call));
}
async #execute(
name: Parameters<AnalysisOperationPort["execute"]>[0],
arguments_: Readonly<Record<string, JsonValue>>,
@@ -32,6 +32,12 @@ export interface SavedAnalysisSnapshot {
/** Target lifecycle used by CLI and MCP without exposing a concrete provider. */
export interface BinarySessionPort
extends AnalysisOperationPort, InvestigationRecordPort {
/** 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>>;
open(
path: string,
options?: {