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,596 @@
1
+ /**
2
+ * report.summarize tool implementation
3
+ * Generates quick triage report with summary, confidence, IOCs, evidence, and recommendations.
4
+ */
5
+ import { z } from 'zod';
6
+ import { createTriageWorkflowHandler } from '../workflows/triage.js';
7
+ import { loadDynamicTraceEvidence } from '../dynamic-trace.js';
8
+ import { loadSemanticFunctionExplanationIndex, } from '../semantic-name-suggestion-artifacts.js';
9
+ import { ConfidenceSemanticsSchema, buildReportConfidenceSemantics, } from '../confidence-semantics.js';
10
+ import { AnalysisProvenanceSchema, buildRuntimeArtifactProvenance, buildSemanticArtifactProvenance, } from '../analysis-provenance.js';
11
+ import { AnalysisSelectionDiffSchema, buildArtifactSelectionDiff, } from '../selection-diff.js';
12
+ const TOOL_NAME = 'report.summarize';
13
+ export const ReportSummarizeInputSchema = z.object({
14
+ sample_id: z.string().describe('Sample ID (format: sha256:<hex>)'),
15
+ mode: z
16
+ .enum(['triage', 'dotnet'])
17
+ .default('triage')
18
+ .describe('Report mode: triage for quick assessment, dotnet for .NET-specific analysis'),
19
+ evidence_scope: z
20
+ .enum(['all', 'latest', 'session'])
21
+ .default('all')
22
+ .describe('Runtime evidence scope: all artifacts, only the latest artifact window, or a specific session selector'),
23
+ evidence_session_tag: z
24
+ .string()
25
+ .optional()
26
+ .describe('Optional runtime evidence session selector used when evidence_scope=session or to narrow all/latest results'),
27
+ semantic_scope: z
28
+ .enum(['all', 'latest', 'session'])
29
+ .default('all')
30
+ .describe('Semantic explanation artifact scope: all artifacts, latest explanation window, or a specific semantic review session'),
31
+ semantic_session_tag: z
32
+ .string()
33
+ .optional()
34
+ .describe('Optional semantic review session selector used when semantic_scope=session or to narrow all/latest results'),
35
+ compare_evidence_scope: z
36
+ .enum(['all', 'latest', 'session'])
37
+ .optional()
38
+ .describe('Optional baseline runtime evidence scope used to compare this report against another runtime artifact selection'),
39
+ compare_evidence_session_tag: z
40
+ .string()
41
+ .optional()
42
+ .describe('Optional baseline runtime evidence session selector used when compare_evidence_scope=session'),
43
+ compare_semantic_scope: z
44
+ .enum(['all', 'latest', 'session'])
45
+ .optional()
46
+ .describe('Optional baseline semantic explanation scope used to compare this report against another semantic artifact selection'),
47
+ compare_semantic_session_tag: z
48
+ .string()
49
+ .optional()
50
+ .describe('Optional baseline semantic explanation session selector used when compare_semantic_scope=session'),
51
+ force_refresh: z
52
+ .boolean()
53
+ .optional()
54
+ .default(false)
55
+ .describe('Bypass cache in downstream analysis tools'),
56
+ })
57
+ .refine((value) => value.evidence_scope !== 'session' || Boolean(value.evidence_session_tag?.trim()), {
58
+ message: 'evidence_session_tag is required when evidence_scope=session',
59
+ path: ['evidence_session_tag'],
60
+ })
61
+ .refine((value) => value.semantic_scope !== 'session' || Boolean(value.semantic_session_tag?.trim()), {
62
+ message: 'semantic_session_tag is required when semantic_scope=session',
63
+ path: ['semantic_session_tag'],
64
+ })
65
+ .refine((value) => value.compare_evidence_scope !== 'session' || Boolean(value.compare_evidence_session_tag?.trim()), {
66
+ message: 'compare_evidence_session_tag is required when compare_evidence_scope=session',
67
+ path: ['compare_evidence_session_tag'],
68
+ })
69
+ .refine((value) => value.compare_semantic_scope !== 'session' || Boolean(value.compare_semantic_session_tag?.trim()), {
70
+ message: 'compare_semantic_session_tag is required when compare_semantic_scope=session',
71
+ path: ['compare_semantic_session_tag'],
72
+ });
73
+ const EvidenceLineageLayerSchema = z.object({
74
+ layer: z.enum(['static_only', 'safe_simulation', 'memory_or_hybrid', 'executed_trace']),
75
+ confidence_band: z.enum(['baseline', 'suggestive', 'high']),
76
+ artifact_count: z.number().int().nonnegative(),
77
+ source_formats: z.array(z.string()),
78
+ evidence_kinds: z.array(z.string()),
79
+ source_names: z.array(z.string()),
80
+ latest_imported_at: z.string().nullable(),
81
+ summary: z.string(),
82
+ });
83
+ const EvidenceLineageSchema = z.object({
84
+ layers: z.array(EvidenceLineageLayerSchema),
85
+ latest_runtime_artifact_at: z.string().nullable(),
86
+ scope_note: z.string(),
87
+ });
88
+ const ReportAssessmentConfidenceSchema = z.object({
89
+ assessment: ConfidenceSemanticsSchema,
90
+ });
91
+ const FunctionExplanationSummarySchema = z.object({
92
+ address: z.string().nullable(),
93
+ function: z.string().nullable(),
94
+ behavior: z.string(),
95
+ summary: z.string(),
96
+ confidence: z.number().min(0).max(1),
97
+ rewrite_guidance: z.array(z.string()),
98
+ source: z.string().nullable(),
99
+ });
100
+ export const ReportSummarizeOutputSchema = z.object({
101
+ ok: z.boolean(),
102
+ data: z
103
+ .object({
104
+ summary: z.string().describe('Natural language summary of the analysis'),
105
+ confidence: z.number().min(0).max(1).describe('Confidence score (0-1)'),
106
+ threat_level: z
107
+ .enum(['clean', 'suspicious', 'malicious', 'unknown'])
108
+ .describe('Assessed threat level'),
109
+ iocs: z
110
+ .object({
111
+ suspicious_imports: z.array(z.string()).describe('Suspicious imported functions'),
112
+ suspicious_strings: z.array(z.string()).describe('Suspicious strings found'),
113
+ yara_matches: z.array(z.string()).describe('YARA rule matches'),
114
+ yara_low_confidence: z.array(z.string()).optional().describe('YARA matches downgraded due to weak evidence'),
115
+ urls: z.array(z.string()).optional().describe('URLs found in strings'),
116
+ ip_addresses: z.array(z.string()).optional().describe('IP addresses found'),
117
+ file_paths: z.array(z.string()).optional().describe('File paths found'),
118
+ registry_keys: z.array(z.string()).optional().describe('Registry keys found'),
119
+ high_value_iocs: z
120
+ .object({
121
+ suspicious_apis: z.array(z.string()).optional(),
122
+ commands: z.array(z.string()).optional(),
123
+ pipes: z.array(z.string()).optional(),
124
+ urls: z.array(z.string()).optional(),
125
+ network: z.array(z.string()).optional(),
126
+ })
127
+ .optional(),
128
+ compiler_artifacts: z
129
+ .object({
130
+ cargo_paths: z.array(z.string()).optional(),
131
+ rust_markers: z.array(z.string()).optional(),
132
+ library_profile: z
133
+ .object({
134
+ ecosystems: z.array(z.string()),
135
+ top_crates: z.array(z.string()),
136
+ notable_libraries: z.array(z.string()),
137
+ evidence: z.array(z.string()),
138
+ })
139
+ .optional(),
140
+ })
141
+ .optional(),
142
+ })
143
+ .describe('Indicators of Compromise'),
144
+ evidence: z.array(z.string()).describe('Evidence supporting the assessment'),
145
+ evidence_lineage: EvidenceLineageSchema.optional().describe('Explicit evidence layers separating static-only, simulated, memory/hybrid, and executed runtime evidence.'),
146
+ confidence_semantics: ReportAssessmentConfidenceSchema.optional().describe('Explains how to interpret confidence scores. These are heuristic evidence scores, not calibrated probabilities.'),
147
+ provenance: AnalysisProvenanceSchema.optional().describe('Explicit runtime/semantic artifact selection used to produce this report, including scope, session selector, and selected artifact IDs.'),
148
+ selection_diffs: AnalysisSelectionDiffSchema.optional().describe('Optional comparison between the current artifact selection and a caller-provided baseline runtime/semantic selection.'),
149
+ function_explanations: z
150
+ .array(FunctionExplanationSummarySchema)
151
+ .optional()
152
+ .describe('Optional external LLM explanation summaries loaded from semantic explanation artifacts.'),
153
+ evidence_weights: z
154
+ .object({
155
+ import: z.number().min(0).max(1),
156
+ string: z.number().min(0).max(1),
157
+ runtime: z.number().min(0).max(1),
158
+ })
159
+ .optional()
160
+ .describe('Relative evidence contribution weights (import/string/runtime)'),
161
+ inference: z
162
+ .object({
163
+ classification: z.enum(['benign', 'suspicious', 'malicious', 'unknown']),
164
+ hypotheses: z.array(z.string()),
165
+ false_positive_risks: z.array(z.string()),
166
+ intent_assessment: z
167
+ .object({
168
+ label: z.enum(['dual_use_tool', 'operator_utility', 'malware_like_payload', 'unknown']),
169
+ confidence: z.number().min(0).max(1),
170
+ evidence: z.array(z.string()),
171
+ counter_evidence: z.array(z.string()),
172
+ })
173
+ .optional(),
174
+ tooling_assessment: z
175
+ .object({
176
+ help_text_detected: z.boolean(),
177
+ cli_surface_detected: z.boolean(),
178
+ framework_hints: z.array(z.string()),
179
+ toolchain_markers: z.array(z.string()),
180
+ library_profile: z
181
+ .object({
182
+ ecosystems: z.array(z.string()),
183
+ top_crates: z.array(z.string()),
184
+ notable_libraries: z.array(z.string()),
185
+ evidence: z.array(z.string()),
186
+ })
187
+ .optional(),
188
+ })
189
+ .optional(),
190
+ })
191
+ .optional()
192
+ .describe('Inference layer separated from raw evidence'),
193
+ recommendation: z.string().describe('Recommended next steps'),
194
+ })
195
+ .optional(),
196
+ warnings: z.array(z.string()).optional(),
197
+ errors: z.array(z.string()).optional(),
198
+ metrics: z
199
+ .object({
200
+ elapsed_ms: z.number(),
201
+ tool: z.string(),
202
+ })
203
+ .optional(),
204
+ });
205
+ export const reportSummarizeToolDefinition = {
206
+ name: TOOL_NAME,
207
+ description: 'Generate a quick triage report with summary, confidence, IOC, evidence, and recommendations. Supports triage mode and dotnet fallback mode.',
208
+ inputSchema: ReportSummarizeInputSchema,
209
+ outputSchema: ReportSummarizeOutputSchema,
210
+ };
211
+ function toolMetrics(startTime) {
212
+ return {
213
+ elapsed_ms: Date.now() - startTime,
214
+ tool: TOOL_NAME,
215
+ };
216
+ }
217
+ function dedupe(values) {
218
+ return Array.from(new Set(values.filter((item) => item.trim().length > 0)));
219
+ }
220
+ function buildEvidenceLineage(dynamicEvidence) {
221
+ const staticLayer = {
222
+ layer: 'static_only',
223
+ confidence_band: 'baseline',
224
+ artifact_count: 0,
225
+ source_formats: ['static_analysis'],
226
+ evidence_kinds: ['static'],
227
+ source_names: [],
228
+ latest_imported_at: null,
229
+ summary: 'Static analysis evidence from triage, imports, strings, and reconstruction outputs.',
230
+ };
231
+ if (!dynamicEvidence) {
232
+ return {
233
+ layers: [staticLayer],
234
+ latest_runtime_artifact_at: null,
235
+ scope_note: 'No registered runtime artifacts were merged into this report.',
236
+ };
237
+ }
238
+ const runtimeLayers = (dynamicEvidence.confidence_layers || []).map((item) => ({
239
+ layer: item.layer,
240
+ confidence_band: item.confidence_band,
241
+ artifact_count: item.artifact_count,
242
+ source_formats: item.source_formats,
243
+ evidence_kinds: item.evidence_kinds,
244
+ source_names: item.source_names,
245
+ latest_imported_at: item.latest_imported_at,
246
+ summary: item.summary,
247
+ }));
248
+ return {
249
+ layers: [staticLayer, ...runtimeLayers],
250
+ latest_runtime_artifact_at: dynamicEvidence.latest_imported_at || null,
251
+ scope_note: dynamicEvidence.scope_note ||
252
+ 'Runtime evidence was merged from registered artifacts and may include historical imports.',
253
+ };
254
+ }
255
+ function buildEvidenceLayerHeadline(lineage) {
256
+ const labels = lineage.layers.map((item) => item.layer);
257
+ return `Evidence layers: ${labels.join(' -> ')}.`;
258
+ }
259
+ function buildAssessmentConfidencePayload(confidence, evidenceScope, lineage) {
260
+ return {
261
+ assessment: buildReportConfidenceSemantics({
262
+ score: confidence,
263
+ evidenceScope,
264
+ runtimeLayers: lineage?.layers.map((item) => item.layer) || ['static_only'],
265
+ executedTracePresent: lineage?.layers.some((item) => item.layer === 'executed_trace') || false,
266
+ }),
267
+ };
268
+ }
269
+ async function loadFunctionExplanationSummaries(workspaceManager, database, sampleId, options) {
270
+ const index = await loadSemanticFunctionExplanationIndex(workspaceManager, database, sampleId, {
271
+ scope: options?.scope,
272
+ sessionTag: options?.sessionTag,
273
+ });
274
+ const explanations = Array.from(index.byAddress.values());
275
+ explanations.sort((a, b) => {
276
+ if (b.confidence !== a.confidence) {
277
+ return b.confidence - a.confidence;
278
+ }
279
+ return (b.created_at || '').localeCompare(a.created_at || '');
280
+ });
281
+ return {
282
+ summaries: explanations.slice(0, 6).map((item) => ({
283
+ address: item.address,
284
+ function: item.function,
285
+ behavior: item.behavior,
286
+ summary: item.summary,
287
+ confidence: item.confidence,
288
+ rewrite_guidance: item.rewrite_guidance.slice(0, 4),
289
+ source: item.model_name || item.client_name || null,
290
+ })),
291
+ index,
292
+ };
293
+ }
294
+ function augmentWithFunctionExplanations(triageData, functionExplanations) {
295
+ if (functionExplanations.length === 0) {
296
+ return triageData;
297
+ }
298
+ return {
299
+ ...triageData,
300
+ evidence: dedupe([
301
+ ...triageData.evidence,
302
+ `External semantic explanations are available for ${functionExplanations.length} function(s).`,
303
+ ]),
304
+ function_explanations: functionExplanations,
305
+ recommendation: `${triageData.recommendation} Cross-check the attached function explanations before treating rewrite output as source-equivalent.`,
306
+ };
307
+ }
308
+ function augmentWithDynamicEvidence(triageData, dynamicEvidence) {
309
+ const evidenceLineage = buildEvidenceLineage(dynamicEvidence);
310
+ const suspiciousApis = dedupe([
311
+ ...(triageData.iocs.high_value_iocs?.suspicious_apis || []),
312
+ ...dynamicEvidence.high_signal_apis,
313
+ ]);
314
+ const updatedThreatLevel = dynamicEvidence.executed && dynamicEvidence.high_signal_apis.length > 0 && triageData.threat_level === 'clean'
315
+ ? 'suspicious'
316
+ : triageData.threat_level;
317
+ const updatedClassification = dynamicEvidence.executed &&
318
+ dynamicEvidence.high_signal_apis.length > 0 &&
319
+ triageData.inference?.classification === 'benign'
320
+ ? 'suspicious'
321
+ : triageData.inference?.classification;
322
+ return {
323
+ ...triageData,
324
+ summary: `${triageData.summary} ${buildEvidenceLayerHeadline(evidenceLineage)} Runtime evidence: ${dynamicEvidence.summary}`,
325
+ threat_level: updatedThreatLevel,
326
+ iocs: {
327
+ ...triageData.iocs,
328
+ high_value_iocs: {
329
+ ...(triageData.iocs.high_value_iocs || {}),
330
+ suspicious_apis: suspiciousApis,
331
+ },
332
+ },
333
+ evidence: dedupe([
334
+ buildEvidenceLayerHeadline(evidenceLineage),
335
+ ...triageData.evidence,
336
+ ...dynamicEvidence.evidence,
337
+ ]),
338
+ evidence_lineage: evidenceLineage,
339
+ evidence_weights: {
340
+ import: triageData.evidence_weights?.import ?? 0.33,
341
+ string: triageData.evidence_weights?.string ?? 0.33,
342
+ runtime: Math.max(triageData.evidence_weights?.runtime ?? 0.2, dynamicEvidence.executed ? 0.78 : 0.58),
343
+ },
344
+ inference: triageData.inference
345
+ ? {
346
+ ...triageData.inference,
347
+ classification: updatedClassification || triageData.inference.classification,
348
+ hypotheses: dedupe([
349
+ ...triageData.inference.hypotheses,
350
+ ...dynamicEvidence.stages.map((item) => `Imported runtime evidence indicates stage: ${item}.`),
351
+ ]),
352
+ false_positive_risks: dedupe([
353
+ ...triageData.inference.false_positive_risks,
354
+ dynamicEvidence.executed
355
+ ? 'Imported runtime evidence reduces uncertainty from string-only indicators.'
356
+ : 'Imported memory/hybrid evidence still requires correlation with execution trace or function-level analysis.',
357
+ ]),
358
+ }
359
+ : {
360
+ classification: dynamicEvidence.high_signal_apis.length > 0 ? 'suspicious' : 'unknown',
361
+ hypotheses: dynamicEvidence.stages.map((item) => `Imported runtime evidence indicates stage: ${item}.`),
362
+ false_positive_risks: [
363
+ dynamicEvidence.executed
364
+ ? 'Imported runtime evidence should still be correlated with static function ownership.'
365
+ : 'Memory snapshot evidence alone can overstate execution confidence without trace correlation.',
366
+ ],
367
+ },
368
+ };
369
+ }
370
+ function createMinimalDotnetFallback(triageResult, startTime, functionExplanations = [], provenance, evidenceScope = 'all') {
371
+ const triageErrors = triageResult.errors || [];
372
+ const warnings = [
373
+ 'report.summarize(mode=dotnet) is not fully implemented; returned degraded fallback output.',
374
+ ...(triageResult.warnings || []),
375
+ ];
376
+ if (triageErrors.length > 0) {
377
+ warnings.push(`dotnet fallback triage failed: ${triageErrors.join('; ')}`);
378
+ }
379
+ return {
380
+ ok: true,
381
+ data: {
382
+ summary: '[dotnet fallback] Dotnet-specific summarize pipeline is unavailable and triage fallback failed. Returning minimal placeholder report.',
383
+ confidence: 0.2,
384
+ threat_level: 'unknown',
385
+ iocs: {
386
+ suspicious_imports: [],
387
+ suspicious_strings: [],
388
+ yara_matches: [],
389
+ },
390
+ evidence: [
391
+ 'Dotnet mode unavailable; triage fallback failed.',
392
+ ...triageErrors.map((item) => `triage_error: ${item}`),
393
+ ],
394
+ confidence_semantics: buildAssessmentConfidencePayload(0.2, evidenceScope),
395
+ provenance,
396
+ function_explanations: functionExplanations.length > 0 ? functionExplanations : undefined,
397
+ inference: {
398
+ classification: 'unknown',
399
+ hypotheses: [
400
+ 'Insufficient evidence to infer behavior because dotnet mode is unavailable and triage fallback failed.',
401
+ ],
402
+ false_positive_risks: ['No triage evidence is available in this degraded fallback result.'],
403
+ },
404
+ recommendation: 'Re-run after ensuring workspace/original sample file exists, then use workflow.reconstruct or dotnet.reconstruct.export for .NET-specific structure.',
405
+ },
406
+ warnings,
407
+ errors: triageErrors.length > 0 ? triageErrors : undefined,
408
+ metrics: toolMetrics(startTime),
409
+ };
410
+ }
411
+ function createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime, functionExplanations = [], provenance, evidenceScope = 'all') {
412
+ const evidenceLineage = buildEvidenceLineage(dynamicEvidence);
413
+ const threatLevel = dynamicEvidence.high_signal_apis.length > 0 ? 'suspicious' : dynamicEvidence.executed ? 'suspicious' : 'unknown';
414
+ return {
415
+ ok: true,
416
+ data: {
417
+ summary: `Triage pipeline failed, but imported runtime evidence is available. ${buildEvidenceLayerHeadline(evidenceLineage)} ${dynamicEvidence.summary}`,
418
+ confidence: dynamicEvidence.executed ? 0.66 : 0.5,
419
+ threat_level: threatLevel,
420
+ iocs: {
421
+ suspicious_imports: [],
422
+ suspicious_strings: [],
423
+ yara_matches: [],
424
+ high_value_iocs: {
425
+ suspicious_apis: dynamicEvidence.high_signal_apis,
426
+ },
427
+ },
428
+ evidence: dedupe([buildEvidenceLayerHeadline(evidenceLineage), ...dynamicEvidence.evidence]),
429
+ evidence_lineage: evidenceLineage,
430
+ confidence_semantics: buildAssessmentConfidencePayload(dynamicEvidence.executed ? 0.66 : 0.5, evidenceScope, evidenceLineage),
431
+ provenance,
432
+ function_explanations: functionExplanations.length > 0 ? functionExplanations : undefined,
433
+ evidence_weights: {
434
+ import: 0.05,
435
+ string: 0.1,
436
+ runtime: dynamicEvidence.executed ? 0.85 : 0.68,
437
+ },
438
+ inference: {
439
+ classification: threatLevel === 'unknown' ? 'unknown' : 'suspicious',
440
+ hypotheses: dynamicEvidence.stages.map((item) => `Imported runtime evidence indicates stage: ${item}.`),
441
+ false_positive_risks: [
442
+ dynamicEvidence.executed
443
+ ? 'Runtime evidence is imported and should still be correlated with static ownership.'
444
+ : 'Memory/hybrid evidence is suggestive but not equivalent to a fully executed trace.',
445
+ ],
446
+ },
447
+ recommendation: 'Correlate imported runtime evidence with code.functions.search, code.functions.reconstruct, and code.reconstruct.export to assign concrete function ownership.',
448
+ },
449
+ warnings: [
450
+ 'Triage pipeline failed; returned imported runtime-evidence fallback.',
451
+ ...(triageResult.warnings || []),
452
+ ],
453
+ errors: triageResult.errors,
454
+ metrics: toolMetrics(startTime),
455
+ };
456
+ }
457
+ export function createReportSummarizeHandler(workspaceManager, database, cacheManager, deps) {
458
+ const triageHandler = deps?.triageHandler || createTriageWorkflowHandler(workspaceManager, database, cacheManager);
459
+ return async (args) => {
460
+ const startTime = Date.now();
461
+ try {
462
+ const input = ReportSummarizeInputSchema.parse(args);
463
+ const sample = database.findSample(input.sample_id);
464
+ if (!sample) {
465
+ return {
466
+ ok: false,
467
+ errors: [`Sample not found: ${input.sample_id}`],
468
+ };
469
+ }
470
+ const dynamicEvidence = await loadDynamicTraceEvidence(workspaceManager, database, input.sample_id, {
471
+ evidenceScope: input.evidence_scope,
472
+ sessionTag: input.evidence_session_tag,
473
+ });
474
+ const functionExplanationBundle = await loadFunctionExplanationSummaries(workspaceManager, database, input.sample_id, {
475
+ scope: input.semantic_scope,
476
+ sessionTag: input.semantic_session_tag,
477
+ });
478
+ const functionExplanations = functionExplanationBundle.summaries;
479
+ const provenance = {
480
+ runtime: buildRuntimeArtifactProvenance(dynamicEvidence, input.evidence_scope, input.evidence_session_tag),
481
+ semantic_explanations: buildSemanticArtifactProvenance('semantic explanation artifacts', functionExplanationBundle.index, input.semantic_scope, input.semantic_session_tag),
482
+ };
483
+ const selectionDiffs = {};
484
+ if (input.compare_evidence_scope) {
485
+ const baselineDynamicEvidence = await loadDynamicTraceEvidence(workspaceManager, database, input.sample_id, {
486
+ evidenceScope: input.compare_evidence_scope,
487
+ sessionTag: input.compare_evidence_session_tag,
488
+ });
489
+ selectionDiffs.runtime = buildArtifactSelectionDiff('runtime', provenance.runtime, buildRuntimeArtifactProvenance(baselineDynamicEvidence, input.compare_evidence_scope, input.compare_evidence_session_tag));
490
+ }
491
+ if (input.compare_semantic_scope) {
492
+ const baselineSemanticIndex = await loadSemanticFunctionExplanationIndex(workspaceManager, database, input.sample_id, {
493
+ scope: input.compare_semantic_scope,
494
+ sessionTag: input.compare_semantic_session_tag,
495
+ });
496
+ selectionDiffs.semantic_explanations = buildArtifactSelectionDiff('semantic_explanations', provenance.semantic_explanations, buildSemanticArtifactProvenance('semantic explanation artifacts', baselineSemanticIndex, input.compare_semantic_scope, input.compare_semantic_session_tag));
497
+ }
498
+ const triageResult = await triageHandler({
499
+ sample_id: input.sample_id,
500
+ force_refresh: input.force_refresh,
501
+ });
502
+ if (input.mode === 'triage') {
503
+ if (!triageResult.ok || !triageResult.data) {
504
+ if (dynamicEvidence) {
505
+ return createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime, functionExplanations, provenance, input.evidence_scope);
506
+ }
507
+ return {
508
+ ok: false,
509
+ errors: triageResult.errors,
510
+ warnings: triageResult.warnings,
511
+ metrics: toolMetrics(startTime),
512
+ };
513
+ }
514
+ const triageDataBase = triageResult.data;
515
+ const triageData = dynamicEvidence
516
+ ? augmentWithDynamicEvidence(triageDataBase, dynamicEvidence)
517
+ : triageDataBase;
518
+ const enrichedTriageData = augmentWithFunctionExplanations(triageData, functionExplanations);
519
+ return {
520
+ ok: true,
521
+ data: {
522
+ summary: enrichedTriageData.summary,
523
+ confidence: enrichedTriageData.confidence,
524
+ threat_level: enrichedTriageData.threat_level,
525
+ iocs: enrichedTriageData.iocs,
526
+ evidence: enrichedTriageData.evidence,
527
+ evidence_lineage: enrichedTriageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence),
528
+ confidence_semantics: buildAssessmentConfidencePayload(enrichedTriageData.confidence, input.evidence_scope, enrichedTriageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence)),
529
+ provenance,
530
+ selection_diffs: Object.keys(selectionDiffs).length > 0 ? selectionDiffs : undefined,
531
+ function_explanations: enrichedTriageData.function_explanations,
532
+ evidence_weights: enrichedTriageData.evidence_weights,
533
+ inference: enrichedTriageData.inference,
534
+ recommendation: enrichedTriageData.recommendation,
535
+ },
536
+ warnings: dynamicEvidence
537
+ ? dedupe([
538
+ ...(triageResult.warnings || []),
539
+ `Merged imported runtime evidence from ${dynamicEvidence.artifact_count} artifact(s) using scope=${input.evidence_scope}${input.evidence_session_tag ? ` selector=${input.evidence_session_tag}` : ''}.`,
540
+ dynamicEvidence.scope_note || '',
541
+ ])
542
+ : triageResult.warnings,
543
+ errors: triageResult.errors,
544
+ metrics: toolMetrics(startTime),
545
+ };
546
+ }
547
+ if (input.mode === 'dotnet') {
548
+ if (!triageResult.ok || !triageResult.data) {
549
+ return createMinimalDotnetFallback(triageResult, startTime, functionExplanations, provenance, input.evidence_scope);
550
+ }
551
+ const triageData = triageResult.data;
552
+ return {
553
+ ok: true,
554
+ data: {
555
+ summary: `[dotnet fallback] ${triageData.summary}. ` +
556
+ 'Dotnet-specific summarize pipeline is not implemented yet; returning triage-compatible summary.',
557
+ confidence: Math.max(0.05, Math.min(0.95, triageData.confidence * 0.92)),
558
+ threat_level: triageData.threat_level,
559
+ iocs: triageData.iocs,
560
+ evidence: [
561
+ ...triageData.evidence,
562
+ 'Dotnet-specific mode unavailable; downgraded to triage-compatible summary.',
563
+ ],
564
+ evidence_lineage: triageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence),
565
+ confidence_semantics: buildAssessmentConfidencePayload(Math.max(0.05, Math.min(0.95, triageData.confidence * 0.92)), input.evidence_scope, triageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence)),
566
+ provenance,
567
+ selection_diffs: Object.keys(selectionDiffs).length > 0 ? selectionDiffs : undefined,
568
+ function_explanations: functionExplanations.length > 0 ? functionExplanations : undefined,
569
+ evidence_weights: triageData.evidence_weights,
570
+ inference: triageData.inference,
571
+ recommendation: `${triageData.recommendation}; additionally run runtime.detect plus ` +
572
+ 'dotnet.reconstruct.export / workflow.reconstruct for .NET-specific structure.',
573
+ },
574
+ warnings: [
575
+ 'report.summarize(mode=dotnet) not fully implemented; returned triage fallback.',
576
+ ...(triageResult.warnings || []),
577
+ ],
578
+ metrics: toolMetrics(startTime),
579
+ };
580
+ }
581
+ return {
582
+ ok: false,
583
+ errors: [`Unsupported mode: ${input.mode}`],
584
+ metrics: toolMetrics(startTime),
585
+ };
586
+ }
587
+ catch (error) {
588
+ return {
589
+ ok: false,
590
+ errors: [error.message],
591
+ metrics: toolMetrics(startTime),
592
+ };
593
+ }
594
+ };
595
+ }
596
+ //# sourceMappingURL=report-summarize.js.map