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.
Files changed (179) hide show
  1. package/README.md +57 -10
  2. package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
  3. package/dist/application/ArtifactExtraction.js +5 -1
  4. package/dist/application/ArtifactGraphConstruction.js +3 -15
  5. package/dist/application/ArtifactInventory/classify.js +5 -1
  6. package/dist/application/ArtifactInventory/reader.js +2 -0
  7. package/dist/application/BinarySession.js +9 -2
  8. package/dist/application/BinarySessionStatus.js +40 -1
  9. package/dist/application/CapabilityInventory.js +26 -3
  10. package/dist/application/CommandShimReplay.js +6 -3
  11. package/dist/application/CompositeProvider.js +5 -2
  12. package/dist/application/DirectAnalysis.js +1 -20
  13. package/dist/application/DirectAnalysisStatus.js +83 -0
  14. package/dist/application/Doctor.js +34 -25
  15. package/dist/application/DoctorDiagnostics.js +1 -4
  16. package/dist/application/DoctorProjection.js +43 -0
  17. package/dist/application/DoctorScope.js +102 -0
  18. package/dist/application/EvidenceReferenceResolver.js +26 -0
  19. package/dist/application/JavaScriptApplicationEvidence.js +1 -1
  20. package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
  21. package/dist/application/JavaScriptApplicationService.js +3 -2
  22. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
  23. package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
  24. package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
  25. package/dist/application/JavaScriptModuleRelationships.js +25 -1
  26. package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
  27. package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
  28. package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
  29. package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
  30. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
  31. package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
  32. package/dist/application/JavaScriptSemanticTraceService.js +45 -0
  33. package/dist/application/LoopbackReplay.js +277 -133
  34. package/dist/application/LoopbackReplayRecorder.js +101 -0
  35. package/dist/application/PermissionAuthority.js +7 -3
  36. package/dist/application/ProcessCaptureEnvironment.js +26 -0
  37. package/dist/application/ProcessCaptureJournal.js +95 -0
  38. package/dist/application/ProcessCaptureLifecycle.js +25 -13
  39. package/dist/application/ProcessCheckpoints.js +35 -4
  40. package/dist/application/ProcessCli.js +26 -4
  41. package/dist/application/ProcessHarness.js +64 -83
  42. package/dist/application/ProcessNormalization.js +9 -2
  43. package/dist/application/ProcessReactiveCoordinator.js +225 -0
  44. package/dist/application/ProcessReactiveEffects.js +141 -0
  45. package/dist/application/ProcessReactiveHarness.js +85 -0
  46. package/dist/application/ProcessReactiveObservations.js +105 -0
  47. package/dist/application/ProcessSampling.js +2 -0
  48. package/dist/application/SessionProviderRouter.js +7 -6
  49. package/dist/application/Setup.js +11 -10
  50. package/dist/application/SetupPlan.js +1 -1
  51. package/dist/application/SetupRegistrationEnvironment.js +12 -0
  52. package/dist/application/TerminalRenderer.js +3 -1
  53. package/dist/browser/CdpEndpoint.js +37 -4
  54. package/dist/catalogIdentity.js +16 -7
  55. package/dist/cli/coreAnalysisCommands.js +34 -2
  56. package/dist/cli/javascriptApplicationAnalysis.js +19 -0
  57. package/dist/cli/setupCommands.js +81 -32
  58. package/dist/cli/utilityCommands.js +10 -2
  59. package/dist/cliApplicationCommands.js +79 -16
  60. package/dist/cliCommandNames.js +3 -0
  61. package/dist/cliElectronCommands.js +23 -33
  62. package/dist/cliObservationOptions.js +1 -1
  63. package/dist/cliOutput.js +56 -0
  64. package/dist/cliProcessCommands.js +32 -1
  65. package/dist/cliSetup.js +30 -21
  66. package/dist/contracts/applicationToolContracts.js +54 -7
  67. package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
  68. package/dist/contracts/electronToolContracts.js +53 -32
  69. package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
  70. package/dist/contracts/processCaptureExample.js +1 -0
  71. package/dist/contracts/replayMachineExample.js +37 -0
  72. package/dist/contracts/toolContractExamples.js +2 -0
  73. package/dist/contracts/toolContracts.js +5 -1
  74. package/dist/contracts/toolEffects.js +3 -0
  75. package/dist/contracts/toolOutputSchemaGroups.js +2 -0
  76. package/dist/contracts/toolOutputSchemaPrimitives.js +43 -0
  77. package/dist/doctorRuntime.js +41 -0
  78. package/dist/domain/analysisErrorPresentation.js +5 -3
  79. package/dist/domain/analysisErrorProjection.js +7 -1
  80. package/dist/domain/analysisSnapshot.js +2 -0
  81. package/dist/domain/artifactGraph.js +2 -0
  82. package/dist/domain/binaryTarget.js +3 -6
  83. package/dist/domain/changedBehavior.js +5 -4
  84. package/dist/domain/completionLedgerGeneration.js +190 -0
  85. package/dist/domain/errors.js +4 -2
  86. package/dist/domain/evidence.js +2 -0
  87. package/dist/domain/evidenceCompletionLedger.js +113 -0
  88. package/dist/domain/hopperStartupFailure.js +9 -0
  89. package/dist/domain/javascriptApplicationAnalysis.js +44 -2
  90. package/dist/domain/javascriptExportShapeComparison.js +145 -0
  91. package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
  92. package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
  93. package/dist/domain/javascriptExportShapeSelection.js +132 -0
  94. package/dist/domain/javascriptExportShapeVariants.js +272 -0
  95. package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
  96. package/dist/domain/javascriptSemanticAnalysis.js +17 -36
  97. package/dist/domain/javascriptSemanticCallResolution.js +129 -0
  98. package/dist/domain/javascriptSemanticCalls.js +269 -0
  99. package/dist/domain/javascriptSemanticGraph.js +356 -0
  100. package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
  101. package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
  102. package/dist/domain/javascriptSemanticIr.js +14 -1
  103. package/dist/domain/javascriptSemanticPrimitives.js +36 -0
  104. package/dist/domain/javascriptSemanticProjection.js +36 -4
  105. package/dist/domain/javascriptSemanticProvenance.js +29 -0
  106. package/dist/domain/javascriptSemanticQuery.js +294 -0
  107. package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
  108. package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
  109. package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
  110. package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
  111. package/dist/domain/javascriptSemanticReturns.js +187 -0
  112. package/dist/domain/javascriptSemanticState.js +32 -0
  113. package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
  114. package/dist/domain/javascriptSemanticValues.js +54 -70
  115. package/dist/domain/processCapture.js +100 -0
  116. package/dist/domain/processCaptureReactiveValidation.js +175 -0
  117. package/dist/domain/processCaptureValidation.js +103 -12
  118. package/dist/domain/processComparison.js +78 -25
  119. package/dist/domain/processObservation.js +162 -0
  120. package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
  121. package/dist/domain/processReactiveMatching.js +210 -0
  122. package/dist/domain/processReactiveRuntime.js +120 -0
  123. package/dist/domain/processReactiveScenario.js +361 -0
  124. package/dist/domain/processReactiveScenarioPreflight.js +120 -0
  125. package/dist/domain/processReactiveTransition.js +161 -0
  126. package/dist/domain/processScenario.js +33 -0
  127. package/dist/domain/processTraceComparison.js +43 -0
  128. package/dist/domain/processTraceDimensionProjection.js +50 -0
  129. package/dist/domain/processTraceEvaluation.js +312 -0
  130. package/dist/domain/processTraceSpecification.js +373 -0
  131. package/dist/domain/reconstructionVerification.js +5 -4
  132. package/dist/domain/replayMachine.js +18 -2
  133. package/dist/domain/replayMachineRun.js +216 -0
  134. package/dist/domain/replayMachineRuntime.js +88 -9
  135. package/dist/domain/staticRuntimeCorrelation.js +4 -2
  136. package/dist/domain/zipPackageFormat.js +20 -0
  137. package/dist/evaluation/CodexAgentEval.js +24 -0
  138. package/dist/generatedPackageMetadata.js +1 -1
  139. package/dist/ghidra/GhidraClient.js +13 -2
  140. package/dist/ghidra/GhidraDiagnostics.js +1 -0
  141. package/dist/ghidra/GhidraLauncher.js +7 -3
  142. package/dist/ghidra/GhidraProvider.js +8 -1
  143. package/dist/hopper/BridgeLauncher.js +56 -14
  144. package/dist/hopper/HopperClient.js +23 -10
  145. package/dist/hopper/HopperDiagnostics.js +14 -0
  146. package/dist/hopper/HopperProcessDiagnostic.js +14 -0
  147. package/dist/hopper/HopperProvider.js +8 -1
  148. package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
  149. package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
  150. package/dist/main/transport.js +2 -0
  151. package/dist/mcpDoctor.js +310 -0
  152. package/dist/native/NativeMacOSProvider.js +1 -0
  153. package/dist/process/ProcessOwnership.js +200 -53
  154. package/dist/process/ProviderRunLineage.js +21 -0
  155. package/dist/server/createServer.js +4 -1
  156. package/dist/server/javascriptApplicationResult.js +22 -1
  157. package/dist/server/registerApplicationTools/characterization.js +3 -3
  158. package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
  159. package/dist/server/registerApplicationTools/compareVersions.js +12 -6
  160. package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
  161. package/dist/server/registerApplicationTools/coverage.js +3 -3
  162. package/dist/server/registerApplicationTools/helpers.js +37 -25
  163. package/dist/server/registerApplicationTools/traceFeature.js +9 -5
  164. package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
  165. package/dist/server/registerApplicationTools.js +4 -0
  166. package/dist/server/registerEvidenceResources.js +5 -1
  167. package/dist/server/registerProcessComparisonTool.js +17 -7
  168. package/dist/server/registerReplayMachineTool.js +20 -0
  169. package/dist/server/registerSessionTools.js +12 -7
  170. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  171. package/dist/serverIdentity.js +19 -0
  172. package/package.json +62 -30
  173. package/scripts/hopper-demo-x11.py +459 -61
  174. package/scripts/prepack.mjs +55 -0
  175. package/scripts/prepare.mjs +28 -0
  176. package/scripts/rea.mjs +26 -5
  177. package/skills/reverse-engineer-anything/SKILL.md +4 -3
  178. package/skills/reverse-engineer-anything/references/javascript-applications.md +10 -0
  179. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +2 -2
@@ -0,0 +1,272 @@
1
+ import { compareCodePoints } from "./javascriptApplicationGraph.js";
2
+ import { canonicalExportShapeValue, digestExportShapeValue, } from "./javascriptExportShapeComparisonIdentity.js";
3
+ /** Pair variants only through reciprocal unique exact literal discriminants. */
4
+ export const pairJavaScriptExportShapeVariants = (left, right) => {
5
+ const leftKeys = discriminantOccurrences(left);
6
+ const rightKeys = discriminantOccurrences(right);
7
+ const edges = new Map();
8
+ const leftTargets = new Map();
9
+ const rightTargets = new Map();
10
+ for (const [key, leftOccurrence] of leftKeys) {
11
+ const rightOccurrence = rightKeys.get(key);
12
+ if (leftOccurrence.indexes.length !== 1 ||
13
+ rightOccurrence?.indexes.length !== 1)
14
+ continue;
15
+ const leftIndex = leftOccurrence.indexes[0];
16
+ const rightIndex = rightOccurrence.indexes[0];
17
+ if (leftIndex === undefined || rightIndex === undefined)
18
+ continue;
19
+ const edgeKey = `${String(leftIndex)}:${String(rightIndex)}`;
20
+ edges.set(edgeKey, [
21
+ ...(edges.get(edgeKey) ?? []),
22
+ leftOccurrence.discriminant,
23
+ ]);
24
+ addTarget(leftTargets, leftIndex, rightIndex);
25
+ addTarget(rightTargets, rightIndex, leftIndex);
26
+ }
27
+ const pairs = reciprocalPairs(leftTargets, rightTargets, edges);
28
+ const pairedLeft = new Set(pairs.map(({ leftIndex }) => leftIndex));
29
+ const pairedRight = new Set(pairs.map(({ rightIndex }) => rightIndex));
30
+ return {
31
+ pairs,
32
+ unpairedLeft: indexesNotIn(left, pairedLeft),
33
+ unpairedRight: indexesNotIn(right, pairedRight),
34
+ };
35
+ };
36
+ /** Build bounded-ready field and unpaired-variant changes before caller slicing. */
37
+ export const buildJavaScriptExportShapeChanges = (input) => {
38
+ if (input.leftSelection.selection.status !== "selected" ||
39
+ input.rightSelection.selection.status !== "selected")
40
+ return [selectionUnknownChange(input)];
41
+ if (input.leftShapes.length === 0 || input.rightShapes.length === 0)
42
+ return [emptyShapeUnknownChange(input)];
43
+ const paired = input.pairing.pairs.flatMap((pair) => {
44
+ const left = input.leftShapes[pair.leftIndex];
45
+ const right = input.rightShapes[pair.rightIndex];
46
+ return left === undefined || right === undefined
47
+ ? []
48
+ : diffPair(left, right, pair.discriminant, input.evidenceLinks);
49
+ });
50
+ const unpairedLeft = input.pairing.unpairedLeft.flatMap((index) => {
51
+ const shape = input.leftShapes[index];
52
+ return shape === undefined
53
+ ? []
54
+ : [unpairedChange("left", shape, input.evidenceLinks)];
55
+ });
56
+ const unpairedRight = input.pairing.unpairedRight.flatMap((index) => {
57
+ const shape = input.rightShapes[index];
58
+ return shape === undefined
59
+ ? []
60
+ : [unpairedChange("right", shape, input.evidenceLinks)];
61
+ });
62
+ return [...paired, ...unpairedLeft, ...unpairedRight];
63
+ };
64
+ /** Sort changes by semantic content rather than traversal order. */
65
+ export const compareJavaScriptExportShapeChanges = (left, right) => compareCodePoints(canonicalExportShapeValue(changeSortKey(left)), canonicalExportShapeValue(changeSortKey(right)));
66
+ /** Report whether any retained shape lacks complete property coverage. */
67
+ export const hasPartialJavaScriptExportPropertyCoverage = (shapes) => shapes.some((shape) => shape.property_coverage.some(({ status }) => status === "partial"));
68
+ const discriminantOccurrences = (shapes) => {
69
+ const output = new Map();
70
+ shapes.forEach((shape, index) => {
71
+ for (const field of shape.fields) {
72
+ const value = literalValue(field);
73
+ if (!value.found)
74
+ continue;
75
+ const discriminant = { path: field.path, value: value.value };
76
+ const key = canonicalExportShapeValue(discriminant);
77
+ const current = output.get(key);
78
+ output.set(key, {
79
+ discriminant,
80
+ indexes: [...(current?.indexes ?? []), index],
81
+ });
82
+ }
83
+ });
84
+ return output;
85
+ };
86
+ const reciprocalPairs = (leftTargets, rightTargets, edges) => {
87
+ const pairs = [];
88
+ for (const [leftIndex, targets] of leftTargets) {
89
+ if (targets.size !== 1)
90
+ continue;
91
+ const rightIndex = [...targets][0];
92
+ if (rightIndex === undefined ||
93
+ rightTargets.get(rightIndex)?.size !== 1 ||
94
+ !rightTargets.get(rightIndex)?.has(leftIndex))
95
+ continue;
96
+ const discriminants = edges
97
+ .get(`${String(leftIndex)}:${String(rightIndex)}`)
98
+ ?.toSorted(compareDiscriminants);
99
+ const discriminant = discriminants?.[0];
100
+ if (discriminant !== undefined)
101
+ pairs.push({ leftIndex, rightIndex, discriminant });
102
+ }
103
+ return pairs.sort((first, second) => compareDiscriminants(first.discriminant, second.discriminant));
104
+ };
105
+ const addTarget = (map, source, target) => {
106
+ const values = map.get(source) ?? new Set();
107
+ values.add(target);
108
+ map.set(source, values);
109
+ };
110
+ const indexesNotIn = (shapes, paired) => shapes.map((_, index) => index).filter((index) => !paired.has(index));
111
+ const compareDiscriminants = (left, right) => compareCodePoints(canonicalExportShapeValue(left), canonicalExportShapeValue(right));
112
+ const selectionUnknownChange = (input) => changeWithId({
113
+ status: "unknown",
114
+ path: "",
115
+ discriminant: null,
116
+ left: selectionAvailability(input.leftSelection.selection, "left"),
117
+ right: selectionAvailability(input.rightSelection.selection, "right"),
118
+ left_source_range: null,
119
+ right_source_range: null,
120
+ evidence_links: input.evidenceLinks,
121
+ limitations: [
122
+ "Both selectors must resolve one exact export with trusted static return shapes before comparison.",
123
+ ],
124
+ });
125
+ const emptyShapeUnknownChange = (input) => changeWithId({
126
+ status: "unknown",
127
+ path: "",
128
+ discriminant: null,
129
+ left: emptyShapeAvailability(input.leftShapes, "left"),
130
+ right: emptyShapeAvailability(input.rightShapes, "right"),
131
+ left_source_range: null,
132
+ right_source_range: null,
133
+ evidence_links: input.evidenceLinks,
134
+ limitations: [
135
+ "At least one selected export has no retained direct return shape.",
136
+ ],
137
+ });
138
+ const diffPair = (left, right, discriminant, evidenceLinks) => {
139
+ const leftFields = new Map(left.fields.map((field) => [field.path, field]));
140
+ const rightFields = new Map(right.fields.map((field) => [field.path, field]));
141
+ const paths = uniqueSorted([...leftFields.keys(), ...rightFields.keys()]);
142
+ return paths.flatMap((path) => {
143
+ const leftField = leftFields.get(path);
144
+ const rightField = rightFields.get(path);
145
+ const status = fieldChangeStatus({
146
+ leftShape: left,
147
+ rightShape: right,
148
+ path,
149
+ leftField,
150
+ rightField,
151
+ });
152
+ if (status === null)
153
+ return [];
154
+ return [
155
+ changeWithId({
156
+ status,
157
+ path,
158
+ discriminant,
159
+ left: fieldAvailability(leftField),
160
+ right: fieldAvailability(rightField),
161
+ left_source_range: left.source_range,
162
+ right_source_range: right.source_range,
163
+ evidence_links: evidenceLinks,
164
+ limitations: status === "unknown"
165
+ ? [
166
+ "The static value or relevant parent-property coverage is incomplete.",
167
+ ]
168
+ : [],
169
+ }),
170
+ ];
171
+ });
172
+ };
173
+ const fieldChangeStatus = ({ leftShape, rightShape, path, leftField, rightField, }) => {
174
+ if (leftField !== undefined && rightField !== undefined) {
175
+ if (canonicalExportShapeValue(leftField) ===
176
+ canonicalExportShapeValue(rightField))
177
+ return null;
178
+ return leftField.state === "unknown" || rightField.state === "unknown"
179
+ ? "unknown"
180
+ : "changed";
181
+ }
182
+ const present = leftField ?? rightField;
183
+ if (present === undefined)
184
+ return null;
185
+ const parent = parentPointer(path);
186
+ const parentsComplete = propertyCoverageComplete(leftShape, parent) &&
187
+ propertyCoverageComplete(rightShape, parent);
188
+ if (present.state === "unknown" || !parentsComplete)
189
+ return "unknown";
190
+ return leftField === undefined ? "added" : "removed";
191
+ };
192
+ const propertyCoverageComplete = (shape, path) => path !== null &&
193
+ shape.property_coverage.some((coverage) => coverage.path === path && coverage.status === "complete");
194
+ const parentPointer = (path) => {
195
+ if (path === "")
196
+ return null;
197
+ const separator = path.lastIndexOf("/");
198
+ return separator < 0 ? null : path.slice(0, separator);
199
+ };
200
+ const fieldAvailability = (field) => {
201
+ if (field === undefined)
202
+ return { availability: "absent" };
203
+ if (field.state === "unknown")
204
+ return {
205
+ availability: "unknown",
206
+ reason: field.reason ?? "Static field value is unknown.",
207
+ };
208
+ if (field.state === "union")
209
+ return { availability: "union", values: primitiveArray(field.value) };
210
+ const literal = literalValue(field);
211
+ return literal.found
212
+ ? { availability: "literal", value: literal.value }
213
+ : {
214
+ availability: "unknown",
215
+ reason: "Static literal field failed its projection boundary.",
216
+ };
217
+ };
218
+ const selectionAvailability = (selection, side) => ({
219
+ availability: "unknown",
220
+ reason: `${capitalize(side)} export selection is ${selection.status}.`,
221
+ });
222
+ const emptyShapeAvailability = (shapes, side) => ({
223
+ availability: "unknown",
224
+ reason: shapes.length === 0
225
+ ? `${capitalize(side)} export has no retained direct return shape.`
226
+ : `${capitalize(side)} export return shape cannot be paired without an opposite variant.`,
227
+ });
228
+ const unpairedChange = (side, shape, evidenceLinks) => changeWithId({
229
+ status: "unknown",
230
+ path: "",
231
+ discriminant: null,
232
+ left: {
233
+ availability: "unknown",
234
+ reason: side === "left"
235
+ ? "Left return variant has no unique exact cross-version pairing."
236
+ : "No left return variant was uniquely paired with this right variant.",
237
+ },
238
+ right: {
239
+ availability: "unknown",
240
+ reason: side === "right"
241
+ ? "Right return variant has no unique exact cross-version pairing."
242
+ : "No right return variant was uniquely paired with this left variant.",
243
+ },
244
+ left_source_range: side === "left" ? shape.source_range : null,
245
+ right_source_range: side === "right" ? shape.source_range : null,
246
+ evidence_links: evidenceLinks,
247
+ limitations: [
248
+ "The return variant was not paired because no reciprocal unique literal discriminant exists.",
249
+ ],
250
+ });
251
+ const changeWithId = (semantic) => ({
252
+ ...semantic,
253
+ change_id: `jesc_change_${digestExportShapeValue(semantic)}`,
254
+ });
255
+ const changeSortKey = (change) => ({
256
+ discriminant: change.discriminant,
257
+ path: change.path,
258
+ status: change.status,
259
+ left_source_range: change.left_source_range,
260
+ right_source_range: change.right_source_range,
261
+ change_id: change.change_id,
262
+ });
263
+ const literalValue = (field) => field.state === "literal" && isPrimitive(field.value)
264
+ ? { found: true, value: field.value }
265
+ : { found: false };
266
+ const primitiveArray = (value) => Array.isArray(value) ? value.filter(isPrimitive) : [];
267
+ const isPrimitive = (value) => value === null ||
268
+ typeof value === "string" ||
269
+ typeof value === "number" ||
270
+ typeof value === "boolean";
271
+ const capitalize = (value) => `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
272
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);
@@ -22,16 +22,16 @@ export const digestCanonical = (value) => {
22
22
  };
23
23
  const parseStaticLayer = (layer) => {
24
24
  const evidence = parseEvidence(layer.analysis);
25
+ const result = javascriptApplicationAnalysisResultSchema.parse(evidence.normalized_result);
25
26
  assertEvidenceIdentity(evidence, {
26
27
  operation: "analyze_javascript_application",
27
- predicate: "rea.javascript-application-analysis/v1",
28
+ predicate: `rea.javascript-application-analysis/v${String(result.schema_version)}`,
28
29
  providerId: "rea-javascript-application",
29
30
  providerName: "REA JavaScript application analyzer",
30
31
  providerVersion: "1",
31
32
  authority: "shipped-artifact",
32
33
  confidence: "derived",
33
34
  });
34
- const result = javascriptApplicationAnalysisResultSchema.parse(evidence.normalized_result);
35
35
  if (evidence.subject === null ||
36
36
  evidence.subject.digest.sha256 !== result.root_artifact_sha256 ||
37
37
  evidence.subject.format !== result.format ||
@@ -2,8 +2,10 @@ import { parse } from "@babel/parser";
2
2
  import * as t from "@babel/types";
3
3
  import { DEFAULT_JAVASCRIPT_SEMANTIC_LIMITS, failedJavaScriptSemanticIr, } from "./javascriptSemanticIr.js";
4
4
  import { collectSemanticModuleLink, collectSemanticCallable, collectSemanticReferences, immutableSemanticBindings, immutableSemanticScopes, reachSemanticLimit, semanticModuleOrigin, semanticStaticPropertyName, } from "./javascriptSemanticProjection.js";
5
- import { currentSemanticScope, semanticScopeId, } from "./javascriptSemanticState.js";
5
+ import { currentSemanticScope, resolveSemanticBindingFromScope, semanticScopeId, semanticVariableScope, } from "./javascriptSemanticState.js";
6
6
  import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
7
+ import { collectSemanticReturns, resolveSemanticModuleCallables, } from "./javascriptSemanticReturns.js";
8
+ import { collectJavaScriptSemanticCalls } from "./javascriptSemanticCalls.js";
7
9
  import { compareCodePoints, propertyName, range, } from "./javascriptStaticAnalysisHelpers.js";
8
10
  /** Recover bounded lexical bindings, aliases, constants, and module links. */
9
11
  export const analyzeJavaScriptSemantics = (source, inputLimits = {}) => {
@@ -23,14 +25,19 @@ export const analyzeJavaScriptSemantics = (source, inputLimits = {}) => {
23
25
  collectDefinitions(file.program, state);
24
26
  const references = collectSemanticReferences(file.program, state);
25
27
  const parserPartial = file.errors.length > 0;
28
+ const bindings = immutableSemanticBindings(state);
29
+ const callables = collectSemanticReturns(file.program, state, parserPartial);
30
+ const moduleLinks = resolveSemanticModuleCallables(state, callables);
31
+ const calls = collectJavaScriptSemanticCalls(file.program, state, callables);
26
32
  return {
27
33
  schema: "JavaScriptSemanticIR",
28
- schemaVersion: 1,
34
+ schemaVersion: 3,
29
35
  scopes: immutableSemanticScopes(state),
30
- bindings: immutableSemanticBindings(state),
31
- callables: [...state.callables],
36
+ bindings,
37
+ callables,
32
38
  references,
33
- moduleLinks: [...state.moduleLinks],
39
+ moduleLinks,
40
+ ...calls,
34
41
  coverage: {
35
42
  status: state.limitsReached.size > 0
36
43
  ? "truncated"
@@ -50,6 +57,8 @@ export const analyzeJavaScriptSemantics = (source, inputLimits = {}) => {
50
57
  ? []
51
58
  : ["Semantic recovery stopped retaining facts at explicit limits."]),
52
59
  "Values and aliases were recovered from inert syntax only; no JavaScript was executed.",
60
+ "Return sites include only direct callable returns; nested callable returns remain separate.",
61
+ "Local call, argument, return, and closure relations are static candidates and do not prove runtime invocation.",
53
62
  "Cross-function mutation and dynamic property resolution remain unknown.",
54
63
  ],
55
64
  };
@@ -70,6 +79,7 @@ const createState = (program, limits) => {
70
79
  scopeByNode: new WeakMap([[program, root]]),
71
80
  bindingsById: new Map(),
72
81
  callables: [],
82
+ callableNodesById: new Map(),
73
83
  moduleLinks: [],
74
84
  limitsReached: new Set(),
75
85
  omittedCount: 0,
@@ -136,7 +146,7 @@ const bindInnerDeclaration = (node, parent, scope, state) => {
136
146
  bindPattern({
137
147
  pattern: node.id,
138
148
  initializer: node.init ?? null,
139
- scope: variableScope(scope, parent, state),
149
+ scope: semanticVariableScope(scope, parent, state),
140
150
  state,
141
151
  mutable: parent !== null && t.isVariableDeclaration(parent)
142
152
  ? parent.kind !== "const"
@@ -348,39 +358,10 @@ const createBinding = (scope, name, kind, mutable) => ({
348
358
  directOrigins: [],
349
359
  });
350
360
  const addAssignment = (identifier, initializer, scope, state) => {
351
- const binding = resolveFromScope(scope, identifier.name, state);
361
+ const binding = resolveSemanticBindingFromScope(scope, identifier.name, state);
352
362
  if (binding === undefined)
353
363
  return;
354
364
  binding.mutable = true;
355
365
  binding.definitions.push({ kind: "assignment", location: range(identifier) });
356
366
  binding.initializers.push({ node: initializer, projection: [] });
357
367
  };
358
- const resolveFromScope = (scope, name, state) => {
359
- let candidate = scope;
360
- while (candidate !== undefined) {
361
- const binding = candidate.bindings.get(name);
362
- if (binding !== undefined)
363
- return binding;
364
- if (!candidate.bindingsComplete)
365
- return undefined;
366
- candidate =
367
- candidate.parentScopeId === null
368
- ? undefined
369
- : state.scopesById.get(candidate.parentScopeId);
370
- }
371
- return undefined;
372
- };
373
- const variableScope = (scope, parent, state) => {
374
- if (!(parent !== null && t.isVariableDeclaration(parent, { kind: "var" })))
375
- return scope;
376
- let candidate = scope;
377
- while (candidate.kind === "block" || candidate.kind === "catch") {
378
- const outer = candidate.parentScopeId === null
379
- ? undefined
380
- : state.scopesById.get(candidate.parentScopeId);
381
- if (outer === undefined)
382
- break;
383
- candidate = outer;
384
- }
385
- return candidate;
386
- };
@@ -0,0 +1,129 @@
1
+ import * as t from "@babel/types";
2
+ import { reachSemanticLimit, semanticCallableIdForNode, } from "./javascriptSemanticProjection.js";
3
+ import { resolveSemanticBindingState, } from "./javascriptSemanticState.js";
4
+ import { compareCodePoints, range } from "./javascriptStaticAnalysisHelpers.js";
5
+ /** Resolve bounded local callable candidates without following dynamic properties. */
6
+ export const resolveLocalCallables = (input) => resolveCallables(input.node, {
7
+ state: input.state,
8
+ callableById: input.callableById,
9
+ seenBindings: input.seenBindings,
10
+ depth: input.depth,
11
+ bindingCache: input.bindingCache,
12
+ });
13
+ const resolveCallables = (node, context) => {
14
+ if (context.depth >= context.state.limits.maxValueDepth) {
15
+ reachSemanticLimit(context.state, "maxValueDepth");
16
+ return {
17
+ callableIds: [],
18
+ complete: false,
19
+ reason: "Call target depth limit reached.",
20
+ };
21
+ }
22
+ const direct = semanticCallableIdForNode(node);
23
+ if (direct !== null && context.callableById.has(direct))
24
+ return {
25
+ callableIds: [direct],
26
+ complete: true,
27
+ reason: "Direct local callable.",
28
+ };
29
+ if (t.isIdentifier(node))
30
+ return resolveIdentifier(node, context);
31
+ if (t.isTSAsExpression(node) ||
32
+ t.isTSTypeAssertion(node) ||
33
+ t.isTSNonNullExpression(node))
34
+ return resolveCallables(node.expression, nestedContext(context));
35
+ if (t.isConditionalExpression(node) || t.isLogicalExpression(node))
36
+ return resolveAlternatives(t.isConditionalExpression(node) ? node.consequent : node.left, t.isConditionalExpression(node) ? node.alternate : node.right, context);
37
+ return {
38
+ callableIds: [],
39
+ complete: false,
40
+ reason: `Unsupported ${node.type} call target.`,
41
+ };
42
+ };
43
+ const resolveIdentifier = (node, context) => {
44
+ const binding = resolveSemanticBindingState(context.state, node, node.name);
45
+ return binding === undefined
46
+ ? {
47
+ callableIds: [],
48
+ complete: false,
49
+ reason: `Unresolved call target ${node.name}.`,
50
+ }
51
+ : resolveBindingCallables(binding, nestedContext(context));
52
+ };
53
+ const resolveAlternatives = (left, right, context) => {
54
+ const candidates = [left, right].map((candidate) => resolveCallables(candidate, nestedContext(context)));
55
+ return {
56
+ callableIds: uniqueCallableIds(candidates.flatMap(({ callableIds }) => callableIds)),
57
+ complete: candidates.every(({ complete }) => complete),
58
+ reason: "Conditional or logical call target has multiple candidates.",
59
+ };
60
+ };
61
+ const resolveBindingCallables = (binding, context) => {
62
+ const cached = context.bindingCache.get(binding.bindingId);
63
+ if (cached !== undefined)
64
+ return cached;
65
+ if (context.seenBindings.has(binding.bindingId))
66
+ return {
67
+ callableIds: [],
68
+ complete: false,
69
+ reason: `Call target alias cycle at ${binding.name}.`,
70
+ };
71
+ if (binding.initializers.length === 0)
72
+ return missingBindingInitializer(binding);
73
+ const candidateContext = {
74
+ ...nestedContext(context),
75
+ seenBindings: new Set([...context.seenBindings, binding.bindingId]),
76
+ };
77
+ const candidates = binding.initializers.map(({ node, projection }) => projection.length === 0
78
+ ? resolveCallables(node, candidateContext)
79
+ : {
80
+ callableIds: [],
81
+ complete: false,
82
+ reason: `Projected call target ${binding.name} is unresolved.`,
83
+ });
84
+ const callableIds = uniqueCallableIds(candidates.flatMap((candidate) => candidate.callableIds));
85
+ const resolution = {
86
+ callableIds,
87
+ complete: candidates.every(({ complete }) => complete),
88
+ reason: callableIds.length === 1 && candidates.every(({ complete }) => complete)
89
+ ? "Unique local callable target."
90
+ : `Call target ${binding.name} has ambiguous or unsupported assignments.`,
91
+ };
92
+ if (resolution.complete)
93
+ context.bindingCache.set(binding.bindingId, resolution);
94
+ return resolution;
95
+ };
96
+ const missingBindingInitializer = (binding) => ({
97
+ callableIds: [],
98
+ complete: false,
99
+ reason: binding.kind === "import"
100
+ ? `Call target ${binding.name} is imported from outside this source.`
101
+ : `Call target ${binding.name} has no local initializer.`,
102
+ });
103
+ /** Find all bindings introduced by one positional parameter pattern. */
104
+ export const parameterBindings = (callable, index, state) => {
105
+ if (callable.bodyScopeId === null)
106
+ return [];
107
+ const scope = state.scopesById.get(callable.bodyScopeId);
108
+ if (scope === undefined)
109
+ return [];
110
+ return [...scope.bindings.values()]
111
+ .filter((binding) => binding.kind === "parameter" &&
112
+ binding.definitions.some(({ kind, location }) => kind === "parameter" &&
113
+ parameterIndex(callable, location, state) === index))
114
+ .sort((left, right) => compareCodePoints(left.bindingId, right.bindingId));
115
+ };
116
+ const parameterIndex = (callable, location, state) => {
117
+ const node = state.callableNodesById.get(callable.callableId);
118
+ if (!t.isFunction(node))
119
+ return -1;
120
+ return node.params.findIndex((parameter) => rangeContains(range(parameter), location));
121
+ };
122
+ const rangeContains = (outer, inner) => (outer.start.line < inner.start.line ||
123
+ (outer.start.line === inner.start.line &&
124
+ outer.start.column <= inner.start.column)) &&
125
+ (outer.end.line > inner.end.line ||
126
+ (outer.end.line === inner.end.line &&
127
+ outer.end.column >= inner.end.column));
128
+ const nestedContext = (context) => ({ ...context, depth: context.depth + 1 });
129
+ const uniqueCallableIds = (values) => [...new Set(values)].sort(compareCodePoints);