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
@@ -0,0 +1,566 @@
1
+ import { z } from 'zod';
2
+ import { createCodeModuleReviewPrepareHandler } from './code-module-review-prepare.js';
3
+ import { createCodeModuleReviewApplyHandler } from './code-module-review-apply.js';
4
+ const TOOL_NAME = 'code.module.review';
5
+ const ReviewModuleSchema = z.object({
6
+ module_name: z.string().min(1).max(120),
7
+ refined_name: z.string().min(1).max(120).optional(),
8
+ summary: z.string().min(1).max(1600),
9
+ role_hint: z.string().min(1).max(240),
10
+ confidence: z.number().min(0).max(1),
11
+ assumptions: z.array(z.string()).optional().default([]),
12
+ evidence_used: z.array(z.string()).optional().default([]),
13
+ rewrite_guidance: z.union([z.string().min(1), z.array(z.string().min(1))]).optional(),
14
+ focus_areas: z.array(z.string().min(1)).optional().default([]),
15
+ priority_functions: z.array(z.string().min(1)).optional().default([]),
16
+ });
17
+ const ReviewModulePayloadSchema = z.object({
18
+ reviews: z.array(ReviewModuleSchema).min(1),
19
+ });
20
+ export const codeModuleReviewInputSchema = z
21
+ .object({
22
+ sample_id: z.string().describe('Sample ID (format: sha256:<hex>)'),
23
+ topk: z
24
+ .number()
25
+ .int()
26
+ .min(1)
27
+ .max(40)
28
+ .default(12)
29
+ .describe('Top-K high-value functions forwarded to code.reconstruct.export'),
30
+ module_limit: z
31
+ .number()
32
+ .int()
33
+ .min(1)
34
+ .max(12)
35
+ .default(6)
36
+ .describe('Maximum module count in the prepared reconstruction bundle'),
37
+ min_module_size: z
38
+ .number()
39
+ .int()
40
+ .min(1)
41
+ .max(20)
42
+ .default(2)
43
+ .describe('Modules with fewer functions than this threshold are merged into core'),
44
+ include_imports: z.boolean().default(true).describe('Use import features for module hints'),
45
+ include_strings: z.boolean().default(true).describe('Use high-value string clusters for module hints'),
46
+ analysis_goal: z
47
+ .string()
48
+ .min(1)
49
+ .max(400)
50
+ .default('Review reconstructed modules, refine their role labels, and propose evidence-grounded rewrite guidance.')
51
+ .describe('Human-readable analysis goal injected into the MCP prompt and sampling request'),
52
+ session_tag: z
53
+ .string()
54
+ .optional()
55
+ .describe('Optional semantic module review session tag used for artifact grouping'),
56
+ evidence_scope: z
57
+ .enum(['all', 'latest', 'session'])
58
+ .default('all')
59
+ .describe('Runtime evidence scope forwarded to prepare and optional export refresh'),
60
+ evidence_session_tag: z
61
+ .string()
62
+ .optional()
63
+ .describe('Optional runtime evidence session selector used when evidence_scope=session or to narrow all/latest results'),
64
+ semantic_scope: z
65
+ .enum(['all', 'latest', 'session'])
66
+ .default('all')
67
+ .describe('Semantic artifact scope forwarded to prepare and optional export refresh'),
68
+ semantic_session_tag: z
69
+ .string()
70
+ .optional()
71
+ .describe('Optional semantic artifact session selector used when semantic_scope=session or to narrow all/latest results'),
72
+ role_target: z
73
+ .string()
74
+ .min(1)
75
+ .max(64)
76
+ .optional()
77
+ .describe('Optional high-level binary role hint such as native_rust_executable, dll_library, or com_server'),
78
+ role_focus_areas: z
79
+ .array(z.string().min(1).max(96))
80
+ .max(16)
81
+ .default([])
82
+ .describe('Optional role-aware focus areas forwarded to module preparation'),
83
+ role_priority_order: z
84
+ .array(z.string().min(1).max(96))
85
+ .max(24)
86
+ .default([])
87
+ .describe('Optional role-aware priority-order hints forwarded to module preparation'),
88
+ persist_artifact: z
89
+ .boolean()
90
+ .default(true)
91
+ .describe('Persist the prepared bundle artifact before requesting external module review'),
92
+ auto_apply: z
93
+ .boolean()
94
+ .default(true)
95
+ .describe('Persist accepted module reviews automatically via code.module.review.apply'),
96
+ temperature: z
97
+ .number()
98
+ .min(0)
99
+ .max(1)
100
+ .default(0.2)
101
+ .describe('Sampling temperature passed to the connected MCP client'),
102
+ max_tokens: z
103
+ .number()
104
+ .int()
105
+ .min(200)
106
+ .max(8000)
107
+ .default(2400)
108
+ .describe('Maximum sampling tokens requested from the connected MCP client'),
109
+ include_context: z
110
+ .enum(['none', 'thisServer', 'allServers'])
111
+ .default('none')
112
+ .describe('Requested MCP sampling context scope; clients may ignore this preference'),
113
+ model_hint: z
114
+ .string()
115
+ .min(1)
116
+ .max(120)
117
+ .optional()
118
+ .describe('Optional advisory model-family hint for client-mediated MCP sampling'),
119
+ cost_priority: z.number().min(0).max(1).default(0.1),
120
+ speed_priority: z.number().min(0).max(1).default(0.2),
121
+ intelligence_priority: z.number().min(0).max(1).default(0.95),
122
+ system_prompt: z
123
+ .string()
124
+ .min(1)
125
+ .max(800)
126
+ .optional()
127
+ .describe('Optional extra system prompt for the client-mediated module review'),
128
+ })
129
+ .refine((value) => value.evidence_scope !== 'session' || Boolean(value.evidence_session_tag?.trim()), {
130
+ message: 'evidence_session_tag is required when evidence_scope=session',
131
+ path: ['evidence_session_tag'],
132
+ })
133
+ .refine((value) => value.semantic_scope !== 'session' || Boolean(value.semantic_session_tag?.trim()), {
134
+ message: 'semantic_session_tag is required when semantic_scope=session',
135
+ path: ['semantic_session_tag'],
136
+ });
137
+ export const codeModuleReviewOutputSchema = z.object({
138
+ ok: z.boolean(),
139
+ data: z
140
+ .object({
141
+ sample_id: z.string(),
142
+ review_status: z.enum([
143
+ 'sampled_and_applied',
144
+ 'sampled_only',
145
+ 'prompt_contract_only',
146
+ 'no_targets',
147
+ 'sampling_parse_failed',
148
+ ]),
149
+ prompt_name: z.literal('reverse.module_reconstruction_review'),
150
+ prompt_arguments: z.object({
151
+ analysis_goal: z.string(),
152
+ prepared_bundle_json: z.string(),
153
+ }),
154
+ task_prompt: z.string(),
155
+ client: z.object({
156
+ name: z.string().nullable(),
157
+ version: z.string().nullable(),
158
+ sampling_available: z.boolean(),
159
+ }),
160
+ prepare: z.object({
161
+ prepared_count: z.number().int().nonnegative(),
162
+ artifact_id: z.string().nullable(),
163
+ }),
164
+ sampling: z.object({
165
+ attempted: z.boolean(),
166
+ model: z.string().nullable(),
167
+ stop_reason: z.string().nullable(),
168
+ response_text: z.string().nullable(),
169
+ parsed_review_count: z.number().int().nonnegative(),
170
+ }),
171
+ apply: z.object({
172
+ attempted: z.boolean(),
173
+ accepted_count: z.number().int().nonnegative(),
174
+ rejected_count: z.number().int().nonnegative(),
175
+ artifact_id: z.string().nullable(),
176
+ }),
177
+ confidence_policy: z.object({
178
+ calibrated: z.boolean(),
179
+ review_scores_are_heuristic: z.boolean(),
180
+ meaning: z.string(),
181
+ }),
182
+ next_steps: z.array(z.string()),
183
+ })
184
+ .optional(),
185
+ warnings: z.array(z.string()).optional(),
186
+ errors: z.array(z.string()).optional(),
187
+ artifacts: z.array(z.any()).optional(),
188
+ metrics: z
189
+ .object({
190
+ elapsed_ms: z.number(),
191
+ tool: z.string(),
192
+ })
193
+ .optional(),
194
+ });
195
+ export const codeModuleReviewToolDefinition = {
196
+ name: TOOL_NAME,
197
+ description: 'Use MCP client-mediated sampling to request an external LLM review of reconstructed modules, then optionally persist module-level summaries and rewrite guidance.',
198
+ inputSchema: codeModuleReviewInputSchema,
199
+ outputSchema: codeModuleReviewOutputSchema,
200
+ };
201
+ function extractTextBlocks(result) {
202
+ const blocks = Array.isArray(result.content) ? result.content : [result.content];
203
+ return blocks
204
+ .filter((block) => block?.type === 'text')
205
+ .map((block) => block.text || '')
206
+ .join('\n')
207
+ .trim();
208
+ }
209
+ function extractJsonCandidates(rawText) {
210
+ const trimmed = rawText.trim();
211
+ const candidates = new Set();
212
+ if (trimmed.length > 0) {
213
+ candidates.add(trimmed);
214
+ }
215
+ const fencedMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
216
+ if (fencedMatch?.[1]) {
217
+ candidates.add(fencedMatch[1].trim());
218
+ }
219
+ const firstBrace = trimmed.indexOf('{');
220
+ const lastBrace = trimmed.lastIndexOf('}');
221
+ if (firstBrace >= 0 && lastBrace > firstBrace) {
222
+ candidates.add(trimmed.slice(firstBrace, lastBrace + 1));
223
+ }
224
+ const firstBracket = trimmed.indexOf('[');
225
+ const lastBracket = trimmed.lastIndexOf(']');
226
+ if (firstBracket >= 0 && lastBracket > firstBracket) {
227
+ candidates.add(trimmed.slice(firstBracket, lastBracket + 1));
228
+ }
229
+ return Array.from(candidates);
230
+ }
231
+ function parseSamplingReviews(rawText) {
232
+ for (const candidate of extractJsonCandidates(rawText)) {
233
+ try {
234
+ const parsed = JSON.parse(candidate);
235
+ if (Array.isArray(parsed)) {
236
+ return ReviewModulePayloadSchema.parse({ reviews: parsed }).reviews;
237
+ }
238
+ return ReviewModulePayloadSchema.parse(parsed).reviews;
239
+ }
240
+ catch {
241
+ continue;
242
+ }
243
+ }
244
+ throw new Error('Sampling response could not be parsed as strict JSON module reviews. Return {"reviews":[...]} only.');
245
+ }
246
+ function buildSamplingRequest(input, taskPrompt) {
247
+ return {
248
+ messages: [
249
+ {
250
+ role: 'user',
251
+ content: {
252
+ type: 'text',
253
+ text: taskPrompt,
254
+ },
255
+ },
256
+ ],
257
+ systemPrompt: input.system_prompt ||
258
+ 'You are an evidence-grounded reverse-engineering assistant. Return strict JSON only.',
259
+ includeContext: input.include_context,
260
+ maxTokens: input.max_tokens,
261
+ temperature: input.temperature,
262
+ modelPreferences: {
263
+ hints: input.model_hint ? [{ name: input.model_hint }] : undefined,
264
+ costPriority: input.cost_priority,
265
+ speedPriority: input.speed_priority,
266
+ intelligencePriority: input.intelligence_priority,
267
+ },
268
+ };
269
+ }
270
+ function buildModuleReviewConfidencePolicy() {
271
+ return {
272
+ calibrated: false,
273
+ review_scores_are_heuristic: true,
274
+ meaning: 'Module review confidence values rank evidence support strength only. They do not prove semantic equivalence or recover original source-level intent with calibrated probability.',
275
+ };
276
+ }
277
+ export function createCodeModuleReviewHandler(workspaceManager, database, cacheManager, mcpServer, dependencies) {
278
+ const prepareHandler = dependencies?.prepareHandler ||
279
+ createCodeModuleReviewPrepareHandler(workspaceManager, database, cacheManager);
280
+ const applyHandler = dependencies?.applyHandler || createCodeModuleReviewApplyHandler(workspaceManager, database);
281
+ const samplingRequester = dependencies?.samplingRequester ||
282
+ (mcpServer ? (params) => mcpServer.createMessage(params) : undefined);
283
+ const clientCapabilitiesProvider = dependencies?.clientCapabilitiesProvider ||
284
+ (mcpServer ? () => mcpServer.getClientCapabilities() : undefined);
285
+ const clientVersionProvider = dependencies?.clientVersionProvider ||
286
+ (mcpServer ? () => mcpServer.getClientVersion() : undefined);
287
+ return async (args) => {
288
+ const startTime = Date.now();
289
+ const warnings = [];
290
+ const artifacts = [];
291
+ try {
292
+ const input = codeModuleReviewInputSchema.parse(args);
293
+ const prepareResult = await prepareHandler({
294
+ sample_id: input.sample_id,
295
+ topk: input.topk,
296
+ module_limit: input.module_limit,
297
+ min_module_size: input.min_module_size,
298
+ include_imports: input.include_imports,
299
+ include_strings: input.include_strings,
300
+ analysis_goal: input.analysis_goal,
301
+ persist_artifact: input.persist_artifact,
302
+ session_tag: input.session_tag,
303
+ evidence_scope: input.evidence_scope,
304
+ evidence_session_tag: input.evidence_session_tag,
305
+ semantic_scope: input.semantic_scope,
306
+ semantic_session_tag: input.semantic_session_tag,
307
+ role_target: input.role_target,
308
+ role_focus_areas: input.role_focus_areas,
309
+ role_priority_order: input.role_priority_order,
310
+ });
311
+ warnings.push(...(prepareResult.warnings || []));
312
+ artifacts.push(...(prepareResult.artifacts || []));
313
+ if (!prepareResult.ok) {
314
+ return {
315
+ ok: false,
316
+ errors: prepareResult.errors || ['code.module.review.prepare failed'],
317
+ warnings: warnings.length > 0 ? warnings : undefined,
318
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
319
+ metrics: {
320
+ elapsed_ms: Date.now() - startTime,
321
+ tool: TOOL_NAME,
322
+ },
323
+ };
324
+ }
325
+ const prepareData = (prepareResult.data || {});
326
+ const preparedCount = Number(prepareData.prepared_count || 0);
327
+ const prepareArtifactId = prepareData.artifact?.id || null;
328
+ const promptArguments = prepareData.prompt_arguments;
329
+ const taskPrompt = prepareData.task_prompt;
330
+ const clientCapabilities = clientCapabilitiesProvider?.();
331
+ const samplingAvailable = Boolean(clientCapabilities?.sampling && samplingRequester);
332
+ const clientVersion = clientVersionProvider?.();
333
+ if (preparedCount === 0) {
334
+ return {
335
+ ok: true,
336
+ data: {
337
+ sample_id: input.sample_id,
338
+ review_status: 'no_targets',
339
+ prompt_name: 'reverse.module_reconstruction_review',
340
+ prompt_arguments: promptArguments,
341
+ task_prompt: taskPrompt,
342
+ client: {
343
+ name: clientVersion?.name || null,
344
+ version: clientVersion?.version || null,
345
+ sampling_available: samplingAvailable,
346
+ },
347
+ prepare: {
348
+ prepared_count: 0,
349
+ artifact_id: prepareArtifactId,
350
+ },
351
+ sampling: {
352
+ attempted: false,
353
+ model: null,
354
+ stop_reason: null,
355
+ response_text: null,
356
+ parsed_review_count: 0,
357
+ },
358
+ apply: {
359
+ attempted: false,
360
+ accepted_count: 0,
361
+ rejected_count: 0,
362
+ artifact_id: null,
363
+ },
364
+ confidence_policy: buildModuleReviewConfidencePolicy(),
365
+ next_steps: ['increase topk or module_limit', 'rerun code.reconstruct.export to produce module output'],
366
+ },
367
+ warnings: warnings.length > 0 ? warnings : undefined,
368
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
369
+ metrics: {
370
+ elapsed_ms: Date.now() - startTime,
371
+ tool: TOOL_NAME,
372
+ },
373
+ };
374
+ }
375
+ if (!samplingAvailable) {
376
+ warnings.push('Connected MCP client did not advertise sampling support; returning prompt contract only.');
377
+ return {
378
+ ok: true,
379
+ data: {
380
+ sample_id: input.sample_id,
381
+ review_status: 'prompt_contract_only',
382
+ prompt_name: 'reverse.module_reconstruction_review',
383
+ prompt_arguments: promptArguments,
384
+ task_prompt: taskPrompt,
385
+ client: {
386
+ name: clientVersion?.name || null,
387
+ version: clientVersion?.version || null,
388
+ sampling_available: false,
389
+ },
390
+ prepare: {
391
+ prepared_count: preparedCount,
392
+ artifact_id: prepareArtifactId,
393
+ },
394
+ sampling: {
395
+ attempted: false,
396
+ model: null,
397
+ stop_reason: null,
398
+ response_text: null,
399
+ parsed_review_count: 0,
400
+ },
401
+ apply: {
402
+ attempted: false,
403
+ accepted_count: 0,
404
+ rejected_count: 0,
405
+ artifact_id: null,
406
+ },
407
+ confidence_policy: buildModuleReviewConfidencePolicy(),
408
+ next_steps: [
409
+ 'call prompts/get for reverse.module_reconstruction_review with the returned prompt arguments',
410
+ 'send the prompt to any MCP-capable tool-calling LLM client that supports sampling or manual prompt execution',
411
+ 'pass the JSON result to code.module.review.apply',
412
+ ],
413
+ },
414
+ warnings: warnings.length > 0 ? warnings : undefined,
415
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
416
+ metrics: {
417
+ elapsed_ms: Date.now() - startTime,
418
+ tool: TOOL_NAME,
419
+ },
420
+ };
421
+ }
422
+ const samplingResult = await samplingRequester(buildSamplingRequest(input, taskPrompt));
423
+ const responseText = extractTextBlocks(samplingResult);
424
+ let parsedReviews;
425
+ try {
426
+ parsedReviews = parseSamplingReviews(responseText);
427
+ }
428
+ catch (error) {
429
+ warnings.push(error instanceof Error ? error.message : String(error));
430
+ return {
431
+ ok: true,
432
+ data: {
433
+ sample_id: input.sample_id,
434
+ review_status: 'sampling_parse_failed',
435
+ prompt_name: 'reverse.module_reconstruction_review',
436
+ prompt_arguments: promptArguments,
437
+ task_prompt: taskPrompt,
438
+ client: {
439
+ name: clientVersion?.name || null,
440
+ version: clientVersion?.version || null,
441
+ sampling_available: true,
442
+ },
443
+ prepare: {
444
+ prepared_count: preparedCount,
445
+ artifact_id: prepareArtifactId,
446
+ },
447
+ sampling: {
448
+ attempted: true,
449
+ model: samplingResult.model || null,
450
+ stop_reason: samplingResult.stopReason || null,
451
+ response_text: responseText || null,
452
+ parsed_review_count: 0,
453
+ },
454
+ apply: {
455
+ attempted: false,
456
+ accepted_count: 0,
457
+ rejected_count: 0,
458
+ artifact_id: null,
459
+ },
460
+ confidence_policy: buildModuleReviewConfidencePolicy(),
461
+ next_steps: [
462
+ 'inspect the sampling response and ensure it returns strict JSON with the shape {"reviews":[...]}',
463
+ 'rerun code.module.review with a stricter system_prompt if needed',
464
+ ],
465
+ },
466
+ warnings: warnings.length > 0 ? warnings : undefined,
467
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
468
+ metrics: {
469
+ elapsed_ms: Date.now() - startTime,
470
+ tool: TOOL_NAME,
471
+ },
472
+ };
473
+ }
474
+ let applyAttempted = false;
475
+ let applyAcceptedCount = 0;
476
+ let applyRejectedCount = 0;
477
+ let applyArtifactId = null;
478
+ if (input.auto_apply) {
479
+ applyAttempted = true;
480
+ const applyResult = await applyHandler({
481
+ sample_id: input.sample_id,
482
+ client_name: clientVersion?.name || null,
483
+ model_name: samplingResult.model || null,
484
+ prepare_artifact_id: prepareArtifactId || undefined,
485
+ session_tag: input.session_tag,
486
+ reviews: parsedReviews,
487
+ });
488
+ warnings.push(...(applyResult.warnings || []));
489
+ artifacts.push(...(applyResult.artifacts || []));
490
+ if (!applyResult.ok) {
491
+ return {
492
+ ok: false,
493
+ errors: applyResult.errors || ['code.module.review.apply failed'],
494
+ warnings: warnings.length > 0 ? warnings : undefined,
495
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
496
+ metrics: {
497
+ elapsed_ms: Date.now() - startTime,
498
+ tool: TOOL_NAME,
499
+ },
500
+ };
501
+ }
502
+ applyAcceptedCount = Number(applyResult.data?.accepted_count || 0);
503
+ applyRejectedCount = Number(applyResult.data?.rejected_count || 0);
504
+ applyArtifactId = applyResult.data?.artifact?.id || null;
505
+ }
506
+ return {
507
+ ok: true,
508
+ data: {
509
+ sample_id: input.sample_id,
510
+ review_status: input.auto_apply ? 'sampled_and_applied' : 'sampled_only',
511
+ prompt_name: 'reverse.module_reconstruction_review',
512
+ prompt_arguments: promptArguments,
513
+ task_prompt: taskPrompt,
514
+ client: {
515
+ name: clientVersion?.name || null,
516
+ version: clientVersion?.version || null,
517
+ sampling_available: true,
518
+ },
519
+ prepare: {
520
+ prepared_count: preparedCount,
521
+ artifact_id: prepareArtifactId,
522
+ },
523
+ sampling: {
524
+ attempted: true,
525
+ model: samplingResult.model || null,
526
+ stop_reason: samplingResult.stopReason || null,
527
+ response_text: responseText || null,
528
+ parsed_review_count: parsedReviews.length,
529
+ },
530
+ apply: {
531
+ attempted: applyAttempted,
532
+ accepted_count: applyAcceptedCount,
533
+ rejected_count: applyRejectedCount,
534
+ artifact_id: applyArtifactId,
535
+ },
536
+ confidence_policy: buildModuleReviewConfidencePolicy(),
537
+ next_steps: input.auto_apply
538
+ ? [
539
+ 'rerun code.reconstruct.export or workflow.reconstruct to propagate module review summaries into rewrite output',
540
+ 'inspect reverse_notes.md and module rewrite headers for updated module-level guidance',
541
+ ]
542
+ : ['pass the parsed JSON result to code.module.review.apply'],
543
+ },
544
+ warnings: warnings.length > 0 ? warnings : undefined,
545
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
546
+ metrics: {
547
+ elapsed_ms: Date.now() - startTime,
548
+ tool: TOOL_NAME,
549
+ },
550
+ };
551
+ }
552
+ catch (error) {
553
+ return {
554
+ ok: false,
555
+ errors: [error instanceof Error ? error.message : String(error)],
556
+ warnings: warnings.length > 0 ? warnings : undefined,
557
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
558
+ metrics: {
559
+ elapsed_ms: Date.now() - startTime,
560
+ tool: TOOL_NAME,
561
+ },
562
+ };
563
+ }
564
+ };
565
+ }
566
+ //# sourceMappingURL=code-module-review.js.map