windows-exe-decompiler-mcp-server 0.1.0 → 0.1.3

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 (134) hide show
  1. package/CLAUDE_INSTALLATION.md +129 -0
  2. package/CODEX_INSTALLATION.md +25 -1
  3. package/COPILOT_INSTALLATION.md +29 -1
  4. package/LICENSE +21 -21
  5. package/README.md +232 -110
  6. package/dist/analysis-provenance.d.ts +50 -2
  7. package/dist/analysis-provenance.js +1 -0
  8. package/dist/analysis-task-runner.js +92 -0
  9. package/dist/config.d.ts +35 -16
  10. package/dist/config.js +37 -3
  11. package/dist/database.js +115 -115
  12. package/dist/decompiler-worker.d.ts +10 -5
  13. package/dist/decompiler-worker.js +240 -58
  14. package/dist/dynamic-trace.d.ts +6 -0
  15. package/dist/dynamic-trace.js +52 -1
  16. package/dist/ghidra-config.js +17 -1
  17. package/dist/index.js +38 -8
  18. package/dist/pe-runtime-functions.d.ts +90 -0
  19. package/dist/pe-runtime-functions.js +452 -0
  20. package/dist/prompts/module-reconstruction-review.d.ts +5 -0
  21. package/dist/prompts/module-reconstruction-review.js +65 -0
  22. package/dist/runtime-correlation.d.ts +5 -0
  23. package/dist/runtime-correlation.js +179 -2
  24. package/dist/sample-workspace.d.ts +28 -0
  25. package/dist/sample-workspace.js +186 -0
  26. package/dist/semantic-name-suggestion-artifacts.d.ts +56 -0
  27. package/dist/semantic-name-suggestion-artifacts.js +87 -0
  28. package/dist/server.js +1 -1
  29. package/dist/setup-guidance.d.ts +73 -0
  30. package/dist/setup-guidance.js +211 -0
  31. package/dist/tools/artifact-read.d.ts +10 -10
  32. package/dist/tools/artifacts-diff.d.ts +8 -8
  33. package/dist/tools/artifacts-list.d.ts +16 -16
  34. package/dist/tools/attack-map.d.ts +8 -8
  35. package/dist/tools/binary-role-profile.d.ts +1197 -0
  36. package/dist/tools/binary-role-profile.js +575 -0
  37. package/dist/tools/code-function-explain-apply.d.ts +12 -12
  38. package/dist/tools/code-function-explain-prepare.d.ts +12 -12
  39. package/dist/tools/code-function-explain-review.d.ts +58 -58
  40. package/dist/tools/code-function-rename-apply.d.ts +12 -12
  41. package/dist/tools/code-function-rename-prepare.d.ts +14 -14
  42. package/dist/tools/code-function-rename-review.d.ts +66 -66
  43. package/dist/tools/code-functions-define.d.ts +337 -0
  44. package/dist/tools/code-functions-define.js +337 -0
  45. package/dist/tools/code-functions-list.js +1 -1
  46. package/dist/tools/code-functions-rank.js +1 -1
  47. package/dist/tools/code-functions-reconstruct.d.ts +368 -58
  48. package/dist/tools/code-functions-reconstruct.js +130 -10
  49. package/dist/tools/code-functions-smart-recover.d.ts +352 -0
  50. package/dist/tools/code-functions-smart-recover.js +190 -0
  51. package/dist/tools/code-module-review-apply.d.ts +233 -0
  52. package/dist/tools/code-module-review-apply.js +209 -0
  53. package/dist/tools/code-module-review-prepare.d.ts +756 -0
  54. package/dist/tools/code-module-review-prepare.js +343 -0
  55. package/dist/tools/code-module-review.d.ts +474 -0
  56. package/dist/tools/code-module-review.js +566 -0
  57. package/dist/tools/code-reconstruct-export.d.ts +193 -21
  58. package/dist/tools/code-reconstruct-export.js +578 -21
  59. package/dist/tools/code-reconstruct-plan.d.ts +20 -20
  60. package/dist/tools/com-role-profile.d.ts +353 -0
  61. package/dist/tools/com-role-profile.js +186 -0
  62. package/dist/tools/dll-export-profile.d.ts +625 -0
  63. package/dist/tools/dll-export-profile.js +230 -0
  64. package/dist/tools/dotnet-metadata-extract.d.ts +122 -122
  65. package/dist/tools/dotnet-reconstruct-export.d.ts +49 -49
  66. package/dist/tools/dotnet-types-list.d.ts +66 -66
  67. package/dist/tools/dynamic-dependencies.d.ts +144 -8
  68. package/dist/tools/dynamic-dependencies.js +20 -1
  69. package/dist/tools/dynamic-memory-import.js +105 -2
  70. package/dist/tools/ghidra-analyze.d.ts +20 -0
  71. package/dist/tools/ghidra-analyze.js +10 -2
  72. package/dist/tools/ghidra-health.d.ts +177 -0
  73. package/dist/tools/ghidra-health.js +28 -0
  74. package/dist/tools/ioc-export.d.ts +8 -8
  75. package/dist/tools/packer-detect.d.ts +14 -14
  76. package/dist/tools/packer-detect.js +6 -9
  77. package/dist/tools/pe-exports-extract.d.ts +8 -8
  78. package/dist/tools/pe-exports-extract.js +6 -9
  79. package/dist/tools/pe-fingerprint.d.ts +36 -36
  80. package/dist/tools/pe-imports-extract.d.ts +8 -8
  81. package/dist/tools/pe-imports-extract.js +6 -9
  82. package/dist/tools/pe-pdata-extract.d.ts +448 -0
  83. package/dist/tools/pe-pdata-extract.js +219 -0
  84. package/dist/tools/pe-symbols-recover.d.ts +227 -0
  85. package/dist/tools/pe-symbols-recover.js +316 -0
  86. package/dist/tools/report-generate.d.ts +15 -1
  87. package/dist/tools/report-generate.js +139 -16
  88. package/dist/tools/report-summarize.d.ts +2242 -8
  89. package/dist/tools/report-summarize.js +246 -10
  90. package/dist/tools/runtime-detect.d.ts +8 -8
  91. package/dist/tools/runtime-detect.js +2 -12
  92. package/dist/tools/rust-binary-analyze.d.ts +2047 -0
  93. package/dist/tools/rust-binary-analyze.js +443 -0
  94. package/dist/tools/sample-profile-get.d.ts +135 -16
  95. package/dist/tools/sample-profile-get.js +35 -32
  96. package/dist/tools/sandbox-execute.d.ts +10 -10
  97. package/dist/tools/strings-extract.d.ts +8 -8
  98. package/dist/tools/strings-extract.js +2 -12
  99. package/dist/tools/strings-floss-decode.d.ts +8 -8
  100. package/dist/tools/system-health.d.ts +172 -36
  101. package/dist/tools/system-health.js +14 -0
  102. package/dist/tools/system-setup-guide.d.ts +179 -0
  103. package/dist/tools/system-setup-guide.js +62 -0
  104. package/dist/tools/tool-help.d.ts +16 -16
  105. package/dist/tools/tool-help.js +172 -0
  106. package/dist/tools/yara-scan.d.ts +8 -8
  107. package/dist/types.d.ts +2 -0
  108. package/dist/workflows/function-explanation-review.d.ts +3034 -76
  109. package/dist/workflows/function-explanation-review.js +172 -42
  110. package/dist/workflows/function-index-recover.d.ts +333 -0
  111. package/dist/workflows/function-index-recover.js +291 -0
  112. package/dist/workflows/module-reconstruction-review.d.ts +3537 -0
  113. package/dist/workflows/module-reconstruction-review.js +354 -0
  114. package/dist/workflows/reconstruct.d.ts +2182 -223
  115. package/dist/workflows/reconstruct.js +575 -32
  116. package/dist/workflows/semantic-name-review.d.ts +1436 -85
  117. package/dist/workflows/semantic-name-review.js +150 -58
  118. package/dist/workflows/triage.d.ts +8 -8
  119. package/ghidra_scripts/DecompileFunction.java +487 -487
  120. package/ghidra_scripts/ExtractCFG.java +256 -256
  121. package/ghidra_scripts/ExtractFunctions.java +442 -442
  122. package/ghidra_scripts/README.md +112 -112
  123. package/ghidra_scripts/SearchFunctionReferences.java +380 -380
  124. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -9
  125. package/helpers/DotNetMetadataProbe/Program.cs +566 -566
  126. package/install-to-claude.ps1 +432 -0
  127. package/install-to-codex.ps1 +256 -178
  128. package/install-to-copilot.ps1 +389 -303
  129. package/package.json +4 -2
  130. package/requirements.txt +9 -9
  131. package/workers/requirements-dynamic.txt +11 -11
  132. package/workers/requirements.txt +8 -8
  133. package/workers/speakeasy_compat.py +175 -175
  134. package/workers/static_worker.py +3474 -3474
@@ -9,13 +9,19 @@ import { createRuntimeDetectHandler } from '../tools/runtime-detect.js';
9
9
  import { createCodeReconstructPlanHandler } from '../tools/code-reconstruct-plan.js';
10
10
  import { createCodeReconstructExportHandler } from '../tools/code-reconstruct-export.js';
11
11
  import { createDotNetReconstructExportHandler } from '../tools/dotnet-reconstruct-export.js';
12
- import { findBestGhidraAnalysis } from '../ghidra-analysis-status.js';
12
+ import { findBestGhidraAnalysis, isGhidraCapabilityReady, } from '../ghidra-analysis-status.js';
13
13
  import { loadDynamicTraceEvidence } from '../dynamic-trace.js';
14
14
  import { loadSemanticFunctionExplanationIndex, loadSemanticNameSuggestionIndex, } from '../semantic-name-suggestion-artifacts.js';
15
+ import { BinaryRoleProfileDataSchema, createBinaryRoleProfileHandler, } from '../tools/binary-role-profile.js';
16
+ import { ComRoleProfileDataSchema, createComRoleProfileHandler, } from '../tools/com-role-profile.js';
17
+ import { DllExportProfileDataSchema, createDllExportProfileHandler, } from '../tools/dll-export-profile.js';
18
+ import { createRustBinaryAnalyzeHandler, } from '../tools/rust-binary-analyze.js';
19
+ import { createFunctionIndexRecoverWorkflowHandler } from './function-index-recover.js';
15
20
  import { AnalysisProvenanceSchema, buildRuntimeArtifactProvenance, buildSemanticArtifactProvenance, } from '../analysis-provenance.js';
16
21
  import { AnalysisSelectionDiffSchema, buildArtifactSelectionDiff, } from '../selection-diff.js';
22
+ import { RequiredUserInputSchema, SetupActionSchema, collectSetupGuidanceFromWorkerResult, mergeRequiredUserInputs, mergeSetupActions, } from '../setup-guidance.js';
17
23
  const TOOL_NAME = 'workflow.reconstruct';
18
- const TOOL_VERSION = '0.1.3';
24
+ const TOOL_VERSION = '0.1.5';
19
25
  const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
20
26
  export const ReconstructWorkflowInputSchema = z.object({
21
27
  sample_id: z.string().describe('Sample ID (format: sha256:<hex>)'),
@@ -96,6 +102,14 @@ export const ReconstructWorkflowInputSchema = z.object({
96
102
  .string()
97
103
  .optional()
98
104
  .describe('Optional baseline semantic artifact session selector used when compare_semantic_scope=session'),
105
+ include_preflight: z
106
+ .boolean()
107
+ .default(true)
108
+ .describe('Run binary role and language-specific preflight profiling before planning and export'),
109
+ auto_recover_function_index: z
110
+ .boolean()
111
+ .default(true)
112
+ .describe('When native function-index coverage is missing, automatically run workflow.function_index_recover before export'),
99
113
  include_plan: z
100
114
  .boolean()
101
115
  .default(true)
@@ -196,29 +210,115 @@ const ExportSummarySchema = z.object({
196
210
  binary_profile: BinaryProfileSchema.nullable(),
197
211
  managed_profile: ManagedProfileSchema.nullable(),
198
212
  });
213
+ const PreflightRustProfileSchema = z.object({
214
+ suspected_rust: z.boolean(),
215
+ confidence: z.number().min(0).max(1),
216
+ primary_runtime: z.string().nullable(),
217
+ runtime_hints: z.array(z.string()),
218
+ crate_hints: z.array(z.string()),
219
+ cargo_paths: z.array(z.string()),
220
+ recovered_function_count: z.number().int().nonnegative(),
221
+ recovered_symbol_count: z.number().int().nonnegative(),
222
+ importable_with_code_functions_define: z.boolean(),
223
+ analysis_priorities: z.array(z.string()),
224
+ });
225
+ const PreflightDllProfileSchema = z.object({
226
+ library_like: z.boolean(),
227
+ role_confidence: z.number().min(0).max(1),
228
+ likely_entry_model: z.string(),
229
+ dll_entry_hints: z.array(z.string()),
230
+ dispatch_model: z.string(),
231
+ host_hints: z.array(z.string()),
232
+ lifecycle_surface: DllExportProfileDataSchema.shape.lifecycle_surface,
233
+ class_factory_surface: DllExportProfileDataSchema.shape.class_factory_surface,
234
+ callback_surface: DllExportProfileDataSchema.shape.callback_surface,
235
+ analysis_priorities: z.array(z.string()),
236
+ });
237
+ const PreflightComProfileSchema = z.object({
238
+ likely_com_server: z.boolean(),
239
+ com_confidence: z.number().min(0).max(1),
240
+ activation_model: z.string(),
241
+ class_factory_exports: z.array(z.string()),
242
+ registration_exports: z.array(z.string()),
243
+ clsid_strings: z.array(z.string()),
244
+ progid_strings: z.array(z.string()),
245
+ interface_hints: z.array(z.string()),
246
+ class_factory_surface: ComRoleProfileDataSchema.shape.class_factory_surface,
247
+ activation_steps: z.array(z.string()),
248
+ analysis_priorities: z.array(z.string()),
249
+ });
250
+ const RoleAwareExportTuningSchema = z.object({
251
+ topk: z.number().int().positive(),
252
+ module_limit: z.number().int().positive(),
253
+ min_module_size: z.number().int().positive(),
254
+ include_imports: z.boolean(),
255
+ include_strings: z.boolean(),
256
+ });
257
+ const RoleAwareStrategySchema = z.object({
258
+ target_role: z.string(),
259
+ priority_order: z.array(z.string()),
260
+ focus_areas: z.array(z.string()),
261
+ rationale: z.array(z.string()),
262
+ export_tuning: RoleAwareExportTuningSchema,
263
+ });
264
+ const FunctionIndexRecoverySummarySchema = z.object({
265
+ applied: z.boolean(),
266
+ define_from: z.enum(['smart_recover', 'symbols_recover']).nullable(),
267
+ recovered_function_count: z.number().int().nonnegative(),
268
+ recovered_symbol_count: z.number().int().nonnegative(),
269
+ imported_count: z.number().int().nonnegative(),
270
+ function_index_status: z.enum(['ready']).nullable(),
271
+ decompile_status: z.enum(['missing']).nullable(),
272
+ cfg_status: z.enum(['missing']).nullable(),
273
+ recovery_strategy: z.array(z.string()),
274
+ next_steps: z.array(z.string()),
275
+ });
276
+ const PreflightSummarySchema = z.object({
277
+ binary_profile: BinaryRoleProfileDataSchema.nullable(),
278
+ dll_profile: PreflightDllProfileSchema.nullable(),
279
+ com_profile: PreflightComProfileSchema.nullable(),
280
+ rust_profile: PreflightRustProfileSchema.nullable(),
281
+ function_index_recovery: FunctionIndexRecoverySummarySchema.nullable(),
282
+ role_strategy: RoleAwareStrategySchema.nullable(),
283
+ });
284
+ const ReconstructQueuedDataSchema = z.object({
285
+ job_id: z.string(),
286
+ status: z.literal('queued'),
287
+ tool: z.literal(TOOL_NAME),
288
+ sample_id: z.string(),
289
+ requested_path: z.enum(['auto', 'native', 'dotnet']),
290
+ progress: z.number().int().min(0).max(100),
291
+ });
292
+ const ReconstructCompletedDataSchema = z.object({
293
+ sample_id: z.string(),
294
+ selected_path: z.enum(['native', 'dotnet']),
295
+ degraded: z.boolean(),
296
+ stage_status: z.object({
297
+ runtime: z.enum(['ok', 'failed']),
298
+ preflight_binary_profile: z.enum(['ok', 'failed', 'skipped']),
299
+ preflight_dll_profile: z.enum(['ok', 'failed', 'skipped']),
300
+ preflight_com_profile: z.enum(['ok', 'failed', 'skipped']),
301
+ preflight_rust_profile: z.enum(['ok', 'failed', 'skipped']),
302
+ function_index_recovery: z.enum(['ok', 'failed', 'skipped']),
303
+ plan: z.enum(['ok', 'failed', 'skipped']),
304
+ export_primary: z.enum(['ok', 'failed', 'skipped']),
305
+ export_fallback: z.enum(['ok', 'failed', 'skipped']),
306
+ }),
307
+ provenance: AnalysisProvenanceSchema,
308
+ selection_diffs: AnalysisSelectionDiffSchema.optional(),
309
+ runtime: RuntimeSummarySchema,
310
+ preflight: PreflightSummarySchema.optional(),
311
+ plan: PlanSummarySchema.nullable(),
312
+ export: ExportSummarySchema.nullable(),
313
+ notes: z.array(z.string()),
314
+ });
199
315
  export const ReconstructWorkflowOutputSchema = z.object({
200
316
  ok: z.boolean(),
201
- data: z
202
- .object({
203
- sample_id: z.string(),
204
- selected_path: z.enum(['native', 'dotnet']),
205
- degraded: z.boolean(),
206
- stage_status: z.object({
207
- runtime: z.enum(['ok', 'failed']),
208
- plan: z.enum(['ok', 'failed', 'skipped']),
209
- export_primary: z.enum(['ok', 'failed', 'skipped']),
210
- export_fallback: z.enum(['ok', 'failed', 'skipped']),
211
- }),
212
- provenance: AnalysisProvenanceSchema,
213
- selection_diffs: AnalysisSelectionDiffSchema.optional(),
214
- runtime: RuntimeSummarySchema,
215
- plan: PlanSummarySchema.nullable(),
216
- export: ExportSummarySchema.nullable(),
217
- notes: z.array(z.string()),
218
- })
219
- .optional(),
317
+ data: z.union([ReconstructCompletedDataSchema, ReconstructQueuedDataSchema]).optional(),
220
318
  warnings: z.array(z.string()).optional(),
221
319
  errors: z.array(z.string()).optional(),
320
+ setup_actions: z.array(SetupActionSchema).optional(),
321
+ required_user_inputs: z.array(RequiredUserInputSchema).optional(),
222
322
  artifacts: z.array(z.any()).optional(),
223
323
  metrics: z
224
324
  .object({
@@ -235,7 +335,7 @@ export const ReconstructWorkflowOutputSchema = z.object({
235
335
  });
236
336
  export const reconstructWorkflowToolDefinition = {
237
337
  name: TOOL_NAME,
238
- description: 'Run a complete source-reconstruction workflow with auto routing (native/.NET), planning, export, and cache observability.',
338
+ description: 'Run a complete source-reconstruction workflow with auto routing (native/.NET), binary/language preflight profiling, optional function-index recovery, planning, export, and cache observability.',
239
339
  inputSchema: ReconstructWorkflowInputSchema,
240
340
  outputSchema: ReconstructWorkflowOutputSchema,
241
341
  };
@@ -261,7 +361,174 @@ function summarizeRuntime(runtimeData) {
261
361
  primary_runtime: pickPrimaryRuntime(runtimeData),
262
362
  };
263
363
  }
264
- export function createReconstructWorkflowHandler(workspaceManager, database, cacheManager, dependencies) {
364
+ function pickLatestAnalysisMarker(analyses, predicate) {
365
+ const sorted = [...analyses]
366
+ .filter(predicate)
367
+ .sort((left, right) => {
368
+ const leftTs = new Date(left.finished_at || left.started_at || 0).getTime();
369
+ const rightTs = new Date(right.finished_at || right.started_at || 0).getTime();
370
+ return rightTs - leftTs;
371
+ });
372
+ const selected = sorted[0];
373
+ if (!selected) {
374
+ return null;
375
+ }
376
+ return {
377
+ stage: selected.stage,
378
+ backend: selected.backend,
379
+ status: selected.status,
380
+ finished_at: selected.finished_at || selected.started_at || null,
381
+ };
382
+ }
383
+ function summarizeRustPreflight(data) {
384
+ return {
385
+ suspected_rust: data.suspected_rust,
386
+ confidence: data.confidence,
387
+ primary_runtime: data.primary_runtime,
388
+ runtime_hints: data.runtime_hints,
389
+ crate_hints: data.crate_hints,
390
+ cargo_paths: data.cargo_paths,
391
+ recovered_function_count: data.recovered_function_count,
392
+ recovered_symbol_count: data.recovered_symbol_count,
393
+ importable_with_code_functions_define: data.importable_with_code_functions_define,
394
+ analysis_priorities: data.analysis_priorities,
395
+ };
396
+ }
397
+ function summarizeDllPreflight(data) {
398
+ return {
399
+ library_like: data.library_like,
400
+ role_confidence: data.role_confidence,
401
+ likely_entry_model: data.likely_entry_model,
402
+ dll_entry_hints: data.dll_entry_hints,
403
+ dispatch_model: data.export_dispatch_profile.likely_dispatch_model,
404
+ host_hints: data.host_interaction_profile.host_hints,
405
+ lifecycle_surface: data.lifecycle_surface,
406
+ class_factory_surface: data.class_factory_surface,
407
+ callback_surface: data.callback_surface,
408
+ analysis_priorities: data.analysis_priorities,
409
+ };
410
+ }
411
+ function summarizeComPreflight(data) {
412
+ return {
413
+ likely_com_server: data.likely_com_server,
414
+ com_confidence: data.com_confidence,
415
+ activation_model: data.activation_model,
416
+ class_factory_exports: data.class_factory_exports,
417
+ registration_exports: data.registration_exports,
418
+ clsid_strings: data.clsid_strings,
419
+ progid_strings: data.progid_strings,
420
+ interface_hints: data.interface_hints,
421
+ class_factory_surface: data.class_factory_surface,
422
+ activation_steps: data.activation_steps,
423
+ analysis_priorities: data.analysis_priorities,
424
+ };
425
+ }
426
+ function buildRoleAwareStrategy(args) {
427
+ const rationale = [];
428
+ const focusAreas = new Set();
429
+ const priorityOrder = new Set();
430
+ let targetRole = 'native_executable';
431
+ const exportTuning = {
432
+ topk: 16,
433
+ module_limit: 8,
434
+ min_module_size: 1,
435
+ include_imports: true,
436
+ include_strings: true,
437
+ };
438
+ if (args.runtimeData?.is_dotnet) {
439
+ targetRole = 'managed_assembly';
440
+ rationale.push('runtime.detect reported CLR/.NET metadata');
441
+ focusAreas.add('managed_metadata_and_il');
442
+ }
443
+ else if (args.comProfile?.likely_com_server) {
444
+ targetRole = 'com_server';
445
+ rationale.push(`COM preflight suggests activation model ${args.comProfile.activation_model}`);
446
+ focusAreas.add('class_factory_and_registration');
447
+ exportTuning.topk = 20;
448
+ exportTuning.module_limit = 10;
449
+ }
450
+ else if (args.dllProfile?.library_like && args.dllProfile.dispatch_model !== 'none') {
451
+ targetRole = 'export_dispatch_dll';
452
+ rationale.push(`DLL preflight suggests dispatch model ${args.dllProfile.dispatch_model}`);
453
+ focusAreas.add('export_dispatch_surface');
454
+ exportTuning.topk = 18;
455
+ exportTuning.module_limit = 10;
456
+ }
457
+ else if (args.dllProfile?.library_like && args.dllProfile.host_hints.length > 0) {
458
+ targetRole = 'hosted_plugin_or_service_dll';
459
+ rationale.push('DLL preflight suggests hosted/plugin lifecycle');
460
+ focusAreas.add('host_callbacks_and_attach_detach');
461
+ exportTuning.topk = 18;
462
+ exportTuning.module_limit = 9;
463
+ }
464
+ else if (args.dllProfile?.library_like) {
465
+ targetRole = 'dll_library';
466
+ rationale.push(`DLL preflight suggests entry model ${args.dllProfile.likely_entry_model}`);
467
+ focusAreas.add('dllmain_and_export_surface');
468
+ exportTuning.topk = 18;
469
+ exportTuning.module_limit = 9;
470
+ }
471
+ else if (args.rustProfile?.suspected_rust) {
472
+ targetRole = 'native_rust_executable';
473
+ rationale.push(`Rust preflight confidence ${args.rustProfile.confidence.toFixed(2)}`);
474
+ focusAreas.add('pdata_recovery_and_runtime_wrappers');
475
+ exportTuning.topk = 20;
476
+ exportTuning.module_limit = 9;
477
+ }
478
+ else if (args.binaryProfile?.indicators.service_binary.likely) {
479
+ targetRole = 'service_binary';
480
+ rationale.push('binary.role.profile found service-oriented indicators');
481
+ focusAreas.add('service_entrypoints_and_hooks');
482
+ exportTuning.topk = 18;
483
+ exportTuning.module_limit = 9;
484
+ }
485
+ for (const item of args.binaryProfile?.analysis_priorities || []) {
486
+ priorityOrder.add(item);
487
+ }
488
+ for (const item of args.dllProfile?.analysis_priorities || []) {
489
+ priorityOrder.add(item);
490
+ }
491
+ for (const item of args.comProfile?.analysis_priorities || []) {
492
+ priorityOrder.add(item);
493
+ }
494
+ for (const item of args.rustProfile?.analysis_priorities || []) {
495
+ priorityOrder.add(item);
496
+ }
497
+ if (args.comProfile?.class_factory_exports.length) {
498
+ focusAreas.add('class_factory_exports');
499
+ }
500
+ if (args.dllProfile?.dll_entry_hints.length) {
501
+ focusAreas.add('dll_entry_lifecycle');
502
+ }
503
+ if (args.binaryProfile?.export_dispatch_profile.likely_dispatch_model !== 'none') {
504
+ focusAreas.add('dispatch_model_reconstruction');
505
+ }
506
+ if (args.binaryProfile?.host_interaction_profile.likely_hosted) {
507
+ focusAreas.add('host_interaction_model');
508
+ }
509
+ return {
510
+ target_role: targetRole,
511
+ priority_order: Array.from(priorityOrder),
512
+ focus_areas: Array.from(focusAreas),
513
+ rationale,
514
+ export_tuning: exportTuning,
515
+ };
516
+ }
517
+ function summarizeFunctionIndexRecovery(data) {
518
+ return {
519
+ applied: true,
520
+ define_from: data.define_from,
521
+ recovered_function_count: data.recovered_function_count,
522
+ recovered_symbol_count: data.recovered_symbol_count,
523
+ imported_count: data.imported_count,
524
+ function_index_status: data.function_index_status,
525
+ decompile_status: data.decompile_status,
526
+ cfg_status: data.cfg_status,
527
+ recovery_strategy: data.recovery_strategy,
528
+ next_steps: data.next_steps,
529
+ };
530
+ }
531
+ export function createReconstructWorkflowHandler(workspaceManager, database, cacheManager, dependencies, jobQueue) {
265
532
  const runtimeDetectHandler = dependencies?.runtimeDetectHandler ||
266
533
  createRuntimeDetectHandler(workspaceManager, database, cacheManager);
267
534
  const planHandler = dependencies?.planHandler ||
@@ -270,6 +537,20 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
270
537
  createCodeReconstructExportHandler(workspaceManager, database, cacheManager);
271
538
  const dotnetExportHandler = dependencies?.dotnetExportHandler ||
272
539
  createDotNetReconstructExportHandler(workspaceManager, database, cacheManager);
540
+ const binaryRoleProfileHandler = dependencies?.binaryRoleProfileHandler ||
541
+ createBinaryRoleProfileHandler(workspaceManager, database, cacheManager);
542
+ const dllExportProfileHandler = dependencies?.dllExportProfileHandler ||
543
+ createDllExportProfileHandler(workspaceManager, database, cacheManager, {
544
+ binaryRoleProfileHandler,
545
+ });
546
+ const comRoleProfileHandler = dependencies?.comRoleProfileHandler ||
547
+ createComRoleProfileHandler(workspaceManager, database, cacheManager, {
548
+ binaryRoleProfileHandler,
549
+ });
550
+ const rustBinaryAnalyzeHandler = dependencies?.rustBinaryAnalyzeHandler ||
551
+ createRustBinaryAnalyzeHandler(workspaceManager, database, cacheManager);
552
+ const functionIndexRecoverHandler = dependencies?.functionIndexRecoverHandler ||
553
+ createFunctionIndexRecoverWorkflowHandler(workspaceManager, database, cacheManager);
273
554
  return async (args) => {
274
555
  const input = ReconstructWorkflowInputSchema.parse(args);
275
556
  const startTime = Date.now();
@@ -281,10 +562,48 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
281
562
  errors: [`Sample not found: ${input.sample_id}`],
282
563
  };
283
564
  }
565
+ if (jobQueue) {
566
+ const jobTimeoutMs = Math.max(input.build_timeout_ms + input.run_timeout_ms + 45 * 60 * 1000, 60 * 60 * 1000);
567
+ const jobId = jobQueue.enqueue({
568
+ type: 'static',
569
+ tool: TOOL_NAME,
570
+ sampleId: input.sample_id,
571
+ args: input,
572
+ priority: 5,
573
+ timeout: jobTimeoutMs,
574
+ retryPolicy: {
575
+ maxRetries: 1,
576
+ backoffMs: 5000,
577
+ retryableErrors: ['E_TIMEOUT', 'E_RESOURCE_EXHAUSTED'],
578
+ },
579
+ });
580
+ return {
581
+ ok: true,
582
+ data: {
583
+ job_id: jobId,
584
+ status: 'queued',
585
+ tool: TOOL_NAME,
586
+ sample_id: input.sample_id,
587
+ requested_path: input.path,
588
+ progress: 0,
589
+ },
590
+ metrics: {
591
+ elapsed_ms: Date.now() - startTime,
592
+ tool: TOOL_NAME,
593
+ },
594
+ };
595
+ }
284
596
  const warnings = [];
285
597
  const notes = [];
598
+ let setupActions = [];
599
+ let requiredUserInputs = [];
286
600
  const stageStatus = {
287
601
  runtime: 'failed',
602
+ preflight_binary_profile: 'skipped',
603
+ preflight_dll_profile: 'skipped',
604
+ preflight_com_profile: 'skipped',
605
+ preflight_rust_profile: 'skipped',
606
+ function_index_recovery: 'skipped',
288
607
  plan: 'skipped',
289
608
  export_primary: 'skipped',
290
609
  export_fallback: 'skipped',
@@ -303,6 +622,11 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
303
622
  else {
304
623
  stageStatus.runtime = 'ok';
305
624
  }
625
+ {
626
+ const setupGuidance = collectSetupGuidanceFromWorkerResult(runtimeResult);
627
+ setupActions = mergeSetupActions(setupActions, setupGuidance.setupActions);
628
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, setupGuidance.requiredUserInputs);
629
+ }
306
630
  let selectedPath;
307
631
  if (input.path === 'auto') {
308
632
  selectedPath = runtimeData?.is_dotnet ? 'dotnet' : 'native';
@@ -330,7 +654,145 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
330
654
  if (selectedPath === 'native' && runtimeData?.is_dotnet) {
331
655
  warnings.push('Selected native path while runtime indicates .NET; forcing native as requested.');
332
656
  }
333
- const completedGhidraAnalysis = findBestGhidraAnalysis(database.findAnalysesBySample(input.sample_id), 'function_index');
657
+ let analyses = database.findAnalysesBySample(input.sample_id);
658
+ let completedGhidraAnalysis = findBestGhidraAnalysis(analyses, 'function_index');
659
+ const hasReadyGhidraFunctionIndex = Boolean(completedGhidraAnalysis && isGhidraCapabilityReady(completedGhidraAnalysis, 'function_index'));
660
+ const hasFunctionDefinitionIndex = analyses.some((analysis) => analysis.stage === 'function_definition' && analysis.status === 'done');
661
+ let binaryProfileData = null;
662
+ let dllProfileData = null;
663
+ let comProfileData = null;
664
+ let rustProfileData = null;
665
+ let functionIndexRecoveryData = null;
666
+ let functionIndexRecoveryApplied = false;
667
+ let roleStrategy = null;
668
+ if (input.include_preflight) {
669
+ const binaryProfileResult = await binaryRoleProfileHandler({
670
+ sample_id: input.sample_id,
671
+ force_refresh: !input.reuse_cached,
672
+ });
673
+ if (binaryProfileResult.ok && binaryProfileResult.data) {
674
+ binaryProfileData = binaryProfileResult.data;
675
+ stageStatus.preflight_binary_profile = 'ok';
676
+ }
677
+ else {
678
+ stageStatus.preflight_binary_profile = 'failed';
679
+ warnings.push(`binary.role.profile unavailable: ${(binaryProfileResult.errors || ['unknown error']).join('; ')}`);
680
+ }
681
+ if (binaryProfileResult.warnings?.length) {
682
+ warnings.push(...binaryProfileResult.warnings.map((item) => `binary.role.profile: ${item}`));
683
+ }
684
+ {
685
+ const setupGuidance = collectSetupGuidanceFromWorkerResult(binaryProfileResult);
686
+ setupActions = mergeSetupActions(setupActions, setupGuidance.setupActions);
687
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, setupGuidance.requiredUserInputs);
688
+ }
689
+ }
690
+ if (selectedPath === 'native' && !runtimeData?.is_dotnet && input.include_preflight) {
691
+ const dllProfileResult = await dllExportProfileHandler({
692
+ sample_id: input.sample_id,
693
+ force_refresh: !input.reuse_cached,
694
+ });
695
+ if (dllProfileResult.ok && dllProfileResult.data) {
696
+ dllProfileData = summarizeDllPreflight(dllProfileResult.data);
697
+ stageStatus.preflight_dll_profile = 'ok';
698
+ }
699
+ else {
700
+ stageStatus.preflight_dll_profile = 'failed';
701
+ warnings.push(`dll.export.profile unavailable: ${(dllProfileResult.errors || ['unknown error']).join('; ')}`);
702
+ }
703
+ if (dllProfileResult.warnings?.length) {
704
+ warnings.push(...dllProfileResult.warnings.map((item) => `dll.export.profile: ${item}`));
705
+ }
706
+ {
707
+ const setupGuidance = collectSetupGuidanceFromWorkerResult(dllProfileResult);
708
+ setupActions = mergeSetupActions(setupActions, setupGuidance.setupActions);
709
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, setupGuidance.requiredUserInputs);
710
+ }
711
+ const comProfileResult = await comRoleProfileHandler({
712
+ sample_id: input.sample_id,
713
+ force_refresh: !input.reuse_cached,
714
+ });
715
+ if (comProfileResult.ok && comProfileResult.data) {
716
+ comProfileData = summarizeComPreflight(comProfileResult.data);
717
+ stageStatus.preflight_com_profile = 'ok';
718
+ }
719
+ else {
720
+ stageStatus.preflight_com_profile = 'failed';
721
+ warnings.push(`com.role.profile unavailable: ${(comProfileResult.errors || ['unknown error']).join('; ')}`);
722
+ }
723
+ if (comProfileResult.warnings?.length) {
724
+ warnings.push(...comProfileResult.warnings.map((item) => `com.role.profile: ${item}`));
725
+ }
726
+ {
727
+ const setupGuidance = collectSetupGuidanceFromWorkerResult(comProfileResult);
728
+ setupActions = mergeSetupActions(setupActions, setupGuidance.setupActions);
729
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, setupGuidance.requiredUserInputs);
730
+ }
731
+ }
732
+ if (selectedPath === 'native' && !runtimeData?.is_dotnet && input.include_preflight) {
733
+ const rustProfileResult = await rustBinaryAnalyzeHandler({
734
+ sample_id: input.sample_id,
735
+ force_refresh: !input.reuse_cached,
736
+ });
737
+ if (rustProfileResult.ok && rustProfileResult.data) {
738
+ rustProfileData = rustProfileResult.data;
739
+ stageStatus.preflight_rust_profile = 'ok';
740
+ }
741
+ else {
742
+ stageStatus.preflight_rust_profile = 'failed';
743
+ warnings.push(`rust_binary.analyze unavailable: ${(rustProfileResult.errors || ['unknown error']).join('; ')}`);
744
+ }
745
+ if (rustProfileResult.warnings?.length) {
746
+ warnings.push(...rustProfileResult.warnings.map((item) => `rust_binary.analyze: ${item}`));
747
+ }
748
+ {
749
+ const setupGuidance = collectSetupGuidanceFromWorkerResult(rustProfileResult);
750
+ setupActions = mergeSetupActions(setupActions, setupGuidance.setupActions);
751
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, setupGuidance.requiredUserInputs);
752
+ }
753
+ }
754
+ if (input.include_preflight) {
755
+ roleStrategy = buildRoleAwareStrategy({
756
+ runtimeData,
757
+ binaryProfile: binaryProfileData,
758
+ dllProfile: dllProfileData,
759
+ comProfile: comProfileData,
760
+ rustProfile: rustProfileData ? summarizeRustPreflight(rustProfileData) : null,
761
+ });
762
+ }
763
+ if (selectedPath === 'native' &&
764
+ input.auto_recover_function_index &&
765
+ !hasReadyGhidraFunctionIndex &&
766
+ !hasFunctionDefinitionIndex) {
767
+ const functionIndexRecoverResult = await functionIndexRecoverHandler({
768
+ sample_id: input.sample_id,
769
+ define_from: 'auto',
770
+ include_rank_preview: false,
771
+ persist_artifact: true,
772
+ register_analysis: true,
773
+ replace_all: true,
774
+ force_refresh: !input.reuse_cached,
775
+ });
776
+ if (functionIndexRecoverResult.ok && functionIndexRecoverResult.data) {
777
+ functionIndexRecoveryData = summarizeFunctionIndexRecovery(functionIndexRecoverResult.data);
778
+ functionIndexRecoveryApplied = true;
779
+ stageStatus.function_index_recovery = 'ok';
780
+ analyses = database.findAnalysesBySample(input.sample_id);
781
+ completedGhidraAnalysis = findBestGhidraAnalysis(analyses, 'function_index');
782
+ }
783
+ else {
784
+ stageStatus.function_index_recovery = 'failed';
785
+ warnings.push(`workflow.function_index_recover unavailable: ${(functionIndexRecoverResult.errors || ['unknown error']).join('; ')}`);
786
+ }
787
+ if (functionIndexRecoverResult.warnings?.length) {
788
+ warnings.push(...functionIndexRecoverResult.warnings.map((item) => `workflow.function_index_recover: ${item}`));
789
+ }
790
+ {
791
+ const setupGuidance = collectSetupGuidanceFromWorkerResult(functionIndexRecoverResult);
792
+ setupActions = mergeSetupActions(setupActions, setupGuidance.setupActions);
793
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, setupGuidance.requiredUserInputs);
794
+ }
795
+ }
334
796
  const dynamicEvidence = await loadDynamicTraceEvidence(workspaceManager, database, input.sample_id, {
335
797
  evidenceScope: input.evidence_scope,
336
798
  sessionTag: input.evidence_session_tag,
@@ -368,7 +830,17 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
368
830
  selectionDiffs.semantic_names = buildArtifactSelectionDiff('semantic_names', provenance.semantic_names, buildSemanticArtifactProvenance('semantic naming artifacts', baselineSemanticNameIndex, input.compare_semantic_scope, input.compare_semantic_session_tag));
369
831
  selectionDiffs.semantic_explanations = buildArtifactSelectionDiff('semantic_explanations', provenance.semantic_explanations, buildSemanticArtifactProvenance('semantic explanation artifacts', baselineSemanticExplanationIndex, input.compare_semantic_scope, input.compare_semantic_session_tag));
370
832
  }
371
- const analysisMarker = completedGhidraAnalysis?.finished_at || completedGhidraAnalysis?.id || 'none';
833
+ const functionDefinitionMarker = pickLatestAnalysisMarker(analyses, (analysis) => analysis.stage === 'function_definition');
834
+ const analysisMarker = JSON.stringify({
835
+ ghidra_function_index: completedGhidraAnalysis
836
+ ? {
837
+ id: completedGhidraAnalysis.id,
838
+ status: completedGhidraAnalysis.status,
839
+ finished_at: completedGhidraAnalysis.finished_at || completedGhidraAnalysis.started_at || null,
840
+ }
841
+ : null,
842
+ function_definition: functionDefinitionMarker,
843
+ });
372
844
  const cacheKey = generateCacheKey({
373
845
  sampleSha256: sample.sha256,
374
846
  toolName: TOOL_NAME,
@@ -391,6 +863,8 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
391
863
  compare_evidence_session_tag: input.compare_evidence_session_tag || null,
392
864
  compare_semantic_scope: input.compare_semantic_scope || null,
393
865
  compare_semantic_session_tag: input.compare_semantic_session_tag || null,
866
+ include_preflight: input.include_preflight,
867
+ auto_recover_function_index: input.auto_recover_function_index,
394
868
  include_plan: input.include_plan,
395
869
  include_obfuscation_fallback: input.include_obfuscation_fallback,
396
870
  fallback_on_error: input.fallback_on_error,
@@ -449,11 +923,23 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
449
923
  if (planResult.warnings && planResult.warnings.length > 0) {
450
924
  warnings.push(...planResult.warnings.map((item) => `plan: ${item}`));
451
925
  }
926
+ {
927
+ const setupGuidance = collectSetupGuidanceFromWorkerResult(planResult);
928
+ setupActions = mergeSetupActions(setupActions, setupGuidance.setupActions);
929
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, setupGuidance.requiredUserInputs);
930
+ }
452
931
  }
453
932
  let exportSummary = null;
454
933
  let artifacts = [];
455
934
  const primaryPath = selectedPath;
456
935
  const fallbackPath = primaryPath === 'dotnet' ? 'native' : 'dotnet';
936
+ const nativeExportTuning = roleStrategy?.export_tuning || {
937
+ topk: Math.max(input.topk, 16),
938
+ module_limit: 8,
939
+ min_module_size: 1,
940
+ include_imports: true,
941
+ include_strings: true,
942
+ };
457
943
  const runExport = async (pathToRun) => {
458
944
  if (pathToRun === 'dotnet') {
459
945
  const dotnetResult = await dotnetExportHandler({
@@ -463,13 +949,14 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
463
949
  include_obfuscation_fallback: input.include_obfuscation_fallback,
464
950
  evidence_scope: input.evidence_scope,
465
951
  evidence_session_tag: input.evidence_session_tag,
466
- reuse_cached: input.reuse_cached,
952
+ reuse_cached: input.reuse_cached && !functionIndexRecoveryApplied,
467
953
  });
468
954
  if (!dotnetResult.ok || !dotnetResult.data) {
469
955
  return {
470
956
  ok: false,
471
957
  errors: dotnetResult.errors || ['dotnet.reconstruct.export failed'],
472
958
  warnings: dotnetResult.warnings || [],
959
+ setupGuidance: collectSetupGuidanceFromWorkerResult(dotnetResult),
473
960
  };
474
961
  }
475
962
  const data = dotnetResult.data;
@@ -477,6 +964,7 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
477
964
  ok: true,
478
965
  warnings: dotnetResult.warnings || [],
479
966
  artifacts: dotnetResult.artifacts || [],
967
+ setupGuidance: collectSetupGuidanceFromWorkerResult(dotnetResult),
480
968
  summary: {
481
969
  tool: 'dotnet.reconstruct.export',
482
970
  export_root: data.export_root,
@@ -503,11 +991,11 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
503
991
  }
504
992
  const nativeResult = await nativeExportHandler({
505
993
  sample_id: input.sample_id,
506
- topk: input.topk,
507
- module_limit: 8,
508
- min_module_size: 1,
509
- include_imports: true,
510
- include_strings: true,
994
+ topk: Math.max(input.topk, nativeExportTuning.topk),
995
+ module_limit: nativeExportTuning.module_limit,
996
+ min_module_size: nativeExportTuning.min_module_size,
997
+ include_imports: nativeExportTuning.include_imports,
998
+ include_strings: nativeExportTuning.include_strings,
511
999
  export_name: input.export_name,
512
1000
  validate_build: input.validate_build,
513
1001
  run_harness: input.run_harness,
@@ -518,13 +1006,17 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
518
1006
  evidence_session_tag: input.evidence_session_tag,
519
1007
  semantic_scope: input.semantic_scope,
520
1008
  semantic_session_tag: input.semantic_session_tag,
521
- reuse_cached: input.reuse_cached,
1009
+ role_target: roleStrategy?.target_role,
1010
+ role_focus_areas: roleStrategy?.focus_areas || [],
1011
+ role_priority_order: roleStrategy?.priority_order || [],
1012
+ reuse_cached: input.reuse_cached && !functionIndexRecoveryApplied,
522
1013
  });
523
1014
  if (!nativeResult.ok || !nativeResult.data) {
524
1015
  return {
525
1016
  ok: false,
526
1017
  errors: nativeResult.errors || ['code.reconstruct.export failed'],
527
1018
  warnings: nativeResult.warnings || [],
1019
+ setupGuidance: collectSetupGuidanceFromWorkerResult(nativeResult),
528
1020
  };
529
1021
  }
530
1022
  const data = nativeResult.data;
@@ -532,6 +1024,7 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
532
1024
  ok: true,
533
1025
  warnings: nativeResult.warnings || [],
534
1026
  artifacts: nativeResult.artifacts || [],
1027
+ setupGuidance: collectSetupGuidanceFromWorkerResult(nativeResult),
535
1028
  summary: {
536
1029
  tool: 'code.reconstruct.export',
537
1030
  export_root: data.export_root,
@@ -561,12 +1054,16 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
561
1054
  stageStatus.export_primary = 'ok';
562
1055
  exportSummary = primaryExportResult.summary;
563
1056
  artifacts = primaryExportResult.artifacts || [];
1057
+ setupActions = mergeSetupActions(setupActions, primaryExportResult.setupGuidance.setupActions);
1058
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, primaryExportResult.setupGuidance.requiredUserInputs);
564
1059
  if (primaryExportResult.warnings.length > 0) {
565
1060
  warnings.push(...primaryExportResult.warnings.map((item) => `${primaryPath === 'dotnet' ? 'dotnet_export' : 'native_export'}: ${item}`));
566
1061
  }
567
1062
  }
568
1063
  else {
569
1064
  stageStatus.export_primary = 'failed';
1065
+ setupActions = mergeSetupActions(setupActions, primaryExportResult.setupGuidance.setupActions);
1066
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, primaryExportResult.setupGuidance.requiredUserInputs);
570
1067
  warnings.push(`primary export(${primaryPath}) failed: ${(primaryExportResult.errors || ['unknown error']).join('; ')}`);
571
1068
  if (primaryExportResult.warnings.length > 0) {
572
1069
  warnings.push(...primaryExportResult.warnings.map((item) => `${primaryPath === 'dotnet' ? 'dotnet_export' : 'native_export'}: ${item}`));
@@ -578,6 +1075,8 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
578
1075
  stageStatus.export_fallback = 'ok';
579
1076
  exportSummary = fallbackExportResult.summary;
580
1077
  artifacts = fallbackExportResult.artifacts || [];
1078
+ setupActions = mergeSetupActions(setupActions, fallbackExportResult.setupGuidance.setupActions);
1079
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, fallbackExportResult.setupGuidance.requiredUserInputs);
581
1080
  selectedPath = fallbackPath;
582
1081
  notes.push(`Primary export path failed; switched to fallback path: ${fallbackPath}.`);
583
1082
  if (fallbackExportResult.warnings.length > 0) {
@@ -586,6 +1085,8 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
586
1085
  }
587
1086
  else {
588
1087
  stageStatus.export_fallback = 'failed';
1088
+ setupActions = mergeSetupActions(setupActions, fallbackExportResult.setupGuidance.setupActions);
1089
+ requiredUserInputs = mergeRequiredUserInputs(requiredUserInputs, fallbackExportResult.setupGuidance.requiredUserInputs);
589
1090
  warnings.push(`fallback export(${fallbackPath}) failed: ${(fallbackExportResult.errors || ['unknown error']).join('; ')}`);
590
1091
  if (fallbackExportResult.warnings.length > 0) {
591
1092
  warnings.push(...fallbackExportResult.warnings.map((item) => `${fallbackPath === 'dotnet' ? 'dotnet_export' : 'native_export'}: ${item}`));
@@ -600,6 +1101,8 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
600
1101
  ok: false,
601
1102
  errors: ['All export paths failed and allow_partial=false.'],
602
1103
  warnings,
1104
+ setup_actions: setupActions.length > 0 ? setupActions : undefined,
1105
+ required_user_inputs: requiredUserInputs.length > 0 ? requiredUserInputs : undefined,
603
1106
  metrics: {
604
1107
  elapsed_ms: Date.now() - startTime,
605
1108
  tool: TOOL_NAME,
@@ -615,6 +1118,32 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
615
1118
  else {
616
1119
  notes.push('Runtime signal indicates native path; exact original source text is not recoverable.');
617
1120
  }
1121
+ if (binaryProfileData?.export_dispatch_profile?.likely_dispatch_model &&
1122
+ binaryProfileData.export_dispatch_profile.likely_dispatch_model !== 'none') {
1123
+ notes.push(`Binary role preflight suggests dispatch model: ${binaryProfileData.export_dispatch_profile.likely_dispatch_model}.`);
1124
+ }
1125
+ if (dllProfileData?.dll_entry_hints.length) {
1126
+ notes.push(`DLL/export preflight hints: ${dllProfileData.dll_entry_hints.slice(0, 3).join(' ')}`);
1127
+ }
1128
+ if (comProfileData?.likely_com_server) {
1129
+ notes.push(`COM preflight suggests activation model: ${comProfileData.activation_model}.`);
1130
+ }
1131
+ if (binaryProfileData?.host_interaction_profile?.likely_hosted) {
1132
+ notes.push('Binary role preflight suggests the sample is likely hosted as a DLL/plugin/service component.');
1133
+ }
1134
+ if (rustProfileData?.suspected_rust) {
1135
+ notes.push(`Rust preflight recovered ${rustProfileData.recovered_function_count} function candidates and ${rustProfileData.recovered_symbol_count} symbol hints.`);
1136
+ if (rustProfileData.crate_hints.length > 0) {
1137
+ notes.push(`Rust crate hints: ${rustProfileData.crate_hints.slice(0, 4).join(', ')}.`);
1138
+ }
1139
+ }
1140
+ if (functionIndexRecoveryData?.applied) {
1141
+ notes.push(`Function index recovery imported ${functionIndexRecoveryData.imported_count} recovered functions before export.`);
1142
+ }
1143
+ if (roleStrategy) {
1144
+ notes.push(`Role-aware strategy selected target role ${roleStrategy.target_role}${roleStrategy.focus_areas.length ? ` with focus on ${roleStrategy.focus_areas.join(', ')}` : ''}.`);
1145
+ notes.push(`Role-aware export tuning: topk=${roleStrategy.export_tuning.topk}, module_limit=${roleStrategy.export_tuning.module_limit}, min_module_size=${roleStrategy.export_tuning.min_module_size}, imports=${roleStrategy.export_tuning.include_imports ? 'on' : 'off'}, strings=${roleStrategy.export_tuning.include_strings ? 'on' : 'off'}.`);
1146
+ }
618
1147
  if (exportSummary?.binary_profile?.analysis_priorities?.length) {
619
1148
  notes.push(`Binary profile priorities: ${exportSummary.binary_profile.analysis_priorities.join(', ')}.`);
620
1149
  }
@@ -635,6 +1164,16 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
635
1164
  provenance,
636
1165
  selection_diffs: Object.keys(selectionDiffs).length > 0 ? selectionDiffs : undefined,
637
1166
  runtime: summarizeRuntime(runtimeData),
1167
+ preflight: input.include_preflight || stageStatus.function_index_recovery !== 'skipped'
1168
+ ? {
1169
+ binary_profile: binaryProfileData,
1170
+ dll_profile: dllProfileData,
1171
+ com_profile: comProfileData,
1172
+ rust_profile: rustProfileData ? summarizeRustPreflight(rustProfileData) : null,
1173
+ function_index_recovery: functionIndexRecoveryData,
1174
+ role_strategy: roleStrategy,
1175
+ }
1176
+ : undefined,
638
1177
  plan: planSummary,
639
1178
  export: exportSummary,
640
1179
  notes,
@@ -644,6 +1183,8 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
644
1183
  ok: true,
645
1184
  data: outputData,
646
1185
  warnings: warnings.length > 0 ? warnings : undefined,
1186
+ setup_actions: setupActions.length > 0 ? setupActions : undefined,
1187
+ required_user_inputs: requiredUserInputs.length > 0 ? requiredUserInputs : undefined,
647
1188
  artifacts: artifacts,
648
1189
  metrics: {
649
1190
  elapsed_ms: Date.now() - startTime,
@@ -655,6 +1196,8 @@ export function createReconstructWorkflowHandler(workspaceManager, database, cac
655
1196
  return {
656
1197
  ok: false,
657
1198
  errors: [normalizeError(error)],
1199
+ setup_actions: undefined,
1200
+ required_user_inputs: undefined,
658
1201
  metrics: {
659
1202
  elapsed_ms: Date.now() - startTime,
660
1203
  tool: TOOL_NAME,