windows-exe-decompiler-mcp-server 0.1.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 (190) hide show
  1. package/CODEX_INSTALLATION.md +69 -0
  2. package/COPILOT_INSTALLATION.md +77 -0
  3. package/LICENSE +21 -0
  4. package/README.md +314 -0
  5. package/bin/windows-exe-decompiler-mcp-server.js +3 -0
  6. package/dist/analysis-provenance.d.ts +184 -0
  7. package/dist/analysis-provenance.js +74 -0
  8. package/dist/analysis-task-runner.d.ts +31 -0
  9. package/dist/analysis-task-runner.js +160 -0
  10. package/dist/artifact-inventory.d.ts +23 -0
  11. package/dist/artifact-inventory.js +175 -0
  12. package/dist/cache-manager.d.ts +128 -0
  13. package/dist/cache-manager.js +454 -0
  14. package/dist/confidence-semantics.d.ts +66 -0
  15. package/dist/confidence-semantics.js +122 -0
  16. package/dist/config.d.ts +335 -0
  17. package/dist/config.js +193 -0
  18. package/dist/database.d.ts +227 -0
  19. package/dist/database.js +601 -0
  20. package/dist/decompiler-worker.d.ts +441 -0
  21. package/dist/decompiler-worker.js +1962 -0
  22. package/dist/dynamic-trace.d.ts +95 -0
  23. package/dist/dynamic-trace.js +629 -0
  24. package/dist/env-validator.d.ts +15 -0
  25. package/dist/env-validator.js +249 -0
  26. package/dist/error-handler.d.ts +28 -0
  27. package/dist/error-handler.example.d.ts +22 -0
  28. package/dist/error-handler.example.js +141 -0
  29. package/dist/error-handler.js +139 -0
  30. package/dist/ghidra-analysis-status.d.ts +49 -0
  31. package/dist/ghidra-analysis-status.js +178 -0
  32. package/dist/ghidra-config.d.ts +134 -0
  33. package/dist/ghidra-config.js +464 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +200 -0
  36. package/dist/job-queue.d.ts +169 -0
  37. package/dist/job-queue.js +407 -0
  38. package/dist/logger.d.ts +106 -0
  39. package/dist/logger.js +176 -0
  40. package/dist/policy-guard.d.ts +115 -0
  41. package/dist/policy-guard.js +243 -0
  42. package/dist/process-output.d.ts +15 -0
  43. package/dist/process-output.js +90 -0
  44. package/dist/prompts/function-explanation-review.d.ts +5 -0
  45. package/dist/prompts/function-explanation-review.js +64 -0
  46. package/dist/prompts/semantic-name-review.d.ts +5 -0
  47. package/dist/prompts/semantic-name-review.js +63 -0
  48. package/dist/runtime-correlation.d.ts +34 -0
  49. package/dist/runtime-correlation.js +279 -0
  50. package/dist/runtime-paths.d.ts +3 -0
  51. package/dist/runtime-paths.js +11 -0
  52. package/dist/selection-diff.d.ts +667 -0
  53. package/dist/selection-diff.js +53 -0
  54. package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
  55. package/dist/semantic-name-suggestion-artifacts.js +314 -0
  56. package/dist/server.d.ts +129 -0
  57. package/dist/server.js +578 -0
  58. package/dist/tools/artifact-read.d.ts +235 -0
  59. package/dist/tools/artifact-read.js +317 -0
  60. package/dist/tools/artifacts-diff.d.ts +728 -0
  61. package/dist/tools/artifacts-diff.js +304 -0
  62. package/dist/tools/artifacts-list.d.ts +515 -0
  63. package/dist/tools/artifacts-list.js +389 -0
  64. package/dist/tools/attack-map.d.ts +290 -0
  65. package/dist/tools/attack-map.js +519 -0
  66. package/dist/tools/cache-observability.d.ts +4 -0
  67. package/dist/tools/cache-observability.js +36 -0
  68. package/dist/tools/code-function-cfg.d.ts +50 -0
  69. package/dist/tools/code-function-cfg.js +102 -0
  70. package/dist/tools/code-function-decompile.d.ts +55 -0
  71. package/dist/tools/code-function-decompile.js +103 -0
  72. package/dist/tools/code-function-disassemble.d.ts +43 -0
  73. package/dist/tools/code-function-disassemble.js +185 -0
  74. package/dist/tools/code-function-explain-apply.d.ts +255 -0
  75. package/dist/tools/code-function-explain-apply.js +225 -0
  76. package/dist/tools/code-function-explain-prepare.d.ts +535 -0
  77. package/dist/tools/code-function-explain-prepare.js +276 -0
  78. package/dist/tools/code-function-explain-review.d.ts +397 -0
  79. package/dist/tools/code-function-explain-review.js +589 -0
  80. package/dist/tools/code-function-rename-apply.d.ts +248 -0
  81. package/dist/tools/code-function-rename-apply.js +220 -0
  82. package/dist/tools/code-function-rename-prepare.d.ts +506 -0
  83. package/dist/tools/code-function-rename-prepare.js +279 -0
  84. package/dist/tools/code-function-rename-review.d.ts +574 -0
  85. package/dist/tools/code-function-rename-review.js +761 -0
  86. package/dist/tools/code-functions-list.d.ts +37 -0
  87. package/dist/tools/code-functions-list.js +91 -0
  88. package/dist/tools/code-functions-rank.d.ts +34 -0
  89. package/dist/tools/code-functions-rank.js +90 -0
  90. package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
  91. package/dist/tools/code-functions-reconstruct.js +2807 -0
  92. package/dist/tools/code-functions-search.d.ts +39 -0
  93. package/dist/tools/code-functions-search.js +90 -0
  94. package/dist/tools/code-reconstruct-export.d.ts +1212 -0
  95. package/dist/tools/code-reconstruct-export.js +4002 -0
  96. package/dist/tools/code-reconstruct-plan.d.ts +274 -0
  97. package/dist/tools/code-reconstruct-plan.js +342 -0
  98. package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
  99. package/dist/tools/dotnet-metadata-extract.js +355 -0
  100. package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
  101. package/dist/tools/dotnet-reconstruct-export.js +1151 -0
  102. package/dist/tools/dotnet-types-list.d.ts +325 -0
  103. package/dist/tools/dotnet-types-list.js +201 -0
  104. package/dist/tools/dynamic-dependencies.d.ts +115 -0
  105. package/dist/tools/dynamic-dependencies.js +213 -0
  106. package/dist/tools/dynamic-memory-import.d.ts +10 -0
  107. package/dist/tools/dynamic-memory-import.js +567 -0
  108. package/dist/tools/dynamic-trace-import.d.ts +10 -0
  109. package/dist/tools/dynamic-trace-import.js +235 -0
  110. package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
  111. package/dist/tools/entrypoint-fallback-disasm.js +89 -0
  112. package/dist/tools/ghidra-analyze.d.ts +88 -0
  113. package/dist/tools/ghidra-analyze.js +208 -0
  114. package/dist/tools/ghidra-health.d.ts +37 -0
  115. package/dist/tools/ghidra-health.js +212 -0
  116. package/dist/tools/ioc-export.d.ts +209 -0
  117. package/dist/tools/ioc-export.js +542 -0
  118. package/dist/tools/packer-detect.d.ts +165 -0
  119. package/dist/tools/packer-detect.js +284 -0
  120. package/dist/tools/pe-exports-extract.d.ts +175 -0
  121. package/dist/tools/pe-exports-extract.js +253 -0
  122. package/dist/tools/pe-fingerprint.d.ts +234 -0
  123. package/dist/tools/pe-fingerprint.js +269 -0
  124. package/dist/tools/pe-imports-extract.d.ts +105 -0
  125. package/dist/tools/pe-imports-extract.js +245 -0
  126. package/dist/tools/report-generate.d.ts +157 -0
  127. package/dist/tools/report-generate.js +457 -0
  128. package/dist/tools/report-summarize.d.ts +2131 -0
  129. package/dist/tools/report-summarize.js +596 -0
  130. package/dist/tools/runtime-detect.d.ts +135 -0
  131. package/dist/tools/runtime-detect.js +247 -0
  132. package/dist/tools/sample-ingest.d.ts +94 -0
  133. package/dist/tools/sample-ingest.js +327 -0
  134. package/dist/tools/sample-profile-get.d.ts +183 -0
  135. package/dist/tools/sample-profile-get.js +121 -0
  136. package/dist/tools/sandbox-execute.d.ts +441 -0
  137. package/dist/tools/sandbox-execute.js +392 -0
  138. package/dist/tools/strings-extract.d.ts +375 -0
  139. package/dist/tools/strings-extract.js +314 -0
  140. package/dist/tools/strings-floss-decode.d.ts +143 -0
  141. package/dist/tools/strings-floss-decode.js +259 -0
  142. package/dist/tools/system-health.d.ts +434 -0
  143. package/dist/tools/system-health.js +446 -0
  144. package/dist/tools/task-cancel.d.ts +21 -0
  145. package/dist/tools/task-cancel.js +70 -0
  146. package/dist/tools/task-status.d.ts +27 -0
  147. package/dist/tools/task-status.js +106 -0
  148. package/dist/tools/task-sweep.d.ts +22 -0
  149. package/dist/tools/task-sweep.js +77 -0
  150. package/dist/tools/tool-help.d.ts +340 -0
  151. package/dist/tools/tool-help.js +261 -0
  152. package/dist/tools/yara-scan.d.ts +554 -0
  153. package/dist/tools/yara-scan.js +313 -0
  154. package/dist/types.d.ts +266 -0
  155. package/dist/types.js +41 -0
  156. package/dist/worker-pool.d.ts +204 -0
  157. package/dist/worker-pool.js +650 -0
  158. package/dist/workflows/deep-static.d.ts +104 -0
  159. package/dist/workflows/deep-static.js +276 -0
  160. package/dist/workflows/function-explanation-review.d.ts +655 -0
  161. package/dist/workflows/function-explanation-review.js +440 -0
  162. package/dist/workflows/reconstruct.d.ts +2053 -0
  163. package/dist/workflows/reconstruct.js +666 -0
  164. package/dist/workflows/semantic-name-review.d.ts +2418 -0
  165. package/dist/workflows/semantic-name-review.js +521 -0
  166. package/dist/workflows/triage.d.ts +659 -0
  167. package/dist/workflows/triage.js +1374 -0
  168. package/dist/workspace-manager.d.ts +150 -0
  169. package/dist/workspace-manager.js +411 -0
  170. package/ghidra_scripts/DecompileFunction.java +487 -0
  171. package/ghidra_scripts/DecompileFunction.py +150 -0
  172. package/ghidra_scripts/ExtractCFG.java +256 -0
  173. package/ghidra_scripts/ExtractCFG.py +233 -0
  174. package/ghidra_scripts/ExtractFunctions.java +442 -0
  175. package/ghidra_scripts/ExtractFunctions.py +101 -0
  176. package/ghidra_scripts/README.md +125 -0
  177. package/ghidra_scripts/SearchFunctionReferences.java +380 -0
  178. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
  179. package/helpers/DotNetMetadataProbe/Program.cs +566 -0
  180. package/install-to-codex.ps1 +178 -0
  181. package/install-to-copilot.ps1 +303 -0
  182. package/package.json +101 -0
  183. package/requirements.txt +9 -0
  184. package/workers/requirements-dynamic.txt +11 -0
  185. package/workers/requirements.txt +8 -0
  186. package/workers/speakeasy_compat.py +175 -0
  187. package/workers/static_worker.py +5183 -0
  188. package/workers/yara_rules/default.yar +33 -0
  189. package/workers/yara_rules/malware_families.yar +93 -0
  190. package/workers/yara_rules/packers.yar +80 -0
@@ -0,0 +1,629 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { deriveArtifactSessionTag } from './artifact-inventory.js';
4
+ const LATEST_DYNAMIC_EVIDENCE_WINDOW_MS = 10 * 1000;
5
+ const HIGH_SIGNAL_APIS = new Set([
6
+ 'OpenProcess',
7
+ 'OpenProcessToken',
8
+ 'CreateProcessW',
9
+ 'CreateProcessA',
10
+ 'WriteProcessMemory',
11
+ 'ReadProcessMemory',
12
+ 'VirtualAllocEx',
13
+ 'VirtualProtectEx',
14
+ 'CreateRemoteThread',
15
+ 'ResumeThread',
16
+ 'SetThreadContext',
17
+ 'NtQueryInformationProcess',
18
+ 'NtQuerySystemInformation',
19
+ 'GetProcAddress',
20
+ 'LoadLibraryA',
21
+ 'LoadLibraryW',
22
+ 'LoadLibraryExA',
23
+ 'LoadLibraryExW',
24
+ ]);
25
+ const DYNAMIC_RESOLUTION_APIS = new Set([
26
+ 'GetProcAddress',
27
+ 'LoadLibrary',
28
+ 'LoadLibraryA',
29
+ 'LoadLibraryW',
30
+ 'LoadLibraryExA',
31
+ 'LoadLibraryExW',
32
+ ]);
33
+ function dedupeStrings(values, limit) {
34
+ const unique = Array.from(new Set(values.map((item) => item.trim()).filter((item) => item.length > 0)));
35
+ return typeof limit === 'number' ? unique.slice(0, limit) : unique;
36
+ }
37
+ function toStringArray(value) {
38
+ if (!Array.isArray(value)) {
39
+ return [];
40
+ }
41
+ return value.filter((item) => typeof item === 'string');
42
+ }
43
+ function normalizeApiName(value) {
44
+ const trimmed = value.trim();
45
+ return trimmed.replace(/\(.*/, '').replace(/^.*!/, '');
46
+ }
47
+ function asObject(value) {
48
+ return value && typeof value === 'object' && !Array.isArray(value)
49
+ ? value
50
+ : null;
51
+ }
52
+ function readFirstString(obj, keys) {
53
+ for (const key of keys) {
54
+ const value = obj[key];
55
+ if (typeof value === 'string' && value.trim().length > 0) {
56
+ return value.trim();
57
+ }
58
+ }
59
+ return undefined;
60
+ }
61
+ function readFirstNumber(obj, keys) {
62
+ for (const key of keys) {
63
+ const value = obj[key];
64
+ if (typeof value === 'number' && Number.isFinite(value)) {
65
+ return value;
66
+ }
67
+ if (typeof value === 'string' && value.trim().length > 0) {
68
+ const parsed = Number(value);
69
+ if (Number.isFinite(parsed)) {
70
+ return parsed;
71
+ }
72
+ }
73
+ }
74
+ return undefined;
75
+ }
76
+ function normalizeAddress(value) {
77
+ if (typeof value === 'number' && Number.isFinite(value)) {
78
+ return `0x${Math.trunc(value).toString(16)}`;
79
+ }
80
+ if (typeof value === 'string' && value.trim().length > 0) {
81
+ return value.trim();
82
+ }
83
+ return undefined;
84
+ }
85
+ function categorizeApi(api) {
86
+ const normalized = normalizeApiName(api);
87
+ if (DYNAMIC_RESOLUTION_APIS.has(normalized)) {
88
+ return 'dynamic_resolution';
89
+ }
90
+ if (/Process|Thread|RemoteThread|VirtualAllocEx|VirtualProtectEx|SetThreadContext|ResumeThread/i.test(normalized)) {
91
+ return 'process_manipulation';
92
+ }
93
+ if (/Reg(Open|Set|Query|Create|Delete)/i.test(normalized)) {
94
+ return 'registry';
95
+ }
96
+ if (/CreateFile|ReadFile|WriteFile|DeleteFile|CopyFile|FindFirstFile|FindNextFile/i.test(normalized)) {
97
+ return 'filesystem';
98
+ }
99
+ if (/Http|WinInet|Internet|WSA|connect|send|recv|socket/i.test(normalized)) {
100
+ return 'network';
101
+ }
102
+ return 'runtime_api';
103
+ }
104
+ function deriveStages(apis, memoryRegions) {
105
+ const stages = [];
106
+ const apiSet = new Set(apis.map((item) => normalizeApiName(item)));
107
+ const regionSet = new Set(memoryRegions.map((item) => item.toLowerCase()));
108
+ if (Array.from(apiSet).some((item) => DYNAMIC_RESOLUTION_APIS.has(item))) {
109
+ stages.push('resolve_dynamic_apis');
110
+ }
111
+ if (Array.from(apiSet).some((item) => [
112
+ 'OpenProcess',
113
+ 'OpenProcessToken',
114
+ 'WriteProcessMemory',
115
+ 'ReadProcessMemory',
116
+ 'VirtualAllocEx',
117
+ 'SetThreadContext',
118
+ 'ResumeThread',
119
+ 'CreateRemoteThread',
120
+ ].includes(item))) {
121
+ stages.push('prepare_remote_process_access');
122
+ }
123
+ if (Array.from(apiSet).some((item) => /CreateFile|ReadFile|WriteFile|DeleteFile|CopyFile/i.test(item))) {
124
+ stages.push('file_operations');
125
+ }
126
+ if (Array.from(apiSet).some((item) => /Reg(Open|Set|Query|Create|Delete)/i.test(item))) {
127
+ stages.push('registry_operations');
128
+ }
129
+ if (Array.from(apiSet).some((item) => /NtQueryInformationProcess|NtQuerySystemInformation/i.test(item))) {
130
+ stages.push('anti_analysis_checks');
131
+ }
132
+ if (Array.from(regionSet).some((item) => item.includes('resolution')) ||
133
+ Array.from(regionSet).some((item) => item.includes('dispatch'))) {
134
+ stages.push('dispatch_table_assembly');
135
+ }
136
+ return dedupeStrings(stages);
137
+ }
138
+ function deriveRiskHints(apis, evidenceKind) {
139
+ const hints = [];
140
+ const apiSet = new Set(apis.map((item) => normalizeApiName(item)));
141
+ if (Array.from(apiSet).some((item) => DYNAMIC_RESOLUTION_APIS.has(item))) {
142
+ hints.push('Dynamic API resolution was observed in runtime evidence.');
143
+ }
144
+ if (Array.from(apiSet).some((item) => ['WriteProcessMemory', 'ReadProcessMemory', 'VirtualAllocEx', 'CreateRemoteThread'].includes(item))) {
145
+ hints.push('Process-memory manipulation APIs were observed in runtime evidence.');
146
+ }
147
+ if (Array.from(apiSet).some((item) => ['NtQueryInformationProcess', 'NtQuerySystemInformation'].includes(item))) {
148
+ hints.push('Anti-analysis or environment-query APIs were observed in runtime evidence.');
149
+ }
150
+ if (evidenceKind === 'memory_snapshot') {
151
+ hints.push('Evidence is memory-snapshot based; execution was not directly proven by this artifact alone.');
152
+ }
153
+ return hints;
154
+ }
155
+ function classifyDynamicEvidenceLayer(trace) {
156
+ if (trace.executed) {
157
+ return 'executed_trace';
158
+ }
159
+ if ((trace.source_mode || '').toLowerCase() === 'safe_simulation') {
160
+ return 'safe_simulation';
161
+ }
162
+ return 'memory_or_hybrid';
163
+ }
164
+ function confidenceBandForLayer(layer) {
165
+ if (layer === 'executed_trace') {
166
+ return 'high';
167
+ }
168
+ if (layer === 'safe_simulation') {
169
+ return 'suggestive';
170
+ }
171
+ return 'baseline';
172
+ }
173
+ function summarizeDynamicEvidenceLayer(layer, artifactCount, sourceModes) {
174
+ if (layer === 'executed_trace') {
175
+ return `Executed trace evidence from ${artifactCount} artifact(s).`;
176
+ }
177
+ if (layer === 'safe_simulation') {
178
+ return `Safe simulation evidence from ${artifactCount} artifact(s).`;
179
+ }
180
+ if (sourceModes.some((item) => item.toLowerCase() === 'memory_guided')) {
181
+ return `Memory-guided or hybrid runtime evidence from ${artifactCount} artifact(s).`;
182
+ }
183
+ return `Memory or hybrid runtime evidence from ${artifactCount} artifact(s).`;
184
+ }
185
+ function collectCandidateEvents(record) {
186
+ const arrays = [
187
+ record.events,
188
+ record.api_calls,
189
+ record.calls,
190
+ record.trace,
191
+ record.entries,
192
+ record.apis,
193
+ ];
194
+ return arrays.flatMap((value) => (Array.isArray(value) ? value : []));
195
+ }
196
+ function collectCandidateRegions(record) {
197
+ const arrays = [
198
+ record.memory_regions,
199
+ record.regions,
200
+ record.memory_map,
201
+ record.memory_maps,
202
+ record.segments,
203
+ ];
204
+ return arrays.flatMap((value) => (Array.isArray(value) ? value : []));
205
+ }
206
+ function normalizeRegion(entry) {
207
+ const obj = asObject(entry);
208
+ if (!obj) {
209
+ return null;
210
+ }
211
+ const indicators = dedupeStrings([
212
+ ...toStringArray(obj.indicators),
213
+ ...toStringArray(obj.apis),
214
+ ...toStringArray(obj.strings),
215
+ ]);
216
+ return {
217
+ region_type: readFirstString(obj, ['region_type', 'type', 'kind']) || 'memory_region',
218
+ purpose: readFirstString(obj, ['purpose', 'label', 'description']) || 'runtime evidence region',
219
+ source: readFirstString(obj, ['source', 'provider']) || 'imported_trace',
220
+ confidence: readFirstNumber(obj, ['confidence']) || 0.72,
221
+ base_address: normalizeAddress(obj.base_address ?? obj.base ?? obj.start),
222
+ size: readFirstNumber(obj, ['size']),
223
+ protection: readFirstString(obj, ['protection', 'protect']),
224
+ indicators,
225
+ };
226
+ }
227
+ function aggregateApiEvents(events) {
228
+ const aggregates = new Map();
229
+ for (const event of events) {
230
+ const obj = asObject(event);
231
+ if (!obj) {
232
+ continue;
233
+ }
234
+ const rawApi = readFirstString(obj, ['api', 'function', 'name', 'symbol', 'target', 'method']) || '';
235
+ if (!rawApi) {
236
+ continue;
237
+ }
238
+ const api = normalizeApiName(rawApi);
239
+ if (!api) {
240
+ continue;
241
+ }
242
+ const moduleName = readFirstString(obj, ['module', 'dll', 'library', 'image']);
243
+ const key = `${moduleName || ''}!${api}`;
244
+ const existing = aggregates.get(key);
245
+ const confidence = readFirstNumber(obj, ['confidence']) || 0.84;
246
+ const count = Math.max(1, Math.trunc(readFirstNumber(obj, ['count', 'hits']) || 1));
247
+ const sources = dedupeStrings([
248
+ ...(existing?.sources || []),
249
+ ...toStringArray(obj.sources),
250
+ ...toStringArray(obj.indicators),
251
+ ...toStringArray(obj.arguments),
252
+ readFirstString(obj, ['source', 'provider']) || '',
253
+ ]);
254
+ aggregates.set(key, {
255
+ api,
256
+ module: moduleName,
257
+ category: categorizeApi(api),
258
+ count: (existing?.count || 0) + count,
259
+ confidence: Math.max(existing?.confidence || 0, confidence),
260
+ sources,
261
+ });
262
+ }
263
+ return Array.from(aggregates.values()).sort((left, right) => {
264
+ if (right.count !== left.count) {
265
+ return right.count - left.count;
266
+ }
267
+ return right.confidence - left.confidence;
268
+ });
269
+ }
270
+ export function normalizeDynamicTrace(raw, options) {
271
+ const record = asObject(raw) || {};
272
+ const sourceFormat = options?.sourceFormat || 'generic_json';
273
+ const evidenceKind = options?.evidenceKind || 'trace';
274
+ const candidateEvents = collectCandidateEvents(record);
275
+ const candidateRegions = collectCandidateRegions(record);
276
+ const apiCalls = aggregateApiEvents(candidateEvents);
277
+ const memoryRegions = candidateRegions
278
+ .map((entry) => normalizeRegion(entry))
279
+ .filter((item) => Boolean(item));
280
+ const modules = dedupeStrings([
281
+ ...toStringArray(record.modules),
282
+ ...apiCalls.map((item) => item.module || ''),
283
+ ]);
284
+ const strings = dedupeStrings([
285
+ ...toStringArray(record.strings),
286
+ ...toStringArray(record.observed_strings),
287
+ ...memoryRegions.flatMap((item) => item.indicators),
288
+ ], 100);
289
+ const stages = dedupeStrings([
290
+ ...toStringArray(record.stages),
291
+ ...deriveStages(apiCalls.map((item) => item.api), memoryRegions.map((item) => `${item.region_type}:${item.purpose}`)),
292
+ ]);
293
+ const executed = typeof record.executed === 'boolean' ? record.executed : evidenceKind !== 'memory_snapshot';
294
+ const riskHints = dedupeStrings([
295
+ ...toStringArray(record.risk_hints),
296
+ ...deriveRiskHints(apiCalls.map((item) => item.api), evidenceKind),
297
+ ]);
298
+ const notes = dedupeStrings([
299
+ readFirstString(record, ['summary', 'description']) || '',
300
+ ...toStringArray(record.notes),
301
+ ]);
302
+ return {
303
+ schema_version: '0.1.0',
304
+ source_format: sourceFormat,
305
+ evidence_kind: evidenceKind,
306
+ source_name: options?.sourceName,
307
+ source_mode: undefined,
308
+ imported_at: new Date().toISOString(),
309
+ executed,
310
+ raw_event_count: candidateEvents.length,
311
+ api_calls: apiCalls,
312
+ memory_regions: memoryRegions,
313
+ modules,
314
+ strings,
315
+ stages,
316
+ risk_hints: riskHints,
317
+ notes,
318
+ };
319
+ }
320
+ export function normalizeDynamicTraceArtifactPayload(raw) {
321
+ const record = asObject(raw);
322
+ if (!record) {
323
+ return null;
324
+ }
325
+ if (record.schema_version === '0.1.0' &&
326
+ typeof record.source_format === 'string' &&
327
+ Array.isArray(record.api_calls)) {
328
+ return raw;
329
+ }
330
+ if (typeof record.run_id === 'string' && (Array.isArray(record.timeline) || Array.isArray(record.api_resolution))) {
331
+ const apiResolution = Array.isArray(record.api_resolution) ? record.api_resolution : [];
332
+ const memoryRegions = Array.isArray(record.memory_regions) ? record.memory_regions : [];
333
+ const executionHypotheses = Array.isArray(record.execution_hypotheses)
334
+ ? record.execution_hypotheses
335
+ : [];
336
+ const timeline = Array.isArray(record.timeline) ? record.timeline : [];
337
+ const environment = asObject(record.environment) || {};
338
+ const mode = typeof record.mode === 'string' ? record.mode : 'sandbox';
339
+ const evidenceKind = mode === 'memory_guided'
340
+ ? 'hybrid'
341
+ : typeof environment.executed === 'boolean' && environment.executed
342
+ ? 'trace'
343
+ : 'hybrid';
344
+ return {
345
+ schema_version: '0.1.0',
346
+ source_format: 'sandbox_trace',
347
+ evidence_kind: evidenceKind,
348
+ source_name: typeof record.run_id === 'string' ? record.run_id : undefined,
349
+ source_mode: mode,
350
+ imported_at: new Date().toISOString(),
351
+ executed: Boolean(environment.executed),
352
+ raw_event_count: timeline.length,
353
+ api_calls: aggregateApiEvents(apiResolution),
354
+ memory_regions: memoryRegions
355
+ .map((entry) => normalizeRegion(entry))
356
+ .filter((item) => Boolean(item)),
357
+ modules: [],
358
+ strings: dedupeStrings(timeline
359
+ .map((entry) => asObject(entry))
360
+ .filter((item) => Boolean(item))
361
+ .map((item) => readFirstString(item, ['indicator']) || '')),
362
+ stages: dedupeStrings(executionHypotheses
363
+ .map((entry) => asObject(entry))
364
+ .filter((item) => Boolean(item))
365
+ .map((item) => readFirstString(item, ['stage']) || '')),
366
+ risk_hints: dedupeStrings([
367
+ readFirstString(asObject(record.risk) || {}, ['level']) || '',
368
+ ...toStringArray(record.warnings),
369
+ ]),
370
+ notes: [
371
+ typeof record.mode === 'string' ? `Imported sandbox trace from mode=${record.mode}` : 'Imported sandbox trace',
372
+ ],
373
+ };
374
+ }
375
+ return null;
376
+ }
377
+ export function summarizeDynamicTrace(trace) {
378
+ const observedApis = trace.api_calls.map((item) => item.api);
379
+ const highSignalApis = observedApis.filter((item) => HIGH_SIGNAL_APIS.has(normalizeApiName(item)));
380
+ const memoryRegions = trace.memory_regions.map((item) => item.purpose || item.region_type);
381
+ const regionTypes = trace.memory_regions.map((item) => item.region_type);
382
+ const evidence = [];
383
+ evidence.push(trace.executed
384
+ ? `Imported runtime trace observed ${trace.api_calls.length} unique API(s).`
385
+ : `Imported ${trace.evidence_kind} evidence observed ${trace.api_calls.length} unique API(s).`);
386
+ if (highSignalApis.length > 0) {
387
+ evidence.push(`High-signal runtime APIs: ${dedupeStrings(highSignalApis, 10).join(', ')}`);
388
+ }
389
+ if (memoryRegions.length > 0) {
390
+ evidence.push(`Memory regions or plans: ${dedupeStrings(memoryRegions, 8).join(', ')}`);
391
+ }
392
+ if (trace.stages.length > 0) {
393
+ evidence.push(`Derived runtime stages: ${trace.stages.join(', ')}`);
394
+ }
395
+ for (const hint of trace.risk_hints) {
396
+ evidence.push(hint);
397
+ }
398
+ return {
399
+ artifact_count: 1,
400
+ executed: trace.executed,
401
+ executed_artifact_count: trace.executed ? 1 : 0,
402
+ api_count: trace.api_calls.length,
403
+ memory_region_count: trace.memory_regions.length,
404
+ stage_count: trace.stages.length,
405
+ observed_apis: dedupeStrings(observedApis, 20),
406
+ high_signal_apis: dedupeStrings(highSignalApis, 12),
407
+ memory_regions: dedupeStrings(memoryRegions, 12),
408
+ region_types: dedupeStrings(regionTypes, 12),
409
+ observed_modules: dedupeStrings(trace.modules, 12),
410
+ observed_strings: dedupeStrings(trace.strings, 12),
411
+ stages: trace.stages,
412
+ risk_hints: trace.risk_hints,
413
+ source_formats: [trace.source_format],
414
+ evidence_kinds: [trace.evidence_kind],
415
+ source_names: dedupeStrings(trace.source_name ? [trace.source_name] : []),
416
+ source_modes: dedupeStrings(trace.source_mode ? [trace.source_mode] : []),
417
+ confidence_layers: [
418
+ {
419
+ layer: classifyDynamicEvidenceLayer(trace),
420
+ artifact_count: 1,
421
+ confidence_band: confidenceBandForLayer(classifyDynamicEvidenceLayer(trace)),
422
+ source_formats: [trace.source_format],
423
+ evidence_kinds: [trace.evidence_kind],
424
+ source_names: dedupeStrings(trace.source_name ? [trace.source_name] : []),
425
+ source_modes: dedupeStrings(trace.source_mode ? [trace.source_mode] : []),
426
+ latest_imported_at: trace.imported_at,
427
+ summary: summarizeDynamicEvidenceLayer(classifyDynamicEvidenceLayer(trace), 1, dedupeStrings(trace.source_mode ? [trace.source_mode] : [])),
428
+ },
429
+ ],
430
+ earliest_imported_at: trace.imported_at,
431
+ latest_imported_at: trace.imported_at,
432
+ scope_note: 'Runtime evidence currently reflects a single registered artifact.',
433
+ evidence: dedupeStrings(evidence),
434
+ summary: trace.executed
435
+ ? `Runtime evidence observed ${trace.api_calls.length} API(s) across ${trace.stages.length || 1} inferred stage(s).`
436
+ : `Imported ${trace.evidence_kind} evidence observed ${trace.api_calls.length} API(s) with ${trace.memory_regions.length} memory-region hint(s).`,
437
+ };
438
+ }
439
+ export async function loadDynamicTraceEvidence(workspaceManager, database, sampleId, options = {}) {
440
+ const artifacts = [
441
+ ...database.findArtifactsByType(sampleId, 'dynamic_trace_json'),
442
+ ...database.findArtifactsByType(sampleId, 'sandbox_trace_json'),
443
+ ];
444
+ if (artifacts.length === 0) {
445
+ return null;
446
+ }
447
+ const workspace = await workspaceManager.getWorkspace(sampleId);
448
+ const loadedTraces = [];
449
+ for (const artifact of artifacts) {
450
+ try {
451
+ const absPath = workspaceManager.normalizePath(workspace.root, artifact.path);
452
+ const content = await fs.readFile(absPath, 'utf-8');
453
+ const parsed = JSON.parse(content);
454
+ const normalized = normalizeDynamicTraceArtifactPayload(parsed) ||
455
+ normalizeDynamicTrace(parsed, { sourceFormat: 'generic_json', evidenceKind: 'hybrid' });
456
+ const sessionTags = new Set();
457
+ const derivedSessionTag = deriveArtifactSessionTag(artifact.path);
458
+ if (derivedSessionTag) {
459
+ sessionTags.add(derivedSessionTag);
460
+ }
461
+ if (typeof normalized.source_name === 'string' && normalized.source_name.trim().length > 0) {
462
+ sessionTags.add(normalized.source_name.trim());
463
+ }
464
+ const basename = path.basename(artifact.path, path.extname(artifact.path)).trim();
465
+ if (basename.length > 0) {
466
+ sessionTags.add(basename);
467
+ }
468
+ loadedTraces.push({
469
+ artifact,
470
+ normalized,
471
+ session_tags: Array.from(sessionTags),
472
+ });
473
+ }
474
+ catch {
475
+ continue;
476
+ }
477
+ }
478
+ if (loadedTraces.length === 0) {
479
+ return null;
480
+ }
481
+ const normalizedSelector = options.sessionTag?.trim().toLowerCase() || null;
482
+ const evidenceScope = options.evidenceScope || 'all';
483
+ let selectedTraces = loadedTraces;
484
+ if (normalizedSelector) {
485
+ selectedTraces = selectedTraces.filter((item) => {
486
+ if (item.artifact.path.toLowerCase().includes(normalizedSelector)) {
487
+ return true;
488
+ }
489
+ return item.session_tags.some((tag) => tag.toLowerCase() === normalizedSelector);
490
+ });
491
+ }
492
+ if (evidenceScope === 'latest' && selectedTraces.length > 1) {
493
+ const latestTimestamp = selectedTraces.reduce((maxValue, item) => {
494
+ const timestamp = new Date(item.artifact.created_at || item.normalized.imported_at).getTime();
495
+ return Number.isFinite(timestamp) && timestamp > maxValue ? timestamp : maxValue;
496
+ }, Number.NEGATIVE_INFINITY);
497
+ if (Number.isFinite(latestTimestamp)) {
498
+ selectedTraces = selectedTraces.filter((item) => {
499
+ const timestamp = new Date(item.artifact.created_at || item.normalized.imported_at).getTime();
500
+ return Number.isFinite(timestamp) && latestTimestamp - timestamp <= LATEST_DYNAMIC_EVIDENCE_WINDOW_MS;
501
+ });
502
+ }
503
+ }
504
+ if (selectedTraces.length === 0) {
505
+ return null;
506
+ }
507
+ const normalizedTraces = selectedTraces.map((item) => item.normalized);
508
+ const aggregated = {
509
+ artifact_count: normalizedTraces.length,
510
+ executed: normalizedTraces.some((item) => item.executed),
511
+ executed_artifact_count: normalizedTraces.filter((item) => item.executed).length,
512
+ observed_apis: dedupeStrings(normalizedTraces.flatMap((item) => item.api_calls.map((entry) => entry.api)), 30),
513
+ memory_regions: dedupeStrings(normalizedTraces.flatMap((item) => item.memory_regions.map((entry) => entry.purpose || entry.region_type)), 20),
514
+ region_types: dedupeStrings(normalizedTraces.flatMap((item) => item.memory_regions.map((entry) => entry.region_type)), 20),
515
+ observed_modules: dedupeStrings(normalizedTraces.flatMap((item) => item.modules), 20),
516
+ observed_strings: dedupeStrings(normalizedTraces.flatMap((item) => item.strings), 20),
517
+ stages: dedupeStrings(normalizedTraces.flatMap((item) => item.stages), 20),
518
+ risk_hints: dedupeStrings(normalizedTraces.flatMap((item) => item.risk_hints), 20),
519
+ source_formats: dedupeStrings(normalizedTraces.map((item) => item.source_format), 12),
520
+ evidence_kinds: dedupeStrings(normalizedTraces.map((item) => item.evidence_kind), 12),
521
+ source_modes: dedupeStrings(normalizedTraces.map((item) => item.source_mode || '').filter((item) => item.length > 0), 12),
522
+ source_names: dedupeStrings(normalizedTraces
523
+ .map((item) => item.source_name || '')
524
+ .filter((item) => item.length > 0), 20),
525
+ imported_at: normalizedTraces
526
+ .map((item) => item.imported_at)
527
+ .filter((item) => item && item.length > 0)
528
+ .sort(),
529
+ };
530
+ const layerBuckets = new Map();
531
+ for (const trace of normalizedTraces) {
532
+ const layer = classifyDynamicEvidenceLayer(trace);
533
+ const existing = layerBuckets.get(layer) || {
534
+ artifact_count: 0,
535
+ source_formats: new Set(),
536
+ evidence_kinds: new Set(),
537
+ source_names: new Set(),
538
+ source_modes: new Set(),
539
+ latest_imported_at: null,
540
+ };
541
+ existing.artifact_count += 1;
542
+ existing.source_formats.add(trace.source_format);
543
+ existing.evidence_kinds.add(trace.evidence_kind);
544
+ if (trace.source_name) {
545
+ existing.source_names.add(trace.source_name);
546
+ }
547
+ if (trace.source_mode) {
548
+ existing.source_modes.add(trace.source_mode);
549
+ }
550
+ if (!existing.latest_imported_at || trace.imported_at > existing.latest_imported_at) {
551
+ existing.latest_imported_at = trace.imported_at;
552
+ }
553
+ layerBuckets.set(layer, existing);
554
+ }
555
+ const confidenceLayers = Array.from(layerBuckets.entries())
556
+ .map(([layer, bucket]) => ({
557
+ layer,
558
+ artifact_count: bucket.artifact_count,
559
+ confidence_band: confidenceBandForLayer(layer),
560
+ source_formats: dedupeStrings(Array.from(bucket.source_formats), 12),
561
+ evidence_kinds: dedupeStrings(Array.from(bucket.evidence_kinds), 12),
562
+ source_names: dedupeStrings(Array.from(bucket.source_names), 12),
563
+ source_modes: dedupeStrings(Array.from(bucket.source_modes), 12),
564
+ latest_imported_at: bucket.latest_imported_at,
565
+ summary: summarizeDynamicEvidenceLayer(layer, bucket.artifact_count, dedupeStrings(Array.from(bucket.source_modes), 12)),
566
+ }))
567
+ .sort((left, right) => {
568
+ const rank = {
569
+ executed_trace: 0,
570
+ safe_simulation: 1,
571
+ memory_or_hybrid: 2,
572
+ };
573
+ return rank[left.layer] - rank[right.layer];
574
+ });
575
+ const highSignalApis = aggregated.observed_apis.filter((item) => HIGH_SIGNAL_APIS.has(normalizeApiName(item)));
576
+ const evidence = dedupeStrings([
577
+ ...normalizedTraces.flatMap((item) => summarizeDynamicTrace(item).evidence),
578
+ confidenceLayers.length > 0
579
+ ? `Runtime evidence layers: ${confidenceLayers
580
+ .map((item) => `${item.layer}(${item.artifact_count})`)
581
+ .join(', ')}`
582
+ : '',
583
+ normalizedTraces.length > 1
584
+ ? 'Runtime evidence is aggregated across registered artifacts for this sample and is not limited to the current call.'
585
+ : '',
586
+ ], 24);
587
+ const earliestImportedAt = aggregated.imported_at[0] || null;
588
+ const latestImportedAt = aggregated.imported_at.length > 0 ? aggregated.imported_at[aggregated.imported_at.length - 1] : null;
589
+ const scopeNote = evidenceScope === 'latest'
590
+ ? `Runtime evidence is limited to the latest artifact window (${selectedTraces.length}/${loadedTraces.length} artifact(s), window=${LATEST_DYNAMIC_EVIDENCE_WINDOW_MS}ms).`
591
+ : normalizedSelector
592
+ ? `Runtime evidence is limited to session selector "${options.sessionTag}" (${selectedTraces.length}/${loadedTraces.length} artifact(s)).`
593
+ : normalizedTraces.length > 1
594
+ ? 'Runtime evidence is aggregated across multiple registered artifacts and may include historical imports, simulations, and executed traces.'
595
+ : 'Runtime evidence currently reflects a single registered artifact for this sample.';
596
+ return {
597
+ artifact_count: aggregated.artifact_count,
598
+ artifact_ids: Array.from(new Set(selectedTraces.map((item) => item.artifact.id))),
599
+ executed: aggregated.executed,
600
+ executed_artifact_count: aggregated.executed_artifact_count,
601
+ api_count: aggregated.observed_apis.length,
602
+ memory_region_count: aggregated.memory_regions.length,
603
+ stage_count: aggregated.stages.length,
604
+ observed_apis: aggregated.observed_apis,
605
+ high_signal_apis: dedupeStrings(highSignalApis, 12),
606
+ memory_regions: aggregated.memory_regions,
607
+ region_types: aggregated.region_types,
608
+ observed_modules: aggregated.observed_modules,
609
+ observed_strings: aggregated.observed_strings,
610
+ stages: aggregated.stages,
611
+ risk_hints: aggregated.risk_hints,
612
+ source_formats: aggregated.source_formats,
613
+ evidence_kinds: aggregated.evidence_kinds,
614
+ source_modes: aggregated.source_modes,
615
+ source_names: aggregated.source_names,
616
+ confidence_layers: confidenceLayers,
617
+ earliest_imported_at: earliestImportedAt,
618
+ latest_imported_at: latestImportedAt,
619
+ scope_note: scopeNote,
620
+ evidence_scope: evidenceScope,
621
+ session_selector: options.sessionTag || null,
622
+ session_tags: dedupeStrings(selectedTraces.flatMap((item) => item.session_tags), 20),
623
+ evidence,
624
+ summary: aggregated.executed
625
+ ? `Imported runtime evidence from ${aggregated.artifact_count} artifact(s) observed ${aggregated.observed_apis.length} API(s).`
626
+ : `Imported memory/runtime evidence from ${aggregated.artifact_count} artifact(s) observed ${aggregated.observed_apis.length} API(s).`,
627
+ };
628
+ }
629
+ //# sourceMappingURL=dynamic-trace.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Environment validation for MCP Server
3
+ * Validates that required dependencies and paths exist
4
+ */
5
+ import type { Config } from './config.js';
6
+ export interface ValidationResult {
7
+ valid: boolean;
8
+ errors: string[];
9
+ warnings: string[];
10
+ }
11
+ /**
12
+ * Validate the entire environment based on configuration
13
+ */
14
+ export declare function validateEnvironment(config: Config): ValidationResult;
15
+ //# sourceMappingURL=env-validator.d.ts.map