rea-agents 2.2.0 → 2.4.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 +57 -10
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
- package/dist/application/ArtifactExtraction.js +5 -1
- package/dist/application/ArtifactGraphConstruction.js +3 -15
- package/dist/application/ArtifactInventory/classify.js +5 -1
- package/dist/application/ArtifactInventory/reader.js +2 -0
- package/dist/application/BinarySession.js +9 -2
- package/dist/application/BinarySessionStatus.js +40 -1
- package/dist/application/CapabilityInventory.js +26 -3
- package/dist/application/CommandShimReplay.js +6 -3
- package/dist/application/CompositeProvider.js +5 -2
- package/dist/application/DirectAnalysis.js +1 -20
- package/dist/application/DirectAnalysisStatus.js +83 -0
- package/dist/application/Doctor.js +34 -25
- package/dist/application/DoctorDiagnostics.js +1 -4
- package/dist/application/DoctorProjection.js +43 -0
- package/dist/application/DoctorScope.js +102 -0
- package/dist/application/EvidenceReferenceResolver.js +26 -0
- package/dist/application/JavaScriptApplicationEvidence.js +1 -1
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
- package/dist/application/JavaScriptApplicationService.js +3 -2
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
- package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
- package/dist/application/JavaScriptModuleRelationships.js +25 -1
- package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
- package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
- package/dist/application/JavaScriptSemanticTraceService.js +45 -0
- package/dist/application/LoopbackReplay.js +277 -133
- package/dist/application/LoopbackReplayRecorder.js +101 -0
- package/dist/application/PermissionAuthority.js +7 -3
- package/dist/application/ProcessCaptureEnvironment.js +26 -0
- package/dist/application/ProcessCaptureJournal.js +95 -0
- package/dist/application/ProcessCaptureLifecycle.js +25 -13
- package/dist/application/ProcessCheckpoints.js +35 -4
- package/dist/application/ProcessCli.js +26 -4
- package/dist/application/ProcessHarness.js +64 -83
- package/dist/application/ProcessNormalization.js +9 -2
- package/dist/application/ProcessReactiveCoordinator.js +225 -0
- package/dist/application/ProcessReactiveEffects.js +141 -0
- package/dist/application/ProcessReactiveHarness.js +85 -0
- package/dist/application/ProcessReactiveObservations.js +105 -0
- package/dist/application/ProcessSampling.js +2 -0
- package/dist/application/SessionProviderRouter.js +7 -6
- package/dist/application/Setup.js +11 -10
- package/dist/application/SetupPlan.js +1 -1
- package/dist/application/SetupRegistrationEnvironment.js +12 -0
- package/dist/application/TerminalRenderer.js +3 -1
- package/dist/browser/CdpEndpoint.js +37 -4
- package/dist/catalogIdentity.js +16 -7
- package/dist/cli/coreAnalysisCommands.js +34 -2
- package/dist/cli/javascriptApplicationAnalysis.js +19 -0
- package/dist/cli/setupCommands.js +81 -32
- package/dist/cli/utilityCommands.js +10 -2
- package/dist/cliApplicationCommands.js +79 -16
- package/dist/cliCommandNames.js +3 -0
- package/dist/cliElectronCommands.js +23 -33
- package/dist/cliObservationOptions.js +1 -1
- package/dist/cliOutput.js +56 -0
- package/dist/cliProcessCommands.js +32 -1
- package/dist/cliSetup.js +30 -21
- package/dist/contracts/applicationToolContracts.js +54 -7
- package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
- package/dist/contracts/electronToolContracts.js +53 -32
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
- package/dist/contracts/processCaptureExample.js +1 -0
- package/dist/contracts/replayMachineExample.js +37 -0
- package/dist/contracts/toolContractExamples.js +2 -0
- package/dist/contracts/toolContracts.js +5 -1
- package/dist/contracts/toolEffects.js +3 -0
- package/dist/contracts/toolOutputSchemaGroups.js +2 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +43 -0
- package/dist/doctorRuntime.js +41 -0
- package/dist/domain/analysisErrorPresentation.js +5 -3
- package/dist/domain/analysisErrorProjection.js +7 -1
- package/dist/domain/analysisSnapshot.js +2 -0
- package/dist/domain/artifactGraph.js +2 -0
- package/dist/domain/binaryTarget.js +3 -6
- package/dist/domain/changedBehavior.js +5 -4
- package/dist/domain/completionLedgerGeneration.js +190 -0
- package/dist/domain/errors.js +4 -2
- package/dist/domain/evidence.js +2 -0
- package/dist/domain/evidenceCompletionLedger.js +113 -0
- package/dist/domain/hopperStartupFailure.js +9 -0
- package/dist/domain/javascriptApplicationAnalysis.js +44 -2
- package/dist/domain/javascriptExportShapeComparison.js +145 -0
- package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
- package/dist/domain/javascriptExportShapeSelection.js +132 -0
- package/dist/domain/javascriptExportShapeVariants.js +272 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
- package/dist/domain/javascriptSemanticAnalysis.js +17 -36
- package/dist/domain/javascriptSemanticCallResolution.js +129 -0
- package/dist/domain/javascriptSemanticCalls.js +269 -0
- package/dist/domain/javascriptSemanticGraph.js +356 -0
- package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
- package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
- package/dist/domain/javascriptSemanticIr.js +14 -1
- package/dist/domain/javascriptSemanticPrimitives.js +36 -0
- package/dist/domain/javascriptSemanticProjection.js +36 -4
- package/dist/domain/javascriptSemanticProvenance.js +29 -0
- package/dist/domain/javascriptSemanticQuery.js +294 -0
- package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
- package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
- package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
- package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
- package/dist/domain/javascriptSemanticReturns.js +187 -0
- package/dist/domain/javascriptSemanticState.js +32 -0
- package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
- package/dist/domain/javascriptSemanticValues.js +54 -70
- package/dist/domain/processCapture.js +100 -0
- package/dist/domain/processCaptureReactiveValidation.js +175 -0
- package/dist/domain/processCaptureValidation.js +103 -12
- package/dist/domain/processComparison.js +78 -25
- package/dist/domain/processObservation.js +162 -0
- package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
- package/dist/domain/processReactiveMatching.js +210 -0
- package/dist/domain/processReactiveRuntime.js +120 -0
- package/dist/domain/processReactiveScenario.js +361 -0
- package/dist/domain/processReactiveScenarioPreflight.js +120 -0
- package/dist/domain/processReactiveTransition.js +161 -0
- package/dist/domain/processScenario.js +33 -0
- package/dist/domain/processTraceComparison.js +43 -0
- package/dist/domain/processTraceDimensionProjection.js +50 -0
- package/dist/domain/processTraceEvaluation.js +312 -0
- package/dist/domain/processTraceSpecification.js +373 -0
- package/dist/domain/reconstructionVerification.js +5 -4
- package/dist/domain/replayMachine.js +18 -2
- package/dist/domain/replayMachineRun.js +216 -0
- package/dist/domain/replayMachineRuntime.js +88 -9
- package/dist/domain/staticRuntimeCorrelation.js +4 -2
- package/dist/domain/zipPackageFormat.js +20 -0
- package/dist/evaluation/CodexAgentEval.js +24 -0
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraClient.js +13 -2
- package/dist/ghidra/GhidraDiagnostics.js +1 -0
- package/dist/ghidra/GhidraLauncher.js +7 -3
- package/dist/ghidra/GhidraProvider.js +8 -1
- package/dist/hopper/BridgeLauncher.js +56 -14
- package/dist/hopper/HopperClient.js +23 -10
- package/dist/hopper/HopperDiagnostics.js +14 -0
- package/dist/hopper/HopperProcessDiagnostic.js +14 -0
- package/dist/hopper/HopperProvider.js +8 -1
- package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
- package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
- package/dist/main/transport.js +2 -0
- package/dist/mcpDoctor.js +310 -0
- package/dist/native/NativeMacOSProvider.js +1 -0
- package/dist/process/ProcessOwnership.js +200 -53
- package/dist/process/ProviderRunLineage.js +21 -0
- package/dist/server/createServer.js +4 -1
- package/dist/server/javascriptApplicationResult.js +22 -1
- package/dist/server/registerApplicationTools/characterization.js +3 -3
- package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
- package/dist/server/registerApplicationTools/compareVersions.js +12 -6
- package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -3
- package/dist/server/registerApplicationTools/helpers.js +37 -25
- package/dist/server/registerApplicationTools/traceFeature.js +9 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
- package/dist/server/registerApplicationTools.js +4 -0
- package/dist/server/registerEvidenceResources.js +5 -1
- package/dist/server/registerProcessComparisonTool.js +17 -7
- package/dist/server/registerReplayMachineTool.js +20 -0
- package/dist/server/registerSessionTools.js +12 -7
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/serverIdentity.js +19 -0
- package/package.json +62 -30
- package/scripts/hopper-demo-x11.py +459 -61
- package/scripts/prepack.mjs +55 -0
- package/scripts/prepare.mjs +28 -0
- package/scripts/rea.mjs +26 -5
- package/skills/reverse-engineer-anything/SKILL.md +4 -3
- package/skills/reverse-engineer-anything/references/javascript-applications.md +10 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +2 -2
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { reachSemanticLimit, semanticCallableIdForNode, } from "./javascriptSemanticProjection.js";
|
|
3
|
+
import { resolveSemanticBindingState, } from "./javascriptSemanticState.js";
|
|
4
|
+
import { evaluateSemanticExpression } from "./javascriptSemanticValues.js";
|
|
5
|
+
import { compareCodePoints, range } from "./javascriptStaticAnalysisHelpers.js";
|
|
6
|
+
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
|
|
7
|
+
/** Evaluate bounded direct returns while excluding every nested callable. */
|
|
8
|
+
export const collectSemanticReturns = (program, state, parserPartial) => {
|
|
9
|
+
const nodes = callableNodes(program);
|
|
10
|
+
let retained = 0;
|
|
11
|
+
return state.callables.map((callable) => {
|
|
12
|
+
const node = nodes.get(callable.callableId);
|
|
13
|
+
if (node === undefined)
|
|
14
|
+
return {
|
|
15
|
+
...callable,
|
|
16
|
+
returnCoverage: {
|
|
17
|
+
status: "partial",
|
|
18
|
+
retainedCount: 0,
|
|
19
|
+
omittedCount: null,
|
|
20
|
+
limitsReached: [],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const expressions = directReturnExpressions(node);
|
|
24
|
+
const sites = [];
|
|
25
|
+
let omitted = 0;
|
|
26
|
+
for (const expression of expressions) {
|
|
27
|
+
if (retained >= state.limits.maxReturnSites) {
|
|
28
|
+
omitted += 1;
|
|
29
|
+
reachSemanticLimit(state, "maxReturnSites");
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
retained += 1;
|
|
33
|
+
sites.push({
|
|
34
|
+
returnSiteId: semanticReturnSiteId(callable.callableId, expression.location),
|
|
35
|
+
location: expression.location,
|
|
36
|
+
identityReferenceLocation: expression.node !== null && t.isIdentifier(expression.node)
|
|
37
|
+
? range(expression.node)
|
|
38
|
+
: null,
|
|
39
|
+
value: expression.node === null
|
|
40
|
+
? { status: "unknown", reason: "Return has no value." }
|
|
41
|
+
: evaluateSemanticExpression(expression.node, state),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
...callable,
|
|
46
|
+
returnSites: sites,
|
|
47
|
+
returnCoverage: {
|
|
48
|
+
status: omitted > 0 ? "truncated" : parserPartial ? "partial" : "complete",
|
|
49
|
+
retainedCount: sites.length,
|
|
50
|
+
omittedCount: omitted,
|
|
51
|
+
limitsReached: omitted > 0 ? ["maxReturnSites"] : [],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const semanticReturnSiteId = (callableId, location) => `${callableId}:return:${String(location.start.line)}:${String(location.start.column)}:${String(location.end.line)}:${String(location.end.column)}`;
|
|
57
|
+
/** Link exports to callables only when lexical resolution is unique and exact. */
|
|
58
|
+
export const resolveSemanticModuleCallables = (state, callables) => {
|
|
59
|
+
const callableIds = new Set(callables.map(({ callableId }) => callableId));
|
|
60
|
+
const root = state.scopes.find(({ kind }) => kind === "program");
|
|
61
|
+
return state.moduleLinks.map((link) => {
|
|
62
|
+
if (link.callableId !== null && callableIds.has(link.callableId))
|
|
63
|
+
return link;
|
|
64
|
+
if (link.localName === null || root === undefined)
|
|
65
|
+
return { ...link, callableId: null };
|
|
66
|
+
const named = callables.filter(({ name, containerScopeId }) => name === link.localName && containerScopeId === root.scopeId);
|
|
67
|
+
if (named.length === 1)
|
|
68
|
+
return { ...link, callableId: named[0]?.callableId ?? null };
|
|
69
|
+
const binding = root.bindings.get(link.localName);
|
|
70
|
+
const resolved = binding === undefined
|
|
71
|
+
? []
|
|
72
|
+
: callableIdsForBinding(binding, state, callableIds, new Set());
|
|
73
|
+
return {
|
|
74
|
+
...link,
|
|
75
|
+
callableId: resolved.length === 1 ? (resolved[0] ?? null) : null,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const callableNodes = (program) => {
|
|
80
|
+
const output = new Map();
|
|
81
|
+
traverseJavaScriptAst(program, {
|
|
82
|
+
enter: (node) => {
|
|
83
|
+
const id = semanticCallableIdForNode(node);
|
|
84
|
+
if (id !== null)
|
|
85
|
+
output.set(id, node);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return output;
|
|
89
|
+
};
|
|
90
|
+
const directReturnExpressions = (callable) => {
|
|
91
|
+
if (t.isArrowFunctionExpression(callable) &&
|
|
92
|
+
!t.isBlockStatement(callable.body))
|
|
93
|
+
return [{ node: callable.body, location: range(callable.body) }];
|
|
94
|
+
if (!t.isFunction(callable))
|
|
95
|
+
return [];
|
|
96
|
+
const output = [];
|
|
97
|
+
const visit = (node) => {
|
|
98
|
+
if (t.isFunction(node) || t.isClass(node))
|
|
99
|
+
return;
|
|
100
|
+
if (t.isReturnStatement(node)) {
|
|
101
|
+
output.push({ node: node.argument ?? null, location: range(node) });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
for (const child of childNodes(node))
|
|
105
|
+
visit(child);
|
|
106
|
+
};
|
|
107
|
+
for (const child of childNodes(callable.body))
|
|
108
|
+
visit(child);
|
|
109
|
+
return output;
|
|
110
|
+
};
|
|
111
|
+
const childNodes = (node) => (t.VISITOR_KEYS[node.type] ?? []).flatMap((key) => {
|
|
112
|
+
const value = Reflect.get(node, key);
|
|
113
|
+
if (t.isNode(value))
|
|
114
|
+
return [value];
|
|
115
|
+
return Array.isArray(value)
|
|
116
|
+
? value.filter((item) => t.isNode(item))
|
|
117
|
+
: [];
|
|
118
|
+
});
|
|
119
|
+
const callableIdsForBinding = (binding, state, admitted, seen) => {
|
|
120
|
+
if (seen.has(binding.bindingId) || binding.initializers.length !== 1)
|
|
121
|
+
return [];
|
|
122
|
+
const initializer = binding.initializers[0];
|
|
123
|
+
if (initializer === undefined || initializer.projection.length > 0)
|
|
124
|
+
return [];
|
|
125
|
+
return callableIdsForNode(initializer.node, state, admitted, new Set([...seen, binding.bindingId]));
|
|
126
|
+
};
|
|
127
|
+
const callableIdsForNode = (node, state, admitted, seen) => {
|
|
128
|
+
const direct = semanticCallableIdForNode(node);
|
|
129
|
+
if (direct !== null && admitted.has(direct))
|
|
130
|
+
return [direct];
|
|
131
|
+
if (t.isIdentifier(node)) {
|
|
132
|
+
const binding = resolveSemanticBindingState(state, node, node.name);
|
|
133
|
+
return binding === undefined
|
|
134
|
+
? []
|
|
135
|
+
: callableIdsForBinding(binding, state, admitted, seen);
|
|
136
|
+
}
|
|
137
|
+
if (t.isTSAsExpression(node) ||
|
|
138
|
+
t.isTSTypeAssertion(node) ||
|
|
139
|
+
t.isTSNonNullExpression(node))
|
|
140
|
+
return callableIdsForNode(node.expression, state, admitted, seen);
|
|
141
|
+
return [];
|
|
142
|
+
};
|
|
143
|
+
/** Flatten a semantic value to bounded JSON-pointer leaves for graph projection. */
|
|
144
|
+
export const flattenSemanticReturnValue = (value) => {
|
|
145
|
+
const fields = [];
|
|
146
|
+
const propertyCoverage = [];
|
|
147
|
+
flattenValue(value, "", fields, propertyCoverage);
|
|
148
|
+
fields.sort((left, right) => compareCodePoints(left.path, right.path));
|
|
149
|
+
propertyCoverage.sort((left, right) => compareCodePoints(left.path, right.path));
|
|
150
|
+
return { fields, propertyCoverage };
|
|
151
|
+
};
|
|
152
|
+
const flattenValue = (value, path, fields, coverage) => {
|
|
153
|
+
if (value.status === "literal") {
|
|
154
|
+
fields.push({ path, state: "literal", value: value.value, reason: null });
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (value.status === "union") {
|
|
158
|
+
fields.push({
|
|
159
|
+
path,
|
|
160
|
+
state: "union",
|
|
161
|
+
value: [...value.values],
|
|
162
|
+
reason: null,
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (value.status === "object") {
|
|
167
|
+
coverage.push({
|
|
168
|
+
path,
|
|
169
|
+
status: value.unknownProperties ? "partial" : "complete",
|
|
170
|
+
omitted: value.omittedProperties,
|
|
171
|
+
});
|
|
172
|
+
for (const property of value.properties)
|
|
173
|
+
flattenValue(property.value, `${path}/${escapePointer(property.name)}`, fields, coverage);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (value.status === "array") {
|
|
177
|
+
coverage.push({
|
|
178
|
+
path,
|
|
179
|
+
status: value.unknownItems ? "partial" : "complete",
|
|
180
|
+
omitted: value.omittedItems,
|
|
181
|
+
});
|
|
182
|
+
value.items.forEach((item, index) => flattenValue(item, `${path}/${String(index)}`, fields, coverage));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
fields.push({ path, state: "unknown", value: null, reason: value.reason });
|
|
186
|
+
};
|
|
187
|
+
const escapePointer = (value) => value.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
1
2
|
/** Return the active scope from a non-empty construction stack. */
|
|
2
3
|
export const currentSemanticScope = (stack) => {
|
|
3
4
|
const scope = stack.at(-1);
|
|
@@ -38,3 +39,34 @@ export const semanticResolutionBlocked = (state, node, name) => {
|
|
|
38
39
|
}
|
|
39
40
|
return false;
|
|
40
41
|
};
|
|
42
|
+
/** Resolve one name starting from an explicitly selected lexical scope. */
|
|
43
|
+
export const resolveSemanticBindingFromScope = (scope, name, state) => {
|
|
44
|
+
let candidate = scope;
|
|
45
|
+
while (candidate !== undefined) {
|
|
46
|
+
const binding = candidate.bindings.get(name);
|
|
47
|
+
if (binding !== undefined)
|
|
48
|
+
return binding;
|
|
49
|
+
if (!candidate.bindingsComplete)
|
|
50
|
+
return undefined;
|
|
51
|
+
candidate =
|
|
52
|
+
candidate.parentScopeId === null
|
|
53
|
+
? undefined
|
|
54
|
+
: state.scopesById.get(candidate.parentScopeId);
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
};
|
|
58
|
+
/** Select the function/program owner for a var declaration. */
|
|
59
|
+
export const semanticVariableScope = (scope, parent, state) => {
|
|
60
|
+
if (!(parent !== null && t.isVariableDeclaration(parent, { kind: "var" })))
|
|
61
|
+
return scope;
|
|
62
|
+
let candidate = scope;
|
|
63
|
+
while (candidate.kind === "block" || candidate.kind === "catch") {
|
|
64
|
+
const outer = candidate.parentScopeId === null
|
|
65
|
+
? undefined
|
|
66
|
+
: state.scopesById.get(candidate.parentScopeId);
|
|
67
|
+
if (outer === undefined)
|
|
68
|
+
break;
|
|
69
|
+
candidate = outer;
|
|
70
|
+
}
|
|
71
|
+
return candidate;
|
|
72
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { evidenceSchema } from "./evidence.js";
|
|
3
|
+
import { javaScriptSemanticQueryInputSchema, javaScriptSemanticQueryResultSchema, } from "./javascriptSemanticQuerySchemas.js";
|
|
4
|
+
const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
|
|
5
|
+
/** Authenticated application Evidence plus one bounded semantic query. */
|
|
6
|
+
export const traceJavaScriptSemanticsInputSchema = z.strictObject({
|
|
7
|
+
application: evidenceSchema,
|
|
8
|
+
query: javaScriptSemanticQueryInputSchema,
|
|
9
|
+
});
|
|
10
|
+
/** Evidence-linked semantic query result shared by CLI and MCP. */
|
|
11
|
+
export const javaScriptSemanticTraceResultSchema = javaScriptSemanticQueryResultSchema.extend({
|
|
12
|
+
source_evidence_id: evidenceIdSchema,
|
|
13
|
+
evidence_links: z.array(evidenceIdSchema).length(1),
|
|
14
|
+
});
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
2
|
import { resolveSemanticBindingState, } from "./javascriptSemanticState.js";
|
|
3
3
|
import { compareCodePoints, propertyName, stringValue, } from "./javascriptStaticAnalysisHelpers.js";
|
|
4
|
+
import { reachSemanticValueLimit, semanticLimitProvenance, semanticOriginsProvenance, semanticProvenance, uniqueSemanticOrigins, } from "./javascriptSemanticProvenance.js";
|
|
5
|
+
import { semanticPrimitiveCandidates as primitiveCandidates, semanticPrimitiveSet as primitiveSet, semanticPrimitiveValue as primitiveValue, } from "./javascriptSemanticPrimitives.js";
|
|
4
6
|
/** Evaluate one binding in the bounded constant-value lattice. */
|
|
5
7
|
export const evaluateSemanticBinding = (binding, state) => evaluateBinding(binding, { state, bindings: new Set(), depth: 0 });
|
|
8
|
+
/** Evaluate one arbitrary inert expression in the established lexical state. */
|
|
9
|
+
export const evaluateSemanticExpression = (node, state) => evaluateExpression(node, { state, bindings: new Set(), depth: 0 });
|
|
6
10
|
/** Follow module provenance through destructuring, members, and aliases. */
|
|
7
11
|
export const evaluateSemanticProvenance = (binding, state) => provenanceForBinding(binding, { state, bindings: new Set(), depth: 0 });
|
|
8
12
|
const evaluateBinding = (binding, context) => {
|
|
@@ -91,19 +95,31 @@ const evaluateTemplate = (node, context) => {
|
|
|
91
95
|
const evaluateObject = (node, context) => {
|
|
92
96
|
const properties = [];
|
|
93
97
|
let unknownProperties = false;
|
|
98
|
+
let omittedProperties = 0;
|
|
94
99
|
for (const property of node.properties) {
|
|
95
|
-
if (t.isSpreadElement(property)
|
|
100
|
+
if (t.isSpreadElement(property)) {
|
|
96
101
|
unknownProperties = true;
|
|
102
|
+
omittedProperties = null;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (property.computed) {
|
|
106
|
+
unknownProperties = true;
|
|
107
|
+
if (omittedProperties !== null)
|
|
108
|
+
omittedProperties += 1;
|
|
97
109
|
continue;
|
|
98
110
|
}
|
|
99
111
|
const name = propertyName(property.key);
|
|
100
112
|
if (name === "" || !t.isObjectProperty(property)) {
|
|
101
113
|
unknownProperties = true;
|
|
114
|
+
if (omittedProperties !== null)
|
|
115
|
+
omittedProperties += 1;
|
|
102
116
|
continue;
|
|
103
117
|
}
|
|
104
118
|
if (properties.length >= context.state.limits.maxObjectProperties) {
|
|
105
|
-
|
|
119
|
+
reachSemanticValueLimit(context.state, "maxObjectProperties");
|
|
106
120
|
unknownProperties = true;
|
|
121
|
+
if (omittedProperties !== null)
|
|
122
|
+
omittedProperties += 1;
|
|
107
123
|
continue;
|
|
108
124
|
}
|
|
109
125
|
properties.push({
|
|
@@ -112,24 +128,39 @@ const evaluateObject = (node, context) => {
|
|
|
112
128
|
});
|
|
113
129
|
}
|
|
114
130
|
properties.sort((left, right) => compareCodePoints(left.name, right.name));
|
|
115
|
-
return {
|
|
131
|
+
return {
|
|
132
|
+
status: "object",
|
|
133
|
+
properties,
|
|
134
|
+
unknownProperties,
|
|
135
|
+
omittedProperties,
|
|
136
|
+
};
|
|
116
137
|
};
|
|
117
138
|
const evaluateArray = (node, context) => {
|
|
118
139
|
const items = [];
|
|
119
140
|
let unknownItems = false;
|
|
141
|
+
let omittedItems = 0;
|
|
120
142
|
for (const element of node.elements) {
|
|
121
|
-
if (
|
|
143
|
+
if (t.isSpreadElement(element)) {
|
|
144
|
+
unknownItems = true;
|
|
145
|
+
omittedItems = null;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (element === null) {
|
|
122
149
|
unknownItems = true;
|
|
150
|
+
if (omittedItems !== null)
|
|
151
|
+
omittedItems += 1;
|
|
123
152
|
continue;
|
|
124
153
|
}
|
|
125
154
|
if (items.length >= context.state.limits.maxObjectProperties) {
|
|
126
|
-
|
|
155
|
+
reachSemanticValueLimit(context.state, "maxObjectProperties");
|
|
127
156
|
unknownItems = true;
|
|
157
|
+
if (omittedItems !== null)
|
|
158
|
+
omittedItems += 1;
|
|
128
159
|
continue;
|
|
129
160
|
}
|
|
130
161
|
items.push(evaluateExpression(element, nestedContext(context)));
|
|
131
162
|
}
|
|
132
|
-
return { status: "array", items, unknownItems };
|
|
163
|
+
return { status: "array", items, unknownItems, omittedItems };
|
|
133
164
|
};
|
|
134
165
|
const evaluateMember = (node, context) => {
|
|
135
166
|
if (!t.isNode(node.object))
|
|
@@ -199,24 +230,24 @@ const projectValue = (value, projection) => {
|
|
|
199
230
|
};
|
|
200
231
|
const provenanceForBinding = (binding, context) => {
|
|
201
232
|
if (context.bindings.has(binding.bindingId))
|
|
202
|
-
return
|
|
233
|
+
return semanticProvenance("cycle", [], `Alias cycle at ${binding.name}.`);
|
|
203
234
|
if (context.depth >= context.state.limits.maxValueDepth)
|
|
204
|
-
return
|
|
235
|
+
return semanticLimitProvenance(context.state, "maxValueDepth");
|
|
205
236
|
if (binding.directOrigins.length > 0)
|
|
206
|
-
return
|
|
237
|
+
return semanticOriginsProvenance(binding.directOrigins, context.state);
|
|
207
238
|
if (binding.initializers.length === 0)
|
|
208
|
-
return
|
|
239
|
+
return semanticProvenance("local", [], null);
|
|
209
240
|
if (binding.initializers.length > 1)
|
|
210
|
-
return
|
|
241
|
+
return semanticProvenance("ambiguous", [], `Binding ${binding.name} has multiple possible assignments.`);
|
|
211
242
|
const initializer = binding.initializers[0];
|
|
212
243
|
if (initializer === undefined)
|
|
213
|
-
return
|
|
244
|
+
return semanticProvenance("unknown", [], "Missing binding initializer.");
|
|
214
245
|
if (initializer.projection.includes(null))
|
|
215
|
-
return
|
|
246
|
+
return semanticProvenance("unknown", [], "Dynamic provenance projection.");
|
|
216
247
|
const resolved = provenanceForExpression(initializer.node, nestedContext(context, binding.bindingId));
|
|
217
248
|
if (resolved.status !== "module" || initializer.projection.length === 0)
|
|
218
249
|
return resolved;
|
|
219
|
-
return
|
|
250
|
+
return semanticOriginsProvenance(resolved.origins.map((origin) => ({
|
|
220
251
|
...origin,
|
|
221
252
|
importedPath: [
|
|
222
253
|
...origin.importedPath,
|
|
@@ -227,23 +258,23 @@ const provenanceForBinding = (binding, context) => {
|
|
|
227
258
|
const provenanceForExpression = (node, context) => {
|
|
228
259
|
const required = requireOrigin(node);
|
|
229
260
|
if (required !== undefined)
|
|
230
|
-
return
|
|
261
|
+
return semanticOriginsProvenance([required], context.state);
|
|
231
262
|
if (t.isIdentifier(node)) {
|
|
232
263
|
const binding = resolveSemanticBindingState(context.state, node, node.name);
|
|
233
264
|
return binding === undefined
|
|
234
|
-
?
|
|
265
|
+
? semanticProvenance("unknown", [], `Unbound identifier ${node.name}.`)
|
|
235
266
|
: provenanceForBinding(binding, nestedContext(context));
|
|
236
267
|
}
|
|
237
268
|
if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
|
|
238
269
|
if (!t.isNode(node.object))
|
|
239
|
-
return
|
|
270
|
+
return semanticProvenance("unknown", [], "Unsupported member base.");
|
|
240
271
|
const member = memberKey(node);
|
|
241
272
|
if (typeof member !== "string")
|
|
242
|
-
return
|
|
273
|
+
return semanticProvenance("unknown", [], "Dynamic provenance member.");
|
|
243
274
|
const base = provenanceForExpression(node.object, nestedContext(context));
|
|
244
275
|
return base.status !== "module"
|
|
245
276
|
? base
|
|
246
|
-
:
|
|
277
|
+
: semanticOriginsProvenance(base.origins.map((origin) => ({
|
|
247
278
|
...origin,
|
|
248
279
|
importedPath: [...origin.importedPath, member],
|
|
249
280
|
})), context.state);
|
|
@@ -257,10 +288,10 @@ const provenanceForExpression = (node, context) => {
|
|
|
257
288
|
];
|
|
258
289
|
const origins = candidates.flatMap((candidate) => candidate.origins);
|
|
259
290
|
return origins.length > 0
|
|
260
|
-
?
|
|
261
|
-
:
|
|
291
|
+
? semanticProvenance("ambiguous", uniqueSemanticOrigins(origins), "Multiple module origins.")
|
|
292
|
+
: semanticProvenance("unknown", [], "Conditional provenance is unresolved.");
|
|
262
293
|
}
|
|
263
|
-
return
|
|
294
|
+
return semanticProvenance("local", [], null);
|
|
264
295
|
};
|
|
265
296
|
const requireOrigin = (node) => {
|
|
266
297
|
if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
|
|
@@ -285,31 +316,6 @@ const mergeValues = (values, state) => {
|
|
|
285
316
|
? primitiveSet(primitives, state)
|
|
286
317
|
: { status: "ambiguous", reason: "Branches have incompatible values." };
|
|
287
318
|
};
|
|
288
|
-
const primitiveSet = (values, state) => {
|
|
289
|
-
const unique = [
|
|
290
|
-
...new Map(values.map((value) => [primitiveKey(value), value])).values(),
|
|
291
|
-
].sort((left, right) => compareCodePoints(primitiveKey(left), primitiveKey(right)));
|
|
292
|
-
if (unique.length > state.limits.maxUnionValues)
|
|
293
|
-
return limitValue(state, "maxUnionValues");
|
|
294
|
-
const only = unique[0];
|
|
295
|
-
return unique.length === 1 && only !== undefined
|
|
296
|
-
? { status: "literal", value: only }
|
|
297
|
-
: { status: "union", values: unique };
|
|
298
|
-
};
|
|
299
|
-
const primitiveCandidates = (value) => value.status === "literal"
|
|
300
|
-
? [value.value]
|
|
301
|
-
: value.status === "union"
|
|
302
|
-
? value.values
|
|
303
|
-
: null;
|
|
304
|
-
const primitiveValue = (node) => {
|
|
305
|
-
if (t.isStringLiteral(node) || t.isNumericLiteral(node))
|
|
306
|
-
return { found: true, value: node.value };
|
|
307
|
-
if (t.isBooleanLiteral(node))
|
|
308
|
-
return { found: true, value: node.value };
|
|
309
|
-
if (t.isNullLiteral(node))
|
|
310
|
-
return { found: true, value: null };
|
|
311
|
-
return { found: false };
|
|
312
|
-
};
|
|
313
319
|
const memberKey = (node) => {
|
|
314
320
|
if (!node.computed)
|
|
315
321
|
return propertyName(node.property) || undefined;
|
|
@@ -317,30 +323,10 @@ const memberKey = (node) => {
|
|
|
317
323
|
return node.property.value;
|
|
318
324
|
return undefined;
|
|
319
325
|
};
|
|
320
|
-
const originsProvenance = (origins, state) => {
|
|
321
|
-
const unique = uniqueOrigins(origins);
|
|
322
|
-
if (unique.length > state.limits.maxUnionValues)
|
|
323
|
-
return limitProvenance(state, "maxUnionValues");
|
|
324
|
-
return unique.length === 1
|
|
325
|
-
? provenance("module", unique, null)
|
|
326
|
-
: provenance("ambiguous", unique, "Multiple module origins.");
|
|
327
|
-
};
|
|
328
|
-
const uniqueOrigins = (origins) => [
|
|
329
|
-
...new Map(origins.map((origin) => [originKey(origin), origin])).values(),
|
|
330
|
-
].sort((left, right) => compareCodePoints(originKey(left), originKey(right)));
|
|
331
|
-
const provenance = (status, origins, reason) => ({ status, origins, reason });
|
|
332
326
|
const limitValue = (state, limit) => {
|
|
333
|
-
|
|
327
|
+
reachSemanticValueLimit(state, limit);
|
|
334
328
|
return { status: "limit-reached", reason: `${limit} reached.` };
|
|
335
329
|
};
|
|
336
|
-
const limitProvenance = (state, limit) => {
|
|
337
|
-
markLimit(state, limit);
|
|
338
|
-
return provenance("limit-reached", [], `${limit} reached.`);
|
|
339
|
-
};
|
|
340
|
-
const markLimit = (state, limit) => {
|
|
341
|
-
state.limitsReached.add(limit);
|
|
342
|
-
state.omittedCount += 1;
|
|
343
|
-
};
|
|
344
330
|
const nestedContext = (context, bindingId) => ({
|
|
345
331
|
state: context.state,
|
|
346
332
|
depth: context.depth + 1,
|
|
@@ -348,5 +334,3 @@ const nestedContext = (context, bindingId) => ({
|
|
|
348
334
|
? context.bindings
|
|
349
335
|
: new Set([...context.bindings, bindingId]),
|
|
350
336
|
});
|
|
351
|
-
const primitiveKey = (value) => `${value === null ? "null" : typeof value}:${JSON.stringify(value)}`;
|
|
352
|
-
const originKey = (origin) => `${origin.specifier}\0${origin.importedPath.join("\0")}`;
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { jsonValueSchema } from "./jsonValue.js";
|
|
3
3
|
import { LEGACY_PROCESS_CAPTURE_MESSAGE, normalizationSchema, } from "./processScenario.js";
|
|
4
|
+
import { PROCESS_REACTIVE_LIMITS } from "./processReactiveScenario.js";
|
|
4
5
|
export * from "./processScenario.js";
|
|
6
|
+
/** Capture collection whose members participate in global observation order. */
|
|
7
|
+
export const PROCESS_CAPTURE_EVENT_COLLECTIONS = [
|
|
8
|
+
"frames",
|
|
9
|
+
"rendered_frames",
|
|
10
|
+
"interaction_events",
|
|
11
|
+
"lifecycle",
|
|
12
|
+
"process_samples",
|
|
13
|
+
"filesystem_checkpoints",
|
|
14
|
+
"shim_events",
|
|
15
|
+
"protocol_events",
|
|
16
|
+
"replay_transitions",
|
|
17
|
+
];
|
|
5
18
|
const fileStateSchema = z.object({
|
|
6
19
|
path: z.string(),
|
|
7
20
|
type: z.enum(["file", "directory", "symlink", "other"]),
|
|
@@ -115,8 +128,94 @@ export const processCaptureSchema = z.object({
|
|
|
115
128
|
"unmatched",
|
|
116
129
|
"script_exhausted",
|
|
117
130
|
"disconnected",
|
|
131
|
+
"invalid_state",
|
|
132
|
+
"guard_failed",
|
|
133
|
+
"transition_exhausted",
|
|
134
|
+
"invalid_capture",
|
|
135
|
+
"unexpected_reconnect",
|
|
136
|
+
"limit_exhausted",
|
|
118
137
|
]),
|
|
119
138
|
})),
|
|
139
|
+
replay_transitions: z
|
|
140
|
+
.array(z.object({
|
|
141
|
+
sequence: z.number().int().nonnegative(),
|
|
142
|
+
at_ms: z.number().int().nonnegative(),
|
|
143
|
+
transition_id: z.string().min(1).max(64),
|
|
144
|
+
state_before: z.string().min(1).max(64),
|
|
145
|
+
state_after: z.string().min(1).max(64),
|
|
146
|
+
sensitive_aliases: z.array(z.string().min(1).max(64)).max(32),
|
|
147
|
+
}))
|
|
148
|
+
.default([]),
|
|
149
|
+
reactive_run: z
|
|
150
|
+
.object({
|
|
151
|
+
status: z.enum(["running", "finished"]),
|
|
152
|
+
outcome: z
|
|
153
|
+
.enum([
|
|
154
|
+
"passed",
|
|
155
|
+
"predicate_timeout",
|
|
156
|
+
"scenario_deadline",
|
|
157
|
+
"ambiguous_match",
|
|
158
|
+
"action_rejected",
|
|
159
|
+
"target_lost",
|
|
160
|
+
"capture_incomplete",
|
|
161
|
+
"cancelled",
|
|
162
|
+
"cleanup_failed",
|
|
163
|
+
])
|
|
164
|
+
.nullable(),
|
|
165
|
+
active_state: z.string().min(1).max(64),
|
|
166
|
+
controls: z
|
|
167
|
+
.array(z.object({
|
|
168
|
+
sequence: z.number().int().nonnegative(),
|
|
169
|
+
kind: z.enum([
|
|
170
|
+
"state_deadline",
|
|
171
|
+
"scenario_deadline",
|
|
172
|
+
"target_lost",
|
|
173
|
+
"cancelled",
|
|
174
|
+
"cleanup_failed",
|
|
175
|
+
]),
|
|
176
|
+
after_capture_order: z.number().int().min(-1),
|
|
177
|
+
}))
|
|
178
|
+
.default([]),
|
|
179
|
+
transitions: z
|
|
180
|
+
.array(z.object({
|
|
181
|
+
sequence: z.number().int().nonnegative(),
|
|
182
|
+
transition_id: z.string().min(1).max(64),
|
|
183
|
+
state_before: z.string().min(1).max(64),
|
|
184
|
+
state_after: z.string().min(1).max(64).nullable(),
|
|
185
|
+
outcome: z
|
|
186
|
+
.enum([
|
|
187
|
+
"passed",
|
|
188
|
+
"predicate_timeout",
|
|
189
|
+
"scenario_deadline",
|
|
190
|
+
"ambiguous_match",
|
|
191
|
+
"action_rejected",
|
|
192
|
+
"target_lost",
|
|
193
|
+
"capture_incomplete",
|
|
194
|
+
"cancelled",
|
|
195
|
+
"cleanup_failed",
|
|
196
|
+
])
|
|
197
|
+
.nullable(),
|
|
198
|
+
trigger_event_ids: z
|
|
199
|
+
.array(z.string().min(1))
|
|
200
|
+
.max(PROCESS_REACTIVE_LIMITS.predicates),
|
|
201
|
+
action_event_ids: z
|
|
202
|
+
.array(z.string().min(1))
|
|
203
|
+
.max(PROCESS_REACTIVE_LIMITS.actionsPerTransition),
|
|
204
|
+
action_types: z
|
|
205
|
+
.array(z.enum(["send_input", "resize", "send_signal", "checkpoint"]))
|
|
206
|
+
.max(PROCESS_REACTIVE_LIMITS.actionsPerTransition),
|
|
207
|
+
}))
|
|
208
|
+
.max(PROCESS_REACTIVE_LIMITS.transitions),
|
|
209
|
+
})
|
|
210
|
+
.nullable()
|
|
211
|
+
.default(null),
|
|
212
|
+
event_journal: z
|
|
213
|
+
.array(z.object({
|
|
214
|
+
capture_order: z.number().int().nonnegative(),
|
|
215
|
+
collection: z.enum(PROCESS_CAPTURE_EVENT_COLLECTIONS),
|
|
216
|
+
index: z.number().int().nonnegative(),
|
|
217
|
+
}))
|
|
218
|
+
.default([]),
|
|
120
219
|
files_before: z.array(fileStateSchema),
|
|
121
220
|
files_after: z.array(fileStateSchema),
|
|
122
221
|
filesystem_effects: z.array(fileEffectSchema),
|
|
@@ -157,3 +256,4 @@ export const parseProcessCapture = (input) => {
|
|
|
157
256
|
return capture;
|
|
158
257
|
};
|
|
159
258
|
export { compareProcessCaptures, comparisonStatusSchema, deriveProcessComparisonStatus, PROCESS_COMPARISON_DIMENSIONS, processCaptureComparisonSchema, } from "./processComparison.js";
|
|
259
|
+
export { compareProcessTraces, processTraceComparisonResultSchema, processTraceSourceSchema, processTraceSpecificationSchema, } from "./processTraceComparison.js";
|