rea-agents 2.1.0 → 2.3.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 (193) hide show
  1. package/README.md +84 -18
  2. package/dist/application/AndroidApplicationService.js +17 -0
  3. package/dist/application/AppleApplicationService.js +17 -0
  4. package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
  5. package/dist/application/BinarySession.js +9 -2
  6. package/dist/application/BinarySessionStatus.js +39 -1
  7. package/dist/application/CapabilityInventory.js +15 -0
  8. package/dist/application/ClientRegistrationStatus.js +11 -4
  9. package/dist/application/CommandShimReplay.js +6 -3
  10. package/dist/application/CompositeProvider.js +5 -2
  11. package/dist/application/DirectAnalysis.js +1 -20
  12. package/dist/application/DirectAnalysisStatus.js +83 -0
  13. package/dist/application/Doctor.js +34 -25
  14. package/dist/application/DoctorDiagnostics.js +1 -4
  15. package/dist/application/DoctorProjection.js +43 -0
  16. package/dist/application/DoctorScope.js +102 -0
  17. package/dist/application/EvidenceReferenceResolver.js +26 -0
  18. package/dist/application/InventoryProjectionEvidence.js +41 -0
  19. package/dist/application/InvestigationProviders.js +12 -0
  20. package/dist/application/JavaScriptApplicationEvidence.js +1 -1
  21. package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
  22. package/dist/application/JavaScriptApplicationService.js +3 -2
  23. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
  24. package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
  25. package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
  26. package/dist/application/JavaScriptModuleRelationships.js +25 -1
  27. package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
  28. package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
  29. package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
  30. package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
  31. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
  32. package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
  33. package/dist/application/JavaScriptSemanticTraceService.js +45 -0
  34. package/dist/application/LoopbackReplay.js +277 -133
  35. package/dist/application/LoopbackReplayRecorder.js +101 -0
  36. package/dist/application/PermissionAuthority.js +7 -3
  37. package/dist/application/ProcessCaptureJournal.js +95 -0
  38. package/dist/application/ProcessCaptureLifecycle.js +24 -13
  39. package/dist/application/ProcessCheckpoints.js +30 -4
  40. package/dist/application/ProcessCli.js +26 -4
  41. package/dist/application/ProcessHarness.js +20 -50
  42. package/dist/application/ProcessNormalization.js +3 -2
  43. package/dist/application/ProcessPairedExperiment.js +72 -0
  44. package/dist/application/ProcessReactiveCoordinator.js +218 -0
  45. package/dist/application/ProcessReactiveEffects.js +133 -0
  46. package/dist/application/ProcessReactiveObservations.js +20 -0
  47. package/dist/application/ProcessSampling.js +2 -0
  48. package/dist/application/SessionProviderRouter.js +7 -6
  49. package/dist/application/Setup.js +14 -13
  50. package/dist/application/SetupClientConfiguration.js +10 -6
  51. package/dist/application/SetupPlan.js +4 -3
  52. package/dist/application/SetupRegistrationEnvironment.js +12 -0
  53. package/dist/application/SetupSkill.js +44 -40
  54. package/dist/application/TerminalRenderer.js +3 -1
  55. package/dist/application/Uninstall.js +7 -1
  56. package/dist/application/Upgrade.js +16 -1
  57. package/dist/browser/CdpEndpoint.js +37 -4
  58. package/dist/catalogIdentity.js +16 -7
  59. package/dist/cli/coreAnalysisCommands.js +34 -2
  60. package/dist/cli/javascriptApplicationAnalysis.js +19 -0
  61. package/dist/cli/setupCommands.js +84 -30
  62. package/dist/cli/utilityCommands.js +10 -2
  63. package/dist/cliApplicationCommands.js +79 -16
  64. package/dist/cliCommandNames.js +3 -0
  65. package/dist/cliElectronCommands.js +23 -33
  66. package/dist/cliObservationOptions.js +1 -1
  67. package/dist/cliOutput.js +56 -0
  68. package/dist/cliProcessCommands.js +32 -1
  69. package/dist/cliSetup.js +55 -29
  70. package/dist/contracts/applicationToolContracts.js +54 -7
  71. package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
  72. package/dist/contracts/electronToolContracts.js +73 -4
  73. package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
  74. package/dist/contracts/managedToolContracts.js +7 -2
  75. package/dist/contracts/processCaptureExample.js +1 -0
  76. package/dist/contracts/replayMachineExample.js +37 -0
  77. package/dist/contracts/sessionStatusContract.js +26 -0
  78. package/dist/contracts/toolContractExamples.js +2 -0
  79. package/dist/contracts/toolContractTypes.js +12 -1
  80. package/dist/contracts/toolContracts.js +8 -11
  81. package/dist/contracts/toolEffects.js +3 -0
  82. package/dist/contracts/toolOutputSchemaGroups.js +53 -9
  83. package/dist/contracts/toolOutputSchemaPrimitives.js +73 -32
  84. package/dist/doctorRuntime.js +41 -0
  85. package/dist/domain/analysisErrorPresentation.js +5 -3
  86. package/dist/domain/analysisErrorProjection.js +7 -1
  87. package/dist/domain/androidApplication.js +206 -0
  88. package/dist/domain/appleApplication.js +221 -0
  89. package/dist/domain/boundedCartesianProjection.js +15 -0
  90. package/dist/domain/changedBehavior.js +5 -4
  91. package/dist/domain/completionLedgerGeneration.js +190 -0
  92. package/dist/domain/errors.js +4 -2
  93. package/dist/domain/evidenceCompletionLedger.js +113 -0
  94. package/dist/domain/hopperStartupFailure.js +9 -0
  95. package/dist/domain/javascriptApplicationAnalysis.js +44 -2
  96. package/dist/domain/javascriptExportShapeComparison.js +145 -0
  97. package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
  98. package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
  99. package/dist/domain/javascriptExportShapeSelection.js +132 -0
  100. package/dist/domain/javascriptExportShapeVariants.js +272 -0
  101. package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
  102. package/dist/domain/javascriptSemanticAnalysis.js +17 -36
  103. package/dist/domain/javascriptSemanticCallResolution.js +129 -0
  104. package/dist/domain/javascriptSemanticCalls.js +269 -0
  105. package/dist/domain/javascriptSemanticGraph.js +356 -0
  106. package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
  107. package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
  108. package/dist/domain/javascriptSemanticIr.js +14 -1
  109. package/dist/domain/javascriptSemanticPrimitives.js +36 -0
  110. package/dist/domain/javascriptSemanticProjection.js +36 -4
  111. package/dist/domain/javascriptSemanticProvenance.js +29 -0
  112. package/dist/domain/javascriptSemanticQuery.js +294 -0
  113. package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
  114. package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
  115. package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
  116. package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
  117. package/dist/domain/javascriptSemanticReturns.js +187 -0
  118. package/dist/domain/javascriptSemanticState.js +32 -0
  119. package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
  120. package/dist/domain/javascriptSemanticValues.js +54 -70
  121. package/dist/domain/processCapture.js +36 -0
  122. package/dist/domain/processCaptureValidation.js +101 -12
  123. package/dist/domain/processComparison.js +96 -24
  124. package/dist/domain/processObservation.js +153 -0
  125. package/dist/domain/processPairedExperiment.js +128 -0
  126. package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
  127. package/dist/domain/processReactiveMatching.js +210 -0
  128. package/dist/domain/processReactiveRuntime.js +109 -0
  129. package/dist/domain/processReactiveScenario.js +361 -0
  130. package/dist/domain/processReactiveScenarioPreflight.js +120 -0
  131. package/dist/domain/processReactiveTransition.js +159 -0
  132. package/dist/domain/processScenario.js +12 -0
  133. package/dist/domain/processTraceComparison.js +43 -0
  134. package/dist/domain/processTraceDimensionProjection.js +50 -0
  135. package/dist/domain/processTraceEvaluation.js +312 -0
  136. package/dist/domain/processTraceSpecification.js +373 -0
  137. package/dist/domain/reconstructionVerification.js +5 -4
  138. package/dist/domain/replayMachine.js +332 -0
  139. package/dist/domain/replayMachineRun.js +216 -0
  140. package/dist/domain/replayMachineRuntime.js +294 -0
  141. package/dist/domain/runtimeIdentification.js +210 -0
  142. package/dist/domain/staticRuntimeCorrelation.js +4 -2
  143. package/dist/evaluation/CodexAgentEval.js +156 -0
  144. package/dist/generatedPackageMetadata.js +2 -2
  145. package/dist/ghidra/GhidraClient.js +13 -2
  146. package/dist/ghidra/GhidraDiagnostics.js +1 -0
  147. package/dist/ghidra/GhidraLauncher.js +7 -3
  148. package/dist/ghidra/GhidraProvider.js +8 -1
  149. package/dist/hopper/BridgeLauncher.js +56 -14
  150. package/dist/hopper/HopperClient.js +23 -10
  151. package/dist/hopper/HopperDiagnostics.js +14 -0
  152. package/dist/hopper/HopperProcessDiagnostic.js +14 -0
  153. package/dist/hopper/HopperProvider.js +8 -1
  154. package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
  155. package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
  156. package/dist/identity.js +2 -1
  157. package/dist/main/transport.js +2 -0
  158. package/dist/mcpDoctor.js +310 -0
  159. package/dist/process/ProcessOwnership.js +200 -53
  160. package/dist/process/ProviderRunLineage.js +21 -0
  161. package/dist/server/createServer.js +8 -2
  162. package/dist/server/javascriptApplicationResult.js +106 -0
  163. package/dist/server/registerApplicationTools/characterization.js +3 -3
  164. package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
  165. package/dist/server/registerApplicationTools/compareVersions.js +12 -6
  166. package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
  167. package/dist/server/registerApplicationTools/coverage.js +3 -3
  168. package/dist/server/registerApplicationTools/helpers.js +37 -25
  169. package/dist/server/registerApplicationTools/traceFeature.js +9 -5
  170. package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
  171. package/dist/server/registerApplicationTools.js +4 -0
  172. package/dist/server/registerElectronTools.js +19 -5
  173. package/dist/server/registerEvidenceResources.js +7 -1
  174. package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
  175. package/dist/server/registerManagedTools.js +18 -1
  176. package/dist/server/registerProcessComparisonTool.js +17 -7
  177. package/dist/server/registerReplayMachineTool.js +20 -0
  178. package/dist/server/registerSessionStatusTool.js +95 -25
  179. package/dist/server/registerSessionTools.js +12 -7
  180. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  181. package/dist/server/toolResult.js +10 -4
  182. package/dist/serverIdentity.js +19 -0
  183. package/package.json +62 -29
  184. package/scripts/hopper-demo-x11.py +459 -61
  185. package/scripts/prepack.mjs +55 -0
  186. package/scripts/prepare.mjs +28 -0
  187. package/scripts/rea.mjs +26 -5
  188. package/skills/reverse-engineer-anything/SKILL.md +69 -228
  189. package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
  190. package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
  191. package/skills/reverse-engineer-anything/references/javascript-applications.md +35 -0
  192. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
  193. package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
@@ -0,0 +1,277 @@
1
+ import { z } from "zod";
2
+ import { evidenceSchema } from "./evidence.js";
3
+ const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
4
+ const graphIdSchema = z.string().regex(/^jag_[a-f0-9]{64}$/u);
5
+ const nodeIdSchema = z.string().regex(/^jag_node_[a-f0-9]{64}$/u);
6
+ const boundedTextSchema = z.string().min(1).max(4_096);
7
+ const selectorTextSchema = z.string().min(1).max(4_096);
8
+ const semanticPrimitiveSchema = z.union([
9
+ z.string().max(4_096),
10
+ z.number().finite(),
11
+ z.boolean(),
12
+ z.null(),
13
+ ]);
14
+ function isJsonPointer(value) {
15
+ if (value === "")
16
+ return true;
17
+ if (!value.startsWith("/"))
18
+ return false;
19
+ for (let index = 0; index < value.length; index += 1) {
20
+ if (value[index] !== "~")
21
+ continue;
22
+ const escaped = value[index + 1];
23
+ if (escaped !== "0" && escaped !== "1")
24
+ return false;
25
+ index += 1;
26
+ }
27
+ return true;
28
+ }
29
+ const jsonPointerSchema = z
30
+ .string()
31
+ .max(4_096)
32
+ .refine(isJsonPointer, "Expected an RFC 6901 JSON Pointer");
33
+ const sourcePointSchema = z.strictObject({
34
+ line: z.number().int().min(1),
35
+ column: z.number().int().min(0),
36
+ });
37
+ const sourceRangeSchema = z
38
+ .strictObject({
39
+ start: sourcePointSchema,
40
+ end: sourcePointSchema,
41
+ })
42
+ .superRefine((range, context) => {
43
+ if (range.end.line < range.start.line ||
44
+ (range.end.line === range.start.line &&
45
+ range.end.column < range.start.column))
46
+ context.addIssue({
47
+ code: "custom",
48
+ path: ["end"],
49
+ message: "Source range end must not precede its start",
50
+ });
51
+ });
52
+ const comparisonLimitsSchema = z.strictObject({
53
+ max_candidate_exports: z.number().int().min(1).max(1_000).default(100),
54
+ max_return_variants: z.number().int().min(1).max(1_000).default(128),
55
+ max_changes: z.number().int().min(1).max(10_000).default(1_000),
56
+ });
57
+ /** Two authenticated application graphs, exact export selectors, and bounds. */
58
+ export const compareJavaScriptExportShapesInputSchema = z
59
+ .strictObject({
60
+ left: evidenceSchema,
61
+ right: evidenceSchema,
62
+ left_module_path: selectorTextSchema,
63
+ left_export_name: selectorTextSchema,
64
+ right_module_path: selectorTextSchema,
65
+ right_export_name: selectorTextSchema,
66
+ limits: comparisonLimitsSchema.default({
67
+ max_candidate_exports: 100,
68
+ max_return_variants: 128,
69
+ max_changes: 1_000,
70
+ }),
71
+ unknown_registry_approved: z.literal(true).optional(),
72
+ })
73
+ .superRefine((input, context) => {
74
+ if (input.left.evidence_id === input.right.evidence_id)
75
+ context.addIssue({
76
+ code: "custom",
77
+ path: ["right"],
78
+ message: "JavaScript export shape Evidence must be distinct",
79
+ });
80
+ });
81
+ const projectedReturnFieldSchema = z
82
+ .strictObject({
83
+ path: jsonPointerSchema,
84
+ state: z.enum(["literal", "union", "unknown"]),
85
+ value: z.union([
86
+ semanticPrimitiveSchema,
87
+ z.array(semanticPrimitiveSchema).min(1).max(32),
88
+ ]),
89
+ reason: boundedTextSchema.nullable(),
90
+ })
91
+ .superRefine((field, context) => {
92
+ if (field.state === "union" && !Array.isArray(field.value))
93
+ context.addIssue({
94
+ code: "custom",
95
+ path: ["value"],
96
+ message: "Union return fields require a primitive value array",
97
+ });
98
+ if (field.state !== "union" && Array.isArray(field.value))
99
+ context.addIssue({
100
+ code: "custom",
101
+ path: ["value"],
102
+ message: "Only union return fields may contain a value array",
103
+ });
104
+ if (field.state === "unknown" && field.reason === null)
105
+ context.addIssue({
106
+ code: "custom",
107
+ path: ["reason"],
108
+ message: "Unknown return fields require a reason",
109
+ });
110
+ if (field.state !== "unknown" && field.reason !== null)
111
+ context.addIssue({
112
+ code: "custom",
113
+ path: ["reason"],
114
+ message: "Known return fields cannot carry an unknown reason",
115
+ });
116
+ });
117
+ const projectedPropertyCoverageSchema = z.strictObject({
118
+ path: jsonPointerSchema,
119
+ status: z.enum(["complete", "partial"]),
120
+ omitted: z.number().int().min(0).nullable(),
121
+ });
122
+ const projectedReturnShapeSchema = z
123
+ .strictObject({
124
+ source_range: sourceRangeSchema,
125
+ value_status: z.enum([
126
+ "literal",
127
+ "union",
128
+ "object",
129
+ "array",
130
+ "unknown",
131
+ "ambiguous",
132
+ "cycle",
133
+ "limit-reached",
134
+ ]),
135
+ fields: z.array(projectedReturnFieldSchema).max(64),
136
+ property_coverage: z.array(projectedPropertyCoverageSchema).max(64),
137
+ })
138
+ .superRefine((shape, context) => {
139
+ const fieldPaths = shape.fields.map(({ path }) => path);
140
+ if (new Set(fieldPaths).size !== fieldPaths.length)
141
+ context.addIssue({
142
+ code: "custom",
143
+ path: ["fields"],
144
+ message: "Projected return field paths must be unique",
145
+ });
146
+ const coveragePaths = shape.property_coverage.map(({ path }) => path);
147
+ if (new Set(coveragePaths).size !== coveragePaths.length)
148
+ context.addIssue({
149
+ code: "custom",
150
+ path: ["property_coverage"],
151
+ message: "Projected property coverage paths must be unique",
152
+ });
153
+ });
154
+ /** Strict graph-observation payload produced by static return-shape recovery. */
155
+ export const projectedExportReturnShapesSchema = z
156
+ .strictObject({
157
+ semantic_role: z.literal("export-return-shapes"),
158
+ module_path: selectorTextSchema,
159
+ exported_name: selectorTextSchema,
160
+ callable_id: boundedTextSchema,
161
+ callable_kind: z.enum(["function", "class", "method"]),
162
+ static_return_shapes: z.array(projectedReturnShapeSchema).max(32),
163
+ return_shape_coverage: z.strictObject({
164
+ status: z.enum(["complete", "partial", "truncated"]),
165
+ retained_return_sites: z.number().int().min(0).max(32),
166
+ omitted_return_sites: z.number().int().min(0).nullable(),
167
+ omitted_fields: z.number().int().min(0),
168
+ omitted_property_coverage: z.number().int().min(0),
169
+ projection_complete: z.boolean(),
170
+ }),
171
+ })
172
+ .superRefine((projection, context) => {
173
+ if (projection.return_shape_coverage.retained_return_sites !==
174
+ projection.static_return_shapes.length)
175
+ context.addIssue({
176
+ code: "custom",
177
+ path: ["return_shape_coverage", "retained_return_sites"],
178
+ message: "Retained return-site count must match projected shapes",
179
+ });
180
+ });
181
+ const exportCandidateSchema = z.strictObject({
182
+ node_id: nodeIdSchema,
183
+ module_path: selectorTextSchema,
184
+ export_name: selectorTextSchema,
185
+ matches_requested_module: z.boolean(),
186
+ matches_requested_export: z.boolean(),
187
+ });
188
+ const selectorResultSchema = z.strictObject({
189
+ evidence_id: evidenceIdSchema,
190
+ graph_id: graphIdSchema,
191
+ requested_module_path: selectorTextSchema,
192
+ requested_export_name: selectorTextSchema,
193
+ status: z.enum(["selected", "missing", "ambiguous", "unavailable"]),
194
+ selected_node_id: nodeIdSchema.nullable(),
195
+ candidates: z.array(exportCandidateSchema).max(1_000),
196
+ omitted_candidates: z.number().int().min(0),
197
+ });
198
+ const valueAvailabilitySchema = z.discriminatedUnion("availability", [
199
+ z.strictObject({ availability: z.literal("absent") }),
200
+ z.strictObject({
201
+ availability: z.literal("literal"),
202
+ value: semanticPrimitiveSchema,
203
+ }),
204
+ z.strictObject({
205
+ availability: z.literal("union"),
206
+ values: z.array(semanticPrimitiveSchema).min(1).max(32),
207
+ }),
208
+ z.strictObject({
209
+ availability: z.literal("unknown"),
210
+ reason: boundedTextSchema,
211
+ }),
212
+ ]);
213
+ const discriminantSchema = z.strictObject({
214
+ path: jsonPointerSchema,
215
+ value: semanticPrimitiveSchema,
216
+ });
217
+ const comparisonChangeSchema = z.strictObject({
218
+ change_id: z.string().regex(/^jesc_change_[a-f0-9]{64}$/u),
219
+ status: z.enum(["added", "removed", "changed", "unknown"]),
220
+ path: jsonPointerSchema,
221
+ discriminant: discriminantSchema.nullable(),
222
+ left: valueAvailabilitySchema,
223
+ right: valueAvailabilitySchema,
224
+ left_source_range: sourceRangeSchema.nullable(),
225
+ right_source_range: sourceRangeSchema.nullable(),
226
+ evidence_links: z.tuple([evidenceIdSchema, evidenceIdSchema]),
227
+ limitations: z.array(boundedTextSchema).max(20),
228
+ });
229
+ /** Bounded static export-return comparison with explicit unknown semantics. */
230
+ export const javaScriptExportShapeComparisonResultSchema = z.strictObject({
231
+ schema_version: z.literal(1),
232
+ comparison_id: z.string().regex(/^jesc_[a-f0-9]{64}$/u),
233
+ left: selectorResultSchema,
234
+ right: selectorResultSchema,
235
+ summary: z.strictObject({
236
+ added: z.number().int().min(0),
237
+ removed: z.number().int().min(0),
238
+ changed: z.number().int().min(0),
239
+ unknown: z.number().int().min(0),
240
+ }),
241
+ changes: z.array(comparisonChangeSchema).max(10_000),
242
+ coverage: z.strictObject({
243
+ status: z.enum(["complete-within-inputs", "partial", "truncated"]),
244
+ left_graph_status: z.enum([
245
+ "complete",
246
+ "partial",
247
+ "unknown",
248
+ "unavailable",
249
+ ]),
250
+ right_graph_status: z.enum([
251
+ "complete",
252
+ "partial",
253
+ "unknown",
254
+ "unavailable",
255
+ ]),
256
+ paired_variants: z.number().int().min(0),
257
+ unpaired_left_variants: z.number().int().min(0),
258
+ unpaired_right_variants: z.number().int().min(0),
259
+ omitted_left_variants: z.number().int().min(0),
260
+ omitted_right_variants: z.number().int().min(0),
261
+ left_source_omitted_variants: z.number().int().min(0).nullable(),
262
+ right_source_omitted_variants: z.number().int().min(0).nullable(),
263
+ left_omitted_fields: z.number().int().min(0),
264
+ right_omitted_fields: z.number().int().min(0),
265
+ left_omitted_property_coverage: z.number().int().min(0),
266
+ right_omitted_property_coverage: z.number().int().min(0),
267
+ omitted_candidates: z.number().int().min(0),
268
+ omitted_changes: z.number().int().min(0),
269
+ }),
270
+ evidence_links: z.tuple([evidenceIdSchema, evidenceIdSchema]),
271
+ limitations: z.array(boundedTextSchema).max(1_000),
272
+ runtime_validation: z.strictObject({
273
+ recommended_tool: z.literal("run_controlled_replay"),
274
+ automatically_started: z.literal(false),
275
+ required_for: z.literal("runtime-semantics"),
276
+ }),
277
+ });
@@ -0,0 +1,132 @@
1
+ import { compareCodePoints } from "./javascriptApplicationGraph.js";
2
+ import { projectedExportReturnShapesSchema, } from "./javascriptExportShapeComparisonSchemas.js";
3
+ /** Select one exact trusted export and its exact static return-shape observation. */
4
+ export const selectJavaScriptExport = (side, maxCandidates) => {
5
+ const candidates = exportCandidates(side.graph);
6
+ const exact = candidates.filter(({ modulePath, exportName }) => modulePath === side.modulePath && exportName === side.exportName);
7
+ const matchingOneSelector = candidates.filter(({ modulePath, exportName }) => modulePath === side.modulePath || exportName === side.exportName);
8
+ const diagnosticPool = exact.length > 0
9
+ ? exact
10
+ : matchingOneSelector.length > 0
11
+ ? matchingOneSelector
12
+ : candidates;
13
+ const retainedCandidates = diagnosticPool.slice(0, maxCandidates);
14
+ const base = selectorBase(side, diagnosticPool, retainedCandidates);
15
+ if (exact.length === 0)
16
+ return unresolvedSelection(base, "missing", null, [
17
+ `No exact export binding matched ${side.modulePath}:${side.exportName}.`,
18
+ ]);
19
+ if (exact.length > 1)
20
+ return unresolvedSelection(base, "ambiguous", null, [
21
+ `Multiple exact export bindings matched ${side.modulePath}:${side.exportName}; none was selected.`,
22
+ ]);
23
+ const selected = exact[0];
24
+ if (selected === undefined || !selected.trusted)
25
+ return unresolvedSelection(base, "unavailable", selected?.node.node_id ?? null, [
26
+ "The exact export binding lacks the expected static-analysis authority.",
27
+ ]);
28
+ const returnShape = returnShapeFor(selected.node, side);
29
+ if (returnShape.projection === null)
30
+ return unresolvedSelection(base, "unavailable", selected.node.node_id, [
31
+ returnShape.reason,
32
+ ]);
33
+ return {
34
+ selection: {
35
+ ...base,
36
+ status: "selected",
37
+ selected_node_id: selected.node.node_id,
38
+ },
39
+ projection: returnShape.projection,
40
+ observationComplete: returnShape.observationComplete,
41
+ limitations: [],
42
+ };
43
+ };
44
+ /** Apply the caller's explicit return-variant limit. */
45
+ export const retainJavaScriptExportShapes = (selection, maximum) => {
46
+ const shapes = selection.projection?.static_return_shapes ?? [];
47
+ const retained = shapes.slice(0, maximum);
48
+ return { shapes: retained, omitted: shapes.length - retained.length };
49
+ };
50
+ const selectorBase = (side, candidates, retained) => ({
51
+ evidence_id: side.evidenceId,
52
+ graph_id: side.graph.graph_id,
53
+ requested_module_path: side.modulePath,
54
+ requested_export_name: side.exportName,
55
+ candidates: retained.map((candidate) => ({
56
+ node_id: candidate.node.node_id,
57
+ module_path: candidate.modulePath,
58
+ export_name: candidate.exportName,
59
+ matches_requested_module: candidate.modulePath === side.modulePath,
60
+ matches_requested_export: candidate.exportName === side.exportName,
61
+ })),
62
+ omitted_candidates: candidates.length - retained.length,
63
+ });
64
+ const unresolvedSelection = (base, status, nodeId, limitations) => ({
65
+ selection: { ...base, status, selected_node_id: nodeId },
66
+ projection: null,
67
+ observationComplete: false,
68
+ limitations,
69
+ });
70
+ const exportCandidates = (graph) => {
71
+ const candidates = new Map();
72
+ for (const node of graph.nodes) {
73
+ for (const observation of node.observations) {
74
+ const properties = observation.properties;
75
+ if (properties.semantic_role !== "export-binding")
76
+ continue;
77
+ const modulePath = properties.module_path;
78
+ const exportName = properties.exported_name;
79
+ if (typeof modulePath !== "string" || typeof exportName !== "string")
80
+ continue;
81
+ const key = `${node.node_id}\0${modulePath}\0${exportName}`;
82
+ const trusted = observation.evidence.authority === "ast-static-analysis" &&
83
+ observation.evidence.state === "observed" &&
84
+ observation.evidence.extractor.operation === "recover-module-export";
85
+ const existing = candidates.get(key);
86
+ candidates.set(key, {
87
+ node,
88
+ modulePath,
89
+ exportName,
90
+ trusted: trusted || existing?.trusted === true,
91
+ });
92
+ }
93
+ }
94
+ return [...candidates.values()].sort((left, right) => compareCodePoints(candidateKey(left), candidateKey(right)));
95
+ };
96
+ const candidateKey = (candidate) => `${candidate.modulePath}\0${candidate.exportName}\0${candidate.node.node_id}`;
97
+ const returnShapeFor = (node, side) => {
98
+ const roleObservations = node.observations.filter(({ properties }) => properties.semantic_role === "export-return-shapes");
99
+ const parsed = roleObservations.map((observation) => ({
100
+ observation,
101
+ result: projectedExportReturnShapesSchema.safeParse(observation.properties),
102
+ }));
103
+ if (parsed.some(({ result }) => !result.success))
104
+ return unavailableReturnShape("The export return-shape observation is malformed.");
105
+ const matching = parsed.filter(({ result }) => result.success &&
106
+ result.data.module_path === side.modulePath &&
107
+ result.data.exported_name === side.exportName);
108
+ if (matching.length !== 1)
109
+ return unavailableReturnShape(matching.length === 0
110
+ ? "No exact static return-shape observation is available for the selected export."
111
+ : "Multiple static return-shape observations matched the selected export.");
112
+ const selected = matching[0];
113
+ if (selected === undefined || !selected.result.success)
114
+ return unavailableReturnShape("The selected return-shape observation could not be parsed.");
115
+ const { observation } = selected;
116
+ const trusted = observation.evidence.authority === "static-relationship-inference" &&
117
+ observation.evidence.state === "inferred" &&
118
+ observation.evidence.extractor.operation === "recover-export-return-shapes";
119
+ if (!trusted)
120
+ return unavailableReturnShape("The return-shape observation lacks the expected static-inference authority.");
121
+ return {
122
+ projection: selected.result.data,
123
+ observationComplete: observation.evidence.coverage.status === "complete" &&
124
+ !observation.evidence.coverage.truncated,
125
+ reason: "",
126
+ };
127
+ };
128
+ const unavailableReturnShape = (reason) => ({
129
+ projection: null,
130
+ observationComplete: false,
131
+ reason,
132
+ });
@@ -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);