rea-agents 1.7.0 → 2.0.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 (156) hide show
  1. package/README.md +38 -31
  2. package/dist/application/CapabilityInventory.js +18 -0
  3. package/dist/application/CrossVersionInvestigation.js +10 -6
  4. package/dist/application/Doctor.js +56 -6
  5. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  6. package/dist/application/ElectronBoundaryGraph.js +9 -0
  7. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  8. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  9. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  10. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  11. package/dist/application/EnhancedTools.js +38 -13
  12. package/dist/application/InvestigationProviders.js +30 -0
  13. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  14. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  15. package/dist/application/JavaScriptApplicationService.js +74 -0
  16. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  17. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  18. package/dist/application/JavaScriptArtifactAnalysis.js +7 -1
  19. package/dist/application/JavaScriptArtifactGraphBuilder.js +59 -16
  20. package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
  21. package/dist/application/JavaScriptArtifactReconstruction.js +3 -0
  22. package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
  23. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  24. package/dist/application/JavaScriptReplayService.js +266 -0
  25. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  26. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  27. package/dist/application/ManagedApplicationGraphService.js +55 -0
  28. package/dist/application/ManagedMemberComparisonService.js +122 -0
  29. package/dist/application/ManagedNativeVerificationService.js +39 -0
  30. package/dist/application/ManagedReconstructionService.js +58 -0
  31. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  32. package/dist/application/PermissionAuthority.js +1 -1
  33. package/dist/application/ProcessSampling.js +15 -11
  34. package/dist/application/ProjectPermissionStore.js +1 -0
  35. package/dist/application/runtime.js +2 -0
  36. package/dist/browser/CdpCaptureEvents.js +49 -0
  37. package/dist/browser/CdpElectronInspection.js +106 -162
  38. package/dist/browser/CdpElectronProvider.js +5 -1
  39. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  40. package/dist/browser/CdpElectronScripts.js +94 -0
  41. package/dist/browser/CdpElectronWorkers.js +56 -0
  42. package/dist/browser/CdpPageCapture.js +8 -4
  43. package/dist/catalogIdentity.js +4 -1
  44. package/dist/cli.js +388 -0
  45. package/dist/cliApplicationCommands.js +62 -0
  46. package/dist/cliCommandNames.js +13 -0
  47. package/dist/cliElectronCommands.js +103 -1
  48. package/dist/cliJsonInput.js +54 -0
  49. package/dist/config.js +83 -0
  50. package/dist/contracts/applicationToolContracts.js +91 -0
  51. package/dist/contracts/artifactToolContracts.js +5 -9
  52. package/dist/contracts/browserToolContracts.js +14 -62
  53. package/dist/contracts/electronToolContracts.js +45 -19
  54. package/dist/contracts/errorSchemas.js +1 -0
  55. package/dist/contracts/investigationExamples.js +0 -6
  56. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  57. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  58. package/dist/contracts/managedToolContracts.js +153 -0
  59. package/dist/contracts/managedWorkflowExamples.js +346 -0
  60. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  61. package/dist/contracts/nativeToolContracts.js +2 -6
  62. package/dist/contracts/promptContracts.js +18 -2
  63. package/dist/contracts/toolContractExamples.js +10 -25
  64. package/dist/contracts/toolContracts.js +47 -45
  65. package/dist/contracts/toolEffects.js +160 -0
  66. package/dist/contracts/toolOutputSchemas.js +46 -31
  67. package/dist/doctorRuntime.js +42 -1
  68. package/dist/domain/artifactComparison.js +3 -4
  69. package/dist/domain/browserObservation.js +3 -0
  70. package/dist/domain/bundleComparison.js +4 -4
  71. package/dist/domain/electronObservation.js +13 -0
  72. package/dist/domain/electronStaticAnalysis.js +9 -0
  73. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  74. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  75. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  76. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  77. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  78. package/dist/domain/errors.js +67 -1
  79. package/dist/domain/functionComparisonSchemas.js +3 -8
  80. package/dist/domain/inputIssueProjection.js +52 -0
  81. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  82. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  83. package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
  84. package/dist/domain/javascriptApplicationGraph.js +2 -1
  85. package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
  86. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  87. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  88. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  89. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  90. package/dist/domain/javascriptFeatureSeed.js +140 -0
  91. package/dist/domain/javascriptFeatureTrace.js +232 -0
  92. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  93. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  94. package/dist/domain/javascriptNativeHandoff.js +85 -0
  95. package/dist/domain/javascriptReplay.js +361 -0
  96. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  97. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  98. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  99. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  100. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  101. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  102. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  103. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  104. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  105. package/dist/domain/javascriptStaticAnalysis.js +31 -43
  106. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  107. package/dist/domain/javascriptStaticAnalysisHelpers.js +10 -0
  108. package/dist/domain/javascriptStaticAnalysisState.js +6 -0
  109. package/dist/domain/managedApplicationGraph.js +556 -0
  110. package/dist/domain/managedArtifact.js +444 -0
  111. package/dist/domain/managedMemberComparison.js +565 -0
  112. package/dist/domain/managedNativeVerification.js +408 -0
  113. package/dist/domain/managedReconstruction.js +183 -0
  114. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  115. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  116. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  117. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  118. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  119. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  120. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  121. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  122. package/dist/dotnet/ManagedPeReader.js +157 -0
  123. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  124. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  125. package/dist/generatedPackageMetadata.js +2 -2
  126. package/dist/ghidra/GhidraProvider.js +6 -0
  127. package/dist/main.js +14 -0
  128. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  129. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  130. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  131. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  132. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  133. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  134. package/dist/server/createServer.js +52 -0
  135. package/dist/server/registerApplicationTools.js +115 -0
  136. package/dist/server/registerArtifactComparisonTool.js +16 -9
  137. package/dist/server/registerBrowserTools.js +33 -8
  138. package/dist/server/registerBundleComparisonTool.js +17 -20
  139. package/dist/server/registerElectronTools.js +45 -3
  140. package/dist/server/registerEnhancedTools.js +58 -13
  141. package/dist/server/registerEvidenceTools.js +5 -1
  142. package/dist/server/registerFunctionComparisonTool.js +14 -7
  143. package/dist/server/registerInvestigationTools.js +21 -17
  144. package/dist/server/registerManagedTools.js +6 -0
  145. package/dist/server/registerManagedWorkflowTools.js +277 -0
  146. package/dist/server/registerOfficialTools.js +8 -8
  147. package/dist/server/registerProcessComparisonTool.js +25 -47
  148. package/dist/server/registerSessionStatusTool.js +7 -7
  149. package/dist/server/registerSessionTools.js +51 -86
  150. package/dist/server/sessionEvidence.js +14 -19
  151. package/dist/server/toolInputValidation.js +77 -0
  152. package/dist/server/toolRegistrationOptions.js +79 -2
  153. package/dist/server/toolResult.js +25 -17
  154. package/package.json +12 -4
  155. package/scripts/rea.mjs +1 -1
  156. package/skills/rea-analysis/SKILL.md +59 -3
@@ -0,0 +1,887 @@
1
+ import { managedMemberInspectionSchema, } from "../domain/managedArtifact.js";
2
+ import { readManagedPeLayout, } from "./ManagedPeReader.js";
3
+ import { managedTableRowCounts, readManagedMetadataInventory, } from "./ManagedMetadataInventory.js";
4
+ import { metadataRowOffset, readManagedMetadataLayout, } from "./ManagedMetadataLayout.js";
5
+ import { MetadataRowCursor, metadataToken, readMetadataBlob, readMetadataString, sha256Bytes, } from "./ManagedMetadataHeaps.js";
6
+ import { ManagedReaderFailure, managedFailure, } from "./ManagedReaderFailure.js";
7
+ const emptyPage = (offset, limit) => ({
8
+ items: [],
9
+ offset,
10
+ limit,
11
+ total: 0,
12
+ returned: 0,
13
+ dropped: 0,
14
+ complete: offset === 0,
15
+ });
16
+ const page = (all, offset, limit) => {
17
+ const items = all.slice(offset, offset + limit);
18
+ return {
19
+ items,
20
+ offset,
21
+ limit,
22
+ total: all.length,
23
+ returned: items.length,
24
+ dropped: all.length - items.length,
25
+ complete: offset === 0 && offset + limit >= all.length,
26
+ };
27
+ };
28
+ const rowCursor = (bytes, layout, table, row) => {
29
+ const descriptor = layout.table(table);
30
+ const start = metadataRowOffset(layout, table, row);
31
+ if (descriptor === undefined)
32
+ throw managedFailure("invalid-row", `metadata.${String(table)}`, "Metadata table is absent", start);
33
+ return new MetadataRowCursor(bytes, start, start + descriptor.rowSize, `metadata.${descriptor.name}`);
34
+ };
35
+ const codedToken = (raw, bits, tables) => {
36
+ if (raw === 0)
37
+ return null;
38
+ const tag = raw & (2 ** bits - 1);
39
+ const row = Math.floor(raw / 2 ** bits);
40
+ const table = tables[tag];
41
+ return table === undefined || row === 0 ? null : metadataToken(table, row);
42
+ };
43
+ const rowRange = (table, start, nextStart) => {
44
+ const total = table?.rowCount ?? 0;
45
+ if (total === 0 || start === 0)
46
+ return { first: null, last: null, count: 0 };
47
+ const end = Math.min(nextStart === 0 ? total + 1 : nextStart, total + 1);
48
+ if (start >= end)
49
+ return { first: null, last: null, count: 0 };
50
+ return { first: start, last: end - 1, count: end - start };
51
+ };
52
+ const fullName = (namespace, name) => namespace.length === 0 ? name : `${namespace}.${name}`;
53
+ const readTypeRange = (bytes, layout, row, maxBytes) => {
54
+ const methods = layout.table(6);
55
+ const fields = layout.table(4);
56
+ const cursor = rowCursor(bytes, layout, 2, row);
57
+ cursor.readUInt32();
58
+ const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
59
+ const namespace = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
60
+ cursor.readIndex(layout.codedIndexSize("TypeDefOrRef"));
61
+ const fieldStart = cursor.readIndex(layout.tableIndexSize(4));
62
+ const methodStart = cursor.readIndex(layout.tableIndexSize(6));
63
+ let nextField = (fields?.rowCount ?? 0) + 1;
64
+ let nextMethod = (methods?.rowCount ?? 0) + 1;
65
+ const typeTable = layout.table(2);
66
+ if (typeTable !== undefined && row < typeTable.rowCount) {
67
+ const next = rowCursor(bytes, layout, 2, row + 1);
68
+ next.readUInt32();
69
+ next.readIndex(layout.stringIndexSize);
70
+ next.readIndex(layout.stringIndexSize);
71
+ next.readIndex(layout.codedIndexSize("TypeDefOrRef"));
72
+ nextField = next.readIndex(layout.tableIndexSize(4));
73
+ nextMethod = next.readIndex(layout.tableIndexSize(6));
74
+ }
75
+ return {
76
+ token: metadataToken(2, row),
77
+ fullName: fullName(namespace, name),
78
+ fieldStart,
79
+ fieldEnd: nextField,
80
+ methodStart,
81
+ methodEnd: nextMethod,
82
+ };
83
+ };
84
+ const typeRanges = (bytes, layout, maxBytes) => {
85
+ const typeTable = layout.table(2);
86
+ const ranges = [];
87
+ for (let row = 1; row <= (typeTable?.rowCount ?? 0); row += 1)
88
+ ranges.push(readTypeRange(bytes, layout, row, maxBytes));
89
+ return ranges;
90
+ };
91
+ const declaringType = (ranges, table, row) => {
92
+ for (const range of ranges) {
93
+ const start = table === "field" ? range.fieldStart : range.methodStart;
94
+ const end = table === "field" ? range.fieldEnd : range.methodEnd;
95
+ if (row >= start && row < end)
96
+ return { token: range.token, fullName: range.fullName };
97
+ }
98
+ return null;
99
+ };
100
+ const parseTypes = (bytes, layout, ranges, maxBytes) => {
101
+ const typeTable = layout.table(2);
102
+ const fields = layout.table(4);
103
+ const methods = layout.table(6);
104
+ const items = [];
105
+ for (let row = 1; row <= (typeTable?.rowCount ?? 0); row += 1) {
106
+ const cursor = rowCursor(bytes, layout, 2, row);
107
+ const flags = cursor.readUInt32();
108
+ const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
109
+ const namespace = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
110
+ const extendsRaw = cursor.readIndex(layout.codedIndexSize("TypeDefOrRef"));
111
+ const fieldStart = cursor.readIndex(layout.tableIndexSize(4));
112
+ const methodStart = cursor.readIndex(layout.tableIndexSize(6));
113
+ const nextRange = ranges[row] ?? null;
114
+ const fieldRange = rowRange(fields, fieldStart, nextRange?.fieldStart ?? 0);
115
+ const methodRange = rowRange(methods, methodStart, nextRange?.methodStart ?? 0);
116
+ items.push({
117
+ token: metadataToken(2, row),
118
+ row_offset: cursor.start,
119
+ namespace,
120
+ name,
121
+ full_name: fullName(namespace, name),
122
+ flags,
123
+ extends_token: codedToken(extendsRaw, 2, [2, 1, 27]),
124
+ field_list: {
125
+ first_row: fieldRange.first,
126
+ last_row: fieldRange.last,
127
+ count: fieldRange.count,
128
+ },
129
+ method_list: {
130
+ first_row: methodRange.first,
131
+ last_row: methodRange.last,
132
+ count: methodRange.count,
133
+ },
134
+ });
135
+ }
136
+ return items;
137
+ };
138
+ const readCompressed = (bytes, offset) => {
139
+ const first = bytes[offset];
140
+ if (first === undefined)
141
+ throw new RangeError("truncated compressed integer");
142
+ if ((first & 0x80) === 0)
143
+ return { value: first, next: offset + 1 };
144
+ const second = bytes[offset + 1];
145
+ if ((first & 0xc0) === 0x80 && second !== undefined)
146
+ return { value: ((first & 0x3f) << 8) | second, next: offset + 2 };
147
+ const b1 = bytes[offset + 1];
148
+ const b2 = bytes[offset + 2];
149
+ const b3 = bytes[offset + 3];
150
+ if ((first & 0xe0) === 0xc0 &&
151
+ b1 !== undefined &&
152
+ b2 !== undefined &&
153
+ b3 !== undefined)
154
+ return {
155
+ value: (first & 0x1f) * 0x01_00_00_00 + b1 * 0x01_00_00 + b2 * 0x0100 + b3,
156
+ next: offset + 4,
157
+ };
158
+ throw new RangeError("reserved compressed integer");
159
+ };
160
+ const ELEMENT_TYPES = new Map([
161
+ [0x01, "void"],
162
+ [0x02, "bool"],
163
+ [0x03, "char"],
164
+ [0x04, "i1"],
165
+ [0x05, "u1"],
166
+ [0x06, "i2"],
167
+ [0x07, "u2"],
168
+ [0x08, "i4"],
169
+ [0x09, "u4"],
170
+ [0x0a, "i8"],
171
+ [0x0b, "u8"],
172
+ [0x0c, "r4"],
173
+ [0x0d, "r8"],
174
+ [0x0e, "string"],
175
+ [0x18, "native-int"],
176
+ [0x19, "native-uint"],
177
+ [0x1c, "object"],
178
+ ]);
179
+ const readTypeSignature = (blob, offset) => {
180
+ const kind = blob[offset];
181
+ if (kind === undefined)
182
+ throw new RangeError("truncated type signature");
183
+ const named = ELEMENT_TYPES.get(kind);
184
+ if (named !== undefined)
185
+ return { value: named, next: offset + 1 };
186
+ if (kind === 0x0f) {
187
+ const inner = readTypeSignature(blob, offset + 1);
188
+ return { value: `${inner.value}&`, next: inner.next };
189
+ }
190
+ if (kind === 0x10) {
191
+ const inner = readTypeSignature(blob, offset + 1);
192
+ return { value: `${inner.value}*`, next: inner.next };
193
+ }
194
+ if (kind === 0x11 || kind === 0x12) {
195
+ const token = readCompressed(blob, offset + 1);
196
+ return {
197
+ value: `${kind === 0x11 ? "valuetype" : "class"}:${String(token.value)}`,
198
+ next: token.next,
199
+ };
200
+ }
201
+ if (kind === 0x1d) {
202
+ const inner = readTypeSignature(blob, offset + 1);
203
+ return { value: `${inner.value}[]`, next: inner.next };
204
+ }
205
+ if (kind === 0x1e) {
206
+ const variable = readCompressed(blob, offset + 1);
207
+ return { value: `mvar:${String(variable.value)}`, next: variable.next };
208
+ }
209
+ if (kind === 0x13) {
210
+ const variable = readCompressed(blob, offset + 1);
211
+ return { value: `var:${String(variable.value)}`, next: variable.next };
212
+ }
213
+ throw new RangeError(`unsupported element type 0x${kind.toString(16)}`);
214
+ };
215
+ const callingConvention = (value) => {
216
+ const base = value & 0x0f;
217
+ const flags = [
218
+ (value & 0x20) === 0 ? null : "has-this",
219
+ (value & 0x40) === 0 ? null : "explicit-this",
220
+ (value & 0x10) === 0 ? null : "generic",
221
+ ].filter((flag) => flag !== null);
222
+ const name = base === 0
223
+ ? "default"
224
+ : base === 5
225
+ ? "vararg"
226
+ : base === 6
227
+ ? "field"
228
+ : `unknown:${String(base)}`;
229
+ return flags.length === 0 ? name : `${name} ${flags.join(" ")}`;
230
+ };
231
+ const signature = (blob) => {
232
+ const raw = {
233
+ raw_length: blob.length,
234
+ raw_sha256: sha256Bytes(blob),
235
+ };
236
+ try {
237
+ if (blob.length === 0)
238
+ throw new RangeError("empty signature");
239
+ const first = blob[0] ?? 0;
240
+ if ((first & 0x0f) === 6) {
241
+ const fieldType = readTypeSignature(blob, 1);
242
+ return {
243
+ ...raw,
244
+ kind: "field",
245
+ parse_status: fieldType.next === blob.length ? "decoded" : "partial",
246
+ calling_convention: callingConvention(first),
247
+ generic_parameter_count: null,
248
+ parameter_count: null,
249
+ return_type: null,
250
+ parameter_types: [],
251
+ field_type: fieldType.value,
252
+ issue: fieldType.next === blob.length ? null : "Trailing signature data",
253
+ };
254
+ }
255
+ let offset = 1;
256
+ let genericParameterCount = null;
257
+ if ((first & 0x10) !== 0) {
258
+ const generic = readCompressed(blob, offset);
259
+ genericParameterCount = generic.value;
260
+ offset = generic.next;
261
+ }
262
+ const parameterCount = readCompressed(blob, offset);
263
+ offset = parameterCount.next;
264
+ const returnType = readTypeSignature(blob, offset);
265
+ offset = returnType.next;
266
+ const parameters = [];
267
+ for (let index = 0; index < parameterCount.value; index += 1) {
268
+ const parameter = readTypeSignature(blob, offset);
269
+ parameters.push(parameter.value);
270
+ offset = parameter.next;
271
+ }
272
+ return {
273
+ ...raw,
274
+ kind: "method",
275
+ parse_status: offset === blob.length ? "decoded" : "partial",
276
+ calling_convention: callingConvention(first),
277
+ generic_parameter_count: genericParameterCount,
278
+ parameter_count: parameterCount.value,
279
+ return_type: returnType.value,
280
+ parameter_types: parameters,
281
+ field_type: null,
282
+ issue: offset === blob.length ? null : "Trailing signature data",
283
+ };
284
+ }
285
+ catch (cause) {
286
+ return {
287
+ ...raw,
288
+ kind: "unknown",
289
+ parse_status: cause instanceof RangeError ? "unsupported" : "malformed",
290
+ calling_convention: null,
291
+ generic_parameter_count: null,
292
+ parameter_count: null,
293
+ return_type: null,
294
+ parameter_types: [],
295
+ field_type: null,
296
+ issue: cause instanceof Error ? cause.message : "Signature parse failed",
297
+ };
298
+ }
299
+ };
300
+ const opcode = (code) => OPCODES.get(code);
301
+ const OPCODES = new Map([
302
+ [0x00, { name: "nop", operand: "none" }],
303
+ [0x02, { name: "ldarg.0", operand: "none" }],
304
+ [0x03, { name: "ldarg.1", operand: "none" }],
305
+ [0x04, { name: "ldarg.2", operand: "none" }],
306
+ [0x05, { name: "ldarg.3", operand: "none" }],
307
+ [0x06, { name: "ldloc.0", operand: "none" }],
308
+ [0x07, { name: "ldloc.1", operand: "none" }],
309
+ [0x08, { name: "ldloc.2", operand: "none" }],
310
+ [0x09, { name: "ldloc.3", operand: "none" }],
311
+ [0x0a, { name: "stloc.0", operand: "none" }],
312
+ [0x0b, { name: "stloc.1", operand: "none" }],
313
+ [0x0c, { name: "stloc.2", operand: "none" }],
314
+ [0x0d, { name: "stloc.3", operand: "none" }],
315
+ [0x0e, { name: "ldarg.s", operand: "short-var" }],
316
+ [0x0f, { name: "ldarga.s", operand: "short-var" }],
317
+ [0x11, { name: "ldloc.s", operand: "short-var" }],
318
+ [0x13, { name: "stloc.s", operand: "short-var" }],
319
+ [0x14, { name: "ldnull", operand: "none" }],
320
+ [0x15, { name: "ldc.i4.m1", operand: "none" }],
321
+ [0x16, { name: "ldc.i4.0", operand: "none" }],
322
+ [0x17, { name: "ldc.i4.1", operand: "none" }],
323
+ [0x18, { name: "ldc.i4.2", operand: "none" }],
324
+ [0x19, { name: "ldc.i4.3", operand: "none" }],
325
+ [0x1a, { name: "ldc.i4.4", operand: "none" }],
326
+ [0x1b, { name: "ldc.i4.5", operand: "none" }],
327
+ [0x1c, { name: "ldc.i4.6", operand: "none" }],
328
+ [0x1d, { name: "ldc.i4.7", operand: "none" }],
329
+ [0x1e, { name: "ldc.i4.8", operand: "none" }],
330
+ [0x1f, { name: "ldc.i4.s", operand: "short-i" }],
331
+ [0x20, { name: "ldc.i4", operand: "i" }],
332
+ [0x25, { name: "dup", operand: "none" }],
333
+ [0x26, { name: "pop", operand: "none" }],
334
+ [0x28, { name: "call", operand: "method" }],
335
+ [0x2a, { name: "ret", operand: "none" }],
336
+ [0x2b, { name: "br.s", operand: "short-branch" }],
337
+ [0x2c, { name: "brfalse.s", operand: "short-branch" }],
338
+ [0x2d, { name: "brtrue.s", operand: "short-branch" }],
339
+ [0x38, { name: "br", operand: "branch" }],
340
+ [0x39, { name: "brfalse", operand: "branch" }],
341
+ [0x3a, { name: "brtrue", operand: "branch" }],
342
+ [0x45, { name: "switch", operand: "switch" }],
343
+ [0x58, { name: "add", operand: "none" }],
344
+ [0x59, { name: "sub", operand: "none" }],
345
+ [0x5a, { name: "mul", operand: "none" }],
346
+ [0x5b, { name: "div", operand: "none" }],
347
+ [0x6f, { name: "callvirt", operand: "method" }],
348
+ [0x70, { name: "cpobj", operand: "type" }],
349
+ [0x72, { name: "ldstr", operand: "string" }],
350
+ [0x73, { name: "newobj", operand: "method" }],
351
+ [0x74, { name: "castclass", operand: "type" }],
352
+ [0x75, { name: "isinst", operand: "type" }],
353
+ [0x7b, { name: "ldfld", operand: "field" }],
354
+ [0x7c, { name: "ldflda", operand: "field" }],
355
+ [0x7d, { name: "stfld", operand: "field" }],
356
+ [0x7e, { name: "ldsfld", operand: "field" }],
357
+ [0x7f, { name: "ldsflda", operand: "field" }],
358
+ [0x80, { name: "stsfld", operand: "field" }],
359
+ [0x8c, { name: "box", operand: "type" }],
360
+ [0x8d, { name: "newarr", operand: "type" }],
361
+ [0xa5, { name: "unbox.any", operand: "type" }],
362
+ [0xd0, { name: "ldtoken", operand: "token" }],
363
+ [0xdd, { name: "leave", operand: "branch" }],
364
+ [0xde, { name: "leave.s", operand: "short-branch" }],
365
+ [0xfe09, { name: "ldarg", operand: "var" }],
366
+ [0xfe0a, { name: "ldarga", operand: "var" }],
367
+ [0xfe0c, { name: "ldloc", operand: "var" }],
368
+ [0xfe0e, { name: "stloc", operand: "var" }],
369
+ ]);
370
+ const tokenKind = (token) => {
371
+ if (token.startsWith("0x06") ||
372
+ token.startsWith("0x0a") ||
373
+ token.startsWith("0x2b"))
374
+ return "method";
375
+ if (token.startsWith("0x04"))
376
+ return "field";
377
+ if (token.startsWith("0x70"))
378
+ return "string";
379
+ if (token.startsWith("0x11"))
380
+ return "signature";
381
+ if (token.startsWith("0x01") ||
382
+ token.startsWith("0x02") ||
383
+ token.startsWith("0x1b"))
384
+ return "type";
385
+ return "token";
386
+ };
387
+ const readOperand = (il, offset, kind) => {
388
+ switch (kind) {
389
+ case "none":
390
+ return { next: offset, anchorKind: "none", value: null };
391
+ case "short-var":
392
+ return {
393
+ next: offset + 1,
394
+ anchorKind: "variable",
395
+ value: String(il.readUInt8(offset)),
396
+ };
397
+ case "var":
398
+ return {
399
+ next: offset + 2,
400
+ anchorKind: "variable",
401
+ value: String(il.readUInt16LE(offset)),
402
+ };
403
+ case "short-i":
404
+ return {
405
+ next: offset + 1,
406
+ anchorKind: "constant",
407
+ value: String(il.readInt8(offset)),
408
+ };
409
+ case "i":
410
+ return {
411
+ next: offset + 4,
412
+ anchorKind: "constant",
413
+ value: String(il.readInt32LE(offset)),
414
+ };
415
+ case "short-branch":
416
+ return {
417
+ next: offset + 1,
418
+ anchorKind: "branch",
419
+ value: String(offset + 1 + il.readInt8(offset)),
420
+ };
421
+ case "branch":
422
+ return {
423
+ next: offset + 4,
424
+ anchorKind: "branch",
425
+ value: String(offset + 4 + il.readInt32LE(offset)),
426
+ };
427
+ case "switch": {
428
+ const count = il.readUInt32LE(offset);
429
+ return {
430
+ next: offset + 4 + count * 4,
431
+ anchorKind: "switch",
432
+ value: String(count),
433
+ };
434
+ }
435
+ case "method":
436
+ case "field":
437
+ case "type":
438
+ case "string":
439
+ case "token": {
440
+ const raw = il.readUInt32LE(offset);
441
+ const token = `0x${raw.toString(16).padStart(8, "0")}`;
442
+ return {
443
+ next: offset + 4,
444
+ anchorKind: kind === "token" ? tokenKind(token) : kind,
445
+ value: token,
446
+ };
447
+ }
448
+ default:
449
+ return { next: offset, anchorKind: "unknown", value: null };
450
+ }
451
+ };
452
+ const decodeInstructions = (il, limit) => {
453
+ const parsed = [];
454
+ let offset = 0;
455
+ let issue = null;
456
+ try {
457
+ while (offset < il.length && parsed.length < limit) {
458
+ const start = offset;
459
+ const first = il.readUInt8(offset);
460
+ offset += 1;
461
+ const code = first === 0xfe ? 0xfe00 + il.readUInt8(offset++) : first;
462
+ const descriptor = opcode(code) ?? {
463
+ name: `unknown.0x${code.toString(16)}`,
464
+ operand: "none",
465
+ };
466
+ const operand = readOperand(il, offset, descriptor.operand);
467
+ if (operand.next < offset || operand.next > il.length) {
468
+ issue = `Instruction ${descriptor.name} at IL offset ${String(start)} leaves method body`;
469
+ break;
470
+ }
471
+ offset = operand.next;
472
+ parsed.push({
473
+ offset: start,
474
+ opcode: descriptor.name,
475
+ operandKind: operand.anchorKind,
476
+ operand: operand.value,
477
+ });
478
+ }
479
+ }
480
+ catch (cause) {
481
+ issue =
482
+ cause instanceof Error ? cause.message : "Instruction decode failed";
483
+ }
484
+ const truncated = offset < il.length && issue === null ? 1 : 0;
485
+ return { parsed, count: parsed.length, truncated, issue };
486
+ };
487
+ const parseExceptionRegions = (bytes, offset, methodEnd) => {
488
+ if (offset >= methodEnd)
489
+ return [];
490
+ const kind = bytes.readUInt8(offset);
491
+ if ((kind & 0x3f) !== 1)
492
+ return [];
493
+ const fat = (kind & 0x40) !== 0;
494
+ const size = fat
495
+ ? bytes.readUInt32LE(offset) >>> 8
496
+ : bytes.readUInt8(offset + 1);
497
+ const start = fat ? offset + 4 : offset + 4;
498
+ const clauseSize = fat ? 24 : 12;
499
+ if (size < 4 || offset > methodEnd - size)
500
+ return [];
501
+ const count = Math.floor((size - 4) / clauseSize);
502
+ const regions = [];
503
+ for (let index = 0; index < count; index += 1) {
504
+ const clause = start + index * clauseSize;
505
+ if (fat) {
506
+ const flags = bytes.readUInt32LE(clause);
507
+ const extra = bytes.readUInt32LE(clause + 20);
508
+ regions.push({
509
+ flags,
510
+ try_offset: bytes.readUInt32LE(clause + 4),
511
+ try_length: bytes.readUInt32LE(clause + 8),
512
+ handler_offset: bytes.readUInt32LE(clause + 12),
513
+ handler_length: bytes.readUInt32LE(clause + 16),
514
+ class_token: flags === 0 ? `0x${extra.toString(16).padStart(8, "0")}` : null,
515
+ filter_offset: flags === 1 ? extra : null,
516
+ });
517
+ }
518
+ else {
519
+ const flags = bytes.readUInt16LE(clause);
520
+ const extra = bytes.readUInt32LE(clause + 8);
521
+ regions.push({
522
+ flags,
523
+ try_offset: bytes.readUInt16LE(clause + 2),
524
+ try_length: bytes.readUInt8(clause + 4),
525
+ handler_offset: bytes.readUInt16LE(clause + 5),
526
+ handler_length: bytes.readUInt8(clause + 7),
527
+ class_token: flags === 0 ? `0x${extra.toString(16).padStart(8, "0")}` : null,
528
+ filter_offset: flags === 1 ? extra : null,
529
+ });
530
+ }
531
+ }
532
+ return regions;
533
+ };
534
+ const methodBody = (bytes, pe, rva, limits) => {
535
+ if (rva === 0)
536
+ return {
537
+ status: "absent",
538
+ header_format: "none",
539
+ rva,
540
+ file_offset: null,
541
+ max_stack: null,
542
+ init_locals: null,
543
+ local_var_sig_token: null,
544
+ il_size: 0,
545
+ il_sha256: null,
546
+ normalized_il_sha256: null,
547
+ instruction_count: 0,
548
+ decoded_instruction_count: 0,
549
+ truncated_instructions: 0,
550
+ opcode_counts: {},
551
+ anchors: [],
552
+ exception_regions: [],
553
+ issue: null,
554
+ };
555
+ try {
556
+ const offset = pe.rvaToOffset(rva, 1, "method.body");
557
+ const first = bytes.readUInt8(offset);
558
+ const tiny = (first & 3) === 2;
559
+ const fat = (first & 3) === 3;
560
+ if (!tiny && !fat)
561
+ throw new RangeError("Unsupported method body header");
562
+ const headerSize = tiny ? 1 : (first >> 4) * 4;
563
+ const flags = tiny ? 0 : bytes.readUInt16LE(offset);
564
+ const maxStack = tiny ? 8 : bytes.readUInt16LE(offset + 2);
565
+ const ilSize = tiny ? first >> 2 : bytes.readUInt32LE(offset + 4);
566
+ const localSig = tiny ? 0 : bytes.readUInt32LE(offset + 8);
567
+ if (ilSize > limits.maxMethodBodyBytes)
568
+ return {
569
+ status: "too-large",
570
+ header_format: tiny ? "tiny" : "fat",
571
+ rva,
572
+ file_offset: offset,
573
+ max_stack: maxStack,
574
+ init_locals: tiny ? false : (flags & 0x10) !== 0,
575
+ local_var_sig_token: localSig === 0 ? null : `0x${localSig.toString(16).padStart(8, "0")}`,
576
+ il_size: ilSize,
577
+ il_sha256: null,
578
+ normalized_il_sha256: null,
579
+ instruction_count: 0,
580
+ decoded_instruction_count: 0,
581
+ truncated_instructions: 0,
582
+ opcode_counts: {},
583
+ anchors: [],
584
+ exception_regions: [],
585
+ issue: `Method body exceeds max_method_body_bytes ${String(limits.maxMethodBodyBytes)}`,
586
+ };
587
+ const ilOffset = offset + headerSize;
588
+ if (ilOffset > bytes.length - ilSize)
589
+ throw new RangeError("Method IL bytes leave artifact");
590
+ const il = bytes.subarray(ilOffset, ilOffset + ilSize);
591
+ const decoded = decodeInstructions(il, limits.maxMethodInstructions);
592
+ const opcodeCounts = {};
593
+ for (const instruction of decoded.parsed)
594
+ opcodeCounts[instruction.opcode] =
595
+ (opcodeCounts[instruction.opcode] ?? 0) + 1;
596
+ const anchors = decoded.parsed
597
+ .map((instruction, index) => ({ instruction, index }))
598
+ .filter(({ instruction }) => instruction.operandKind !== "none")
599
+ .slice(0, limits.instructionAnchorLimit)
600
+ .map(({ instruction }) => ({
601
+ il_offset: instruction.offset,
602
+ opcode: instruction.opcode,
603
+ operand_kind: instruction.operandKind,
604
+ operand: instruction.operand,
605
+ }));
606
+ const normalized = Buffer.from(JSON.stringify(decoded.parsed.map(({ opcode, operandKind, operand }) => [
607
+ opcode,
608
+ operandKind,
609
+ operand,
610
+ ])), "utf8");
611
+ const methodEnd = ilOffset + ilSize;
612
+ const sectionOffset = (methodEnd + 3) & ~3;
613
+ return {
614
+ status: decoded.issue === null ? "present" : "malformed",
615
+ header_format: tiny ? "tiny" : "fat",
616
+ rva,
617
+ file_offset: offset,
618
+ max_stack: maxStack,
619
+ init_locals: tiny ? false : (flags & 0x10) !== 0,
620
+ local_var_sig_token: localSig === 0 ? null : `0x${localSig.toString(16).padStart(8, "0")}`,
621
+ il_size: ilSize,
622
+ il_sha256: sha256Bytes(il),
623
+ normalized_il_sha256: sha256Bytes(normalized),
624
+ instruction_count: decoded.count,
625
+ decoded_instruction_count: decoded.parsed.length,
626
+ truncated_instructions: decoded.truncated,
627
+ opcode_counts: opcodeCounts,
628
+ anchors,
629
+ exception_regions: fat && (flags & 8) !== 0
630
+ ? parseExceptionRegions(bytes, sectionOffset, bytes.length)
631
+ : [],
632
+ issue: decoded.issue,
633
+ };
634
+ }
635
+ catch (cause) {
636
+ return {
637
+ status: "malformed",
638
+ header_format: "unknown",
639
+ rva,
640
+ file_offset: null,
641
+ max_stack: null,
642
+ init_locals: null,
643
+ local_var_sig_token: null,
644
+ il_size: 0,
645
+ il_sha256: null,
646
+ normalized_il_sha256: null,
647
+ instruction_count: 0,
648
+ decoded_instruction_count: 0,
649
+ truncated_instructions: 0,
650
+ opcode_counts: {},
651
+ anchors: [],
652
+ exception_regions: [],
653
+ issue: cause instanceof Error ? cause.message : "Method body parse failed",
654
+ };
655
+ }
656
+ };
657
+ const parseFields = (bytes, layout, ranges, maxBytes) => {
658
+ const fields = [];
659
+ const core = new Map();
660
+ const table = layout.table(4);
661
+ for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
662
+ const cursor = rowCursor(bytes, layout, 4, row);
663
+ const flags = cursor.readUInt16();
664
+ const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
665
+ const sig = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
666
+ const declared = declaringType(ranges, "field", row);
667
+ const token = metadataToken(4, row);
668
+ fields.push({
669
+ token,
670
+ row_offset: cursor.start,
671
+ declaring_type_token: declared?.token ?? null,
672
+ declaring_type: declared?.fullName ?? null,
673
+ name,
674
+ flags,
675
+ signature: signature(sig),
676
+ });
677
+ core.set(token, { token, name });
678
+ }
679
+ return { fields, core };
680
+ };
681
+ const parseMemberRefs = (bytes, layout, maxBytes) => {
682
+ const refs = [];
683
+ const core = new Map();
684
+ const table = layout.table(10);
685
+ for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
686
+ const cursor = rowCursor(bytes, layout, 10, row);
687
+ const parentRaw = cursor.readIndex(layout.codedIndexSize("MemberRefParent"));
688
+ const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
689
+ const sig = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
690
+ const token = metadataToken(10, row);
691
+ refs.push({
692
+ token,
693
+ row_offset: cursor.start,
694
+ parent_token: codedToken(parentRaw, 3, [2, 1, 26, 6, 27]),
695
+ name,
696
+ signature: signature(sig),
697
+ });
698
+ core.set(token, { token, name });
699
+ }
700
+ return { refs, core };
701
+ };
702
+ const parseMethods = (bytes, layout, pe, ranges, maxBytes, limits) => {
703
+ const methods = [];
704
+ const core = new Map();
705
+ const table = layout.table(6);
706
+ for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
707
+ const cursor = rowCursor(bytes, layout, 6, row);
708
+ const rva = cursor.readUInt32();
709
+ const implFlags = cursor.readUInt16();
710
+ const flags = cursor.readUInt16();
711
+ const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), maxBytes);
712
+ const sig = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), maxBytes);
713
+ cursor.readIndex(layout.tableIndexSize(8));
714
+ const declared = declaringType(ranges, "method", row);
715
+ const token = metadataToken(6, row);
716
+ methods.push({
717
+ token,
718
+ row_offset: cursor.start,
719
+ declaring_type_token: declared?.token ?? null,
720
+ declaring_type: declared?.fullName ?? null,
721
+ name,
722
+ rva,
723
+ impl_flags: implFlags,
724
+ flags,
725
+ signature: signature(sig),
726
+ body: methodBody(bytes, pe, rva, limits),
727
+ });
728
+ core.set(token, { token, name, declaringType: declared?.fullName ?? null });
729
+ }
730
+ return { methods, core };
731
+ };
732
+ const targetKind = (token) => token.startsWith("0x06")
733
+ ? "method-def"
734
+ : token.startsWith("0x0a")
735
+ ? "member-ref"
736
+ : token.startsWith("0x2b")
737
+ ? "method-spec"
738
+ : "unknown";
739
+ const edges = (methods, methodCore, fieldCore, refCore) => {
740
+ const callEdges = [];
741
+ const fieldAccesses = [];
742
+ for (const method of methods) {
743
+ for (const anchor of method.body.anchors) {
744
+ if (anchor.operand_kind === "method" && anchor.operand !== null) {
745
+ const named = methodCore.get(anchor.operand)?.name ??
746
+ refCore.get(anchor.operand)?.name ??
747
+ null;
748
+ callEdges.push({
749
+ caller_token: method.token,
750
+ caller: method.declaring_type === null
751
+ ? method.name
752
+ : `${method.declaring_type}.${method.name}`,
753
+ opcode: anchor.opcode,
754
+ target_token: anchor.operand,
755
+ target_kind: targetKind(anchor.operand),
756
+ target_name: named,
757
+ });
758
+ }
759
+ if (anchor.operand_kind === "field" && anchor.operand !== null) {
760
+ fieldAccesses.push({
761
+ method_token: method.token,
762
+ method: method.declaring_type === null
763
+ ? method.name
764
+ : `${method.declaring_type}.${method.name}`,
765
+ opcode: anchor.opcode,
766
+ field_token: anchor.operand,
767
+ field_name: fieldCore.get(anchor.operand)?.name ?? null,
768
+ });
769
+ }
770
+ }
771
+ }
772
+ return { callEdges, fieldAccesses };
773
+ };
774
+ const unavailable = (target, bytes, limits, issue) => managedMemberInspectionSchema.parse({
775
+ schema_version: 1,
776
+ artifact: {
777
+ path: target.path,
778
+ sha256: target.sha256,
779
+ byte_length: bytes.length,
780
+ format: "pe",
781
+ },
782
+ module: null,
783
+ metadata: {
784
+ status: issue === null ? "absent" : "malformed",
785
+ version: null,
786
+ table_row_counts: {},
787
+ },
788
+ identity_scope: {
789
+ token_identity: "build-local",
790
+ requires_artifact_sha256: target.sha256,
791
+ requires_mvid: null,
792
+ },
793
+ types: emptyPage(limits.typeOffset, limits.typeLimit),
794
+ fields: emptyPage(limits.fieldOffset, limits.fieldLimit),
795
+ methods: emptyPage(limits.methodOffset, limits.methodLimit),
796
+ member_refs: emptyPage(limits.memberRefOffset, limits.memberRefLimit),
797
+ call_edges: emptyPage(limits.edgeOffset, limits.edgeLimit),
798
+ field_accesses: emptyPage(limits.edgeOffset, limits.edgeLimit),
799
+ coverage: {
800
+ state: "unavailable",
801
+ issues: issue === null ? [] : [issue],
802
+ },
803
+ limitations: [
804
+ issue === null
805
+ ? "The PE has no admitted CLI metadata; managed member inspection is unavailable."
806
+ : "The CLI metadata could not be admitted; managed member inspection is unavailable.",
807
+ ],
808
+ });
809
+ const resourceDirectory = (pe) => {
810
+ if (pe.cli === null ||
811
+ pe.cli.resources.rva === 0 ||
812
+ pe.cli.resources.size === 0)
813
+ return null;
814
+ return {
815
+ offset: pe.rvaToOffset(pe.cli.resources.rva, pe.cli.resources.size, "cli.resources"),
816
+ size: pe.cli.resources.size,
817
+ };
818
+ };
819
+ /** Inspect metadata members and method bodies without loading target code. */
820
+ export const inspectManagedMembersBytes = (bytes, target, limits) => {
821
+ const pe = readManagedPeLayout(bytes);
822
+ if (pe.cli === null)
823
+ return unavailable(target, bytes, limits, pe.cliIssue);
824
+ const issues = [];
825
+ try {
826
+ const rootOffset = pe.rvaToOffset(pe.cli.metadata.rva, pe.cli.metadata.size, "cli.metadata");
827
+ if (pe.cli.metadata.size > limits.maxMetadataBytes)
828
+ throw managedFailure("limit-exceeded", "metadata.root", `CLI metadata size exceeds max_metadata_bytes ${String(limits.maxMetadataBytes)}`, rootOffset);
829
+ const layout = readManagedMetadataLayout(bytes, rootOffset, pe.cli.metadata.size, limits.maxTableRows);
830
+ const inventory = readManagedMetadataInventory(bytes, layout, {
831
+ referenceOffset: 0,
832
+ referenceLimit: 1,
833
+ resourceOffset: 0,
834
+ resourceLimit: 1,
835
+ attributeOffset: 0,
836
+ attributeLimit: 1,
837
+ maxHeapItemBytes: limits.maxHeapItemBytes,
838
+ }, resourceDirectory(pe));
839
+ issues.push(...inventory.issues);
840
+ const ranges = typeRanges(bytes, layout, limits.maxHeapItemBytes);
841
+ const types = parseTypes(bytes, layout, ranges, limits.maxHeapItemBytes);
842
+ const fields = parseFields(bytes, layout, ranges, limits.maxHeapItemBytes);
843
+ const memberRefs = parseMemberRefs(bytes, layout, limits.maxHeapItemBytes);
844
+ const methods = parseMethods(bytes, layout, pe, ranges, limits.maxHeapItemBytes, limits);
845
+ const related = edges(methods.methods, methods.core, fields.core, memberRefs.core);
846
+ return managedMemberInspectionSchema.parse({
847
+ schema_version: 1,
848
+ artifact: {
849
+ path: target.path,
850
+ sha256: target.sha256,
851
+ byte_length: bytes.length,
852
+ format: "pe",
853
+ },
854
+ module: inventory.module,
855
+ metadata: {
856
+ status: issues.length === 0 ? "complete" : "partial",
857
+ version: layout.version,
858
+ table_row_counts: managedTableRowCounts(layout),
859
+ },
860
+ identity_scope: {
861
+ token_identity: "build-local",
862
+ requires_artifact_sha256: target.sha256,
863
+ requires_mvid: inventory.module?.mvid ?? null,
864
+ },
865
+ types: page(types, limits.typeOffset, limits.typeLimit),
866
+ fields: page(fields.fields, limits.fieldOffset, limits.fieldLimit),
867
+ methods: page(methods.methods, limits.methodOffset, limits.methodLimit),
868
+ member_refs: page(memberRefs.refs, limits.memberRefOffset, limits.memberRefLimit),
869
+ call_edges: page(related.callEdges, limits.edgeOffset, limits.edgeLimit),
870
+ field_accesses: page(related.fieldAccesses, limits.edgeOffset, limits.edgeLimit),
871
+ coverage: {
872
+ state: issues.length === 0 ? "complete" : "partial",
873
+ issues,
874
+ },
875
+ limitations: [
876
+ "Metadata tokens are build-local coordinates and are only meaningful with the reported artifact SHA-256 and MVID.",
877
+ "CIL instruction anchors are decoded from file-backed method bodies only; no target assembly is loaded or executed.",
878
+ "Signatures are decoded for common ECMA-335 primitive, class, valuetype, pointer, byref, array, and generic variable forms; unsupported forms retain raw signature hashes.",
879
+ ],
880
+ });
881
+ }
882
+ catch (cause) {
883
+ if (cause instanceof ManagedReaderFailure)
884
+ return unavailable(target, bytes, limits, cause.issue);
885
+ throw cause;
886
+ }
887
+ };