rea-agents 3.0.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 +14 -16
- package/dist/application/AnalysisContextQueries.js +21 -9
- 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 +14 -16
- package/dist/application/BinarySessionRecords.js +31 -5
- 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 +134 -63
- package/dist/application/CrossVersionInventory.js +7 -6
- 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 +22 -20
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +8 -1
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- 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/SetupClientConfiguration.js +6 -1
- package/dist/application/WindowsCapabilities.js +5 -4
- 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/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 +12 -6
- 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 +1 -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 +27 -34
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +13 -29
- package/dist/contracts/functionWorkflowToolContracts.js +2 -3
- 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/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +1 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +5 -77
- package/dist/contracts/toolEffects.js +15 -0
- package/dist/contracts/toolOutputSchemaGroups.js +17 -2
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- 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 +33 -35
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformanceReplay.js +3 -3
- package/dist/domain/conformanceTrustGate.js +151 -16
- package/dist/domain/customProtocolCapture.js +3 -3
- 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 +82 -79
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperValues.js +68 -71
- package/dist/domain/inputIssueProjection.js +4 -1
- 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/knownPageCoverage.js +15 -7
- package/dist/domain/nativeApiBoundary.js +15 -7
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- 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 +8 -6
- 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/generatedMcpToolCatalog.js +1 -1
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +17 -15
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +5 -1
- 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 +1 -1
- package/dist/hopper/HopperProvider.js +0 -14
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +30 -37
- package/dist/main.js +17 -15
- package/dist/mcpDoctor.js +2 -24
- 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 +158 -94
- 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 +114 -122
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +41 -57
- 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/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +69 -40
- package/dist/server/registerSessionStatusTool.js +13 -28
- package/dist/server/registerSessionTools.js +36 -52
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -192
- package/dist/server/toolResult.js +2 -18
- package/package.json +22 -14
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/scripts/rea.mjs +1 -11
- package/skills/reverse-engineer-anything/SKILL.md +2 -2
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/LazyToolCatalog.js +0 -134
- package/dist/server/hydrateServerTools.js +0 -191
- package/dist/server/toolInputValidation.js +0 -77
- package/scripts/package-runner-bootstrap.mjs +0 -72
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# REA: Reverse Engineer Anything
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### Reverse engineer anything with agents, from app behavior down to native binaries.
|
|
8
8
|
|
|
9
9
|
**See a feature you like. Understand how it works, down to the binary level.**
|
|
10
10
|
|
|
@@ -89,13 +89,13 @@ REA shows how it reached its conclusions. It does not claim to recover original
|
|
|
89
89
|
### Run setup — recommended
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
|
-
npx rea-agents setup
|
|
92
|
+
npx --yes rea-agents@latest setup
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
The npm package-runner prompt, when shown, approves downloading REA for this
|
|
96
96
|
invocation; it does not approve any setup changes. The REA wizard separately
|
|
97
97
|
shows its complete plan and asks before applying it. Setup does not update
|
|
98
|
-
Homebrew, Node.js, or npm.
|
|
98
|
+
Homebrew, Node.js, or npm. The setup command opens with the work it
|
|
99
99
|
enables: investigate local apps from an agent, recover evidence through a
|
|
100
100
|
deep-analysis provider, and reuse REA's guided workflow. It summarizes the
|
|
101
101
|
detected agents, then asks which capabilities to set up: agent integration
|
|
@@ -103,12 +103,10 @@ detected agents, then asks which capabilities to set up: agent integration
|
|
|
103
103
|
Nothing is preselected. Choosing agent integration opens a second empty
|
|
104
104
|
checklist for the specific detected agents that should receive a registration.
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
`npx -y rea-agents@latest setup` once to repair registrations created by one.
|
|
111
|
-
Intentional rollbacks remain available through an exact package request.
|
|
106
|
+
`@latest` makes the requested release explicit and asks npm for the release
|
|
107
|
+
currently published under that tag. REA does not silently replace the package
|
|
108
|
+
version npm selected. Intentional rollbacks therefore remain available through
|
|
109
|
+
an exact package request.
|
|
112
110
|
|
|
113
111
|
REA keeps the journey inline so its history remains in the terminal. Selecting
|
|
114
112
|
a capability does not select every detected target or authorize a change.
|
|
@@ -139,7 +137,7 @@ Pass installer options after `bash -s --`, for example `--dry-run`, `--no-setup`
|
|
|
139
137
|
### With an agent — recommended
|
|
140
138
|
|
|
141
139
|
```bash
|
|
142
|
-
npx rea-agents setup
|
|
140
|
+
npx --yes rea-agents@latest setup
|
|
143
141
|
```
|
|
144
142
|
|
|
145
143
|
Choose Agent Integration in the reviewed setup plan. REA installs the pinned MCP
|
|
@@ -151,7 +149,7 @@ Review the setup plan, approve it if appropriate, then describe the app or featu
|
|
|
151
149
|
### From Terminal — no installation
|
|
152
150
|
|
|
153
151
|
```bash
|
|
154
|
-
npx rea-agents setup
|
|
152
|
+
npx --yes rea-agents@latest setup
|
|
155
153
|
npx -y rea-agents@latest doctor
|
|
156
154
|
npx -y rea-agents@latest analyze /Applications/Notes.app
|
|
157
155
|
```
|
|
@@ -386,10 +384,10 @@ REA handles the app analysis in steps 1–5. The agent performs step 6 with its
|
|
|
386
384
|
| Artifact graph | 3 | bounded provider-neutral inspection, deterministic directory/ZIP/APK/IPA/MSIX/AppX/ASAR inventory, and explicitly selected extraction into an absent owned tree |
|
|
387
385
|
| Managed PE/CLI | 8 | PE/CLI identity, metadata members, CIL hashes, P/Invoke/native-boundary declarations and verification, application-graph projection, decompiler reconstruction import, token remapping, runtime-correlation plans, and version comparison |
|
|
388
386
|
| Browser observation | 9 | exact-origin passive CDP capture, bundle and source-map analysis, WebMCP discovery, session timelines, capture diff, visual evidence, and bounded Playwright scenarios |
|
|
389
|
-
| Electron analysis |
|
|
387
|
+
| Electron analysis | 5 | passive root-confined observation, bounded static application mapping, evidence-backed static/runtime reconciliation, and separately approved provider-owned click/wait scenarios |
|
|
390
388
|
| JavaScript runtime | 2 | approved attach-only Node/Electron Inspector target discovery plus bounded script and execution-context observation without evaluation or instrumentation |
|
|
391
389
|
| Application workflows | 12 | bounded cross-layer traces, unique-only version matching, historical-source to bundle mapping, static export return-shape comparison, approved Linux-isolated extracted-module replay, managed-runtime characterization, reconstruction coverage closure, deterministic obligation ledgers, and end-to-end readiness conformance |
|
|
392
|
-
| Workspace and observation |
|
|
390
|
+
| Workspace and observation | 23 | target lifecycle, Evidence v2 bundle snapshots, retained-bundle release, aggregate navigation/address context, direct finite replay-machine evaluation, process/artifact/function comparison, evidence-linked residual-unknown lifecycle |
|
|
393
391
|
|
|
394
392
|
The public interface describes what the agent is trying to learn. Providers decide how to answer. macOS utilities handle common semantic inspection without launching Hopper; Hopper handles deeper native analysis; the process harness implements controlled behavioral capture.
|
|
395
393
|
|
|
@@ -509,14 +507,14 @@ REA is growing into a toolkit for understanding software across static artifacts
|
|
|
509
507
|
|
|
510
508
|
### Next
|
|
511
509
|
|
|
512
|
-
1. **Controlled replay conformance growth** — extend the shipped Linux extracted-module sandbox with more source-owned hostile fixtures and cross-kernel conformance; browser
|
|
510
|
+
1. **Controlled replay conformance growth** — extend the shipped Linux extracted-module sandbox with more source-owned hostile fixtures and cross-kernel conformance; browser and Electron scenarios remain separately permissioned authorities.
|
|
513
511
|
2. **Broader application graph evidence** — extend authenticated cross-layer traces with additional static extractors and separately approved runtime authorities.
|
|
514
512
|
3. **Professional managed-code analysis** — extend shipped PE/CLI triage, CIL evidence, managed/native declaration inventory, source-owned conformance, and obfuscation-resistant comparisons toward verified native-provider composition under the accepted [managed-code boundary](docs/managed-code-analysis.md).
|
|
515
513
|
4. **Deterministic behavior harnesses** — extend process ownership, protocol fixtures, filesystem observation, reconnects, and cross-version behavioral comparison.
|
|
516
514
|
|
|
517
515
|
### Later
|
|
518
516
|
|
|
519
|
-
1. **
|
|
517
|
+
1. **Broader controlled application interaction** — extend the separately authorized browser and Electron scenario surfaces beyond the current bounded click/wait actions without widening passive observation or extracted-module replay authority.
|
|
520
518
|
2. **Native runtime observation** — approval-gated LLDB, Frida, system logs, process/filesystem observers, and native API tracing.
|
|
521
519
|
3. **Additional providers and targets** — evaluate IDA/Hex-Rays, Binary Ninja, Rizin, LIEF, Windows-native providers, mobile artifacts, firmware, document formats, and other software-defined systems.
|
|
522
520
|
|
|
@@ -537,7 +535,7 @@ Setup detects Claude Code, Claude Desktop, Codex, Cursor, Gemini CLI, Windsurf,
|
|
|
537
535
|
"mcpServers": {
|
|
538
536
|
"rea": {
|
|
539
537
|
"command": "npx",
|
|
540
|
-
"args": ["-y", "rea-agents@3.
|
|
538
|
+
"args": ["-y", "rea-agents@3.1.0", "mcp"]
|
|
541
539
|
}
|
|
542
540
|
}
|
|
543
541
|
}
|
|
@@ -69,10 +69,7 @@ export const inspectAddressContext = async (analysis, input, signal) => {
|
|
|
69
69
|
comment,
|
|
70
70
|
inline_comment: inlineComment,
|
|
71
71
|
bookmarks: bookmarks.state === "available"
|
|
72
|
-
?
|
|
73
|
-
state: "available",
|
|
74
|
-
value: matchingBookmarks(bookmarks.value, resolvedAddress(results[1], input.address)),
|
|
75
|
-
}
|
|
72
|
+
? matchingBookmarks(bookmarks.value, resolvedAddress(results[1], input.address))
|
|
76
73
|
: bookmarks,
|
|
77
74
|
});
|
|
78
75
|
};
|
|
@@ -122,9 +119,24 @@ const resolvedAddress = (result, fallback) => {
|
|
|
122
119
|
};
|
|
123
120
|
const matchingBookmarks = (value, address) => {
|
|
124
121
|
if (!Array.isArray(value))
|
|
125
|
-
return
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
+
};
|
|
130
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";
|
|
@@ -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("policy", "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({
|
|
@@ -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();
|
|
@@ -185,7 +185,7 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
185
185
|
target: this.#active?.target,
|
|
186
186
|
route: this.#currentRoute(),
|
|
187
187
|
router: this.#providerRouter,
|
|
188
|
-
|
|
188
|
+
runtimeUnavailability: this.#runtimeUnavailability,
|
|
189
189
|
runId: this.#active?.runId,
|
|
190
190
|
runtimeLineageSnapshots: this.#active?.client.runtimeLineageSnapshots?.() ?? [],
|
|
191
191
|
requestActivitySnapshots: this.#active?.client.requestActivitySnapshots?.() ?? [],
|
|
@@ -246,12 +246,12 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
246
246
|
}
|
|
247
247
|
#observeRuntimeAvailability(operation, result) {
|
|
248
248
|
if (result.ok) {
|
|
249
|
-
if (this.#
|
|
249
|
+
if (this.#markRuntimeAvailable(operation))
|
|
250
250
|
this.#emitAvailabilityChanged();
|
|
251
251
|
return;
|
|
252
252
|
}
|
|
253
253
|
if (result.error._tag === "AnalysisCapabilityUnavailableError") {
|
|
254
|
-
if (this.#
|
|
254
|
+
if (this.#markRuntimeUnavailable(operation, result.error.message))
|
|
255
255
|
this.#emitAvailabilityChanged();
|
|
256
256
|
return;
|
|
257
257
|
}
|
|
@@ -267,27 +267,25 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
267
267
|
for (const descriptor of capabilities?.values() ?? [])
|
|
268
268
|
if (providerId !== undefined && descriptor.provider.id === providerId)
|
|
269
269
|
changed =
|
|
270
|
-
this.#
|
|
270
|
+
this.#markRuntimeUnavailable(descriptor.operation, "Provider became unavailable during this session.") || changed;
|
|
271
271
|
if (changed)
|
|
272
272
|
this.#emitAvailabilityChanged();
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
|
-
#
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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)
|
|
280
281
|
return false;
|
|
281
|
-
|
|
282
|
-
this.#runtimeAvailability.delete(operation);
|
|
283
|
-
else
|
|
284
|
-
this.#runtimeAvailability.set(operation, { available, reason });
|
|
282
|
+
this.#runtimeUnavailability.set(operation, { reason });
|
|
285
283
|
return true;
|
|
286
284
|
}
|
|
287
285
|
#clearRuntimeAvailability() {
|
|
288
|
-
if (this.#
|
|
286
|
+
if (this.#runtimeUnavailability.size === 0)
|
|
289
287
|
return;
|
|
290
|
-
this.#
|
|
288
|
+
this.#runtimeUnavailability.clear();
|
|
291
289
|
this.#emitAvailabilityChanged();
|
|
292
290
|
}
|
|
293
291
|
#emitAvailabilityChanged() {
|
|
@@ -63,17 +63,31 @@ export class BinarySessionRecords {
|
|
|
63
63
|
bytes: Buffer.byteLength(existing ?? encoded),
|
|
64
64
|
records: bundle.records.length,
|
|
65
65
|
unknowns: bundle.unknowns.length,
|
|
66
|
+
scope: "session",
|
|
67
|
+
survivesSession: false,
|
|
66
68
|
uri: `rea://evidence-bundle/${digest}`,
|
|
67
69
|
});
|
|
68
70
|
}
|
|
69
71
|
retainedEvidenceBundle(digest) {
|
|
70
72
|
return this.#retainedBundles.get(digest);
|
|
71
73
|
}
|
|
74
|
+
/** Release one immutable bundle so bounded retention has an explicit recovery path. */
|
|
75
|
+
releaseEvidenceBundle(bundleDigest) {
|
|
76
|
+
const encoded = this.#retainedBundles.get(bundleDigest);
|
|
77
|
+
if (encoded === undefined)
|
|
78
|
+
return false;
|
|
79
|
+
this.#retainedBundles.delete(bundleDigest);
|
|
80
|
+
this.#retainedBundleBytes -= Buffer.byteLength(encoded);
|
|
81
|
+
this.#emitSnapshotChanged();
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
72
84
|
importEvidenceBundle(bundle) {
|
|
73
85
|
const imported = this.#evidence.import(bundle);
|
|
74
|
-
if (imported.ok
|
|
86
|
+
if (!imported.ok)
|
|
87
|
+
return imported;
|
|
88
|
+
if (imported.value.changed)
|
|
75
89
|
this.#emitSnapshotChanged();
|
|
76
|
-
return imported;
|
|
90
|
+
return ok(imported.value.recordsAdded);
|
|
77
91
|
}
|
|
78
92
|
exportAnalysisSnapshot() {
|
|
79
93
|
const active = this.activeAnalysisBinding();
|
|
@@ -93,7 +107,10 @@ export class BinarySessionRecords {
|
|
|
93
107
|
return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: the active target has no concrete analysis profile"));
|
|
94
108
|
const imported = this.#snapshot.import(snapshot, active === undefined
|
|
95
109
|
? undefined
|
|
96
|
-
: { target: active.target, profile: active.profile }, (bundle) =>
|
|
110
|
+
: { target: active.target, profile: active.profile }, (bundle) => {
|
|
111
|
+
const imported = this.#evidence.import(bundle);
|
|
112
|
+
return imported.ok ? ok(imported.value.recordsAdded) : imported;
|
|
113
|
+
});
|
|
97
114
|
if (imported.ok)
|
|
98
115
|
this.#emitSnapshotChanged();
|
|
99
116
|
return imported;
|
|
@@ -136,8 +153,17 @@ export class BinarySessionRecords {
|
|
|
136
153
|
this.#emitSnapshotChanged();
|
|
137
154
|
}
|
|
138
155
|
#emitSnapshotChanged() {
|
|
139
|
-
for (const listener of this.#snapshotListeners)
|
|
140
|
-
|
|
156
|
+
for (const listener of this.#snapshotListeners) {
|
|
157
|
+
try {
|
|
158
|
+
const notification = listener();
|
|
159
|
+
if (notification !== undefined)
|
|
160
|
+
void notification.catch(() => undefined);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// External resource observers are best-effort; one callback must not
|
|
164
|
+
// make a committed evidence mutation appear to fail.
|
|
165
|
+
}
|
|
166
|
+
}
|
|
141
167
|
}
|
|
142
168
|
retainInvestigationWorkspace(workspace) {
|
|
143
169
|
const parsed = parseInvestigationWorkspace(workspace);
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
/** Project internal provider routing state into the caller-visible session status. */
|
|
2
|
-
export const binarySessionStatus = ({ target, route, router,
|
|
2
|
+
export const binarySessionStatus = ({ target, route, router, runtimeUnavailability, runId, runtimeLineageSnapshots, requestActivitySnapshots, }) => {
|
|
3
3
|
const configuredProvider = router.configuredIdentity();
|
|
4
4
|
const provider = providerSummary(configuredProvider);
|
|
5
5
|
const providers = router.providerIdentities(route).map(providerSummary);
|
|
6
6
|
const capabilities = [...(route.capabilities?.values() ?? [])]
|
|
7
7
|
.sort((left, right) => left.operation.localeCompare(right.operation))
|
|
8
|
-
.map((descriptor) =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
.map((descriptor) => {
|
|
9
|
+
const unavailable = runtimeUnavailability.get(descriptor.operation);
|
|
10
|
+
return unavailable === undefined
|
|
11
|
+
? descriptor
|
|
12
|
+
: {
|
|
13
|
+
...descriptor,
|
|
14
|
+
available: false,
|
|
15
|
+
reason: unavailable.reason,
|
|
16
|
+
};
|
|
17
|
+
})
|
|
12
18
|
.map(capabilityStatus);
|
|
13
19
|
const analysisProviderBinding = route.binding === null
|
|
14
20
|
? null
|
|
@@ -21,9 +21,7 @@ export const createBrowserEvidence = (operation, input, result, provider) => cre
|
|
|
21
21
|
});
|
|
22
22
|
const browserParameters = (input) => {
|
|
23
23
|
if (!("cdp_endpoint" in input)) {
|
|
24
|
-
if ("before_scenario" in input
|
|
25
|
-
input.before_scenario !== undefined &&
|
|
26
|
-
input.after_scenario !== undefined)
|
|
24
|
+
if ("before_scenario" in input)
|
|
27
25
|
return {
|
|
28
26
|
comparison_kind: "browser_scenario",
|
|
29
27
|
before_browser: input.before_scenario.browser,
|
|
@@ -89,9 +87,9 @@ const browserParameters = (input) => {
|
|
|
89
87
|
include_storage_keys: input.include_storage_keys,
|
|
90
88
|
include_storage_fingerprints: input.include_storage_fingerprints,
|
|
91
89
|
limits: input.limits,
|
|
92
|
-
|
|
90
|
+
source_capture_approved: input.source_capture_approved,
|
|
91
|
+
...(input.include_script_sources && "analysis_limits" in input
|
|
93
92
|
? {
|
|
94
|
-
source_capture_approved: input.source_capture_approved,
|
|
95
93
|
fetch_source_maps: input.fetch_source_maps,
|
|
96
94
|
source_map_fetch_approved: input.source_map_fetch_approved,
|
|
97
95
|
analysis_limits: input.analysis_limits,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Empty MCP client feature declaration used when the caller supplies none. */
|
|
2
|
+
export const NO_CLIENT_FEATURES = {
|
|
3
|
+
elicitation_form: false,
|
|
4
|
+
elicitation_url: false,
|
|
5
|
+
roots: false,
|
|
6
|
+
sampling: false,
|
|
7
|
+
};
|
|
8
|
+
const CLIENT_FEATURE_REQUIREMENTS = {
|
|
9
|
+
capture_process_scenario: {
|
|
10
|
+
required: [],
|
|
11
|
+
optional: ["elicitation_form"],
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
/** Project a tool's client requirements against the negotiated feature set. */
|
|
15
|
+
export const clientRequirementsFor = (name, clientFeatures) => {
|
|
16
|
+
const requirements = CLIENT_FEATURE_REQUIREMENTS[name] ?? {
|
|
17
|
+
required: [],
|
|
18
|
+
optional: [],
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
required: [...requirements.required],
|
|
22
|
+
optional: [...requirements.optional],
|
|
23
|
+
missing_required: requirements.required.filter((feature) => !clientFeatures[feature]),
|
|
24
|
+
missing_optional: requirements.optional.filter((feature) => !clientFeatures[feature]),
|
|
25
|
+
};
|
|
26
|
+
};
|