rea-agents 1.6.0 → 1.7.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 (119) hide show
  1. package/README.md +129 -45
  2. package/bridge/ghidra/ReaGhidraBridge.java +2075 -0
  3. package/bridge/hopper_bridge.py +13 -3
  4. package/dist/application/AbortablePromise.js +25 -0
  5. package/dist/application/AnalysisProvider.js +3 -0
  6. package/dist/application/AnalysisProviderEvaluation.js +60 -0
  7. package/dist/application/AnalysisProviderRegistry.js +228 -0
  8. package/dist/application/AnalysisSnapshotCache.js +41 -21
  9. package/dist/application/AnalysisSnapshotFiles.js +5 -6
  10. package/dist/application/BinarySession.js +218 -101
  11. package/dist/application/CompositeProvider.js +20 -8
  12. package/dist/application/DirectAnalysis.js +49 -35
  13. package/dist/application/Doctor.js +54 -2
  14. package/dist/application/EnhancedTools.js +1 -1
  15. package/dist/application/InvestigationProviders.js +11 -0
  16. package/dist/application/JavaScriptArtifactAnalysis.js +299 -0
  17. package/dist/application/JavaScriptArtifactAnalysisTypes.js +1 -0
  18. package/dist/application/JavaScriptArtifactFiles.js +231 -0
  19. package/dist/application/JavaScriptArtifactGraphAccumulator.js +54 -0
  20. package/dist/application/JavaScriptArtifactGraphBuilder.js +101 -0
  21. package/dist/application/JavaScriptArtifactGraphContext.js +205 -0
  22. package/dist/application/JavaScriptArtifactGraphDocuments.js +108 -0
  23. package/dist/application/JavaScriptArtifactGraphEvidence.js +89 -0
  24. package/dist/application/JavaScriptArtifactGraphFindings.js +271 -0
  25. package/dist/application/JavaScriptArtifactGraphStructure.js +409 -0
  26. package/dist/application/JavaScriptArtifactReconstruction.js +74 -0
  27. package/dist/application/JavaScriptArtifactReconstructionInput.js +99 -0
  28. package/dist/application/MacHopper.js +20 -4
  29. package/dist/application/ProcessCaptureLifecycle.js +1 -1
  30. package/dist/application/ProcessHarness.js +1 -1
  31. package/dist/application/ProcessSampling.js +1 -1
  32. package/dist/application/SessionProviderRouter.js +219 -0
  33. package/dist/application/Setup.js +84 -60
  34. package/dist/application/SetupClients.js +1 -1
  35. package/dist/application/SetupPlan.js +9 -2
  36. package/dist/application/SupportedClients.js +40 -16
  37. package/dist/application/Upgrade.js +1 -1
  38. package/dist/application/runtime.js +9 -6
  39. package/dist/artifacts/AsarArtifactReader.js +23 -3
  40. package/dist/browser/CdpBrowserProvider.js +4 -2
  41. package/dist/browser/CdpElectronProvider.js +4 -2
  42. package/dist/browser/CdpEndpoint.js +14 -1
  43. package/dist/catalogIdentity.js +2 -41
  44. package/dist/cli.js +58 -34
  45. package/dist/cliBrowserAdvancedCommands.js +5 -4
  46. package/dist/cliBrowserCommands.js +5 -4
  47. package/dist/cliCommandNames.js +43 -0
  48. package/dist/cliElectronCommands.js +3 -2
  49. package/dist/cliEvidenceCommands.js +4 -3
  50. package/dist/cliInvestigationCommands.js +2 -1
  51. package/dist/cliPolicyCommands.js +2 -1
  52. package/dist/cliProcessCommands.js +3 -2
  53. package/dist/config.js +18 -2
  54. package/dist/contracts/browserToolContracts.js +5 -5
  55. package/dist/contracts/electronToolContracts.js +3 -3
  56. package/dist/contracts/enhancedInputs.js +2 -2
  57. package/dist/contracts/providerSelection.js +28 -0
  58. package/dist/contracts/sessionLifecycleInputs.js +2 -0
  59. package/dist/contracts/toolContracts.js +22 -20
  60. package/dist/contracts/toolOutputSchemas.js +117 -22
  61. package/dist/doctorRuntime.js +6 -0
  62. package/dist/domain/analysisProfile.js +78 -0
  63. package/dist/domain/analysisSnapshot.js +92 -46
  64. package/dist/domain/artifactGraph.js +1 -0
  65. package/dist/domain/binaryTarget.js +4 -29
  66. package/dist/domain/errors.js +81 -6
  67. package/dist/domain/evidence.js +44 -5
  68. package/dist/domain/evidenceBundle.js +9 -7
  69. package/dist/domain/functionComparison.js +9 -3
  70. package/dist/domain/functionComparisonNormalization.js +37 -0
  71. package/dist/domain/functionDossierEvidence.js +4 -1
  72. package/dist/domain/hopperValues.js +66 -9
  73. package/dist/domain/investigationWorkspace.js +2 -1
  74. package/dist/domain/javascriptApplicationEvidenceSchemas.js +361 -0
  75. package/dist/domain/javascriptApplicationGraph.js +281 -0
  76. package/dist/domain/javascriptApplicationGraphSchemas.js +132 -0
  77. package/dist/domain/javascriptAstFingerprint.js +143 -0
  78. package/dist/domain/javascriptStaticAnalysis.js +358 -0
  79. package/dist/domain/javascriptStaticAnalysisHelpers.js +264 -0
  80. package/dist/domain/javascriptStaticAnalysisState.js +17 -0
  81. package/dist/domain/javascriptStaticAnalysisTypes.js +1 -0
  82. package/dist/generatedPackageMetadata.js +1 -1
  83. package/dist/ghidra/GhidraAnalysisProfile.js +37 -0
  84. package/dist/ghidra/GhidraClient.js +400 -0
  85. package/dist/ghidra/GhidraClientTypes.js +1 -0
  86. package/dist/ghidra/GhidraDefaults.js +20 -0
  87. package/dist/ghidra/GhidraDiagnostics.js +43 -0
  88. package/dist/ghidra/GhidraDoctor.js +59 -0
  89. package/dist/ghidra/GhidraFunctionValues.js +264 -0
  90. package/dist/ghidra/GhidraInstallation.js +239 -0
  91. package/dist/ghidra/GhidraInventoryValues.js +217 -0
  92. package/dist/ghidra/GhidraLauncher.js +139 -0
  93. package/dist/ghidra/GhidraProvider.js +360 -0
  94. package/dist/ghidra/GhidraRequestQueue.js +98 -0
  95. package/dist/ghidra/GhidraResponseBuffer.js +31 -0
  96. package/dist/ghidra/GhidraResponseRouter.js +24 -0
  97. package/dist/ghidra/GhidraSessionError.js +39 -0
  98. package/dist/ghidra/GhidraSessionValues.js +62 -0
  99. package/dist/ghidra/GhidraSocketConnection.js +46 -0
  100. package/dist/ghidra/protocol.js +69 -0
  101. package/dist/hopper/BridgeLauncher.js +19 -54
  102. package/dist/hopper/HopperAnalysisProfile.js +106 -0
  103. package/dist/hopper/HopperClient.js +154 -162
  104. package/dist/hopper/HopperProvider.js +99 -7
  105. package/dist/hopper/HopperSessionValues.js +27 -0
  106. package/dist/hopper/HopperSocketConnection.js +31 -0
  107. package/dist/native/NativeMacOSProvider.js +3 -1
  108. package/dist/process/PendingOperations.js +59 -0
  109. package/dist/process/PrivateRuntimeRoot.js +33 -0
  110. package/dist/process/ProviderDeadline.js +95 -0
  111. package/dist/process/ProviderProcess.js +275 -0
  112. package/dist/server/createServer.js +1 -0
  113. package/dist/server/promptCompletion.js +9 -3
  114. package/dist/server/registerEnhancedTools.js +9 -6
  115. package/dist/server/registerOfficialTools.js +3 -0
  116. package/dist/server/registerSessionTools.js +6 -1
  117. package/package.json +8 -6
  118. package/scripts/rea.mjs +35 -1
  119. /package/dist/{application → process}/ProcessOwnership.js +0 -0
@@ -0,0 +1,108 @@
1
+ import { addArtifactContainsEdge, addStaticInferenceEdge, createElectronRoleNode, resolveArtifactPath, } from "./JavaScriptArtifactGraphContext.js";
2
+ import { artifactObservationEvidence, completeReconstructionCoverage, partialReconstructionCoverage, } from "./JavaScriptArtifactGraphEvidence.js";
3
+ /** Project HTML renderer entrypoints and their local script assets. */
4
+ export const addJavaScriptHtmlRoles = (context) => {
5
+ const byHtml = new Map();
6
+ for (const script of context.analysis.html_scripts) {
7
+ const existing = byHtml.get(script.html_path);
8
+ byHtml.set(script.html_path, existing === undefined ? [script] : [...existing, script]);
9
+ }
10
+ for (const [htmlPath, scripts] of byHtml) {
11
+ const html = context.filesByPath.get(htmlPath);
12
+ if (html === undefined)
13
+ continue;
14
+ const role = createElectronRoleNode(context, {
15
+ kind: "electron-renderer",
16
+ anchor: html,
17
+ declaredPath: html.path,
18
+ resolvedPath: html.path,
19
+ mechanism: "html-script-entrypoint",
20
+ });
21
+ addArtifactContainsEdge(context, {
22
+ source: context.root,
23
+ target: role,
24
+ file: html,
25
+ operation: "discover-html-renderer",
26
+ });
27
+ for (const script of scripts) {
28
+ const resolvedPath = resolveArtifactPath(script.script_path, html.path, context.filesByPath);
29
+ if (resolvedPath === null)
30
+ continue;
31
+ const resolved = context.fileNodes.get(resolvedPath);
32
+ if (resolved === undefined)
33
+ continue;
34
+ addStaticInferenceEdge(context, {
35
+ source: role,
36
+ target: resolved,
37
+ file: html,
38
+ range: script.location,
39
+ coverage: completeReconstructionCoverage(),
40
+ relation: "loads",
41
+ properties: {
42
+ script_path: script.script_path,
43
+ resolved_path: resolvedPath,
44
+ },
45
+ });
46
+ }
47
+ }
48
+ };
49
+ /** Project original source names and optional content digests from approved maps. */
50
+ export const addJavaScriptSourceMapOriginals = (context) => {
51
+ for (const sourceMap of context.analysis.source_maps) {
52
+ const mapFile = context.filesByPath.get(sourceMap.path);
53
+ const mapNode = context.fileNodes.get(sourceMap.path);
54
+ if (mapFile === undefined || mapNode === undefined)
55
+ continue;
56
+ const coverage = sourceMap.status === "truncated"
57
+ ? partialReconstructionCoverage([
58
+ {
59
+ name: "max-source-map-sources",
60
+ value: context.input.limits.max_source_map_sources,
61
+ unit: "items",
62
+ },
63
+ ], sourceMap.omitted_sources, true)
64
+ : completeReconstructionCoverage();
65
+ for (const original of sourceMap.sources) {
66
+ const node = context.accumulator.addNode({
67
+ kind: "source-module",
68
+ identity: {
69
+ strategy: "source-map-original",
70
+ stability: "source-map-exact",
71
+ source_map_sha256: mapFile.sha256,
72
+ original_source: original.source,
73
+ source_sha256: original.content_sha256,
74
+ },
75
+ observations: [
76
+ {
77
+ label: original.source,
78
+ properties: {
79
+ source: original.source,
80
+ content_available: original.content !== null,
81
+ source_sha256: original.content_sha256,
82
+ },
83
+ evidence: artifactObservationEvidence({
84
+ sha256: mapFile.sha256,
85
+ path: mapFile.path,
86
+ operation: "parse-local-source-map",
87
+ coverage,
88
+ limitations: sourceMap.limitation === null ? [] : [sourceMap.limitation],
89
+ }),
90
+ },
91
+ ],
92
+ });
93
+ context.accumulator.addEdge({
94
+ source_node_id: mapNode.node_id,
95
+ target_node_id: node.node_id,
96
+ relation: "contains",
97
+ properties: { original_source: original.source },
98
+ evidence: artifactObservationEvidence({
99
+ sha256: mapFile.sha256,
100
+ path: mapFile.path,
101
+ operation: "parse-local-source-map",
102
+ coverage,
103
+ limitations: sourceMap.limitation === null ? [] : [sourceMap.limitation],
104
+ }),
105
+ });
106
+ }
107
+ }
108
+ };
@@ -0,0 +1,89 @@
1
+ const EXTRACTOR = {
2
+ name: "rea-javascript-artifact-reconstruction",
3
+ version: "1",
4
+ executable_sha256: null,
5
+ };
6
+ /** Exact artifact-byte evidence for one safely inventoried local file. */
7
+ export const artifactObservationEvidence = (input) => ({
8
+ authority: "artifact-bytes",
9
+ state: "observed",
10
+ confidence: "exact",
11
+ artifact: artifactReference(input.sha256),
12
+ location: {
13
+ available: true,
14
+ value: { kind: "artifact-path", path: input.path },
15
+ },
16
+ extractor: { ...EXTRACTOR, operation: input.operation },
17
+ coverage: input.coverage,
18
+ limitations: [...(input.limitations ?? [])],
19
+ evidence_ids: [],
20
+ });
21
+ /** Exact AST syntax evidence with an actionable source range. */
22
+ export const astObservationEvidence = (input) => ({
23
+ authority: "ast-static-analysis",
24
+ state: "observed",
25
+ confidence: "exact",
26
+ artifact: artifactReference(input.sha256),
27
+ location: {
28
+ available: true,
29
+ value: { kind: "source-range", source: input.path, ...input.range },
30
+ },
31
+ extractor: { ...EXTRACTOR, operation: input.operation },
32
+ coverage: input.coverage,
33
+ limitations: [...(input.limitations ?? [])],
34
+ evidence_ids: [],
35
+ });
36
+ /** Explicit static relationship inference; never promoted to observation. */
37
+ export const staticInferenceEvidence = (input) => ({
38
+ authority: "static-relationship-inference",
39
+ state: "inferred",
40
+ confidence: input.confidence ?? "high",
41
+ artifact: artifactReference(input.sha256),
42
+ location: input.range === undefined
43
+ ? { available: true, value: { kind: "artifact-path", path: input.path } }
44
+ : {
45
+ available: true,
46
+ value: { kind: "source-range", source: input.path, ...input.range },
47
+ },
48
+ extractor: { ...EXTRACTOR, operation: input.operation },
49
+ coverage: input.coverage,
50
+ limitations: [
51
+ "Static syntax does not prove that this relationship executes at runtime.",
52
+ ...(input.limitations ?? []),
53
+ ],
54
+ evidence_ids: [],
55
+ });
56
+ /** Unavailable AST fact that preserves a parse, approval, or limit gap. */
57
+ export const unavailableAstEvidence = (input) => ({
58
+ authority: "ast-static-analysis",
59
+ state: "unavailable",
60
+ confidence: "unknown",
61
+ artifact: artifactReference(input.sha256),
62
+ location: {
63
+ available: true,
64
+ value: { kind: "artifact-path", path: input.path },
65
+ },
66
+ extractor: { ...EXTRACTOR, operation: input.operation },
67
+ coverage: input.coverage,
68
+ limitations: [input.limitation, ...(input.limitations ?? [])],
69
+ evidence_ids: [],
70
+ });
71
+ /** Complete local projection coverage under named hard limits. */
72
+ export const completeReconstructionCoverage = (limits = []) => ({
73
+ status: "complete",
74
+ truncated: false,
75
+ omitted_count: 0,
76
+ limits: [...limits],
77
+ });
78
+ /** Partial reconstruction coverage with either exact truncation or a policy gap. */
79
+ export const partialReconstructionCoverage = (limits, omitted, truncated) => ({
80
+ status: "partial",
81
+ truncated,
82
+ omitted_count: omitted,
83
+ limits: [...limits],
84
+ });
85
+ const artifactReference = (sha256) => ({
86
+ available: true,
87
+ artifact_id: `art_${sha256}`,
88
+ sha256,
89
+ });
@@ -0,0 +1,271 @@
1
+ import { addStaticInferenceEdge, artifactLocalIdentity, createElectronRoleNode, javascriptAnalysisCoverage, linkElectronRoleToAsset, moduleLookupKey, resolveArtifactPath, sourceNodeFor, } from "./JavaScriptArtifactGraphContext.js";
2
+ import { astObservationEvidence, staticInferenceEvidence, } from "./JavaScriptArtifactGraphEvidence.js";
3
+ /** Project imports, workers, roles, endpoints, storage, and source-map links. */
4
+ export const addJavaScriptStaticFindings = (context) => {
5
+ for (const analyzed of context.analysis.files) {
6
+ const { file, javascript } = analyzed;
7
+ const asset = context.assetNodes.get(file.path);
8
+ if (javascript === null || asset === undefined)
9
+ continue;
10
+ const coverage = javascriptAnalysisCoverage(javascript, context.input);
11
+ for (const value of javascript.references)
12
+ addReference(context, { file, asset, value, coverage });
13
+ for (const value of javascript.endpoints)
14
+ addEndpoint(context, { file, asset, value, coverage });
15
+ for (const value of javascript.storage)
16
+ addStorage(context, { file, asset, value, coverage });
17
+ for (const value of javascript.role_paths)
18
+ addDiscoveredRole(context, { file, asset, value, coverage });
19
+ for (const value of javascript.source_map_urls)
20
+ addSourceMapEdge(context, { file, asset, value, coverage });
21
+ }
22
+ };
23
+ const addReference = (context, input) => {
24
+ const source = sourceNodeFor(context, input.file.path, input.value.module_key) ??
25
+ input.asset;
26
+ const resolved = input.value.specifier === null
27
+ ? null
28
+ : resolveReference(context, input.file.path, input.value.specifier);
29
+ if (input.value.kind === "worker" || input.value.kind === "service-worker") {
30
+ const worker = context.accumulator.addNode({
31
+ kind: input.value.kind === "worker" ? "worker" : "service-worker",
32
+ identity: artifactLocalIdentity(input.file.sha256, input.value.kind, input.value.specifier ?? input.value.expression ?? "[dynamic]"),
33
+ observations: [
34
+ {
35
+ label: input.value.specifier,
36
+ properties: {
37
+ declared_specifier: input.value.specifier,
38
+ expression: input.value.expression,
39
+ resolved_path: resolved?.path ?? null,
40
+ },
41
+ evidence: staticInferenceEvidence({
42
+ sha256: input.file.sha256,
43
+ path: input.file.path,
44
+ range: input.value.location,
45
+ operation: "discover-worker",
46
+ coverage: input.coverage,
47
+ }),
48
+ },
49
+ ],
50
+ });
51
+ addStaticInferenceEdge(context, {
52
+ source,
53
+ target: worker,
54
+ file: input.file,
55
+ range: input.value.location,
56
+ coverage: input.coverage,
57
+ relation: "loads",
58
+ properties: { kind: input.value.kind },
59
+ });
60
+ if (resolved !== null)
61
+ addStaticInferenceEdge(context, {
62
+ source: worker,
63
+ target: resolved.node,
64
+ file: input.file,
65
+ range: input.value.location,
66
+ coverage: input.coverage,
67
+ relation: "maps_to",
68
+ properties: { resolved_path: resolved.path },
69
+ });
70
+ return;
71
+ }
72
+ const target = resolved?.node ??
73
+ unresolvedReferenceNode(context, input.file, input.value, input.coverage);
74
+ addStaticInferenceEdge(context, {
75
+ source,
76
+ target,
77
+ file: input.file,
78
+ range: input.value.location,
79
+ coverage: input.coverage,
80
+ relation: resolved?.file.kind === "native-addon" ? "loads" : "imports",
81
+ properties: {
82
+ kind: input.value.kind,
83
+ specifier: input.value.specifier,
84
+ expression: input.value.expression,
85
+ resolved_path: resolved?.path ?? null,
86
+ },
87
+ });
88
+ };
89
+ const addEndpoint = (context, input) => {
90
+ const source = sourceNodeFor(context, input.file.path, input.value.module_key) ??
91
+ input.asset;
92
+ const node = context.accumulator.addNode({
93
+ kind: "endpoint",
94
+ identity: artifactLocalIdentity(input.file.sha256, input.value.kind, input.value.value),
95
+ observations: [
96
+ {
97
+ label: input.value.value,
98
+ properties: {
99
+ endpoint_kind: input.value.kind,
100
+ value: input.value.value,
101
+ mechanism: input.value.mechanism,
102
+ },
103
+ evidence: astObservationEvidence({
104
+ sha256: input.file.sha256,
105
+ path: input.file.path,
106
+ range: input.value.location,
107
+ operation: "discover-static-endpoint",
108
+ coverage: input.coverage,
109
+ }),
110
+ },
111
+ ],
112
+ });
113
+ addStaticInferenceEdge(context, {
114
+ source,
115
+ target: node,
116
+ file: input.file,
117
+ range: input.value.location,
118
+ coverage: input.coverage,
119
+ relation: input.value.kind === "route" ? "exposes" : "calls",
120
+ properties: { mechanism: input.value.mechanism },
121
+ });
122
+ };
123
+ const addStorage = (context, input) => {
124
+ const source = sourceNodeFor(context, input.file.path, input.value.module_key) ??
125
+ input.asset;
126
+ const node = context.accumulator.addNode({
127
+ kind: "storage",
128
+ identity: artifactLocalIdentity(input.file.sha256, input.value.kind, input.value.name ?? input.value.mechanism),
129
+ observations: [
130
+ {
131
+ label: input.value.name ?? input.value.kind,
132
+ properties: {
133
+ storage_kind: input.value.kind,
134
+ name: input.value.name,
135
+ mechanism: input.value.mechanism,
136
+ },
137
+ evidence: astObservationEvidence({
138
+ sha256: input.file.sha256,
139
+ path: input.file.path,
140
+ range: input.value.location,
141
+ operation: "discover-static-storage",
142
+ coverage: input.coverage,
143
+ }),
144
+ },
145
+ ],
146
+ });
147
+ addStaticInferenceEdge(context, {
148
+ source,
149
+ target: node,
150
+ file: input.file,
151
+ range: input.value.location,
152
+ coverage: input.coverage,
153
+ relation: "persists_to",
154
+ properties: { mechanism: input.value.mechanism },
155
+ });
156
+ };
157
+ const addDiscoveredRole = (context, input) => {
158
+ const resolvedPath = resolveArtifactPath(input.value.path, input.file.path, context.filesByPath);
159
+ const role = createElectronRoleNode(context, {
160
+ kind: input.value.role === "preload" ? "electron-preload" : "electron-renderer",
161
+ anchor: input.file,
162
+ declaredPath: input.value.path,
163
+ resolvedPath,
164
+ mechanism: input.value.mechanism,
165
+ range: input.value.location,
166
+ coverage: input.coverage,
167
+ });
168
+ const source = sourceNodeFor(context, input.file.path, input.value.module_key) ??
169
+ input.asset;
170
+ addStaticInferenceEdge(context, {
171
+ source,
172
+ target: role,
173
+ file: input.file,
174
+ range: input.value.location,
175
+ coverage: input.coverage,
176
+ relation: "loads",
177
+ properties: { mechanism: input.value.mechanism },
178
+ });
179
+ linkElectronRoleToAsset(context, {
180
+ role,
181
+ anchor: input.file,
182
+ path: resolvedPath,
183
+ range: input.value.location,
184
+ coverage: input.coverage,
185
+ });
186
+ };
187
+ const addSourceMapEdge = (context, input) => {
188
+ const resolvedPath = resolveArtifactPath(input.value.declared_url, input.file.path, context.filesByPath);
189
+ const resolvedFile = resolvedPath === null ? undefined : context.filesByPath.get(resolvedPath);
190
+ const resolvedNode = resolvedPath === null ? undefined : context.fileNodes.get(resolvedPath);
191
+ const target = resolvedFile?.kind === "source-map" && resolvedNode !== undefined
192
+ ? resolvedNode
193
+ : context.accumulator.addNode({
194
+ kind: "source-map",
195
+ identity: artifactLocalIdentity(input.file.sha256, "unresolved-source-map", input.value.declared_url),
196
+ observations: [
197
+ {
198
+ label: input.value.declared_url,
199
+ properties: {
200
+ declared_url: input.value.declared_url,
201
+ resolved_path: resolvedPath,
202
+ available: false,
203
+ },
204
+ evidence: staticInferenceEvidence({
205
+ sha256: input.file.sha256,
206
+ path: input.file.path,
207
+ range: input.value.location,
208
+ operation: "discover-source-map",
209
+ coverage: input.coverage,
210
+ confidence: "medium",
211
+ limitations: [
212
+ "The declared source map was not present in the inventoried artifact.",
213
+ ],
214
+ }),
215
+ },
216
+ ],
217
+ });
218
+ addStaticInferenceEdge(context, {
219
+ source: input.asset,
220
+ target,
221
+ file: input.file,
222
+ range: input.value.location,
223
+ coverage: input.coverage,
224
+ relation: "maps_to",
225
+ properties: {
226
+ declared_url: input.value.declared_url,
227
+ resolved_path: resolvedPath,
228
+ },
229
+ });
230
+ };
231
+ const resolveReference = (context, sourcePath, specifier) => {
232
+ const module = context.moduleNodes.get(moduleLookupKey(sourcePath, specifier));
233
+ if (module !== undefined) {
234
+ const file = context.filesByPath.get(sourcePath);
235
+ return file === undefined
236
+ ? null
237
+ : { path: `${sourcePath}#module:${specifier}`, file, node: module };
238
+ }
239
+ const path = resolveArtifactPath(specifier, sourcePath, context.filesByPath);
240
+ if (path === null)
241
+ return null;
242
+ const file = context.filesByPath.get(path);
243
+ const node = context.fileNodes.get(path);
244
+ return file === undefined || node === undefined ? null : { path, file, node };
245
+ };
246
+ const unresolvedReferenceNode = (context, file, reference, coverage) => context.accumulator.addNode({
247
+ kind: "javascript-module",
248
+ identity: artifactLocalIdentity(file.sha256, "unresolved-reference", `${reference.kind}:${reference.specifier ?? reference.expression ?? "[dynamic]"}`),
249
+ observations: [
250
+ {
251
+ label: reference.specifier,
252
+ properties: {
253
+ reference_kind: reference.kind,
254
+ specifier: reference.specifier,
255
+ expression: reference.expression,
256
+ resolution: "unresolved",
257
+ },
258
+ evidence: staticInferenceEvidence({
259
+ sha256: file.sha256,
260
+ path: file.path,
261
+ range: reference.location,
262
+ operation: "resolve-static-reference",
263
+ coverage,
264
+ confidence: "low",
265
+ limitations: [
266
+ "The static reference could not be resolved within the inventoried artifact.",
267
+ ],
268
+ }),
269
+ },
270
+ ],
271
+ });