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,15 @@
1
+ const OWNERSHIP_RELATIONS = new Set([
2
+ "acquires",
3
+ "aggregates",
4
+ "awaits",
5
+ "chains",
6
+ "connects-stdio",
7
+ "creates-promise",
8
+ "detaches-task",
9
+ "owns",
10
+ "releases",
11
+ "returns-task",
12
+ "spawns",
13
+ ]);
14
+ /** Whether one relation participates in bidirectional ownership traversal. */
15
+ export const isJavaScriptSemanticOwnershipRelation = (relation) => OWNERSHIP_RELATIONS.has(relation);
@@ -0,0 +1,188 @@
1
+ import { z } from "zod";
2
+ import { JAVASCRIPT_SEMANTIC_NODE_KINDS, JAVASCRIPT_SEMANTIC_RELATIONS, javaScriptSemanticNodeSchema, javaScriptSemanticRelationSchema, javaScriptSemanticUnknownSchema, } from "./javascriptSemanticGraphSchemas.js";
3
+ import { jsonValueSchema } from "./jsonValue.js";
4
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
5
+ const semanticNodeIdSchema = z.string().regex(/^jsrg_node_[a-f0-9]{64}$/u);
6
+ const literalSeedSchema = z.strictObject({
7
+ kind: z.literal("literal"),
8
+ value: jsonValueSchema.refine((value) => value === null ||
9
+ typeof value === "string" ||
10
+ typeof value === "number" ||
11
+ typeof value === "boolean", "Literal seeds accept only JSON primitive values"),
12
+ });
13
+ /** Authenticated starting points accepted by semantic tracing. */
14
+ export const javaScriptSemanticQuerySeedSchema = z.discriminatedUnion("kind", [
15
+ z.strictObject({
16
+ kind: z.literal("semantic-node"),
17
+ node_id: semanticNodeIdSchema,
18
+ }),
19
+ z.strictObject({
20
+ kind: z.literal("application-node"),
21
+ node_id: z.string().regex(/^jag_node_[a-f0-9]{64}$/u),
22
+ }),
23
+ literalSeedSchema,
24
+ z.strictObject({
25
+ kind: z.literal("function"),
26
+ fingerprint_sha256: digestSchema,
27
+ }),
28
+ z.strictObject({
29
+ kind: z.literal("property"),
30
+ name: z.string().min(1).max(4_096),
31
+ }),
32
+ z.strictObject({
33
+ kind: z.literal("endpoint"),
34
+ value: z.string().min(1).max(16_384),
35
+ }),
36
+ z.strictObject({
37
+ kind: z.literal("event"),
38
+ name: z.string().min(1).max(4_096),
39
+ }),
40
+ z.strictObject({
41
+ kind: z.literal("boundary-field"),
42
+ field: z.string().min(1).max(4_096),
43
+ }),
44
+ ]);
45
+ /** Strict caller limits for deterministic bounded traversal. */
46
+ export const javaScriptSemanticQueryLimitsSchema = z.strictObject({
47
+ max_seed_matches: z.number().int().min(1).max(1_000).default(25),
48
+ max_nodes: z.number().int().min(1).max(50_000).default(2_000),
49
+ max_edges: z.number().int().min(1).max(100_000).default(4_000),
50
+ max_depth: z.number().int().min(0).max(64).default(12),
51
+ max_functions: z.number().int().min(1).max(10_000).default(500),
52
+ max_modules: z.number().int().min(1).max(10_000).default(500),
53
+ max_unknowns: z.number().int().min(0).max(10_000).default(1_000),
54
+ page_size: z.number().int().min(1).max(1_000).default(200),
55
+ });
56
+ const sourceMapAuthoritySchema = z.strictObject({
57
+ authority: z.literal("none"),
58
+ });
59
+ /** Parsed pure-domain query over one authenticated companion graph. */
60
+ export const javaScriptSemanticQueryInputSchema = z.strictObject({
61
+ seed: javaScriptSemanticQuerySeedSchema,
62
+ direction: z.enum([
63
+ "backward-provenance",
64
+ "forward-influence",
65
+ "callers",
66
+ "ownership",
67
+ ]),
68
+ allowed_relations: z
69
+ .array(z.enum(JAVASCRIPT_SEMANTIC_RELATIONS))
70
+ .min(1)
71
+ .max(JAVASCRIPT_SEMANTIC_RELATIONS.length)
72
+ .optional(),
73
+ include_ambiguous_dynamic_edges: z.boolean().default(false),
74
+ expected: z
75
+ .strictObject({
76
+ role: z.enum(["source", "sink"]),
77
+ classes: z.array(z.enum(JAVASCRIPT_SEMANTIC_NODE_KINDS)).min(1).max(24),
78
+ })
79
+ .nullable()
80
+ .default(null),
81
+ source_map_authority: sourceMapAuthoritySchema.default({ authority: "none" }),
82
+ limits: javaScriptSemanticQueryLimitsSchema.default({
83
+ max_seed_matches: 25,
84
+ max_nodes: 2_000,
85
+ max_edges: 4_000,
86
+ max_depth: 12,
87
+ max_functions: 500,
88
+ max_modules: 500,
89
+ max_unknowns: 1_000,
90
+ page_size: 200,
91
+ }),
92
+ cursor: z
93
+ .string()
94
+ .regex(/^jsrqc_[0-9]+_[a-f0-9]{64}$/u)
95
+ .nullable()
96
+ .default(null),
97
+ });
98
+ const queryFrontierSchema = z.strictObject({
99
+ node_id: semanticNodeIdSchema,
100
+ depth: z.number().int().min(0).max(65),
101
+ reason: z.enum([
102
+ "max-depth",
103
+ "max-edges",
104
+ "max-functions",
105
+ "max-modules",
106
+ "max-nodes",
107
+ "max-seed-matches",
108
+ ]),
109
+ });
110
+ /** Deterministic, pageable semantic trace result. */
111
+ export const javaScriptSemanticQueryResultSchema = z.strictObject({
112
+ schema_version: z.literal(1),
113
+ query_id: z.string().regex(/^jsrq_[a-f0-9]{64}$/u),
114
+ source_graph_id: z.string().regex(/^jsrg_[a-f0-9]{64}$/u),
115
+ seed: javaScriptSemanticQuerySeedSchema,
116
+ direction: javaScriptSemanticQueryInputSchema.shape.direction,
117
+ status: z.enum([
118
+ "found",
119
+ "no-match",
120
+ "ambiguous",
121
+ "partial",
122
+ "truncated",
123
+ "unsupported",
124
+ ]),
125
+ seed_node_ids: z.array(semanticNodeIdSchema).max(1_000),
126
+ nodes: z.array(javaScriptSemanticNodeSchema).max(3_000),
127
+ relations: z.array(javaScriptSemanticRelationSchema).max(1_000),
128
+ unknowns: z.array(javaScriptSemanticUnknownSchema).max(100_000),
129
+ expected_match_node_ids: z.array(semanticNodeIdSchema).max(50_000),
130
+ summary: z.strictObject({
131
+ total_seed_matches: z.number().int().min(0),
132
+ retained_seed_matches: z.number().int().min(0),
133
+ traversed_nodes: z.number().int().min(0),
134
+ traversed_relations: z.number().int().min(0),
135
+ traversed_functions: z.number().int().min(0),
136
+ traversed_modules: z.number().int().min(0),
137
+ relevant_unknowns: z.number().int().min(0),
138
+ retained_unknowns: z.number().int().min(0).max(10_000),
139
+ }),
140
+ coverage: z.strictObject({
141
+ status: z.enum(["complete", "partial", "truncated", "unavailable"]),
142
+ frontier: z.array(queryFrontierSchema).max(100_000),
143
+ }),
144
+ page: z.strictObject({
145
+ offset: z.number().int().min(0),
146
+ size: z.number().int().min(0).max(1_000),
147
+ next_cursor: z
148
+ .string()
149
+ .regex(/^jsrqc_[0-9]+_[a-f0-9]{64}$/u)
150
+ .nullable(),
151
+ }),
152
+ applied_limits: javaScriptSemanticQueryLimitsSchema,
153
+ accepted_limit_ranges: z.strictObject({
154
+ max_seed_matches: z.strictObject({
155
+ minimum: z.literal(1),
156
+ maximum: z.literal(1_000),
157
+ }),
158
+ max_nodes: z.strictObject({
159
+ minimum: z.literal(1),
160
+ maximum: z.literal(50_000),
161
+ }),
162
+ max_edges: z.strictObject({
163
+ minimum: z.literal(1),
164
+ maximum: z.literal(100_000),
165
+ }),
166
+ max_depth: z.strictObject({
167
+ minimum: z.literal(0),
168
+ maximum: z.literal(64),
169
+ }),
170
+ max_functions: z.strictObject({
171
+ minimum: z.literal(1),
172
+ maximum: z.literal(10_000),
173
+ }),
174
+ max_modules: z.strictObject({
175
+ minimum: z.literal(1),
176
+ maximum: z.literal(10_000),
177
+ }),
178
+ max_unknowns: z.strictObject({
179
+ minimum: z.literal(0),
180
+ maximum: z.literal(10_000),
181
+ }),
182
+ page_size: z.strictObject({
183
+ minimum: z.literal(1),
184
+ maximum: z.literal(1_000),
185
+ }),
186
+ }),
187
+ limitations: z.array(z.string().min(1).max(4_096)).max(1_000),
188
+ });
@@ -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) || property.computed) {
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
- markLimit(context.state, "maxObjectProperties");
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 { status: "object", properties, unknownProperties };
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 (element === null || t.isSpreadElement(element)) {
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
- markLimit(context.state, "maxObjectProperties");
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 provenance("cycle", [], `Alias cycle at ${binding.name}.`);
233
+ return semanticProvenance("cycle", [], `Alias cycle at ${binding.name}.`);
203
234
  if (context.depth >= context.state.limits.maxValueDepth)
204
- return limitProvenance(context.state, "maxValueDepth");
235
+ return semanticLimitProvenance(context.state, "maxValueDepth");
205
236
  if (binding.directOrigins.length > 0)
206
- return originsProvenance(binding.directOrigins, context.state);
237
+ return semanticOriginsProvenance(binding.directOrigins, context.state);
207
238
  if (binding.initializers.length === 0)
208
- return provenance("local", [], null);
239
+ return semanticProvenance("local", [], null);
209
240
  if (binding.initializers.length > 1)
210
- return provenance("ambiguous", [], `Binding ${binding.name} has multiple possible assignments.`);
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 provenance("unknown", [], "Missing binding initializer.");
244
+ return semanticProvenance("unknown", [], "Missing binding initializer.");
214
245
  if (initializer.projection.includes(null))
215
- return provenance("unknown", [], "Dynamic provenance projection.");
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 originsProvenance(resolved.origins.map((origin) => ({
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 originsProvenance([required], context.state);
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
- ? provenance("unknown", [], `Unbound identifier ${node.name}.`)
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 provenance("unknown", [], "Unsupported member base.");
270
+ return semanticProvenance("unknown", [], "Unsupported member base.");
240
271
  const member = memberKey(node);
241
272
  if (typeof member !== "string")
242
- return provenance("unknown", [], "Dynamic provenance member.");
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
- : originsProvenance(base.origins.map((origin) => ({
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
- ? provenance("ambiguous", uniqueOrigins(origins), "Multiple module origins.")
261
- : provenance("unknown", [], "Conditional provenance is unresolved.");
291
+ ? semanticProvenance("ambiguous", uniqueSemanticOrigins(origins), "Multiple module origins.")
292
+ : semanticProvenance("unknown", [], "Conditional provenance is unresolved.");
262
293
  }
263
- return provenance("local", [], null);
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
- markLimit(state, limit);
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")}`;