rea-agents 2.5.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -12
- package/bridge/ghidra/ReaGhidraBridge.java +477 -4
- package/bridge/hopper_bridge.py +54 -4
- package/dist/application/AnalysisContextQueries.js +142 -0
- package/dist/application/AnalysisSnapshotCache.js +4 -2
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
- package/dist/application/ArtifactInventory/policy.js +17 -0
- package/dist/application/ArtifactInventory/reader.js +1 -4
- package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
- package/dist/application/ArtifactInventory/scanReader.js +7 -7
- package/dist/application/ArtifactInventory/types.js +1 -5
- package/dist/application/BinarySession.js +19 -20
- package/dist/application/BinarySessionComposition.js +21 -0
- package/dist/application/BinarySessionRecords.js +106 -10
- package/dist/application/BinarySessionStatus.js +11 -5
- package/dist/application/BrowserEvidence.js +3 -5
- package/dist/application/CapabilityClientRequirements.js +26 -0
- package/dist/application/CapabilityInventory.js +140 -55
- package/dist/application/ClientRegistrationStatus.js +4 -1
- package/dist/application/CrossVersionInventory.js +7 -6
- package/dist/application/DirectAnalysis.js +6 -2
- package/dist/application/ElectronActiveEvidence.js +55 -0
- package/dist/application/ElectronActiveObservationPort.js +1 -0
- package/dist/application/ElectronActiveObservationService.js +81 -0
- package/dist/application/EnhancedTools.js +49 -17
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +53 -17
- package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/LazyAnalysisProvider.js +77 -0
- package/dist/application/LoopbackReplay.js +1 -1
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- package/dist/application/NativeApiInspection.js +80 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
- package/dist/application/ProcessCaptureLifecycle.js +5 -0
- package/dist/application/ProcessCli.js +2 -1
- package/dist/application/ProcessHarness.js +8 -3
- package/dist/application/ProcessNormalization.js +2 -1
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReferenceSourceImport.js +2 -2
- package/dist/application/SessionProviderRouter.js +6 -6
- package/dist/application/SetupClientConfiguration.js +10 -3
- package/dist/application/WindowsCapabilities.js +5 -4
- package/dist/application/runtime.js +26 -9
- package/dist/artifacts/ArtifactProvider.js +8 -10
- package/dist/artifacts/SafeOutputTree.js +7 -8
- package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
- package/dist/browser/CdpElectronInspection.js +3 -1
- package/dist/browser/JavaScriptRuntimeScope.js +5 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
- package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
- package/dist/browser/PlaywrightScenarioSession.js +4 -4
- package/dist/browser/SensitiveTextCapture.js +1 -1
- package/dist/browser/V8InspectorCaptureProjection.js +1 -0
- package/dist/browser/V8InspectorProvider.js +3 -3
- package/dist/catalogIdentity.js +15 -9
- package/dist/cli/artifactCommands.js +5 -3
- package/dist/cli/coreAnalysisCommands.js +41 -0
- package/dist/cli/managedCommands.js +1 -1
- package/dist/cliApplicationCommands.js +2 -2
- package/dist/cliBrowserAdvancedCommands.js +11 -5
- package/dist/cliBrowserCommands.js +14 -7
- package/dist/cliCommandNames.js +2 -0
- package/dist/cliElectronCommands.js +46 -4
- package/dist/cliJavaScriptRuntimeCommands.js +14 -6
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/browserScenario.js +77 -0
- package/dist/config/electronAutomation.js +35 -0
- package/dist/config/environment.js +6 -0
- package/dist/config/javascriptReplay.js +41 -0
- package/dist/config/managedRuntime.js +25 -0
- package/dist/config/parseConfig.js +56 -200
- package/dist/config/parsers.js +10 -1
- package/dist/config/passiveObservation.js +157 -0
- package/dist/config/processCapture.js +47 -0
- package/dist/contracts/applicationToolContracts.js +2 -5
- package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
- package/dist/contracts/artifactToolContracts.js +35 -37
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +21 -27
- package/dist/contracts/functionWorkflowToolContracts.js +29 -0
- package/dist/contracts/managedToolContracts.js +4 -9
- package/dist/contracts/managedWorkflowExamples.js +12 -9
- package/dist/contracts/managedWorkflowToolContracts.js +30 -27
- package/dist/contracts/nativeToolContracts.js +2 -3
- package/dist/contracts/promptContracts.js +14 -15
- package/dist/contracts/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +4 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +12 -67
- package/dist/contracts/toolEffects.js +19 -0
- package/dist/contracts/toolOutputSchemaGroups.js +66 -11
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- package/dist/domain/analysisErrorPresentation.js +8 -2
- package/dist/domain/analysisErrorProjection.js +1 -0
- package/dist/domain/androidApplication.js +2 -0
- package/dist/domain/appleApplication.js +2 -0
- package/dist/domain/binaryTarget.js +7 -5
- package/dist/domain/binaryTargetTypes.js +1 -0
- package/dist/domain/browserCaptureComparison.js +21 -69
- package/dist/domain/browserObservation.js +22 -9
- package/dist/domain/bytecodeProvider.js +177 -0
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformancePackage.js +169 -0
- package/dist/domain/conformanceReplay.js +104 -0
- package/dist/domain/conformanceTrustGate.js +328 -0
- package/dist/domain/customProtocolCapture.js +137 -0
- package/dist/domain/electronActiveObservation.js +277 -0
- package/dist/domain/electronObservation.js +15 -11
- package/dist/domain/electronStaticAnalysisValues.js +4 -1
- package/dist/domain/eventProcessTree.js +217 -0
- package/dist/domain/evidenceBundle.js +47 -0
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +68 -68
- package/dist/domain/inputIssueProjection.js +11 -2
- package/dist/domain/investigationWorkspace.js +16 -15
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
- package/dist/domain/javascriptReplay.js +79 -63
- package/dist/domain/javascriptRuntimeObservation.js +1 -0
- package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
- package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +8 -12
- package/dist/domain/javascriptSourceParser.js +15 -0
- package/dist/domain/javascriptStaticAnalysis.js +8 -12
- package/dist/domain/knownPageCoverage.js +15 -7
- package/dist/domain/mobileApplicationInvestigation.js +159 -0
- package/dist/domain/nativeApiBoundary.js +138 -0
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- package/dist/domain/objcSwiftMetadata.js +150 -0
- package/dist/domain/packageAnalysis.js +123 -0
- package/dist/domain/peInspection.js +196 -0
- package/dist/domain/processCaptureReactiveValidation.js +8 -3
- package/dist/domain/processCaptureValidation.js +7 -3
- package/dist/domain/processComparison.js +12 -7
- package/dist/domain/processObservation.js +5 -6
- package/dist/domain/processReactiveMatching.js +14 -7
- package/dist/domain/processReactiveTransition.js +9 -3
- package/dist/domain/processScenario.js +6 -3
- package/dist/domain/processTraceComparison.js +3 -2
- package/dist/domain/protocolCapture.js +245 -0
- package/dist/domain/reconstructionReadinessSchemas.js +30 -2
- package/dist/domain/referenceSourceImportParsing.js +2 -2
- package/dist/domain/replayMachineRuntime.js +5 -3
- package/dist/domain/sourceToBundleComparison.js +2 -2
- package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
- package/dist/domain/sourceToBundleSignals.js +7 -1
- package/dist/domain/staticRuntimeCorrelation.js +7 -5
- package/dist/domain/webBundleAnalysis.js +14 -14
- package/dist/domain/webCaptureDiff.js +15 -12
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
- package/dist/dotnet/ManagedStaticProvider.js +34 -5
- package/dist/generatedMcpToolCatalog.js +37 -0
- package/dist/generatedPackageMetadata.js +4 -4
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +44 -16
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
- package/dist/ghidra/GhidraSocketConnection.js +1 -1
- package/dist/ghidra/protocol.js +19 -42
- package/dist/hopper/BridgeLauncher.js +3 -1
- package/dist/hopper/HopperAnalysisProfile.js +2 -4
- package/dist/hopper/HopperCleanup.js +5 -6
- package/dist/hopper/HopperClient.js +27 -3
- package/dist/hopper/HopperProvider.js +42 -44
- package/dist/hopper/HopperRequestQueue.js +32 -4
- package/dist/hopper/HopperResponseStream.js +2 -2
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/hopper/protocol.js +63 -21
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +31 -41
- package/dist/main.js +17 -13
- package/dist/mcpDoctor.js +4 -26
- package/dist/mcpStartupPolicy.js +14 -0
- package/dist/process/PrivateRuntimeRoot.js +17 -0
- package/dist/process/ProcessOwnership.js +64 -128
- package/dist/process/ProcessOwnershipIdentity.js +13 -0
- package/dist/process/ProcessOwnershipObservation.js +88 -0
- package/dist/process/ProcessOwnershipProcessTree.js +22 -0
- package/dist/process/ProviderDeadline.js +8 -12
- package/dist/process/WindowsAuthority.js +32 -0
- package/dist/reference/ReferenceSourceReader.js +3 -3
- package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
- package/dist/replay/JavaScriptReplayWorker.js +95 -11
- package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
- package/dist/replay/ReplayOutcome.js +26 -15
- package/dist/replay/ReplayWorkerProtocol.js +34 -29
- package/dist/server/createServer.js +101 -144
- package/dist/server/mcpClientMetadata.js +32 -0
- package/dist/server/registerApplicationTools/characterization.js +6 -13
- package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
- package/dist/server/registerApplicationTools/compareVersions.js +3 -8
- package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
- package/dist/server/registerApplicationTools/coverage.js +13 -19
- package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
- package/dist/server/registerApplicationTools/readiness.js +1 -6
- package/dist/server/registerApplicationTools/traceFeature.js +3 -8
- package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
- package/dist/server/registerArtifactComparisonTool.js +12 -16
- package/dist/server/registerBrowserScenarioTool.js +1 -6
- package/dist/server/registerBrowserTools.js +37 -79
- package/dist/server/registerBundleComparisonTool.js +10 -14
- package/dist/server/registerCloseLifecycleTool.js +6 -14
- package/dist/server/registerElectronTools.js +30 -47
- package/dist/server/registerEnhancedTools.js +124 -122
- package/dist/server/registerEvidenceResources.js +50 -101
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +42 -59
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
- package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
- package/dist/server/registerOfficialTools.js +8 -9
- package/dist/server/registerProcessComparisonTool.js +19 -24
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
- package/dist/server/registerReconstructionReadinessResource.js +0 -7
- package/dist/server/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +146 -47
- package/dist/server/registerSessionStatusTool.js +14 -29
- package/dist/server/registerSessionTools.js +45 -41
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -177
- package/dist/server/toolResult.js +14 -18
- package/package.json +35 -16
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/skills/reverse-engineer-anything/SKILL.md +10 -3
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/toolInputValidation.js +0 -77
package/bridge/hopper_bridge.py
CHANGED
|
@@ -1046,29 +1046,65 @@ def _serve_connection(connection):
|
|
|
1046
1046
|
if not line or len(line) > MAX_LINE_BYTES:
|
|
1047
1047
|
break
|
|
1048
1048
|
request_id = None
|
|
1049
|
+
authenticated = False
|
|
1049
1050
|
should_stop = False
|
|
1050
1051
|
try:
|
|
1051
1052
|
request = json.loads(line.decode("utf-8"))
|
|
1052
1053
|
if set(request) != {"id", "token", "method", "params"}:
|
|
1053
1054
|
raise ValueError("Invalid bridge request shape")
|
|
1054
1055
|
request_id = request["id"]
|
|
1056
|
+
if isinstance(request_id, bool) or not isinstance(request_id, int) or request_id < 0:
|
|
1057
|
+
raise ValueError("Invalid bridge request id")
|
|
1055
1058
|
if not isinstance(request["token"], str) or not hmac.compare_digest(request["token"], REA_TOKEN):
|
|
1056
1059
|
raise PermissionError("Invalid bridge capability")
|
|
1060
|
+
authenticated = True
|
|
1061
|
+
_write_message(file, {"id": request_id, "event": {
|
|
1062
|
+
"type": "progress",
|
|
1063
|
+
"phase": "hopper_bridge",
|
|
1064
|
+
"completed": 0,
|
|
1065
|
+
"total": 1,
|
|
1066
|
+
"message": "Hopper bridge started request",
|
|
1067
|
+
}})
|
|
1057
1068
|
result = _dispatch(request["method"], request["params"])
|
|
1058
1069
|
should_stop = request["method"] == "shutdown_document" or (
|
|
1059
1070
|
request["method"] == "shutdown" and not result.get("cleanup_required", False)
|
|
1060
1071
|
)
|
|
1061
|
-
|
|
1072
|
+
safe_result = _json_safe(result)
|
|
1073
|
+
_write_message(file, {"id": request_id, "event": {
|
|
1074
|
+
"type": "progress",
|
|
1075
|
+
"phase": "hopper_bridge",
|
|
1076
|
+
"completed": 1,
|
|
1077
|
+
"total": 1,
|
|
1078
|
+
"message": "Hopper bridge completed request",
|
|
1079
|
+
"terminal": True,
|
|
1080
|
+
}})
|
|
1081
|
+
response = {"id": request_id, "result": safe_result}
|
|
1062
1082
|
except Exception as error:
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1083
|
+
diagnostic = _safe_diagnostic(error)
|
|
1084
|
+
if authenticated:
|
|
1085
|
+
_write_message(file, {"id": request_id, "event": {
|
|
1086
|
+
"type": "diagnostic",
|
|
1087
|
+
"error": diagnostic,
|
|
1088
|
+
}})
|
|
1089
|
+
response_id = request_id if (
|
|
1090
|
+
isinstance(request_id, int)
|
|
1091
|
+
and not isinstance(request_id, bool)
|
|
1092
|
+
and request_id >= 0
|
|
1093
|
+
) else 0
|
|
1094
|
+
response = {"id": response_id, "error": diagnostic}
|
|
1095
|
+
_write_message(file, response)
|
|
1066
1096
|
if should_stop:
|
|
1067
1097
|
break
|
|
1068
1098
|
file.close()
|
|
1069
1099
|
connection.close()
|
|
1070
1100
|
|
|
1071
1101
|
|
|
1102
|
+
def _write_message(file, message):
|
|
1103
|
+
"""Write and flush one compact bridge message."""
|
|
1104
|
+
file.write((json.dumps(message, separators=(",", ":")) + "\n").encode("utf-8"))
|
|
1105
|
+
file.flush()
|
|
1106
|
+
|
|
1107
|
+
|
|
1072
1108
|
def _diagnostic_type(error):
|
|
1073
1109
|
if isinstance(error, CapabilityUnavailableError):
|
|
1074
1110
|
return "capability_unavailable"
|
|
@@ -1079,6 +1115,20 @@ def _diagnostic_type(error):
|
|
|
1079
1115
|
return "bridge_exception"
|
|
1080
1116
|
|
|
1081
1117
|
|
|
1118
|
+
def _safe_diagnostic(error):
|
|
1119
|
+
"""Project one exception without retaining provider or credential text."""
|
|
1120
|
+
diagnostic_type = _diagnostic_type(error)
|
|
1121
|
+
if diagnostic_type == "capability_unavailable":
|
|
1122
|
+
message = str(error)[:512]
|
|
1123
|
+
elif diagnostic_type == "authorization":
|
|
1124
|
+
message = "Invalid bridge capability"
|
|
1125
|
+
elif diagnostic_type == "invalid_request":
|
|
1126
|
+
message = "Invalid Hopper bridge request"
|
|
1127
|
+
else:
|
|
1128
|
+
message = "%s: Hopper bridge operation failed" % type(error).__name__[:128]
|
|
1129
|
+
return {"code": -32000, "message": message, "type": diagnostic_type}
|
|
1130
|
+
|
|
1131
|
+
|
|
1082
1132
|
def _run():
|
|
1083
1133
|
"""Own a permission-restricted, single-client Unix socket for this bridge."""
|
|
1084
1134
|
if os.path.exists(REA_SOCKET):
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { AnalysisOutputError } from "../domain/errors.js";
|
|
2
|
+
import { err, ok } from "../domain/result.js";
|
|
3
|
+
const parameters = (document, address) => ({
|
|
4
|
+
...(document === undefined ? {} : { document }),
|
|
5
|
+
...(address === undefined ? {} : { address }),
|
|
6
|
+
});
|
|
7
|
+
const executionOptions = (signal) => signal === undefined ? {} : { signal };
|
|
8
|
+
/** Compose the provider's volatile selection state into one coherent query. */
|
|
9
|
+
export const getNavigationContext = async (analysis, input, signal) => {
|
|
10
|
+
const document = input.document ??
|
|
11
|
+
(await analysis.execute("current_document", {}, executionOptions(signal)));
|
|
12
|
+
if (typeof document !== "string" && !document.ok)
|
|
13
|
+
return document;
|
|
14
|
+
const documentName = typeof document === "string" ? document : document.value.result;
|
|
15
|
+
const documentArgs = typeof documentName === "string" ? parameters(documentName) : {};
|
|
16
|
+
const address = await analysis.execute("current_address", documentArgs, executionOptions(signal));
|
|
17
|
+
if (!address.ok)
|
|
18
|
+
return address;
|
|
19
|
+
if (typeof address.value.result !== "string")
|
|
20
|
+
return ok({
|
|
21
|
+
document: documentName,
|
|
22
|
+
address: address.value.result,
|
|
23
|
+
procedure: null,
|
|
24
|
+
});
|
|
25
|
+
const procedure = await analysis.execute("resolve_containing_procedure", parameters(typeof documentName === "string" ? documentName : undefined, address.value.result), executionOptions(signal));
|
|
26
|
+
if (!procedure.ok) {
|
|
27
|
+
if (!isMissingCurrentProcedure(procedure.error))
|
|
28
|
+
return procedure;
|
|
29
|
+
return ok({
|
|
30
|
+
document: documentName,
|
|
31
|
+
address: address.value.result,
|
|
32
|
+
procedure: null,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return ok({
|
|
36
|
+
document: documentName,
|
|
37
|
+
address: address.value.result,
|
|
38
|
+
procedure: containingProcedureName(procedure.value.result),
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
/** Inspect bounded provider-neutral facets at one explicit reproducible address. */
|
|
42
|
+
export const inspectAddressContext = async (analysis, input, signal) => {
|
|
43
|
+
const document = await resolveDocument(analysis, input.document, signal);
|
|
44
|
+
if (!document.ok)
|
|
45
|
+
return document;
|
|
46
|
+
const args = parameters(document.value, input.address);
|
|
47
|
+
const operations = [
|
|
48
|
+
"address_name",
|
|
49
|
+
"resolve_containing_procedure",
|
|
50
|
+
"comment",
|
|
51
|
+
"inline_comment",
|
|
52
|
+
"list_bookmarks",
|
|
53
|
+
];
|
|
54
|
+
const results = await Promise.all(operations.map((operation) => analysis.execute(operation, operation === "list_bookmarks" ? parameters(document.value) : args, executionOptions(signal))));
|
|
55
|
+
for (const result of results) {
|
|
56
|
+
if (!result.ok && isRequestLevelFailure(result.error))
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
const name = facet(results[0], operations[0]);
|
|
60
|
+
const procedure = facet(results[1], operations[1]);
|
|
61
|
+
const comment = facet(results[2], operations[2]);
|
|
62
|
+
const inlineComment = facet(results[3], operations[3]);
|
|
63
|
+
const bookmarks = facet(results[4], operations[4]);
|
|
64
|
+
return ok({
|
|
65
|
+
address: input.address,
|
|
66
|
+
document: document.value,
|
|
67
|
+
name,
|
|
68
|
+
procedure,
|
|
69
|
+
comment,
|
|
70
|
+
inline_comment: inlineComment,
|
|
71
|
+
bookmarks: bookmarks.state === "available"
|
|
72
|
+
? matchingBookmarks(bookmarks.value, resolvedAddress(results[1], input.address))
|
|
73
|
+
: bookmarks,
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const resolveDocument = async (analysis, document, signal) => {
|
|
77
|
+
if (document !== undefined)
|
|
78
|
+
return ok(document);
|
|
79
|
+
const current = await analysis.execute("current_document", {}, executionOptions(signal));
|
|
80
|
+
if (!current.ok)
|
|
81
|
+
return current;
|
|
82
|
+
return typeof current.value.result === "string"
|
|
83
|
+
? ok(current.value.result)
|
|
84
|
+
: err(new AnalysisOutputError("current_document", "expected a document identity string"));
|
|
85
|
+
};
|
|
86
|
+
const facet = (result, operation) => result?.ok === true
|
|
87
|
+
? { state: "available", value: result.value.result }
|
|
88
|
+
: {
|
|
89
|
+
state: "unavailable",
|
|
90
|
+
reason: result?.error.message ?? `${operation} returned no result`,
|
|
91
|
+
remediation: `Call ${operation} directly to inspect provider availability and diagnostics.`,
|
|
92
|
+
};
|
|
93
|
+
const isMissingCurrentProcedure = (error) => /(?:no procedure exists|not in a procedure)/iu.test(error.message);
|
|
94
|
+
const isRequestLevelFailure = (error) => error._tag === "AnalysisCancelledError" ||
|
|
95
|
+
error._tag === "AnalysisTimeoutError" ||
|
|
96
|
+
error._tag === "NoBinaryOpenError" ||
|
|
97
|
+
error._tag === "PermissionRequiredError";
|
|
98
|
+
const containingProcedureName = (value) => {
|
|
99
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
100
|
+
return null;
|
|
101
|
+
if (value.found !== true)
|
|
102
|
+
return null;
|
|
103
|
+
const procedure = value.procedure;
|
|
104
|
+
if (typeof procedure !== "object" ||
|
|
105
|
+
procedure === null ||
|
|
106
|
+
Array.isArray(procedure))
|
|
107
|
+
return null;
|
|
108
|
+
return typeof procedure.name === "string" ? procedure.name : null;
|
|
109
|
+
};
|
|
110
|
+
const resolvedAddress = (result, fallback) => {
|
|
111
|
+
if (result?.ok !== true)
|
|
112
|
+
return fallback;
|
|
113
|
+
const value = result.value.result;
|
|
114
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
115
|
+
return fallback;
|
|
116
|
+
return typeof value.query_address === "string"
|
|
117
|
+
? value.query_address
|
|
118
|
+
: fallback;
|
|
119
|
+
};
|
|
120
|
+
const matchingBookmarks = (value, address) => {
|
|
121
|
+
if (!Array.isArray(value))
|
|
122
|
+
return {
|
|
123
|
+
state: "unavailable",
|
|
124
|
+
reason: "list_bookmarks returned malformed output; expected an array.",
|
|
125
|
+
remediation: "Retry list_bookmarks directly and report the provider output shape if it remains malformed.",
|
|
126
|
+
};
|
|
127
|
+
if (!value.every(isBookmark))
|
|
128
|
+
return {
|
|
129
|
+
state: "unavailable",
|
|
130
|
+
reason: "list_bookmarks returned malformed entries; expected address and name strings.",
|
|
131
|
+
remediation: "Retry list_bookmarks directly and report the provider output shape if it remains malformed.",
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
state: "available",
|
|
135
|
+
value: value.filter((bookmark) => bookmark.address === address),
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
const isBookmark = (value) => typeof value === "object" &&
|
|
139
|
+
value !== null &&
|
|
140
|
+
!Array.isArray(value) &&
|
|
141
|
+
typeof value.address === "string" &&
|
|
142
|
+
typeof value.name === "string";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EvidenceIntegrityError, NoBinaryOpenError, } from "../domain/errors.js";
|
|
2
2
|
import { err, ok } from "../domain/result.js";
|
|
3
3
|
import { analysisQueryId, createAnalysisSnapshotEntry, snapshotBinding, snapshotMatchesProfile, snapshotMatchesTarget, snapshotTarget, } from "../domain/analysisSnapshot.js";
|
|
4
|
-
import {
|
|
4
|
+
import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
|
|
5
5
|
const STATEFUL_OPERATIONS = new Set([
|
|
6
6
|
"health",
|
|
7
7
|
"current_address",
|
|
@@ -19,7 +19,9 @@ const CURSOR_DEFAULT_OPERATIONS = new Set([
|
|
|
19
19
|
"prev_address",
|
|
20
20
|
"xrefs",
|
|
21
21
|
]);
|
|
22
|
-
const DOCUMENT_SCOPED_OPERATIONS = new Set(
|
|
22
|
+
const DOCUMENT_SCOPED_OPERATIONS = new Set(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy")
|
|
23
|
+
.map(({ name }) => name)
|
|
24
|
+
.filter((name) => name !== "current_document" &&
|
|
23
25
|
name !== "list_documents" &&
|
|
24
26
|
name !== "set_current_document"));
|
|
25
27
|
/** Whether an operation is immutable and independent of provider UI state. */
|
|
@@ -36,7 +36,7 @@ export const resolveTraceApplicationFeatureRequest = (input, lookup) => {
|
|
|
36
36
|
};
|
|
37
37
|
/** Resolve a trace request already parsed by the caller-facing contract. */
|
|
38
38
|
export const resolveTraceApplicationFeatureRequestValidated = (input, lookup) => {
|
|
39
|
-
const application = graphEvidence(input
|
|
39
|
+
const application = graphEvidence(input, lookup);
|
|
40
40
|
if (!application.ok)
|
|
41
41
|
return application;
|
|
42
42
|
const native = resolveEvidenceReferences(lookup, input.native_observation_evidence_ids);
|
|
@@ -63,7 +63,7 @@ export const resolveTraceJavaScriptSemanticsRequest = (input, lookup) => {
|
|
|
63
63
|
};
|
|
64
64
|
/** Resolve a semantic trace request already parsed by its public contract. */
|
|
65
65
|
export const resolveTraceJavaScriptSemanticsRequestValidated = (input, lookup) => {
|
|
66
|
-
const application = graphEvidence(input
|
|
66
|
+
const application = graphEvidence(input, lookup);
|
|
67
67
|
if (!application.ok)
|
|
68
68
|
return application;
|
|
69
69
|
const raw = { application: application.value, query: input.query };
|
|
@@ -81,10 +81,14 @@ export const resolveCompareApplicationVersionsRequest = (input, lookup) => {
|
|
|
81
81
|
};
|
|
82
82
|
/** Resolve a comparison request parsed by the caller-facing contract. */
|
|
83
83
|
export const resolveCompareApplicationVersionsRequestValidated = (input, lookup) => {
|
|
84
|
-
const left = graphEvidence(
|
|
84
|
+
const left = graphEvidence("left" in input
|
|
85
|
+
? { application: input.left }
|
|
86
|
+
: { application_evidence_id: input.left_evidence_id }, lookup);
|
|
85
87
|
if (!left.ok)
|
|
86
88
|
return left;
|
|
87
|
-
const right = graphEvidence(
|
|
89
|
+
const right = graphEvidence("right" in input
|
|
90
|
+
? { application: input.right }
|
|
91
|
+
: { application_evidence_id: input.right_evidence_id }, lookup);
|
|
88
92
|
if (!right.ok)
|
|
89
93
|
return right;
|
|
90
94
|
const leftNative = resolveEvidenceReferences(lookup, input.left_native_observation_evidence_ids);
|
|
@@ -123,7 +127,7 @@ export const resolveCompareSourceToBundleRequest = (input, lookup) => {
|
|
|
123
127
|
};
|
|
124
128
|
/** Resolve a historical-source comparison request parsed by its public contract. */
|
|
125
129
|
export const resolveCompareSourceToBundleRequestValidated = (input, lookup) => {
|
|
126
|
-
const application = graphEvidence(input
|
|
130
|
+
const application = graphEvidence(input, lookup);
|
|
127
131
|
if (!application.ok)
|
|
128
132
|
return application;
|
|
129
133
|
const raw = {
|
|
@@ -148,10 +152,14 @@ export const resolveCompareJavaScriptExportShapesRequest = (input, lookup) => {
|
|
|
148
152
|
};
|
|
149
153
|
/** Resolve an export-shape request already parsed by the adapter contract. */
|
|
150
154
|
export const resolveCompareJavaScriptExportShapesRequestValidated = (input, lookup) => {
|
|
151
|
-
const left = graphEvidence(
|
|
155
|
+
const left = graphEvidence("left" in input
|
|
156
|
+
? { application: input.left }
|
|
157
|
+
: { application_evidence_id: input.left_evidence_id }, lookup);
|
|
152
158
|
if (!left.ok)
|
|
153
159
|
return left;
|
|
154
|
-
const right = graphEvidence(
|
|
160
|
+
const right = graphEvidence("right" in input
|
|
161
|
+
? { application: input.right }
|
|
162
|
+
: { application_evidence_id: input.right_evidence_id }, lookup);
|
|
155
163
|
if (!right.ok)
|
|
156
164
|
return right;
|
|
157
165
|
const raw = {
|
|
@@ -171,10 +179,10 @@ export const resolveCompareJavaScriptExportShapesRequestValidated = (input, look
|
|
|
171
179
|
? ok(parsed.data)
|
|
172
180
|
: invalid("compare_javascript_export_shapes", parsed.error, raw);
|
|
173
181
|
};
|
|
174
|
-
const graphEvidence = (
|
|
175
|
-
if (
|
|
176
|
-
return ok(
|
|
177
|
-
const resolved = resolveEvidenceReferences(lookup,
|
|
182
|
+
const graphEvidence = (source, lookup) => {
|
|
183
|
+
if ("application" in source)
|
|
184
|
+
return ok(source.application);
|
|
185
|
+
const resolved = resolveEvidenceReferences(lookup, [source.application_evidence_id], APPLICATION_GRAPH_IDENTITIES);
|
|
178
186
|
return resolved.ok ? ok(resolved.value[0]) : resolved;
|
|
179
187
|
};
|
|
180
188
|
const invalid = (operation, cause, input) => err(new AnalysisInputError(operation, undefined, projectInputIssues(cause.issues, input)));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ArtifactReaderFailure } from "../../artifacts/ArtifactReader.js";
|
|
2
|
+
/** Resolve caller approval and operator policy before native reader selection. */
|
|
3
|
+
export const resolveNativeMountPolicy = (approved, enabled) => {
|
|
4
|
+
if (!approved)
|
|
5
|
+
return { status: "disabled" };
|
|
6
|
+
if (!enabled)
|
|
7
|
+
throw new ArtifactReaderFailure("unavailable", "Native DMG mounting is disabled by operator policy");
|
|
8
|
+
return { status: "approved" };
|
|
9
|
+
};
|
|
10
|
+
/** Resolve parsed caller intent and operator policy before artifact scanning. */
|
|
11
|
+
export const resolveArtifactIntegrityPolicy = (intent, enabled) => {
|
|
12
|
+
if (intent.mode === "fail")
|
|
13
|
+
return intent;
|
|
14
|
+
if (!enabled)
|
|
15
|
+
throw new ArtifactReaderFailure("policy", "Integrity continuation requires explicit approval and operator policy");
|
|
16
|
+
return intent;
|
|
17
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AsarArtifactReader } from "../../artifacts/AsarArtifactReader.js";
|
|
2
|
-
import { ArtifactReaderFailure, } from "../../artifacts/ArtifactReader.js";
|
|
3
2
|
import { DirectoryArtifactReader } from "../../artifacts/DirectoryArtifactReader.js";
|
|
4
3
|
import { MachOSliceArtifactReader } from "../../artifacts/MachOSliceArtifactReader.js";
|
|
5
4
|
import { NativeDmgArtifactReader } from "../../artifacts/NativeDmgArtifactReader.js";
|
|
@@ -21,10 +20,8 @@ export const createReader = async (path, format, nativeMount, signal) => {
|
|
|
21
20
|
? new MachOSliceArtifactReader(path)
|
|
22
21
|
: undefined;
|
|
23
22
|
case "dmg":
|
|
24
|
-
if (
|
|
23
|
+
if (nativeMount.status === "disabled")
|
|
25
24
|
return undefined;
|
|
26
|
-
if (!nativeMount.nativeMountEnabled)
|
|
27
|
-
throw new ArtifactReaderFailure("unavailable", "Native DMG mounting is disabled by operator policy");
|
|
28
25
|
return NativeDmgArtifactReader.create(path, signal);
|
|
29
26
|
default:
|
|
30
27
|
return undefined;
|
|
@@ -10,9 +10,6 @@ import { scanReader, } from "./scanReader.js";
|
|
|
10
10
|
import { NATIVE_MOUNT_DISABLED, STRICT_INTEGRITY_POLICY, } from "./types.js";
|
|
11
11
|
export const scanCanonicalArtifactInventory = async (path, limits, options = {}) => {
|
|
12
12
|
const integrity = options.integrity ?? STRICT_INTEGRITY_POLICY;
|
|
13
|
-
if (integrity.mode === "record-and-continue" &&
|
|
14
|
-
(!integrity.approved || !integrity.enabled))
|
|
15
|
-
throw new ArtifactReaderFailure("unavailable", "Integrity continuation requires explicit approval and operator policy");
|
|
16
13
|
const metadata = await lstat(path);
|
|
17
14
|
const rootFormat = await classifyRoot(path, metadata.isDirectory());
|
|
18
15
|
const rootDigest = metadata.isDirectory()
|
|
@@ -69,14 +69,14 @@ const digestArtifactEntry = async (context, currentReader, entry, logicalPath) =
|
|
|
69
69
|
const digest = await hashReadable(await currentReader.open(entry, context.signal), Math.min(context.limits.maxEntryBytes, remainingBytes), context.signal);
|
|
70
70
|
context.totalBytes += digest.bytes;
|
|
71
71
|
const mismatched = entry.declaredSha256 !== null && entry.declaredSha256 !== digest.sha256;
|
|
72
|
-
if (mismatched && context.integrity.mode === "fail")
|
|
73
|
-
throw new ArtifactReaderFailure("integrity", `Artifact integrity metadata disagrees with content: ${logicalPath}`, undefined, {
|
|
74
|
-
logicalPath,
|
|
75
|
-
declaredSha256: entry.declaredSha256,
|
|
76
|
-
calculatedSha256: digest.sha256,
|
|
77
|
-
unpacked: entry.unpacked,
|
|
78
|
-
});
|
|
79
72
|
if (mismatched && entry.declaredSha256 !== null) {
|
|
73
|
+
if (context.integrity.mode === "fail")
|
|
74
|
+
throw new ArtifactReaderFailure("integrity", `Artifact integrity metadata disagrees with content: ${logicalPath}`, undefined, {
|
|
75
|
+
logicalPath,
|
|
76
|
+
declaredSha256: entry.declaredSha256,
|
|
77
|
+
calculatedSha256: digest.sha256,
|
|
78
|
+
unpacked: entry.unpacked,
|
|
79
|
+
});
|
|
80
80
|
if (context.pendingContradictions.length >= context.integrity.maxMismatches)
|
|
81
81
|
throw new ArtifactReaderFailure("limit", "Artifact integrity mismatch limit exceeded");
|
|
82
82
|
context.pendingContradictions.push({
|
|
@@ -2,15 +2,15 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { analysisProfilesEqual, } from "../domain/analysisProfile.js";
|
|
3
3
|
import { AnalysisCancelledError, ProviderAdapterError, } from "../domain/errors.js";
|
|
4
4
|
import { err, ok } from "../domain/result.js";
|
|
5
|
-
import {
|
|
6
|
-
import { OFFICIAL_TOOL_CONTRACTS } from "../contracts/toolContracts.js";
|
|
5
|
+
import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
|
|
7
6
|
import { SessionProviderRouter, } from "./SessionProviderRouter.js";
|
|
8
7
|
import { BinarySessionRecords } from "./BinarySessionRecords.js";
|
|
9
8
|
import { binarySessionStatus } from "./BinarySessionStatus.js";
|
|
10
9
|
import { resolveSessionOpen, } from "./BinarySessionOpen.js";
|
|
11
10
|
import { prepareSessionExecution } from "./BinarySessionExecution.js";
|
|
12
11
|
import { closeAnalysisClient } from "./AnalysisClientCleanup.js";
|
|
13
|
-
const OFFICIAL_OPERATIONS = new Set(
|
|
12
|
+
const OFFICIAL_OPERATIONS = new Set(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy").map(({ name }) => name));
|
|
13
|
+
const ENHANCED_OPERATIONS = new Set(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "enhanced").map(({ name }) => name));
|
|
14
14
|
/**
|
|
15
15
|
* Owns the single active target shared by CLI and MCP adapters.
|
|
16
16
|
*
|
|
@@ -24,7 +24,7 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
24
24
|
#transition = Promise.resolve();
|
|
25
25
|
#calls = new Set();
|
|
26
26
|
#providerRouter;
|
|
27
|
-
#
|
|
27
|
+
#runtimeUnavailability = new Map();
|
|
28
28
|
#availabilityListeners = new Set();
|
|
29
29
|
constructor(provider, options = {}) {
|
|
30
30
|
super();
|
|
@@ -42,7 +42,7 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
42
42
|
const exact = route.capabilities?.get(operation)?.provider;
|
|
43
43
|
if (exact !== undefined)
|
|
44
44
|
selected = exact;
|
|
45
|
-
else if (
|
|
45
|
+
else if (ENHANCED_OPERATIONS.has(operation)) {
|
|
46
46
|
const providers = new Map();
|
|
47
47
|
for (const descriptor of route.capabilities?.values() ?? [])
|
|
48
48
|
if (descriptor.available &&
|
|
@@ -112,6 +112,7 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
112
112
|
if (!imported.ok)
|
|
113
113
|
return imported;
|
|
114
114
|
}
|
|
115
|
+
this.resetSnapshotInvalidation();
|
|
115
116
|
return ok(target);
|
|
116
117
|
}
|
|
117
118
|
await this.#drainCalls();
|
|
@@ -184,7 +185,7 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
184
185
|
target: this.#active?.target,
|
|
185
186
|
route: this.#currentRoute(),
|
|
186
187
|
router: this.#providerRouter,
|
|
187
|
-
|
|
188
|
+
runtimeUnavailability: this.#runtimeUnavailability,
|
|
188
189
|
runId: this.#active?.runId,
|
|
189
190
|
runtimeLineageSnapshots: this.#active?.client.runtimeLineageSnapshots?.() ?? [],
|
|
190
191
|
requestActivitySnapshots: this.#active?.client.requestActivitySnapshots?.() ?? [],
|
|
@@ -245,12 +246,12 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
245
246
|
}
|
|
246
247
|
#observeRuntimeAvailability(operation, result) {
|
|
247
248
|
if (result.ok) {
|
|
248
|
-
if (this.#
|
|
249
|
+
if (this.#markRuntimeAvailable(operation))
|
|
249
250
|
this.#emitAvailabilityChanged();
|
|
250
251
|
return;
|
|
251
252
|
}
|
|
252
253
|
if (result.error._tag === "AnalysisCapabilityUnavailableError") {
|
|
253
|
-
if (this.#
|
|
254
|
+
if (this.#markRuntimeUnavailable(operation, result.error.message))
|
|
254
255
|
this.#emitAvailabilityChanged();
|
|
255
256
|
return;
|
|
256
257
|
}
|
|
@@ -266,27 +267,25 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
266
267
|
for (const descriptor of capabilities?.values() ?? [])
|
|
267
268
|
if (providerId !== undefined && descriptor.provider.id === providerId)
|
|
268
269
|
changed =
|
|
269
|
-
this.#
|
|
270
|
+
this.#markRuntimeUnavailable(descriptor.operation, "Provider became unavailable during this session.") || changed;
|
|
270
271
|
if (changed)
|
|
271
272
|
this.#emitAvailabilityChanged();
|
|
272
273
|
}
|
|
273
274
|
}
|
|
274
|
-
#
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
275
|
+
#markRuntimeAvailable(operation) {
|
|
276
|
+
return this.#runtimeUnavailability.delete(operation);
|
|
277
|
+
}
|
|
278
|
+
#markRuntimeUnavailable(operation, reason) {
|
|
279
|
+
const current = this.#runtimeUnavailability.get(operation);
|
|
280
|
+
if (current?.reason === reason)
|
|
279
281
|
return false;
|
|
280
|
-
|
|
281
|
-
this.#runtimeAvailability.delete(operation);
|
|
282
|
-
else
|
|
283
|
-
this.#runtimeAvailability.set(operation, { available, reason });
|
|
282
|
+
this.#runtimeUnavailability.set(operation, { reason });
|
|
284
283
|
return true;
|
|
285
284
|
}
|
|
286
285
|
#clearRuntimeAvailability() {
|
|
287
|
-
if (this.#
|
|
286
|
+
if (this.#runtimeUnavailability.size === 0)
|
|
288
287
|
return;
|
|
289
|
-
this.#
|
|
288
|
+
this.#runtimeUnavailability.clear();
|
|
290
289
|
this.#emitAvailabilityChanged();
|
|
291
290
|
}
|
|
292
291
|
#emitAvailabilityChanged() {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AnalysisProviderRegistry } from "./AnalysisProviderRegistry.js";
|
|
2
|
+
import { BinarySession } from "./BinarySession.js";
|
|
3
|
+
import { SessionProviderRouter } from "./SessionProviderRouter.js";
|
|
4
|
+
const normalizeBinarySessionOptions = (optionsOrResolver) => typeof optionsOrResolver === "function"
|
|
5
|
+
? { resolveAnalysisProfile: optionsOrResolver }
|
|
6
|
+
: (optionsOrResolver ?? {});
|
|
7
|
+
/**
|
|
8
|
+
* Compose one provider-neutral session from deep-provider selection and
|
|
9
|
+
* disjoint auxiliary operation families.
|
|
10
|
+
*/
|
|
11
|
+
export const composeBinarySession = (registry, auxiliaryProviders = []) => new BinarySession(registry instanceof SessionProviderRouter
|
|
12
|
+
? registry
|
|
13
|
+
: SessionProviderRouter.selectable(registry, auxiliaryProviders));
|
|
14
|
+
/**
|
|
15
|
+
* Compose a session through the same internal seam for focused adapter tests.
|
|
16
|
+
* The constructor remains private to this composition module, so callers test
|
|
17
|
+
* provider behavior without coupling to BinarySession construction.
|
|
18
|
+
*/
|
|
19
|
+
export const composeBinarySessionFromFactory = (provider, optionsOrResolver) => new BinarySession(provider, normalizeBinarySessionOptions(optionsOrResolver));
|
|
20
|
+
/** Compose a focused session from any provider-shaped test seam. */
|
|
21
|
+
export const composeBinarySessionFromProvider = (provider, optionsOrResolver) => new BinarySession(provider, normalizeBinarySessionOptions(optionsOrResolver));
|