rea-agents 2.4.0 → 2.5.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 +80 -18
- package/bridge/ghidra/ReaGhidraBridge.java +48 -1
- package/bridge/hopper_bridge.py +259 -24
- package/dist/application/AnalysisClientCleanup.js +14 -0
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
- package/dist/application/BinarySession.js +15 -4
- package/dist/application/BinarySessionStatus.js +31 -1
- package/dist/application/BrowserEvidence.js +14 -0
- package/dist/application/BrowserScenarioCapturePort.js +1 -0
- package/dist/application/BrowserScenarioCaptureService.js +53 -0
- package/dist/application/BrowserScenarioEvidence.js +40 -0
- package/dist/application/CallPathTracing.js +160 -0
- package/dist/application/CapabilityInventory.js +68 -12
- package/dist/application/CompositeProvider.js +10 -1
- package/dist/application/DirectAnalysis.js +7 -2
- package/dist/application/EnhancedLiteralTracing.js +118 -0
- package/dist/application/EnhancedTools.js +35 -121
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
- package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
- package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
- package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
- package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
- package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
- package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
- package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
- package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
- package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
- package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
- package/dist/application/ProcessReactiveEffects.js +6 -0
- package/dist/application/ProcessReactiveHarness.js +16 -1
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReconstructionObligationAuthority.js +72 -0
- package/dist/application/ReconstructionObligationCandidates.js +265 -0
- package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
- package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
- package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
- package/dist/application/ReconstructionObligationLedgerService.js +72 -0
- package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
- package/dist/application/ReconstructionObligationPolicies.js +132 -0
- package/dist/application/ReconstructionReadinessService.js +48 -0
- package/dist/artifacts/ArtifactProvider.js +87 -22
- package/dist/browser/BrowserScenarioSecrets.js +53 -0
- package/dist/browser/BrowserScenarioSessionPort.js +1 -0
- package/dist/browser/CdpBrowserProvider.js +2 -2
- package/dist/browser/CdpCaptureDocuments.js +57 -0
- package/dist/browser/CdpCaptureStorage.js +71 -29
- package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
- package/dist/browser/CdpEndpoint.js +8 -6
- package/dist/browser/CdpPageCapture.js +2 -0
- package/dist/browser/JavaScriptRuntimeScope.js +38 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +253 -0
- package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
- package/dist/browser/PlaywrightScenarioActions.js +62 -0
- package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
- package/dist/browser/PlaywrightScenarioEvents.js +301 -0
- package/dist/browser/PlaywrightScenarioSession.js +300 -0
- package/dist/browser/V8InspectorCaptureProjection.js +110 -0
- package/dist/browser/V8InspectorEndpoint.js +72 -0
- package/dist/browser/V8InspectorProvider.js +267 -0
- package/dist/catalogIdentity.js +8 -0
- package/dist/cli/artifactCommands.js +39 -0
- package/dist/cli/coreAnalysisCommands.js +37 -0
- package/dist/cli.js +4 -0
- package/dist/cliApplicationCommands.js +30 -2
- package/dist/cliBrowserAdvancedCommands.js +17 -5
- package/dist/cliBrowserCommands.js +1 -0
- package/dist/cliBrowserScenarioCommands.js +43 -0
- package/dist/cliCommandNames.js +8 -0
- package/dist/cliJavaScriptRuntimeCommands.js +164 -0
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/environment.js +12 -0
- package/dist/config/parseConfig.js +88 -17
- package/dist/contracts/analysisSearchContract.js +14 -0
- package/dist/contracts/applicationToolContracts.js +86 -2
- package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
- package/dist/contracts/artifactToolContracts.js +22 -0
- package/dist/contracts/browserProviderToolContracts.js +7 -0
- package/dist/contracts/browserScenarioToolContracts.js +81 -0
- package/dist/contracts/browserToolContracts.js +88 -98
- package/dist/contracts/enhancedInputs.js +25 -6
- package/dist/contracts/functionInstructionContract.js +8 -0
- package/dist/contracts/hopperMemoryContracts.js +22 -0
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
- package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
- package/dist/contracts/reconstructionReadinessExample.js +436 -0
- package/dist/contracts/toolContractExamples.js +5 -0
- package/dist/contracts/toolContractTypes.js +1 -0
- package/dist/contracts/toolContracts.js +13 -21
- package/dist/contracts/toolEffects.js +21 -0
- package/dist/contracts/toolOutputSchemaGroups.js +70 -20
- package/dist/contracts/toolOutputSchemaPrimitives.js +37 -0
- package/dist/domain/analysisErrorProjection.js +8 -0
- package/dist/domain/artifactInspection.js +347 -0
- package/dist/domain/browserCaptureComparison.js +82 -0
- package/dist/domain/browserObservation.js +8 -1
- package/dist/domain/browserObservationErrors.js +1 -0
- package/dist/domain/browserObservationSchemas.js +26 -0
- package/dist/domain/browserScenario.js +165 -0
- package/dist/domain/browserScenarioCapture.js +57 -0
- package/dist/domain/browserScenarioCaptureValues.js +204 -0
- package/dist/domain/browserScenarioDiff.js +324 -0
- package/dist/domain/browserScenarioDiffValues.js +157 -0
- package/dist/domain/browserScenarioNormalization.js +45 -0
- package/dist/domain/browserScenarioValues.js +372 -0
- package/dist/domain/hopperValues.js +10 -0
- package/dist/domain/javascriptRuntimeObservation.js +170 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
- package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +5 -4
- package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
- package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
- package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
- package/dist/domain/javascriptSemanticDataEffects.js +284 -0
- package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
- package/dist/domain/javascriptSemanticFingerprints.js +174 -0
- package/dist/domain/javascriptSemanticIr.js +21 -1
- package/dist/domain/javascriptSemanticObjects.js +115 -0
- package/dist/domain/javascriptSemanticPromises.js +290 -0
- package/dist/domain/javascriptSemanticResources.js +136 -0
- package/dist/domain/javascriptStaticAnalysis.js +4 -3
- package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
- package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
- package/dist/domain/processCapture.js +8 -2
- package/dist/domain/processReactiveScenario.js +1 -0
- package/dist/domain/processReactiveTransition.js +9 -4
- package/dist/domain/providerCleanupError.js +11 -0
- package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
- package/dist/domain/reconstructionReadiness.js +121 -0
- package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
- package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
- package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
- package/dist/domain/reconstructionReadinessSchemas.js +240 -0
- package/dist/domain/sourceToBundleComparison.js +335 -0
- package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
- package/dist/domain/sourceToBundleSignals.js +202 -0
- package/dist/domain/webCaptureDiff.js +141 -27
- package/dist/domain/webScreenshot.js +1 -1
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +13 -1
- package/dist/ghidra/GhidraProviderCapabilities.js +7 -0
- package/dist/hopper/HopperCleanup.js +158 -0
- package/dist/hopper/HopperClient.js +69 -99
- package/dist/hopper/HopperProvider.js +20 -1
- package/dist/hopper/HopperRequestQueue.js +187 -0
- package/dist/hopper/HopperResponseStream.js +46 -0
- package/dist/hopper/protocol.js +1 -0
- package/dist/main/transport.js +24 -24
- package/dist/main.js +6 -0
- package/dist/mcpDoctor.js +25 -2
- package/dist/process/ProcessCommandIdentity.js +19 -0
- package/dist/process/ProcessOwnership.js +11 -8
- package/dist/server/DynamicToolAvailability.js +70 -0
- package/dist/server/createServer.js +46 -1
- package/dist/server/lifecycleProgress.js +10 -0
- package/dist/server/permissionFailure.js +12 -0
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
- package/dist/server/registerApplicationTools/helpers.js +11 -7
- package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
- package/dist/server/registerApplicationTools/readiness.js +55 -0
- package/dist/server/registerApplicationTools.js +6 -0
- package/dist/server/registerArtifactTools.js +9 -1
- package/dist/server/registerBrowserScenarioTool.js +25 -0
- package/dist/server/registerBrowserTools.js +2 -2
- package/dist/server/registerCloseLifecycleTool.js +57 -0
- package/dist/server/registerEnhancedTools.js +16 -5
- package/dist/server/registerEvidenceResources.js +4 -0
- package/dist/server/registerEvidenceTools.js +9 -2
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
- package/dist/server/registerReconstructionObligationLedgerResource.js +39 -0
- package/dist/server/registerReconstructionReadinessResource.js +39 -0
- package/dist/server/registerSessionStatusTool.js +11 -8
- package/dist/server/registerSessionTools.js +11 -57
- package/dist/server/sessionAvailabilityPolicy.js +10 -8
- package/package.json +12 -6
- package/skills/reverse-engineer-anything/SKILL.md +2 -2
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
|
|
2
2
|
import { inventoryArtifact } from "../application/ArtifactInventory.js";
|
|
3
3
|
import { extractArtifact } from "../application/ArtifactExtraction.js";
|
|
4
|
-
import { ARTIFACT_TOOL_CONTRACTS, artifactInventoryInputSchema, artifactExtractionInputSchema, } from "../contracts/artifactToolContracts.js";
|
|
4
|
+
import { ARTIFACT_TOOL_CONTRACTS, artifactInspectionInputSchema, artifactInventoryInputSchema, artifactExtractionInputSchema, } from "../contracts/artifactToolContracts.js";
|
|
5
5
|
import { AnalysisCapabilityUnavailableError, ArtifactOperationError, } from "../domain/errors.js";
|
|
6
6
|
import { err, ok } from "../domain/result.js";
|
|
7
7
|
import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
8
8
|
import { ARTIFACT_GRAPH_PROVIDER } from "../application/InvestigationProviders.js";
|
|
9
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
10
|
+
import { createArtifactInspection } from "../domain/artifactInspection.js";
|
|
9
11
|
const IDENTITY = Object.freeze(ARTIFACT_GRAPH_PROVIDER);
|
|
10
12
|
/** Read-only inventory and exclusively owned extraction provider. */
|
|
11
13
|
export class ArtifactProvider {
|
|
@@ -22,7 +24,9 @@ export class ArtifactProvider {
|
|
|
22
24
|
outputContractVersion: 1,
|
|
23
25
|
available: true,
|
|
24
26
|
reason: null,
|
|
25
|
-
pagination: "
|
|
27
|
+
pagination: contract.name === "inspect_artifact"
|
|
28
|
+
? "none"
|
|
29
|
+
: "offset",
|
|
26
30
|
exhaustive: false,
|
|
27
31
|
effects: Object.freeze({
|
|
28
32
|
mutatesArtifact: false,
|
|
@@ -68,6 +72,10 @@ class ArtifactClient {
|
|
|
68
72
|
if (!isArtifactOperation(operation))
|
|
69
73
|
return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, "Operation is not implemented by artifact graph provider."));
|
|
70
74
|
try {
|
|
75
|
+
if (operation === "inspect_artifact") {
|
|
76
|
+
const inspected = await this.inspectArtifact(parameters, options);
|
|
77
|
+
return inspected;
|
|
78
|
+
}
|
|
71
79
|
if (operation === "extract_artifact") {
|
|
72
80
|
const parsed = artifactExtractionInputSchema.parse(parameters);
|
|
73
81
|
const result = await extractArtifact({
|
|
@@ -90,26 +98,7 @@ class ArtifactClient {
|
|
|
90
98
|
}));
|
|
91
99
|
}
|
|
92
100
|
const parsed = artifactInventoryInputSchema.parse(parameters);
|
|
93
|
-
const result = await
|
|
94
|
-
nodeOffset: parsed.node_offset,
|
|
95
|
-
nodeLimit: parsed.node_limit,
|
|
96
|
-
occurrenceOffset: parsed.occurrence_offset,
|
|
97
|
-
occurrenceLimit: parsed.occurrence_limit,
|
|
98
|
-
edgeOffset: parsed.edge_offset,
|
|
99
|
-
edgeLimit: parsed.edge_limit,
|
|
100
|
-
}, {
|
|
101
|
-
...(options?.signal === undefined ? {} : { signal: options.signal }),
|
|
102
|
-
nativeMount: {
|
|
103
|
-
nativeMountApproved: parsed.native_mount_approved === true,
|
|
104
|
-
nativeMountEnabled: this.nativeMountEnabled,
|
|
105
|
-
},
|
|
106
|
-
integrity: {
|
|
107
|
-
mode: parsed.integrity_policy,
|
|
108
|
-
approved: parsed.integrity_continue_approved === true,
|
|
109
|
-
enabled: this.integrityContinueEnabled,
|
|
110
|
-
maxMismatches: parsed.max_integrity_mismatches,
|
|
111
|
-
},
|
|
112
|
-
});
|
|
101
|
+
const result = await this.inventory(parsed, options);
|
|
113
102
|
return ok(createAnalysisExecution(result, IDENTITY, {
|
|
114
103
|
rawResult: null,
|
|
115
104
|
limitations: result.limitations,
|
|
@@ -127,6 +116,82 @@ class ArtifactClient {
|
|
|
127
116
|
close() {
|
|
128
117
|
return Promise.resolve();
|
|
129
118
|
}
|
|
119
|
+
async inspectArtifact(parameters, options) {
|
|
120
|
+
const parsed = artifactInspectionInputSchema.parse(parameters);
|
|
121
|
+
const inventoryParameters = artifactInventoryInputSchema.parse({
|
|
122
|
+
node_offset: 0,
|
|
123
|
+
node_limit: parsed.max_observations,
|
|
124
|
+
occurrence_offset: 0,
|
|
125
|
+
occurrence_limit: parsed.max_observations,
|
|
126
|
+
edge_offset: 0,
|
|
127
|
+
edge_limit: parsed.max_relationships,
|
|
128
|
+
native_mount_approved: parsed.native_mount_approved,
|
|
129
|
+
integrity_policy: parsed.integrity_policy,
|
|
130
|
+
integrity_continue_approved: parsed.integrity_continue_approved,
|
|
131
|
+
max_integrity_mismatches: parsed.max_integrity_mismatches,
|
|
132
|
+
max_entries: parsed.max_entries,
|
|
133
|
+
max_total_bytes: parsed.max_total_bytes,
|
|
134
|
+
max_entry_bytes: parsed.max_entry_bytes,
|
|
135
|
+
max_compression_ratio: parsed.max_compression_ratio,
|
|
136
|
+
max_depth: parsed.max_depth,
|
|
137
|
+
max_path_bytes: parsed.max_path_bytes,
|
|
138
|
+
});
|
|
139
|
+
await options?.progress?.report({
|
|
140
|
+
phase: "inspect_artifact.inventory",
|
|
141
|
+
completed: 0,
|
|
142
|
+
total: 1,
|
|
143
|
+
message: "inventory substep started",
|
|
144
|
+
});
|
|
145
|
+
const inventory = await this.inventory(inventoryParameters, options);
|
|
146
|
+
const subject = subjectFor(this.target.sourcePath ?? this.target.path, inventory.manifest);
|
|
147
|
+
const locations = inventory.occurrences.items.map(({ logical_path: path }) => ({
|
|
148
|
+
kind: "artifact-path",
|
|
149
|
+
path,
|
|
150
|
+
}));
|
|
151
|
+
const inventoryEvidence = createEvidence(subject, IDENTITY, {
|
|
152
|
+
operation: "inventory_artifact",
|
|
153
|
+
parameters: inventoryParameters,
|
|
154
|
+
result: inventory,
|
|
155
|
+
rawResult: null,
|
|
156
|
+
limitations: inventory.limitations,
|
|
157
|
+
locations,
|
|
158
|
+
});
|
|
159
|
+
const result = createArtifactInspection(inventoryEvidence, parsed);
|
|
160
|
+
await options?.progress?.report({
|
|
161
|
+
phase: "inspect_artifact.inventory",
|
|
162
|
+
completed: 1,
|
|
163
|
+
total: 1,
|
|
164
|
+
message: "inventory substep completed",
|
|
165
|
+
});
|
|
166
|
+
return ok(createAnalysisExecution(result, IDENTITY, {
|
|
167
|
+
rawResult: null,
|
|
168
|
+
limitations: result.limitations,
|
|
169
|
+
subject,
|
|
170
|
+
locations,
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
inventory(parsed, options) {
|
|
174
|
+
return inventoryArtifact(this.target.sourcePath ?? this.target.path, limitsFrom(parsed), {
|
|
175
|
+
nodeOffset: parsed.node_offset,
|
|
176
|
+
nodeLimit: parsed.node_limit,
|
|
177
|
+
occurrenceOffset: parsed.occurrence_offset,
|
|
178
|
+
occurrenceLimit: parsed.occurrence_limit,
|
|
179
|
+
edgeOffset: parsed.edge_offset,
|
|
180
|
+
edgeLimit: parsed.edge_limit,
|
|
181
|
+
}, {
|
|
182
|
+
...(options?.signal === undefined ? {} : { signal: options.signal }),
|
|
183
|
+
nativeMount: {
|
|
184
|
+
nativeMountApproved: parsed.native_mount_approved === true,
|
|
185
|
+
nativeMountEnabled: this.nativeMountEnabled,
|
|
186
|
+
},
|
|
187
|
+
integrity: {
|
|
188
|
+
mode: parsed.integrity_policy,
|
|
189
|
+
approved: parsed.integrity_continue_approved === true,
|
|
190
|
+
enabled: this.integrityContinueEnabled,
|
|
191
|
+
maxMismatches: parsed.max_integrity_mismatches,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
130
195
|
}
|
|
131
196
|
const limitsFrom = (input) => ({
|
|
132
197
|
maxEntries: input.max_entries,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const REDACTION_PREFIX = "[REDACTED:";
|
|
3
|
+
/** Resolved secret values kept only for one in-memory scenario session. */
|
|
4
|
+
export class BrowserScenarioSecrets {
|
|
5
|
+
values;
|
|
6
|
+
constructor(values) {
|
|
7
|
+
this.values = values;
|
|
8
|
+
}
|
|
9
|
+
static resolve(scenario, environment) {
|
|
10
|
+
const values = new Map();
|
|
11
|
+
for (const declaration of scenario.secrets) {
|
|
12
|
+
const value = environment[declaration.environment_variable];
|
|
13
|
+
if (value === undefined)
|
|
14
|
+
return undefined;
|
|
15
|
+
values.set(declaration.secret_id, value);
|
|
16
|
+
}
|
|
17
|
+
return new BrowserScenarioSecrets(values);
|
|
18
|
+
}
|
|
19
|
+
value(source) {
|
|
20
|
+
if (source.source === "literal")
|
|
21
|
+
return source.value;
|
|
22
|
+
const value = this.values.get(source.secret_id);
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
throw new Error("Validated browser secret was not resolved");
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
url(destination) {
|
|
28
|
+
const url = new URL(destination.url);
|
|
29
|
+
for (const { name, value } of destination.query)
|
|
30
|
+
url.searchParams.append(name, this.value(value));
|
|
31
|
+
return url.href;
|
|
32
|
+
}
|
|
33
|
+
redact(value) {
|
|
34
|
+
let output = value;
|
|
35
|
+
const replacements = [...this.values].sort(([leftId, left], [rightId, right]) => right.length - left.length ||
|
|
36
|
+
(leftId < rightId ? -1 : leftId > rightId ? 1 : 0));
|
|
37
|
+
for (const [id, secret] of replacements)
|
|
38
|
+
if (secret !== "")
|
|
39
|
+
output = output.replaceAll(secret, `${REDACTION_PREFIX}${id}]`);
|
|
40
|
+
return output;
|
|
41
|
+
}
|
|
42
|
+
fingerprint(value) {
|
|
43
|
+
for (const secret of this.values.values())
|
|
44
|
+
if (secret !== "" && value.includes(secret))
|
|
45
|
+
return { value_state: "redacted-secret", value_sha256: null };
|
|
46
|
+
return {
|
|
47
|
+
value_state: "hashed",
|
|
48
|
+
value_sha256: createHash("sha256")
|
|
49
|
+
.update(this.redact(value))
|
|
50
|
+
.digest("hex"),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,7 +3,7 @@ import { analyzeCapturedWebBundle } from "../domain/webBundleAnalyzer.js";
|
|
|
3
3
|
import { webBundleAnalysisSchema, } from "../domain/webBundleAnalysis.js";
|
|
4
4
|
import { webObservationSessionSchema, } from "../domain/browserSession.js";
|
|
5
5
|
import { webMcpDiscoverySchema, } from "../domain/webMcpDiscovery.js";
|
|
6
|
-
import {
|
|
6
|
+
import { browserCaptureComparisonSchema, compareBrowserCaptures, } from "../domain/browserCaptureComparison.js";
|
|
7
7
|
import { webScreenshotDiffSchema, webScreenshotSchema, } from "../domain/webScreenshot.js";
|
|
8
8
|
import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from "../domain/errors.js";
|
|
9
9
|
import { err, ok } from "../domain/result.js";
|
|
@@ -136,7 +136,7 @@ export class CdpBrowserProvider {
|
|
|
136
136
|
}
|
|
137
137
|
async compareCaptures(input) {
|
|
138
138
|
try {
|
|
139
|
-
return ok(
|
|
139
|
+
return ok(browserCaptureComparisonSchema.parse(compareBrowserCaptures(input)));
|
|
140
140
|
}
|
|
141
141
|
catch (cause) {
|
|
142
142
|
return err(providerError(cause, "compare_web_captures"));
|
|
@@ -156,6 +156,10 @@ export const captureDom = (result, allowedOrigins, input, completeness) => {
|
|
|
156
156
|
};
|
|
157
157
|
export const captureAccessibility = (results, maximum, options) => {
|
|
158
158
|
const all = results.flatMap((result) => recordsValue(requiredRecord(result).nodes));
|
|
159
|
+
const nodeIds = new Set(all.flatMap((node) => {
|
|
160
|
+
const nodeId = stringValue(node.nodeId);
|
|
161
|
+
return nodeId === undefined ? [] : [nodeId];
|
|
162
|
+
}));
|
|
159
163
|
let retainedBytes = 0;
|
|
160
164
|
let excludedFields = 0;
|
|
161
165
|
let truncatedFields = 0;
|
|
@@ -187,6 +191,7 @@ export const captureAccessibility = (results, maximum, options) => {
|
|
|
187
191
|
name: captureText(node.name),
|
|
188
192
|
description: captureText(node.description),
|
|
189
193
|
ignored: node.ignored === true,
|
|
194
|
+
states: accessibilityStates(node.properties),
|
|
190
195
|
};
|
|
191
196
|
});
|
|
192
197
|
for (const node of all.slice(maximum)) {
|
|
@@ -201,6 +206,11 @@ export const captureAccessibility = (results, maximum, options) => {
|
|
|
201
206
|
return {
|
|
202
207
|
total: all.length,
|
|
203
208
|
nodes,
|
|
209
|
+
treeIncomplete: all.some((node) => Array.isArray(node.childIds) &&
|
|
210
|
+
node.childIds.some((childId) => {
|
|
211
|
+
const id = stringValue(childId);
|
|
212
|
+
return id !== undefined && !nodeIds.has(id);
|
|
213
|
+
})),
|
|
204
214
|
textCapture: {
|
|
205
215
|
status: options.unavailable
|
|
206
216
|
? "unavailable"
|
|
@@ -215,6 +225,53 @@ export const captureAccessibility = (results, maximum, options) => {
|
|
|
215
225
|
},
|
|
216
226
|
};
|
|
217
227
|
};
|
|
228
|
+
const ACCESSIBILITY_STATE_NAMES = new Set([
|
|
229
|
+
"atomic",
|
|
230
|
+
"autocomplete",
|
|
231
|
+
"busy",
|
|
232
|
+
"checked",
|
|
233
|
+
"disabled",
|
|
234
|
+
"editable",
|
|
235
|
+
"expanded",
|
|
236
|
+
"focusable",
|
|
237
|
+
"focused",
|
|
238
|
+
"hasPopup",
|
|
239
|
+
"hidden",
|
|
240
|
+
"invalid",
|
|
241
|
+
"level",
|
|
242
|
+
"live",
|
|
243
|
+
"modal",
|
|
244
|
+
"multiline",
|
|
245
|
+
"multiselectable",
|
|
246
|
+
"orientation",
|
|
247
|
+
"pressed",
|
|
248
|
+
"readonly",
|
|
249
|
+
"required",
|
|
250
|
+
"selected",
|
|
251
|
+
"valuemax",
|
|
252
|
+
"valuemin",
|
|
253
|
+
]);
|
|
254
|
+
const accessibilityStates = (value) => {
|
|
255
|
+
const states = new Map();
|
|
256
|
+
for (const property of recordsValue(value)) {
|
|
257
|
+
const name = stringValue(property.name);
|
|
258
|
+
if (name === undefined || !ACCESSIBILITY_STATE_NAMES.has(name))
|
|
259
|
+
continue;
|
|
260
|
+
const raw = recordValue(property.value)?.value;
|
|
261
|
+
const state = typeof raw === "boolean"
|
|
262
|
+
? raw
|
|
263
|
+
: typeof raw === "number"
|
|
264
|
+
? numberValue(raw)
|
|
265
|
+
: typeof raw === "string"
|
|
266
|
+
? raw.slice(0, 256)
|
|
267
|
+
: undefined;
|
|
268
|
+
if (state !== undefined)
|
|
269
|
+
states.set(name, state);
|
|
270
|
+
}
|
|
271
|
+
return [...states]
|
|
272
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
273
|
+
.map(([name, state]) => ({ name, value: state }));
|
|
274
|
+
};
|
|
218
275
|
const axText = (value) => boundedText(recordValue(value)?.value, 1_024);
|
|
219
276
|
const indexedString = (strings, index) => {
|
|
220
277
|
const integer = numberValue(index);
|
|
@@ -1,53 +1,95 @@
|
|
|
1
1
|
import { CdpConnection } from "./CdpConnection.js";
|
|
2
2
|
import { optionalCdpCommand } from "./CdpOptionalCommand.js";
|
|
3
|
+
import { captureStorageFingerprints, } from "./CdpCaptureStorageFingerprints.js";
|
|
3
4
|
import { numberValue, recordValue, recordsValue, stringValue, } from "./CdpCaptureValues.js";
|
|
4
5
|
/** Capture redacted, bounded storage metadata for one authorized origin. */
|
|
5
6
|
export const captureStorage = async (context, origin, limitations) => {
|
|
6
7
|
const quota = recordValue(await optionalCdpCommand(context, "Storage.getUsageAndQuota", { origin }, limitations));
|
|
7
8
|
const local = context.input.include_storage_keys
|
|
8
|
-
? await
|
|
9
|
-
:
|
|
9
|
+
? await storageItems(context, origin, true, limitations)
|
|
10
|
+
: emptyStorageItems;
|
|
10
11
|
const session = context.input.include_storage_keys
|
|
11
|
-
? await
|
|
12
|
-
:
|
|
13
|
-
const
|
|
14
|
-
?
|
|
15
|
-
:
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
? await storageItems(context, origin, false, limitations)
|
|
13
|
+
: emptyStorageItems;
|
|
14
|
+
const indexedRaw = context.input.include_storage_keys
|
|
15
|
+
? await optionalCdpCommand(context, "IndexedDB.requestDatabaseNames", { securityOrigin: origin }, limitations)
|
|
16
|
+
: undefined;
|
|
17
|
+
const indexedValues = recordValue(indexedRaw)?.databaseNames;
|
|
18
|
+
const indexed = stringArray(indexedValues);
|
|
19
|
+
const cacheRaw = context.input.include_storage_keys
|
|
20
|
+
? await optionalCdpCommand(context, "CacheStorage.requestCacheNames", { securityOrigin: origin }, limitations)
|
|
21
|
+
: undefined;
|
|
22
|
+
const cacheValues = recordsValue(recordValue(cacheRaw)?.caches);
|
|
23
|
+
const caches = capturedCaches(cacheValues);
|
|
22
24
|
const maximum = context.input.limits.max_storage_keys;
|
|
25
|
+
const fingerprints = context.input.include_storage_fingerprints
|
|
26
|
+
? await captureStorageFingerprints({
|
|
27
|
+
context,
|
|
28
|
+
origin,
|
|
29
|
+
local,
|
|
30
|
+
session,
|
|
31
|
+
indexedDbNames: indexed.slice(0, maximum),
|
|
32
|
+
caches: caches.slice(0, maximum),
|
|
33
|
+
limitations,
|
|
34
|
+
})
|
|
35
|
+
: { items: [], complete: false, truncated: false };
|
|
36
|
+
const truncated = [local.items, session.items, indexed, caches].some((items) => items.length > maximum) || fingerprints.truncated;
|
|
37
|
+
const structuredStorageComplete = indexedRaw !== undefined &&
|
|
38
|
+
Array.isArray(indexedValues) &&
|
|
39
|
+
indexed.length === indexedValues.length &&
|
|
40
|
+
cacheRaw !== undefined &&
|
|
41
|
+
caches.length === cacheValues.length;
|
|
23
42
|
return {
|
|
24
43
|
value: {
|
|
25
44
|
origin,
|
|
26
45
|
usage_bytes: numberValue(quota?.usage) ?? null,
|
|
27
46
|
quota_bytes: numberValue(quota?.quota) ?? null,
|
|
28
|
-
local_storage_keys: local.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
local_storage_keys: local.items
|
|
48
|
+
.map(({ key }) => key.slice(0, 1_024))
|
|
49
|
+
.slice(0, maximum),
|
|
50
|
+
session_storage_keys: session.items
|
|
51
|
+
.map(({ key }) => key.slice(0, 1_024))
|
|
52
|
+
.slice(0, maximum),
|
|
53
|
+
indexed_db_names: indexed
|
|
54
|
+
.map((name) => name.slice(0, 1_024))
|
|
55
|
+
.slice(0, maximum),
|
|
56
|
+
cache_names: caches
|
|
57
|
+
.map(({ name }) => name.slice(0, 1_024))
|
|
58
|
+
.slice(0, maximum),
|
|
59
|
+
content_fingerprints: [...fingerprints.items],
|
|
60
|
+
fingerprint_algorithm: "sha256",
|
|
61
|
+
fingerprints_complete: fingerprints.complete && structuredStorageComplete && !truncated,
|
|
32
62
|
values_redacted: true,
|
|
33
63
|
},
|
|
34
|
-
truncated
|
|
64
|
+
truncated,
|
|
35
65
|
};
|
|
36
66
|
};
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
const emptyStorageItems = {
|
|
68
|
+
items: [],
|
|
69
|
+
complete: false,
|
|
70
|
+
};
|
|
71
|
+
const capturedCaches = (values) => values.flatMap((cache) => {
|
|
72
|
+
const name = stringValue(cache.cacheName);
|
|
73
|
+
const id = stringValue(cache.cacheId);
|
|
74
|
+
return name === undefined || id === undefined ? [] : [{ name, id }];
|
|
75
|
+
});
|
|
76
|
+
const storageItems = async (context, origin, isLocalStorage, limitations) => {
|
|
77
|
+
const raw = await optionalCdpCommand(context, "DOMStorage.getDOMStorageItems", { storageId: { securityOrigin: origin, isLocalStorage } }, limitations);
|
|
78
|
+
const entries = recordValue(raw)?.entries;
|
|
79
|
+
if (raw === undefined || !Array.isArray(entries))
|
|
80
|
+
return { items: [], complete: false };
|
|
81
|
+
const items = entries.flatMap((entry) => {
|
|
82
|
+
if (!Array.isArray(entry))
|
|
83
|
+
return [];
|
|
84
|
+
const key = stringValue(entry[0]);
|
|
85
|
+
const value = stringValue(entry[1]);
|
|
86
|
+
return key === undefined || value === undefined ? [] : [{ key, value }];
|
|
87
|
+
});
|
|
88
|
+
return { items, complete: items.length === entries.length };
|
|
47
89
|
};
|
|
48
90
|
const stringArray = (value) => Array.isArray(value)
|
|
49
91
|
? value.flatMap((item) => {
|
|
50
92
|
const text = stringValue(item);
|
|
51
|
-
return text === undefined ? [] : [text
|
|
93
|
+
return text === undefined ? [] : [text];
|
|
52
94
|
})
|
|
53
95
|
: [];
|