@reverse-craft/ai-tools 1.0.3 → 1.0.4

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.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Property-based tests for findJsvmpDispatcherTool
3
+ *
4
+ * Tests the MCP tool's input validation and response format properties.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=findJsvmpDispatcherTool.property.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findJsvmpDispatcherTool.property.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/findJsvmpDispatcherTool.property.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -15,13 +15,37 @@ export interface FormattedCode {
15
15
  /**
16
16
  * Detection type for JSVMP patterns
17
17
  */
18
- export type DetectionType = "If-Else Dispatcher" | "Switch Dispatcher" | "Instruction Array" | "Stack Operation";
18
+ export type DetectionType = "If-Else Dispatcher" | "Switch Dispatcher" | "Instruction Array";
19
19
  /**
20
20
  * Confidence level for detection results
21
21
  */
22
22
  export type ConfidenceLevel = "ultra_high" | "high" | "medium" | "low";
23
23
  /**
24
- * A detected region in the code
24
+ * VM Component variable identification
25
+ */
26
+ export interface VMComponentVariable {
27
+ variable_name: string | null;
28
+ confidence: ConfidenceLevel;
29
+ reasoning: string;
30
+ }
31
+ /**
32
+ * VM Components for a JSVMP instance
33
+ */
34
+ export interface VMComponents {
35
+ instruction_pointer: VMComponentVariable;
36
+ stack_pointer: VMComponentVariable;
37
+ virtual_stack: VMComponentVariable;
38
+ bytecode_array: VMComponentVariable;
39
+ }
40
+ /**
41
+ * Debugging entry point information
42
+ */
43
+ export interface DebuggingEntryPoint {
44
+ line_number: number;
45
+ description: string;
46
+ }
47
+ /**
48
+ * A detected region in the code (enhanced with VM components)
25
49
  */
26
50
  export interface DetectionRegion {
27
51
  start: number;
@@ -29,12 +53,21 @@ export interface DetectionRegion {
29
53
  type: DetectionType;
30
54
  confidence: ConfidenceLevel;
31
55
  description: string;
56
+ vm_components?: VMComponents;
57
+ debugging_entry_point?: DebuggingEntryPoint;
58
+ }
59
+ /**
60
+ * Summary information for detection result
61
+ */
62
+ export interface DetectionSummary {
63
+ overall_description: string;
64
+ debugging_recommendation: string;
32
65
  }
33
66
  /**
34
- * Complete detection result from LLM analysis
67
+ * Complete detection result from LLM analysis (enhanced)
35
68
  */
36
69
  export interface DetectionResult {
37
- summary: string;
70
+ summary: string | DetectionSummary;
38
71
  regions: DetectionRegion[];
39
72
  }
40
73
  /**
@@ -120,8 +153,9 @@ export declare function createBatches(formattedLines: string[], maxTokensPerBatc
120
153
  * Validates:
121
154
  * - JSON is parseable
122
155
  * - Required fields exist: summary, regions
123
- * - Each region has required fields: start, end, type, confidence, description
156
+ * - Each region has required fields: start/start_line, end/end_line, type, confidence, description
124
157
  * - Enum values are valid
158
+ * - Supports both old and new JSON formats
125
159
  *
126
160
  * @param jsonString - JSON string from LLM response
127
161
  * @returns Parsed and validated DetectionResult
@@ -1 +1 @@
1
- {"version":3,"file":"jsvmpDetector.d.ts","sourceRoot":"","sources":["../src/jsvmpDetector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jsvmpDetector.d.ts","sourceRoot":"","sources":["../src/jsvmpDetector.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"llmConfig.d.ts","sourceRoot":"","sources":["../src/llmConfig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAExC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAIpE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAgBA,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,CAM9E;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,SAAS,GAAG,IAAI,CAoC/C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AA6DD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,CAwBpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAyB5D"}
1
+ {"version":3,"file":"llmConfig.d.ts","sourceRoot":"","sources":["../src/llmConfig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAExC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAIpE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAgBA,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,CAM9E;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,SAAS,GAAG,IAAI,CAoC/C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAgGD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,CAwBpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAyB5D"}
package/dist/server.js CHANGED
@@ -78,53 +78,83 @@ function buildJSVMPSystemPrompt() {
78
78
  return `You are a Senior JavaScript Reverse Engineer and De-obfuscation Expert. Your specialty is analyzing **JSVMP (JavaScript Virtual Machine Protection)**.
79
79
 
80
80
  **Context: What is JSVMP?**
81
- JSVMP is a protection technique where original JavaScript code is compiled into custom **bytecode** and executed by a custom **interpreter** (virtual machine) written in JavaScript.
81
+ JSVMP is a protection technique where original JavaScript code is compiled into custom **bytecode** and executed by a custom **interpreter** (virtual machine) written in JavaScript. A single JavaScript file may contain **multiple, independent JSVMP instances**.
82
82
 
83
- Key components of JSVMP code include:
84
- 1. **The Virtual Stack:** A central array used to store operands and results (e.g., \`stack[pointer++]\` or \`v[p--]\`).
85
- 2. **The Dispatcher:** A control flow structure inside a loop that decides which instruction to execute next based on the current bytecode (opcode).
86
- * *Common variants:* A massive \`switch\` statement, a deeply nested \`if-else\` chain (binary search style), or a function array mapping (\`handlers[opcode]()\`).
87
- 3. **The Bytecode:** A large string or array of integers representing the program logic.
83
+ Key components of each JSVMP instance include:
84
+ 1. **The Bytecode Array:** A large array of integers representing the program logic for that specific VM.
85
+ 2. **The Virtual Stack:** A central array used to store operands and results for that VM.
86
+ 3. **The Dispatcher:** A control flow structure (e.g., a \`while\` loop with a \`switch\` or \`if-else\` chain) that reads an opcode and executes the corresponding logic for that VM.
87
+ 4. **Key State Variables:** The "registers" of a specific VM, such as its **Instruction Pointer (IP/PC)** and **Stack Pointer (SP)**.
88
+ 5. **Debugging Entry Point:** The single most critical line number within a specific dispatcher loop to set a breakpoint for observing that VM's state.
88
89
 
89
90
  **Task:**
90
- Analyze the provided JavaScript code snippet to identify regions that match JSVMP structural patterns.
91
+ Your primary task is to analyze the provided JavaScript code snippet to identify **all independent JSVMP instances** and produce a comprehensive report for each one. You are NOT creating or analyzing any Intermediate Representation (IR). Your goal is to provide the necessary information for a subsequent tool to analyze each VM instance separately and create its IR and mappings.
92
+
93
+ Specifically, for **EACH** JSVMP instance you identify, you must:
94
+ 1. Define its location (**region**) and dispatcher type.
95
+ 2. Identify the specific **variables** that function as its core **Key State Variables** (Instruction Pointer, Stack Pointer, Virtual Stack, and Bytecode Array).
96
+ 3. Pinpoint the exact source code **line number** that serves as its optimal **Debugging Entry Point**.
97
+ 4. Summarize all findings in a single, structured JSON output.
91
98
 
92
99
  **Input Data Format:**
93
100
  The code is provided in a simplified format: \`LineNo SourceLoc Code\`.
94
101
  * **Example:** \`10 L234:56 var x = stack[p++];\`
95
- * **Instruction:** Focus on the **LineNo** (1st column) and **Code** (3rd column onwards). Ignore the \`SourceLoc\` (middle column).
96
-
97
- **Detection Rules & Confidence Levels:**
98
- Please assign confidence based on the following criteria:
99
-
100
- * **Ultra High:**
101
- * A combination of a **Main Loop** + **Dispatcher** + **Stack Operations** appears in the same block.
102
- * *Example:* A \`while(true)\` loop containing a huge \`if-else\` chain where branches perform \`stack[p++]\` operations.
102
+ * **Instruction:** Focus on the **LineNo** (1st column) and **Code** (3rd column onwards).
103
103
 
104
- * **High:**
105
- * Distinct **Dispatcher** structures found (e.g., a \`switch\` with >20 cases, or an \`if-else\` chain nested >10 levels deep checking integer values).
106
- * Large arrays containing only function definitions (Instruction Handlers).
107
-
108
- * **Medium:**
109
- * Isolated **Stack Operations** (e.g., \`v2[p2] = v2[p2 - 1]\`) without visible dispatchers nearby.
110
- * Suspicious \`while\` loops iterating over a string/array.
111
-
112
- * **Low:**
113
- * Generic obfuscation patterns (short variable names, comma operators) that *might* be part of a VM but lack specific structural proof.
104
+ **Detection Rules:**
105
+ * **Region Identification:** An individual JSVMP instance is often characterized by a self-contained block containing a **Main Loop** + **Dispatcher** + **Stack Operations**.
106
+ * **Instruction Pointer (IP) Identification:**
107
+ * It is used as the **index for the Bytecode Array of its VM instance**.
108
+ * It is **predictably incremented** in almost every loop iteration.
109
+ * In some branches (jumps), it is **overwritten** with a new value.
110
+ * **Stack Pointer (SP) Identification:**
111
+ * It is used as the **index for the Virtual Stack array of its VM instance**.
112
+ * Its value consistently **increments after a write** (push) and **decrements before a read** (pop).
113
+ * **Debugging Entry Point Identification:**
114
+ * This is the line **inside a specific dispatcher loop** but **before its \`switch\` or \`if-else\` chain begins**. It is typically located right after the \`opcode\` is read from the bytecode array.
114
115
 
115
116
  **Output Format:**
116
117
  Return **ONLY valid JSON**. No markdown wrapper, no conversational text.
117
118
 
118
119
  **JSON Schema:**
119
120
  {
120
- "summary": "Brief analysis of the code structure in chinese, shortly",
121
+ "summary": {
122
+ "overall_description": "\u5BF9\u5728\u6587\u4EF6\u4E2D\u53D1\u73B0\u7684JSVMP\u5B9E\u4F8B\u6570\u91CF\u548C\u7C7B\u578B\u7684\u7B80\u8981\u4E2D\u6587\u603B\u7ED3\u3002",
123
+ "debugging_recommendation": "\u4E3A\u4E0B\u4E00\u6B65\u5206\u6790\u63D0\u4F9B\u7684\u603B\u4F53\u4E2D\u6587\u5EFA\u8BAE\u3002\u4F8B\u5982\uFF1A'\u5DF2\u8BC6\u522B\u51FA N \u4E2A\u72EC\u7ACB\u7684JSVMP\u5B9E\u4F8B\u3002\u5EFA\u8BAE\u5BF9\u6BCF\u4E2A\u5B9E\u4F8B\u5206\u522B\u5728\u6307\u5B9A\u7684"\u8C03\u8BD5\u5165\u53E3\u70B9"\u8BBE\u7F6E\u6761\u4EF6\u65AD\u70B9\uFF0C\u5E76\u76D1\u63A7\u5176\u5404\u81EA\u7684\u7EC4\u4EF6\u53D8\u91CF\u3002'"
124
+ },
121
125
  "regions": [
122
126
  {
123
- "start": <start_line>,
124
- "end": <end_line>,
125
- "type": "<If-Else Dispatcher | Switch Dispatcher | Instruction Array | Stack Operation>",
127
+ "start_line": "<start_line_integer>",
128
+ "end_line": "<end_line_integer>",
129
+ "type": "<If-Else Dispatcher | Switch Dispatcher | Instruction Array>",
126
130
  "confidence": "<ultra_high | high | medium | low>",
127
- "description": "<Why you flagged this. Mention specific variables like 'v2', 'p2' or structures. in chinese, shortly>"
131
+ "description": "\u5BF9\u8FD9\u4E2A\u7279\u5B9AJSVMP\u5B9E\u4F8B\u7684\u7B80\u8981\u4E2D\u6587\u63CF\u8FF0\u3002",
132
+ "vm_components": {
133
+ "instruction_pointer": {
134
+ "variable_name": "<identified_variable_name | null>",
135
+ "confidence": "<high | medium | low>",
136
+ "reasoning": "Why this variable is the IP for THIS VM instance. E.g., 'Used as index for bytecode array _0x123 within this region.'"
137
+ },
138
+ "stack_pointer": {
139
+ "variable_name": "<identified_variable_name | null>",
140
+ "confidence": "<high | medium | low>",
141
+ "reasoning": "Why this variable is the SP for THIS VM instance. E.g., 'Used as index for stack array _0x456.'"
142
+ },
143
+ "virtual_stack": {
144
+ "variable_name": "<identified_array_name | null>",
145
+ "confidence": "<high | medium | low>",
146
+ "reasoning": "Why this array is the stack for THIS VM instance. E.g., 'Frequently accessed using its stack_pointer _0x789.'"
147
+ },
148
+ "bytecode_array": {
149
+ "variable_name": "<identified_array_name | null>",
150
+ "confidence": "<high | medium | low>",
151
+ "reasoning": "Why this array is the bytecode for THIS VM instance. E.g., 'A large, static array indexed by its instruction_pointer _0x123.'"
152
+ }
153
+ },
154
+ "debugging_entry_point": {
155
+ "line_number": "<line_number_integer>",
156
+ "description": "The optimal breakpoint line for THIS VM instance. E.g., 'This line is after the opcode is fetched and before this region's switch statement.'"
157
+ }
128
158
  }
129
159
  ]
130
160
  }`;
@@ -309,8 +339,7 @@ function createBatches(formattedLines, maxTokensPerBatch) {
309
339
  var VALID_DETECTION_TYPES = [
310
340
  "If-Else Dispatcher",
311
341
  "Switch Dispatcher",
312
- "Instruction Array",
313
- "Stack Operation"
342
+ "Instruction Array"
314
343
  ];
315
344
  var VALID_CONFIDENCE_LEVELS = [
316
345
  "ultra_high",
@@ -324,6 +353,57 @@ function isValidDetectionType(value) {
324
353
  function isValidConfidenceLevel(value) {
325
354
  return VALID_CONFIDENCE_LEVELS.includes(value);
326
355
  }
356
+ function parseVMComponentVariable(obj, fieldName) {
357
+ const component = obj[fieldName];
358
+ if (!component || typeof component !== "object") {
359
+ return null;
360
+ }
361
+ const variableName = component.variable_name;
362
+ const confidence = component.confidence;
363
+ const reasoning = component.reasoning;
364
+ if (typeof confidence !== "string" || !isValidConfidenceLevel(confidence)) {
365
+ return null;
366
+ }
367
+ return {
368
+ variable_name: typeof variableName === "string" ? variableName : null,
369
+ confidence,
370
+ reasoning: typeof reasoning === "string" ? reasoning : ""
371
+ };
372
+ }
373
+ function parseVMComponents(obj) {
374
+ const vmComponents = obj.vm_components;
375
+ if (!vmComponents || typeof vmComponents !== "object") {
376
+ return void 0;
377
+ }
378
+ const ip = parseVMComponentVariable(vmComponents, "instruction_pointer");
379
+ const sp = parseVMComponentVariable(vmComponents, "stack_pointer");
380
+ const stack = parseVMComponentVariable(vmComponents, "virtual_stack");
381
+ const bytecode = parseVMComponentVariable(vmComponents, "bytecode_array");
382
+ if (!ip && !sp && !stack && !bytecode) {
383
+ return void 0;
384
+ }
385
+ return {
386
+ instruction_pointer: ip ?? { variable_name: null, confidence: "low", reasoning: "" },
387
+ stack_pointer: sp ?? { variable_name: null, confidence: "low", reasoning: "" },
388
+ virtual_stack: stack ?? { variable_name: null, confidence: "low", reasoning: "" },
389
+ bytecode_array: bytecode ?? { variable_name: null, confidence: "low", reasoning: "" }
390
+ };
391
+ }
392
+ function parseDebuggingEntryPoint(obj) {
393
+ const entryPoint = obj.debugging_entry_point;
394
+ if (!entryPoint || typeof entryPoint !== "object") {
395
+ return void 0;
396
+ }
397
+ const lineNumber = entryPoint.line_number;
398
+ const description = entryPoint.description;
399
+ if (typeof lineNumber !== "number") {
400
+ return void 0;
401
+ }
402
+ return {
403
+ line_number: lineNumber,
404
+ description: typeof description === "string" ? description : ""
405
+ };
406
+ }
327
407
  function parseDetectionResult(jsonString) {
328
408
  let parsed;
329
409
  try {
@@ -335,7 +415,19 @@ function parseDetectionResult(jsonString) {
335
415
  throw new Error("LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u671F\u671B\u5BF9\u8C61\u7C7B\u578B");
336
416
  }
337
417
  const obj = parsed;
338
- if (typeof obj.summary !== "string") {
418
+ let summary;
419
+ if (typeof obj.summary === "string") {
420
+ summary = obj.summary;
421
+ } else if (typeof obj.summary === "object" && obj.summary !== null) {
422
+ const summaryObj = obj.summary;
423
+ if (typeof summaryObj.overall_description !== "string" || typeof summaryObj.debugging_recommendation !== "string") {
424
+ throw new Error("LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Csummary \u5BF9\u8C61\u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5");
425
+ }
426
+ summary = {
427
+ overall_description: summaryObj.overall_description,
428
+ debugging_recommendation: summaryObj.debugging_recommendation
429
+ };
430
+ } else {
339
431
  throw new Error("LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: summary");
340
432
  }
341
433
  if (!Array.isArray(obj.regions)) {
@@ -347,11 +439,13 @@ function parseDetectionResult(jsonString) {
347
439
  if (typeof region !== "object" || region === null) {
348
440
  throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u4E0D\u662F\u5BF9\u8C61`);
349
441
  }
350
- if (typeof region.start !== "number") {
351
- throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: start`);
442
+ const startLine = region.start_line ?? region.start;
443
+ const endLine = region.end_line ?? region.end;
444
+ if (typeof startLine !== "number") {
445
+ throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: start_line \u6216 start`);
352
446
  }
353
- if (typeof region.end !== "number") {
354
- throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: end`);
447
+ if (typeof endLine !== "number") {
448
+ throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: end_line \u6216 end`);
355
449
  }
356
450
  if (typeof region.type !== "string") {
357
451
  throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: type`);
@@ -372,16 +466,20 @@ function parseDetectionResult(jsonString) {
372
466
  `LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}].confidence \u503C\u65E0\u6548: "${region.confidence}". \u6709\u6548\u503C: ${VALID_CONFIDENCE_LEVELS.join(", ")}`
373
467
  );
374
468
  }
469
+ const vmComponents = parseVMComponents(region);
470
+ const debuggingEntryPoint = parseDebuggingEntryPoint(region);
375
471
  validatedRegions.push({
376
- start: region.start,
377
- end: region.end,
472
+ start: startLine,
473
+ end: endLine,
378
474
  type: region.type,
379
475
  confidence: region.confidence,
380
- description: region.description
476
+ description: region.description,
477
+ ...vmComponents && { vm_components: vmComponents },
478
+ ...debuggingEntryPoint && { debugging_entry_point: debuggingEntryPoint }
381
479
  });
382
480
  }
383
481
  return {
384
- summary: obj.summary,
482
+ summary,
385
483
  regions: validatedRegions
386
484
  };
387
485
  }
@@ -390,13 +488,45 @@ function formatDetectionResultOutput(result, filePath, totalLines, batchCount) {
390
488
  lines.push("=== JSVMP Dispatcher Detection Result ===");
391
489
  lines.push(`File: ${filePath} (${totalLines} lines, ${batchCount} batch${batchCount > 1 ? "es" : ""})`);
392
490
  lines.push("");
393
- lines.push(`Summary: ${result.summary}`);
491
+ if (typeof result.summary === "string") {
492
+ lines.push(`Summary: ${result.summary}`);
493
+ } else {
494
+ lines.push(`Summary: ${result.summary.overall_description}`);
495
+ lines.push(`Recommendation: ${result.summary.debugging_recommendation}`);
496
+ }
394
497
  lines.push("");
395
498
  if (result.regions.length > 0) {
396
- lines.push("Detected Regions:");
397
- for (const region of result.regions) {
499
+ lines.push(`Detected Regions (${result.regions.length} JSVMP instance${result.regions.length > 1 ? "s" : ""}):`);
500
+ lines.push("");
501
+ for (let i = 0; i < result.regions.length; i++) {
502
+ const region = result.regions[i];
503
+ lines.push(`--- Instance ${i + 1} ---`);
398
504
  lines.push(`[${region.confidence}] Lines ${region.start}-${region.end}: ${region.type}`);
399
505
  lines.push(` ${region.description}`);
506
+ if (region.vm_components) {
507
+ lines.push(" VM Components:");
508
+ const { instruction_pointer, stack_pointer, virtual_stack, bytecode_array } = region.vm_components;
509
+ if (instruction_pointer.variable_name) {
510
+ lines.push(` - Instruction Pointer: ${instruction_pointer.variable_name} [${instruction_pointer.confidence}]`);
511
+ lines.push(` ${instruction_pointer.reasoning}`);
512
+ }
513
+ if (stack_pointer.variable_name) {
514
+ lines.push(` - Stack Pointer: ${stack_pointer.variable_name} [${stack_pointer.confidence}]`);
515
+ lines.push(` ${stack_pointer.reasoning}`);
516
+ }
517
+ if (virtual_stack.variable_name) {
518
+ lines.push(` - Virtual Stack: ${virtual_stack.variable_name} [${virtual_stack.confidence}]`);
519
+ lines.push(` ${virtual_stack.reasoning}`);
520
+ }
521
+ if (bytecode_array.variable_name) {
522
+ lines.push(` - Bytecode Array: ${bytecode_array.variable_name} [${bytecode_array.confidence}]`);
523
+ lines.push(` ${bytecode_array.reasoning}`);
524
+ }
525
+ }
526
+ if (region.debugging_entry_point) {
527
+ lines.push(` Debugging Entry Point: Line ${region.debugging_entry_point.line_number}`);
528
+ lines.push(` ${region.debugging_entry_point.description}`);
529
+ }
400
530
  lines.push("");
401
531
  }
402
532
  } else {
@@ -412,8 +542,20 @@ function mergeDetectionResults(results) {
412
542
  const sortedRegions = [...results[0].regions].sort((a, b) => a.start - b.start);
413
543
  return { summary: results[0].summary, regions: sortedRegions };
414
544
  }
415
- const summaries = results.map((r, i) => `[Batch ${i + 1}] ${r.summary}`);
416
- const combinedSummary = summaries.join("\n");
545
+ const summaryParts = [];
546
+ for (let i = 0; i < results.length; i++) {
547
+ const summary = results[i].summary;
548
+ if (typeof summary === "string") {
549
+ summaryParts.push(`[Batch ${i + 1}] ${summary}`);
550
+ } else {
551
+ summaryParts.push(`[Batch ${i + 1}] ${summary.overall_description}`);
552
+ }
553
+ }
554
+ const lastSummary = results[results.length - 1].summary;
555
+ const combinedSummary = {
556
+ overall_description: summaryParts.join("\n"),
557
+ debugging_recommendation: typeof lastSummary === "string" ? "\u8BF7\u53C2\u8003\u5404\u6279\u6B21\u7684\u5206\u6790\u7ED3\u679C\u8FDB\u884C\u8C03\u8BD5\u3002" : lastSummary.debugging_recommendation
558
+ };
417
559
  const allRegions = [];
418
560
  for (const result of results) {
419
561
  allRegions.push(...result.regions);
@@ -539,15 +681,16 @@ var findJsvmpDispatcherTool = defineTool({
539
681
  name: "find_jsvmp_dispatcher",
540
682
  description: `Detect JSVMP (JavaScript Virtual Machine Protection) patterns in code using LLM analysis.
541
683
 
542
- JSVMP is a code protection technique that converts JavaScript to bytecode executed by a virtual machine. This tool identifies:
543
- - If-Else Dispatchers: Nested if-else chains for instruction dispatch
544
- - Switch Dispatchers: Large switch statements (>20 cases) for opcode handling
545
- - Instruction Arrays: Arrays storing bytecode instructions
546
- - Stack Operations: Virtual stack push/pop patterns
684
+ JSVMP is a code protection technique that converts JavaScript to bytecode executed by a virtual machine. A single file may contain multiple independent JSVMP instances.
547
685
 
548
- Automatically splits large files into batches based on token limits and merges results.
686
+ This tool identifies for each JSVMP instance:
687
+ - Region location and dispatcher type (If-Else Dispatcher, Switch Dispatcher, Instruction Array)
688
+ - VM Components: Instruction Pointer (IP), Stack Pointer (SP), Virtual Stack, Bytecode Array
689
+ - Debugging Entry Point: The optimal line number to set breakpoints
549
690
 
550
- Returns detection results with confidence levels (ultra_high, high, medium, low) and detailed descriptions.
691
+ Detection confidence levels: ultra_high, high, medium, low
692
+
693
+ Automatically splits large files into batches based on token limits and merges results.
551
694
 
552
695
  Requires OPENAI_API_KEY environment variable. Optional: OPENAI_BASE_URL, OPENAI_MODEL.`,
553
696
  schema: FindJsvmpDispatcherInputSchema,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/server.ts", "../src/tools/findJsvmpDispatcherTool.ts", "../src/tools/ToolDefinition.ts", "../src/jsvmpDetector.ts", "../src/llmConfig.ts", "../src/tokenizer.ts", "../src/tools/index.ts"],
4
- "sourcesContent": ["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { tools } from './tools/index.js';\n\n// Create MCP Server instance\nconst server = new McpServer({\n name: 'ai-tools-mcp',\n version: '1.0.0',\n});\n\n/**\n * Register a tool with the MCP server.\n */\nfunction registerTool(tool: {\n name: string;\n description: string;\n schema: z.ZodRawShape;\n handler: (params: Record<string, unknown>) => Promise<string>;\n}): void {\n const zodSchema = z.object(tool.schema);\n\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: tool.schema,\n },\n async (params, _extra) => {\n try {\n const validatedParams = zodSchema.parse(params);\n const result = await tool.handler(validatedParams as Record<string, unknown>);\n\n return {\n content: [{ type: 'text' as const, text: result }],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n }\n }\n );\n}\n\n// Register all tools\nfor (const tool of tools) {\n registerTool(tool as unknown as {\n name: string;\n description: string;\n schema: z.ZodRawShape;\n handler: (params: Record<string, unknown>) => Promise<string>;\n });\n}\n\n// Main entry point\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error('AI Tools MCP Server running on stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n", "import { z } from 'zod';\nimport { defineTool } from './ToolDefinition.js';\nimport { findJsvmpDispatcher } from '../jsvmpDetector.js';\n\n/**\n * Input schema for find_jsvmp_dispatcher tool\n */\nexport const FindJsvmpDispatcherInputSchema = {\n filePath: z.string().describe('Path to the JavaScript file to analyze'),\n charLimit: z.number().int().positive().optional().describe('Character limit for string truncation (default: 300)'),\n maxTokensPerBatch: z.number().int().positive().optional().describe('Maximum tokens per batch for LLM analysis (default: 150000)'),\n};\n\n/**\n * MCP Tool: find_jsvmp_dispatcher\n * \n * Uses LLM to detect JSVMP (JavaScript Virtual Machine Protection) patterns in code.\n * \n * JSVMP is a code protection technique that converts JavaScript to bytecode\n * executed by a virtual machine. This tool identifies:\n * - If-Else Dispatchers\n * - Switch Dispatchers \n * - Instruction Arrays\n * - Stack Operations\n * \n * Requires OPENAI_API_KEY environment variable to be set.\n */\nexport const findJsvmpDispatcherTool = defineTool({\n name: 'find_jsvmp_dispatcher',\n description: `Detect JSVMP (JavaScript Virtual Machine Protection) patterns in code using LLM analysis.\n\nJSVMP is a code protection technique that converts JavaScript to bytecode executed by a virtual machine. This tool identifies:\n- If-Else Dispatchers: Nested if-else chains for instruction dispatch\n- Switch Dispatchers: Large switch statements (>20 cases) for opcode handling\n- Instruction Arrays: Arrays storing bytecode instructions\n- Stack Operations: Virtual stack push/pop patterns\n\nAutomatically splits large files into batches based on token limits and merges results.\n\nReturns detection results with confidence levels (ultra_high, high, medium, low) and detailed descriptions.\n\nRequires OPENAI_API_KEY environment variable. Optional: OPENAI_BASE_URL, OPENAI_MODEL.`,\n schema: FindJsvmpDispatcherInputSchema,\n handler: async (params): Promise<string> => {\n const { filePath, charLimit, maxTokensPerBatch } = params;\n\n const result = await findJsvmpDispatcher(filePath, {\n charLimit: charLimit ?? 300,\n maxTokensPerBatch: maxTokensPerBatch ?? 150000,\n });\n\n if (!result.success) {\n throw new Error(result.error ?? 'Detection failed');\n }\n\n return result.formattedOutput ?? 'No output generated';\n },\n});\n", "import { z } from 'zod';\n\n/**\n * Tool definition interface for MCP tools.\n * Each tool has a name, description, schema (Zod raw shape), and async handler.\n */\nexport interface ToolDefinition<TSchema extends z.ZodRawShape = z.ZodRawShape> {\n /** Unique tool name (e.g., 'find_jsvmp_dispatcher') */\n name: string;\n /** Human-readable description of what the tool does */\n description: string;\n /** Zod schema object defining input parameters */\n schema: TSchema;\n /** Async handler function that processes the tool request */\n handler: (params: z.infer<z.ZodObject<TSchema>>) => Promise<string>;\n}\n\n/**\n * Helper function to create a type-safe tool definition.\n * Validates the tool definition structure at compile time.\n * \n * @param definition - The tool definition object\n * @returns The same definition with proper typing\n */\nexport function defineTool<TSchema extends z.ZodRawShape>(\n definition: ToolDefinition<TSchema>\n): ToolDefinition<TSchema> {\n return definition;\n}\n", "/**\n * JSVMP Detector Module\n * AI-powered detection of JSVMP (JavaScript Virtual Machine Protection) patterns\n */\n\nimport { SourceMapConsumer } from 'source-map-js';\nimport { ensureBeautified, truncateCodeHighPerf } from '@reverse-craft/smart-fs';\nimport { existsSync } from 'fs';\nimport { getLLMConfig, createLLMClient, LLMClient } from './llmConfig.js';\nimport { countTokens, splitByTokenLimit } from './tokenizer.js';\n\n/**\n * Formatted code result interface\n */\nexport interface FormattedCode {\n content: string; // \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u5B57\u7B26\u4E32\n totalLines: number; // \u603B\u884C\u6570\n startLine: number; // \u5B9E\u9645\u8D77\u59CB\u884C\n endLine: number; // \u5B9E\u9645\u7ED3\u675F\u884C\n}\n\n/**\n * Detection type for JSVMP patterns\n */\nexport type DetectionType = \n | \"If-Else Dispatcher\" \n | \"Switch Dispatcher\" \n | \"Instruction Array\" \n | \"Stack Operation\";\n\n/**\n * Confidence level for detection results\n */\nexport type ConfidenceLevel = \"ultra_high\" | \"high\" | \"medium\" | \"low\";\n\n/**\n * A detected region in the code\n */\nexport interface DetectionRegion {\n start: number; // \u8D77\u59CB\u884C\u53F7\n end: number; // \u7ED3\u675F\u884C\u53F7\n type: DetectionType; // \u68C0\u6D4B\u7C7B\u578B\n confidence: ConfidenceLevel; // \u7F6E\u4FE1\u5EA6\n description: string; // \u63CF\u8FF0\uFF08\u4E2D\u6587\uFF09\n}\n\n/**\n * Complete detection result from LLM analysis\n */\nexport interface DetectionResult {\n summary: string; // \u5206\u6790\u6458\u8981\uFF08\u4E2D\u6587\uFF09\n regions: DetectionRegion[];\n}\n\n/**\n * Options for JSVMP detection\n */\nexport interface JsvmpDetectionOptions {\n charLimit?: number; // Default: 300\n maxTokensPerBatch?: number; // Default: 8000\n}\n\n/**\n * Result from findJsvmpDispatcher function\n */\nexport interface JsvmpDetectionResult {\n success: boolean;\n filePath: string;\n totalLines: number;\n batchCount: number;\n result?: DetectionResult;\n formattedOutput?: string;\n error?: string;\n partialErrors?: string[]; // Errors from failed batches\n}\n\n/**\n * Batch information for processing\n */\nexport interface BatchInfo {\n startLine: number; // \u6279\u6B21\u8D77\u59CB\u884C\u53F7 (1-based)\n endLine: number; // \u6279\u6B21\u7ED3\u675F\u884C\u53F7 (1-based)\n content: string; // \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u5185\u5BB9\n tokenCount: number; // \u8BE5\u6279\u6B21\u7684 token \u6570\u91CF\n}\n\n/**\n * Result from formatEntireFile function\n */\nexport interface FormattedFileResult {\n lines: string[]; // \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u884C\u6570\u7EC4\n totalLines: number; // \u603B\u884C\u6570\n}\n\n/**\n * Format source position as \"L{line}:{column}\" or empty placeholder\n */\nfunction formatSourcePosition(line: number | null, column: number | null): string {\n if (line !== null && column !== null) {\n return `L${line}:${column}`;\n }\n return '';\n}\n\n/**\n * Format a single code line with line number, source coordinates, and content\n * Format: \"LineNo SourceLoc Code\"\n */\nfunction formatCodeLine(lineNumber: number, sourcePos: string, code: string): string {\n const lineNumStr = String(lineNumber).padStart(5, ' ');\n const srcPosPadded = sourcePos ? sourcePos.padEnd(10, ' ') : ' ';\n return `${lineNumStr} ${srcPosPadded} ${code}`;\n}\n\n/**\n * \u683C\u5F0F\u5316\u4EE3\u7801\u4E3A LLM \u5206\u6790\u683C\u5F0F\n * \u683C\u5F0F: \"LineNo SourceLoc Code\"\n * \n * \u5904\u7406\u6D41\u7A0B\uFF1A\n * 1. \u8C03\u7528 ensureBeautified \u7F8E\u5316\u4EE3\u7801\n * 2. \u8C03\u7528 truncateCodeHighPerf \u622A\u65AD\u957F\u5B57\u7B26\u4E32\n * 3. \u4F7F\u7528 SourceMapConsumer \u83B7\u53D6\u539F\u59CB\u5750\u6807\n * 4. \u683C\u5F0F\u5316\u4E3A \"LineNo SourceLoc Code\" \u683C\u5F0F\n * \n * @param filePath - Path to the JavaScript file\n * @param startLine - Start line number (1-based)\n * @param endLine - End line number (1-based)\n * @param charLimit - Character limit for string truncation (default 300)\n * @returns FormattedCode object with formatted content and metadata\n */\nexport async function formatCodeForAnalysis(\n filePath: string,\n startLine: number,\n endLine: number,\n charLimit: number = 300\n): Promise<FormattedCode> {\n // Step 1: Beautify the file and get source map\n const beautifyResult = await ensureBeautified(filePath);\n const { code, rawMap } = beautifyResult;\n\n // Step 2: Truncate long strings\n const truncatedCode = truncateCodeHighPerf(code, charLimit);\n\n // Split into lines\n const lines = truncatedCode.split('\\n');\n const totalLines = lines.length;\n\n // Step 3: Adjust line range boundaries\n const effectiveStartLine = Math.max(1, Math.min(totalLines, startLine));\n const effectiveEndLine = Math.max(effectiveStartLine, Math.min(totalLines, endLine));\n\n // Step 4: Format each line with \"LineNo SourceLoc Code\" format\n const formattedLines: string[] = [];\n\n // Create source map consumer if available\n let consumer: SourceMapConsumer | null = null;\n if (rawMap && rawMap.sources && rawMap.names && rawMap.mappings) {\n consumer = new SourceMapConsumer({\n version: String(rawMap.version),\n sources: rawMap.sources,\n names: rawMap.names,\n mappings: rawMap.mappings,\n file: rawMap.file,\n sourceRoot: rawMap.sourceRoot,\n });\n }\n\n for (let lineNum = effectiveStartLine; lineNum <= effectiveEndLine; lineNum++) {\n const lineIndex = lineNum - 1;\n const lineContent = lines[lineIndex] ?? '';\n\n // Get original position from source map if available\n let sourcePos = '';\n if (consumer) {\n const originalPos = consumer.originalPositionFor({\n line: lineNum,\n column: 0,\n });\n sourcePos = formatSourcePosition(originalPos.line, originalPos.column);\n }\n \n formattedLines.push(formatCodeLine(lineNum, sourcePos, lineContent));\n }\n\n return {\n content: formattedLines.join('\\n'),\n totalLines,\n startLine: effectiveStartLine,\n endLine: effectiveEndLine,\n };\n}\n\n/**\n * \u683C\u5F0F\u5316\u6574\u4E2A\u6587\u4EF6\u4E3A LLM \u5206\u6790\u683C\u5F0F\n * \u683C\u5F0F: \"LineNo SourceLoc Code\"\n * \n * \u5904\u7406\u6D41\u7A0B\uFF1A\n * 1. \u8C03\u7528 ensureBeautified \u7F8E\u5316\u4EE3\u7801\n * 2. \u8C03\u7528 truncateCodeHighPerf \u622A\u65AD\u957F\u5B57\u7B26\u4E32\n * 3. \u4F7F\u7528 SourceMapConsumer \u83B7\u53D6\u539F\u59CB\u5750\u6807\n * 4. \u8FD4\u56DE\u683C\u5F0F\u5316\u540E\u7684\u884C\u6570\u7EC4\uFF08\u4FDD\u7559\u539F\u59CB\u884C\u53F7\uFF09\n * \n * @param filePath - Path to the JavaScript file\n * @param charLimit - Character limit for string truncation (default 300)\n * @returns FormattedFileResult with formatted lines array and metadata\n */\nexport async function formatEntireFile(\n filePath: string,\n charLimit: number = 300\n): Promise<FormattedFileResult> {\n // Step 1: Beautify the file and get source map\n const beautifyResult = await ensureBeautified(filePath);\n const { code, rawMap } = beautifyResult;\n\n // Step 2: Truncate long strings\n const truncatedCode = truncateCodeHighPerf(code, charLimit);\n\n // Split into lines\n const codeLines = truncatedCode.split('\\n');\n const totalLines = codeLines.length;\n\n // Step 3: Format each line with \"LineNo SourceLoc Code\" format\n const formattedLines: string[] = [];\n\n // Create source map consumer if available\n let consumer: SourceMapConsumer | null = null;\n if (rawMap && rawMap.sources && rawMap.names && rawMap.mappings) {\n consumer = new SourceMapConsumer({\n version: String(rawMap.version),\n sources: rawMap.sources,\n names: rawMap.names,\n mappings: rawMap.mappings,\n file: rawMap.file,\n sourceRoot: rawMap.sourceRoot,\n });\n }\n\n for (let lineNum = 1; lineNum <= totalLines; lineNum++) {\n const lineIndex = lineNum - 1;\n const lineContent = codeLines[lineIndex] ?? '';\n\n // Get original position from source map if available\n let sourcePos = '';\n if (consumer) {\n const originalPos = consumer.originalPositionFor({\n line: lineNum,\n column: 0,\n });\n sourcePos = formatSourcePosition(originalPos.line, originalPos.column);\n }\n \n formattedLines.push(formatCodeLine(lineNum, sourcePos, lineContent));\n }\n\n return {\n lines: formattedLines,\n totalLines,\n };\n}\n\n/**\n * Extract line number from a formatted code line\n * Format: \"LineNo SourceLoc Code\"\n * \n * @param formattedLine - A formatted code line\n * @returns The line number (1-based)\n */\nfunction extractLineNumber(formattedLine: string): number {\n const lineNumStr = formattedLine.substring(0, 5).trim();\n return parseInt(lineNumStr, 10);\n}\n\n/**\n * \u521B\u5EFA\u6279\u6B21\u7528\u4E8E\u5206\u6279\u5904\u7406\n * \u4F7F\u7528 tokenizer \u5206\u5272\u4EE3\u7801\uFF0C\u8BB0\u5F55\u6BCF\u4E2A\u6279\u6B21\u7684 startLine/endLine\n * \n * @param formattedLines - \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u884C\u6570\u7EC4\n * @param maxTokensPerBatch - \u6BCF\u6279\u6B21\u6700\u5927 token \u6570\u91CF\n * @returns BatchInfo \u6570\u7EC4\n */\nexport function createBatches(\n formattedLines: string[],\n maxTokensPerBatch: number\n): BatchInfo[] {\n if (formattedLines.length === 0) {\n return [];\n }\n\n // Split lines into batches based on token limit\n const lineBatches = splitByTokenLimit(formattedLines, maxTokensPerBatch);\n \n const batches: BatchInfo[] = [];\n \n for (const batchLines of lineBatches) {\n if (batchLines.length === 0) continue;\n \n // Extract start and end line numbers from formatted lines\n const startLine = extractLineNumber(batchLines[0]);\n const endLine = extractLineNumber(batchLines[batchLines.length - 1]);\n \n // Join lines to create batch content\n const content = batchLines.join('\\n');\n \n // Calculate token count for this batch\n const tokenCount = countTokens(content);\n \n batches.push({\n startLine,\n endLine,\n content,\n tokenCount,\n });\n }\n \n return batches;\n}\n\n/**\n * Valid detection types for validation\n */\nconst VALID_DETECTION_TYPES: DetectionType[] = [\n \"If-Else Dispatcher\",\n \"Switch Dispatcher\",\n \"Instruction Array\",\n \"Stack Operation\"\n];\n\n/**\n * Valid confidence levels for validation\n */\nconst VALID_CONFIDENCE_LEVELS: ConfidenceLevel[] = [\n \"ultra_high\",\n \"high\",\n \"medium\",\n \"low\"\n];\n\n/**\n * Check if a value is a valid DetectionType\n */\nfunction isValidDetectionType(value: unknown): value is DetectionType {\n return VALID_DETECTION_TYPES.includes(value as DetectionType);\n}\n\n/**\n * Check if a value is a valid ConfidenceLevel\n */\nfunction isValidConfidenceLevel(value: unknown): value is ConfidenceLevel {\n return VALID_CONFIDENCE_LEVELS.includes(value as ConfidenceLevel);\n}\n\n/**\n * Parse and validate LLM detection result from JSON string\n * \n * Validates:\n * - JSON is parseable\n * - Required fields exist: summary, regions\n * - Each region has required fields: start, end, type, confidence, description\n * - Enum values are valid\n * \n * @param jsonString - JSON string from LLM response\n * @returns Parsed and validated DetectionResult\n * @throws Error if JSON is invalid or structure doesn't match expected format\n */\nexport function parseDetectionResult(jsonString: string): DetectionResult {\n // Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonString);\n } catch (error) {\n throw new Error(`\u65E0\u6CD5\u89E3\u6790 LLM \u54CD\u5E94: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Validate required top-level fields\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u671F\u671B\u5BF9\u8C61\u7C7B\u578B');\n }\n\n const obj = parsed as Record<string, unknown>;\n\n if (typeof obj.summary !== 'string') {\n throw new Error('LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: summary');\n }\n\n if (!Array.isArray(obj.regions)) {\n throw new Error('LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: regions');\n }\n\n // Validate each region\n const validatedRegions: DetectionRegion[] = [];\n\n for (let i = 0; i < obj.regions.length; i++) {\n const region = obj.regions[i] as Record<string, unknown>;\n\n // Check region is an object\n if (typeof region !== 'object' || region === null) {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u4E0D\u662F\u5BF9\u8C61`);\n }\n\n // Validate required fields exist and have correct types\n if (typeof region.start !== 'number') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: start`);\n }\n\n if (typeof region.end !== 'number') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: end`);\n }\n\n if (typeof region.type !== 'string') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: type`);\n }\n\n if (typeof region.confidence !== 'string') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: confidence`);\n }\n\n if (typeof region.description !== 'string') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: description`);\n }\n\n // Validate enum values\n if (!isValidDetectionType(region.type)) {\n throw new Error(\n `LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}].type \u503C\u65E0\u6548: \"${region.type}\". ` +\n `\u6709\u6548\u503C: ${VALID_DETECTION_TYPES.join(', ')}`\n );\n }\n\n if (!isValidConfidenceLevel(region.confidence)) {\n throw new Error(\n `LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}].confidence \u503C\u65E0\u6548: \"${region.confidence}\". ` +\n `\u6709\u6548\u503C: ${VALID_CONFIDENCE_LEVELS.join(', ')}`\n );\n }\n\n validatedRegions.push({\n start: region.start,\n end: region.end,\n type: region.type,\n confidence: region.confidence,\n description: region.description,\n });\n }\n\n return {\n summary: obj.summary,\n regions: validatedRegions,\n };\n}\n\n/**\n * Format detection result for display\n */\nfunction formatDetectionResultOutput(\n result: DetectionResult,\n filePath: string,\n totalLines: number,\n batchCount: number\n): string {\n const lines: string[] = [];\n \n lines.push('=== JSVMP Dispatcher Detection Result ===');\n lines.push(`File: ${filePath} (${totalLines} lines, ${batchCount} batch${batchCount > 1 ? 'es' : ''})`);\n lines.push('');\n lines.push(`Summary: ${result.summary}`);\n lines.push('');\n \n if (result.regions.length > 0) {\n lines.push('Detected Regions:');\n for (const region of result.regions) {\n lines.push(`[${region.confidence}] Lines ${region.start}-${region.end}: ${region.type}`);\n lines.push(` ${region.description}`);\n lines.push('');\n }\n } else {\n lines.push('No JSVMP dispatcher patterns detected.');\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Merge detection results from multiple batches\n * - Combines all regions from all batches\n * - Combines summaries from all batches\n * - Sorts regions by start line\n * - Deduplicates overlapping regions (keeps higher confidence)\n * \n * @param results - Array of DetectionResult from each batch\n * @returns Merged DetectionResult\n */\nexport function mergeDetectionResults(results: DetectionResult[]): DetectionResult {\n if (results.length === 0) {\n return { summary: '', regions: [] };\n }\n \n if (results.length === 1) {\n // Still need to sort and deduplicate regions for single result\n const sortedRegions = [...results[0].regions].sort((a, b) => a.start - b.start);\n return { summary: results[0].summary, regions: sortedRegions };\n }\n \n // Combine summaries\n const summaries = results.map((r, i) => `[Batch ${i + 1}] ${r.summary}`);\n const combinedSummary = summaries.join('\\n');\n \n // Collect all regions\n const allRegions: DetectionRegion[] = [];\n for (const result of results) {\n allRegions.push(...result.regions);\n }\n \n // Sort by start line\n allRegions.sort((a, b) => a.start - b.start);\n \n // Deduplicate overlapping regions (keep higher confidence)\n const confidenceOrder: Record<ConfidenceLevel, number> = {\n 'ultra_high': 4,\n 'high': 3,\n 'medium': 2,\n 'low': 1,\n };\n \n const deduplicatedRegions: DetectionRegion[] = [];\n for (const region of allRegions) {\n // Check if this region overlaps with any existing region\n let overlappingIndex = -1;\n for (let i = 0; i < deduplicatedRegions.length; i++) {\n const existing = deduplicatedRegions[i];\n // Check for overlap: regions overlap if one starts before the other ends\n if (region.start <= existing.end && region.end >= existing.start) {\n overlappingIndex = i;\n break;\n }\n }\n \n if (overlappingIndex === -1) {\n // No overlap, add the region\n deduplicatedRegions.push(region);\n } else {\n // Overlap found, keep the one with higher confidence\n const existing = deduplicatedRegions[overlappingIndex];\n if (confidenceOrder[region.confidence] > confidenceOrder[existing.confidence]) {\n deduplicatedRegions[overlappingIndex] = region;\n }\n // If equal confidence, keep the first one (existing)\n }\n }\n \n return {\n summary: combinedSummary,\n regions: deduplicatedRegions,\n };\n}\n\n/**\n * Process a single batch through LLM\n * \n * @param client - LLM client\n * @param batch - Batch information\n * @returns DetectionResult from LLM analysis\n */\nasync function processBatch(\n client: LLMClient,\n batch: BatchInfo\n): Promise<DetectionResult> {\n const llmResponse = await client.analyzeJSVMP(batch.content);\n return parseDetectionResult(llmResponse);\n}\n\n/**\n * Process batches with error handling\n * - Continues processing if some batches fail\n * - Collects partial results and error information\n * \n * @param client - LLM client\n * @param batches - Array of BatchInfo\n * @returns Object with successful results and error messages\n */\nexport async function processBatchesWithErrorHandling(\n client: LLMClient,\n batches: BatchInfo[]\n): Promise<{ results: DetectionResult[]; errors: string[] }> {\n const results: DetectionResult[] = [];\n const errors: string[] = [];\n \n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i];\n try {\n const result = await processBatch(client, batch);\n results.push(result);\n } catch (error) {\n const errorMsg = `Batch ${i + 1} (lines ${batch.startLine}-${batch.endLine}) failed: ${\n error instanceof Error ? error.message : String(error)\n }`;\n errors.push(errorMsg);\n }\n }\n \n return { results, errors };\n}\n\n/**\n * Find JSVMP dispatcher patterns in JavaScript code using LLM analysis\n * \n * @param filePath - Path to the JavaScript file to analyze\n * @param options - Optional configuration\n * @returns JsvmpDetectionResult with detection results or error\n */\nexport async function findJsvmpDispatcher(\n filePath: string,\n options?: JsvmpDetectionOptions\n): Promise<JsvmpDetectionResult> {\n const charLimit = options?.charLimit ?? 300;\n const maxTokensPerBatch = options?.maxTokensPerBatch ?? 8000;\n \n // Check LLM configuration\n const config = getLLMConfig();\n if (!config) {\n return {\n success: false,\n filePath,\n totalLines: 0,\n batchCount: 0,\n error: '\u672A\u914D\u7F6E LLM\u3002\u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF OPENAI_API_KEY \u4EE5\u542F\u7528 JSVMP dispatcher \u68C0\u6D4B\u529F\u80FD\u3002'\n };\n }\n \n // Check file exists\n if (!existsSync(filePath)) {\n return {\n success: false,\n filePath,\n totalLines: 0,\n batchCount: 0,\n error: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`\n };\n }\n \n try {\n // Format entire file for analysis\n const formattedCode = await formatEntireFile(filePath, charLimit);\n const totalLines = formattedCode.totalLines;\n \n // Create batches based on token limit\n const batches = createBatches(formattedCode.lines, maxTokensPerBatch);\n const batchCount = batches.length;\n \n // Create LLM client\n const client = createLLMClient(config);\n \n // Process batches with error handling\n const { results, errors } = await processBatchesWithErrorHandling(client, batches);\n \n // If all batches failed, return error\n if (results.length === 0) {\n return {\n success: false,\n filePath,\n totalLines,\n batchCount,\n error: `\u6240\u6709\u6279\u6B21\u5904\u7406\u5931\u8D25: ${errors.join('; ')}`,\n partialErrors: errors\n };\n }\n \n // Merge results from all successful batches\n const mergedResult = mergeDetectionResults(results);\n \n // Format output\n const formattedOutput = formatDetectionResultOutput(mergedResult, filePath, totalLines, batchCount);\n \n return {\n success: true,\n filePath,\n totalLines,\n batchCount,\n result: mergedResult,\n formattedOutput,\n partialErrors: errors.length > 0 ? errors : undefined\n };\n \n } catch (error) {\n return {\n success: false,\n filePath,\n totalLines: 0,\n batchCount: 0,\n error: error instanceof Error ? error.message : String(error)\n };\n }\n}\n", "/**\n * LLM Configuration Module\n * Handles reading and validating LLM configuration from environment variables\n */\n\nimport { generateText } from 'ai';\nimport { createOpenAI } from '@ai-sdk/openai';\nimport { createAnthropic } from '@ai-sdk/anthropic';\nimport { createGoogleGenerativeAI } from '@ai-sdk/google';\nimport type { LanguageModel } from 'ai';\n\n/**\n * Supported LLM providers\n */\nexport type LLMProvider = 'openai' | 'anthropic' | 'google';\n\n/**\n * Provider-specific default configurations\n */\nexport const PROVIDER_DEFAULTS: Record<LLMProvider, { model: string }> = {\n openai: { model: 'gpt-4.1-mini' },\n anthropic: { model: 'claude-haiku-4-5-20241022' },\n google: { model: 'gemini-2.5-flash-lite' },\n};\n\n/**\n * Environment variable names for each provider\n */\nexport const PROVIDER_ENV_KEYS: Record<LLMProvider, { \n apiKey: string; \n model: string; \n baseUrl: string;\n}> = {\n openai: { \n apiKey: 'OPENAI_API_KEY', \n model: 'OPENAI_MODEL', \n baseUrl: 'OPENAI_BASE_URL' \n },\n anthropic: { \n apiKey: 'ANTHROPIC_API_KEY', \n model: 'ANTHROPIC_MODEL',\n baseUrl: 'ANTHROPIC_BASE_URL'\n },\n google: { \n apiKey: 'GOOGLE_API_KEY', \n model: 'GOOGLE_MODEL',\n baseUrl: 'GOOGLE_BASE_URL'\n },\n};\n\n/**\n * Extended LLM configuration with provider information\n */\nexport interface LLMConfig {\n provider: LLMProvider;\n apiKey: string;\n model: string;\n baseUrl?: string; // Custom base URL for all providers\n}\n\n/**\n * Validates provider string against valid values\n * @param value - The provider string to validate\n * @returns The validated LLMProvider or null if invalid\n */\nexport function validateProvider(value: string | undefined): LLMProvider | null {\n if (value === undefined) return null;\n if (value === 'openai' || value === 'anthropic' || value === 'google') {\n return value;\n }\n return null;\n}\n\n/**\n * \u4ECE\u73AF\u5883\u53D8\u91CF\u8BFB\u53D6 LLM \u914D\u7F6E\n * @returns LLMConfig | null (null \u8868\u793A\u672A\u914D\u7F6E)\n */\nexport function getLLMConfig(): LLMConfig | null {\n // 1. Determine provider (default to 'openai')\n const providerEnv = process.env.LLM_PROVIDER?.toLowerCase();\n const provider = validateProvider(providerEnv);\n \n if (provider === null && providerEnv !== undefined) {\n // Invalid provider specified\n console.warn(`Invalid LLM_PROVIDER: ${providerEnv}. Valid values: openai, anthropic, google`);\n return null;\n }\n \n const effectiveProvider = provider ?? 'openai';\n \n // 2. Get provider-specific environment variable names\n const envKeys = PROVIDER_ENV_KEYS[effectiveProvider];\n \n // 3. Read API key (required)\n const apiKey = process.env[envKeys.apiKey];\n if (!apiKey) {\n return null;\n }\n \n // 4. Read model: LLM_MODEL > provider-specific > default\n const model = process.env.LLM_MODEL \n || process.env[envKeys.model] \n || PROVIDER_DEFAULTS[effectiveProvider].model;\n \n // 5. Read base URL: LLM_BASE_URL > provider-specific > undefined\n const baseUrl = process.env.LLM_BASE_URL || process.env[envKeys.baseUrl];\n \n return {\n provider: effectiveProvider,\n apiKey,\n model,\n baseUrl,\n };\n}\n\n/**\n * \u68C0\u67E5 LLM \u662F\u5426\u5DF2\u914D\u7F6E\n */\nexport function isLLMConfigured(): boolean {\n return getLLMConfig() !== null;\n}\n\n/**\n * LLM Client Interface\n */\nexport interface LLMClient {\n /**\n * \u53D1\u9001 JSVMP \u68C0\u6D4B\u8BF7\u6C42\u5230 LLM\n * @param formattedCode \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\n * @returns LLM \u8FD4\u56DE\u7684\u539F\u59CB JSON \u5B57\u7B26\u4E32\n */\n analyzeJSVMP(formattedCode: string): Promise<string>;\n}\n\n/**\n * \u6784\u5EFA JSVMP \u68C0\u6D4B\u7CFB\u7EDF\u63D0\u793A\u8BCD\n */\nfunction buildJSVMPSystemPrompt(): string {\n return `You are a Senior JavaScript Reverse Engineer and De-obfuscation Expert. Your specialty is analyzing **JSVMP (JavaScript Virtual Machine Protection)**.\n\n**Context: What is JSVMP?**\nJSVMP is a protection technique where original JavaScript code is compiled into custom **bytecode** and executed by a custom **interpreter** (virtual machine) written in JavaScript.\n\nKey components of JSVMP code include:\n1. **The Virtual Stack:** A central array used to store operands and results (e.g., \\`stack[pointer++]\\` or \\`v[p--]\\`).\n2. **The Dispatcher:** A control flow structure inside a loop that decides which instruction to execute next based on the current bytecode (opcode).\n * *Common variants:* A massive \\`switch\\` statement, a deeply nested \\`if-else\\` chain (binary search style), or a function array mapping (\\`handlers[opcode]()\\`).\n3. **The Bytecode:** A large string or array of integers representing the program logic.\n\n**Task:**\nAnalyze the provided JavaScript code snippet to identify regions that match JSVMP structural patterns.\n\n**Input Data Format:**\nThe code is provided in a simplified format: \\`LineNo SourceLoc Code\\`.\n* **Example:** \\`10 L234:56 var x = stack[p++];\\`\n* **Instruction:** Focus on the **LineNo** (1st column) and **Code** (3rd column onwards). Ignore the \\`SourceLoc\\` (middle column).\n\n**Detection Rules & Confidence Levels:**\nPlease assign confidence based on the following criteria:\n\n* **Ultra High:**\n * A combination of a **Main Loop** + **Dispatcher** + **Stack Operations** appears in the same block.\n * *Example:* A \\`while(true)\\` loop containing a huge \\`if-else\\` chain where branches perform \\`stack[p++]\\` operations.\n\n* **High:**\n * Distinct **Dispatcher** structures found (e.g., a \\`switch\\` with >20 cases, or an \\`if-else\\` chain nested >10 levels deep checking integer values).\n * Large arrays containing only function definitions (Instruction Handlers).\n\n* **Medium:**\n * Isolated **Stack Operations** (e.g., \\`v2[p2] = v2[p2 - 1]\\`) without visible dispatchers nearby.\n * Suspicious \\`while\\` loops iterating over a string/array.\n\n* **Low:**\n * Generic obfuscation patterns (short variable names, comma operators) that *might* be part of a VM but lack specific structural proof.\n\n**Output Format:**\nReturn **ONLY valid JSON**. No markdown wrapper, no conversational text.\n\n**JSON Schema:**\n{\n \"summary\": \"Brief analysis of the code structure in chinese, shortly\",\n \"regions\": [\n {\n \"start\": <start_line>,\n \"end\": <end_line>,\n \"type\": \"<If-Else Dispatcher | Switch Dispatcher | Instruction Array | Stack Operation>\",\n \"confidence\": \"<ultra_high | high | medium | low>\",\n \"description\": \"<Why you flagged this. Mention specific variables like 'v2', 'p2' or structures. in chinese, shortly>\"\n }\n ]\n}`;\n}\n\n/**\n * Creates a provider-specific model instance using the AI SDK\n * @param config - The LLM configuration\n * @returns A LanguageModel instance for the configured provider\n */\nexport function createProviderModel(config: LLMConfig): LanguageModel {\n switch (config.provider) {\n case 'openai': {\n const openai = createOpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n return openai(config.model);\n }\n case 'anthropic': {\n const anthropic = createAnthropic({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n return anthropic(config.model);\n }\n case 'google': {\n const google = createGoogleGenerativeAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n return google(config.model);\n }\n }\n}\n\n/**\n * \u521B\u5EFA LLM \u5BA2\u6237\u7AEF\u5B9E\u4F8B\n */\nexport function createLLMClient(config: LLMConfig): LLMClient {\n const model = createProviderModel(config);\n \n return {\n async analyzeJSVMP(formattedCode: string): Promise<string> {\n const systemPrompt = buildJSVMPSystemPrompt();\n \n try {\n const result = await generateText({\n model,\n system: systemPrompt,\n prompt: `\u8BF7\u5206\u6790\u4EE5\u4E0B\u4EE3\u7801\uFF0C\u8BC6\u522B JSVMP \u4FDD\u62A4\u7ED3\u6784\uFF1A\\n\\n${formattedCode}`,\n temperature: 0.1,\n });\n \n return result.text;\n } catch (error) {\n const providerName = config.provider.charAt(0).toUpperCase() + config.provider.slice(1);\n if (error instanceof Error) {\n throw new Error(`${providerName} LLM \u8BF7\u6C42\u5931\u8D25: ${error.message}`);\n }\n throw new Error(`${providerName} LLM \u8BF7\u6C42\u5931\u8D25: ${String(error)}`);\n }\n }\n };\n}\n", "/**\n * Tokenizer Module\n * Token counting and batch splitting utilities using tiktoken\n */\n\nimport { encoding_for_model, TiktokenModel } from 'tiktoken';\n\n/**\n * Default model for token counting\n */\nconst DEFAULT_MODEL: TiktokenModel = 'gpt-4o';\n\n/**\n * Calculate token count for text using tiktoken\n * \n * @param text - The text to count tokens for\n * @param model - Optional model name (default: gpt-4o)\n * @returns The number of tokens in the text\n */\nexport function countTokens(text: string, model?: string): number {\n const enc = encoding_for_model((model as TiktokenModel) ?? DEFAULT_MODEL);\n try {\n const tokens = enc.encode(text);\n return tokens.length;\n } finally {\n enc.free();\n }\n}\n\n/**\n * Split lines into batches based on token limit\n * Splits at line boundaries to preserve code structure\n * \n * @param lines - Array of code lines to split\n * @param maxTokens - Maximum tokens per batch\n * @param model - Optional model name (default: gpt-4o)\n * @returns Array of batches, where each batch is an array of lines\n */\nexport function splitByTokenLimit(\n lines: string[],\n maxTokens: number,\n model?: string\n): string[][] {\n if (lines.length === 0) {\n return [];\n }\n\n if (maxTokens <= 0) {\n throw new Error('maxTokens must be a positive number');\n }\n\n const batches: string[][] = [];\n let currentBatch: string[] = [];\n let currentTokenCount = 0;\n\n const enc = encoding_for_model((model as TiktokenModel) ?? DEFAULT_MODEL);\n \n try {\n for (const line of lines) {\n // Calculate tokens for this line (including newline)\n const lineWithNewline = line + '\\n';\n const lineTokens = enc.encode(lineWithNewline).length;\n\n // If a single line exceeds maxTokens, it goes in its own batch\n if (lineTokens > maxTokens) {\n // Flush current batch if not empty\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentTokenCount = 0;\n }\n // Add the oversized line as its own batch\n batches.push([line]);\n continue;\n }\n\n // Check if adding this line would exceed the limit\n if (currentTokenCount + lineTokens > maxTokens && currentBatch.length > 0) {\n // Flush current batch\n batches.push(currentBatch);\n currentBatch = [];\n currentTokenCount = 0;\n }\n\n // Add line to current batch\n currentBatch.push(line);\n currentTokenCount += lineTokens;\n }\n\n // Don't forget the last batch\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n } finally {\n enc.free();\n }\n}\n", "/**\n * Tool aggregation module\n * Collects all tool definitions and exports them as a unified array.\n */\n\nimport { findJsvmpDispatcherTool, FindJsvmpDispatcherInputSchema } from './findJsvmpDispatcherTool.js';\n\n/**\n * Array of all available MCP tool definitions.\n * To add a new tool:\n * 1. Create a new tool module in src/tools/\n * 2. Import it here\n * 3. Add it to this array\n */\nexport const tools = [\n findJsvmpDispatcherTool,\n] as const;\n\n// Re-export ToolDefinition interface and defineTool helper\nexport { ToolDefinition, defineTool } from './ToolDefinition.js';\n\n// Re-export tool and input schema\nexport { findJsvmpDispatcherTool, FindJsvmpDispatcherInputSchema };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { tools } from './tools/index.js';\n\n// Create MCP Server instance\nconst server = new McpServer({\n name: 'ai-tools-mcp',\n version: '1.0.0',\n});\n\n/**\n * Register a tool with the MCP server.\n */\nfunction registerTool(tool: {\n name: string;\n description: string;\n schema: z.ZodRawShape;\n handler: (params: Record<string, unknown>) => Promise<string>;\n}): void {\n const zodSchema = z.object(tool.schema);\n\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: tool.schema,\n },\n async (params, _extra) => {\n try {\n const validatedParams = zodSchema.parse(params);\n const result = await tool.handler(validatedParams as Record<string, unknown>);\n\n return {\n content: [{ type: 'text' as const, text: result }],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n }\n }\n );\n}\n\n// Register all tools\nfor (const tool of tools) {\n registerTool(tool as unknown as {\n name: string;\n description: string;\n schema: z.ZodRawShape;\n handler: (params: Record<string, unknown>) => Promise<string>;\n });\n}\n\n// Main entry point\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error('AI Tools MCP Server running on stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n", "import { z } from 'zod';\nimport { defineTool } from './ToolDefinition.js';\nimport { findJsvmpDispatcher } from '../jsvmpDetector.js';\n\n/**\n * Input schema for find_jsvmp_dispatcher tool\n */\nexport const FindJsvmpDispatcherInputSchema = {\n filePath: z.string().describe('Path to the JavaScript file to analyze'),\n charLimit: z.number().int().positive().optional().describe('Character limit for string truncation (default: 300)'),\n maxTokensPerBatch: z.number().int().positive().optional().describe('Maximum tokens per batch for LLM analysis (default: 150000)'),\n};\n\n/**\n * MCP Tool: find_jsvmp_dispatcher\n * \n * Uses LLM to detect JSVMP (JavaScript Virtual Machine Protection) patterns in code.\n * \n * JSVMP is a code protection technique that converts JavaScript to bytecode\n * executed by a virtual machine. This tool identifies:\n * - Multiple independent JSVMP instances\n * - If-Else Dispatchers\n * - Switch Dispatchers \n * - Instruction Arrays\n * - VM Components (IP, SP, Stack, Bytecode Array)\n * - Debugging Entry Points\n * \n * Requires OPENAI_API_KEY environment variable to be set.\n */\nexport const findJsvmpDispatcherTool = defineTool({\n name: 'find_jsvmp_dispatcher',\n description: `Detect JSVMP (JavaScript Virtual Machine Protection) patterns in code using LLM analysis.\n\nJSVMP is a code protection technique that converts JavaScript to bytecode executed by a virtual machine. A single file may contain multiple independent JSVMP instances.\n\nThis tool identifies for each JSVMP instance:\n- Region location and dispatcher type (If-Else Dispatcher, Switch Dispatcher, Instruction Array)\n- VM Components: Instruction Pointer (IP), Stack Pointer (SP), Virtual Stack, Bytecode Array\n- Debugging Entry Point: The optimal line number to set breakpoints\n\nDetection confidence levels: ultra_high, high, medium, low\n\nAutomatically splits large files into batches based on token limits and merges results.\n\nRequires OPENAI_API_KEY environment variable. Optional: OPENAI_BASE_URL, OPENAI_MODEL.`,\n schema: FindJsvmpDispatcherInputSchema,\n handler: async (params): Promise<string> => {\n const { filePath, charLimit, maxTokensPerBatch } = params;\n\n const result = await findJsvmpDispatcher(filePath, {\n charLimit: charLimit ?? 300,\n maxTokensPerBatch: maxTokensPerBatch ?? 150000,\n });\n\n if (!result.success) {\n throw new Error(result.error ?? 'Detection failed');\n }\n\n return result.formattedOutput ?? 'No output generated';\n },\n});\n", "import { z } from 'zod';\n\n/**\n * Tool definition interface for MCP tools.\n * Each tool has a name, description, schema (Zod raw shape), and async handler.\n */\nexport interface ToolDefinition<TSchema extends z.ZodRawShape = z.ZodRawShape> {\n /** Unique tool name (e.g., 'find_jsvmp_dispatcher') */\n name: string;\n /** Human-readable description of what the tool does */\n description: string;\n /** Zod schema object defining input parameters */\n schema: TSchema;\n /** Async handler function that processes the tool request */\n handler: (params: z.infer<z.ZodObject<TSchema>>) => Promise<string>;\n}\n\n/**\n * Helper function to create a type-safe tool definition.\n * Validates the tool definition structure at compile time.\n * \n * @param definition - The tool definition object\n * @returns The same definition with proper typing\n */\nexport function defineTool<TSchema extends z.ZodRawShape>(\n definition: ToolDefinition<TSchema>\n): ToolDefinition<TSchema> {\n return definition;\n}\n", "/**\n * JSVMP Detector Module\n * AI-powered detection of JSVMP (JavaScript Virtual Machine Protection) patterns\n */\n\nimport { SourceMapConsumer } from 'source-map-js';\nimport { ensureBeautified, truncateCodeHighPerf } from '@reverse-craft/smart-fs';\nimport { existsSync } from 'fs';\nimport { getLLMConfig, createLLMClient, LLMClient } from './llmConfig.js';\nimport { countTokens, splitByTokenLimit } from './tokenizer.js';\n\n/**\n * Formatted code result interface\n */\nexport interface FormattedCode {\n content: string; // \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u5B57\u7B26\u4E32\n totalLines: number; // \u603B\u884C\u6570\n startLine: number; // \u5B9E\u9645\u8D77\u59CB\u884C\n endLine: number; // \u5B9E\u9645\u7ED3\u675F\u884C\n}\n\n/**\n * Detection type for JSVMP patterns\n */\nexport type DetectionType = \n | \"If-Else Dispatcher\" \n | \"Switch Dispatcher\" \n | \"Instruction Array\";\n\n/**\n * Confidence level for detection results\n */\nexport type ConfidenceLevel = \"ultra_high\" | \"high\" | \"medium\" | \"low\";\n\n/**\n * VM Component variable identification\n */\nexport interface VMComponentVariable {\n variable_name: string | null;\n confidence: ConfidenceLevel;\n reasoning: string;\n}\n\n/**\n * VM Components for a JSVMP instance\n */\nexport interface VMComponents {\n instruction_pointer: VMComponentVariable;\n stack_pointer: VMComponentVariable;\n virtual_stack: VMComponentVariable;\n bytecode_array: VMComponentVariable;\n}\n\n/**\n * Debugging entry point information\n */\nexport interface DebuggingEntryPoint {\n line_number: number;\n description: string;\n}\n\n/**\n * A detected region in the code (enhanced with VM components)\n */\nexport interface DetectionRegion {\n start: number; // \u8D77\u59CB\u884C\u53F7 (start_line)\n end: number; // \u7ED3\u675F\u884C\u53F7 (end_line)\n type: DetectionType; // \u68C0\u6D4B\u7C7B\u578B\n confidence: ConfidenceLevel; // \u7F6E\u4FE1\u5EA6\n description: string; // \u63CF\u8FF0\uFF08\u4E2D\u6587\uFF09\n vm_components?: VMComponents; // VM \u7EC4\u4EF6\u53D8\u91CF\u8BC6\u522B\n debugging_entry_point?: DebuggingEntryPoint; // \u8C03\u8BD5\u5165\u53E3\u70B9\n}\n\n/**\n * Summary information for detection result\n */\nexport interface DetectionSummary {\n overall_description: string; // \u603B\u4F53\u63CF\u8FF0\n debugging_recommendation: string; // \u8C03\u8BD5\u5EFA\u8BAE\n}\n\n/**\n * Complete detection result from LLM analysis (enhanced)\n */\nexport interface DetectionResult {\n summary: string | DetectionSummary; // \u5206\u6790\u6458\u8981\uFF08\u652F\u6301\u65B0\u65E7\u683C\u5F0F\uFF09\n regions: DetectionRegion[];\n}\n\n/**\n * Options for JSVMP detection\n */\nexport interface JsvmpDetectionOptions {\n charLimit?: number; // Default: 300\n maxTokensPerBatch?: number; // Default: 8000\n}\n\n/**\n * Result from findJsvmpDispatcher function\n */\nexport interface JsvmpDetectionResult {\n success: boolean;\n filePath: string;\n totalLines: number;\n batchCount: number;\n result?: DetectionResult;\n formattedOutput?: string;\n error?: string;\n partialErrors?: string[]; // Errors from failed batches\n}\n\n/**\n * Batch information for processing\n */\nexport interface BatchInfo {\n startLine: number; // \u6279\u6B21\u8D77\u59CB\u884C\u53F7 (1-based)\n endLine: number; // \u6279\u6B21\u7ED3\u675F\u884C\u53F7 (1-based)\n content: string; // \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u5185\u5BB9\n tokenCount: number; // \u8BE5\u6279\u6B21\u7684 token \u6570\u91CF\n}\n\n/**\n * Result from formatEntireFile function\n */\nexport interface FormattedFileResult {\n lines: string[]; // \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u884C\u6570\u7EC4\n totalLines: number; // \u603B\u884C\u6570\n}\n\n/**\n * Format source position as \"L{line}:{column}\" or empty placeholder\n */\nfunction formatSourcePosition(line: number | null, column: number | null): string {\n if (line !== null && column !== null) {\n return `L${line}:${column}`;\n }\n return '';\n}\n\n/**\n * Format a single code line with line number, source coordinates, and content\n * Format: \"LineNo SourceLoc Code\"\n */\nfunction formatCodeLine(lineNumber: number, sourcePos: string, code: string): string {\n const lineNumStr = String(lineNumber).padStart(5, ' ');\n const srcPosPadded = sourcePos ? sourcePos.padEnd(10, ' ') : ' ';\n return `${lineNumStr} ${srcPosPadded} ${code}`;\n}\n\n/**\n * \u683C\u5F0F\u5316\u4EE3\u7801\u4E3A LLM \u5206\u6790\u683C\u5F0F\n * \u683C\u5F0F: \"LineNo SourceLoc Code\"\n * \n * \u5904\u7406\u6D41\u7A0B\uFF1A\n * 1. \u8C03\u7528 ensureBeautified \u7F8E\u5316\u4EE3\u7801\n * 2. \u8C03\u7528 truncateCodeHighPerf \u622A\u65AD\u957F\u5B57\u7B26\u4E32\n * 3. \u4F7F\u7528 SourceMapConsumer \u83B7\u53D6\u539F\u59CB\u5750\u6807\n * 4. \u683C\u5F0F\u5316\u4E3A \"LineNo SourceLoc Code\" \u683C\u5F0F\n * \n * @param filePath - Path to the JavaScript file\n * @param startLine - Start line number (1-based)\n * @param endLine - End line number (1-based)\n * @param charLimit - Character limit for string truncation (default 300)\n * @returns FormattedCode object with formatted content and metadata\n */\nexport async function formatCodeForAnalysis(\n filePath: string,\n startLine: number,\n endLine: number,\n charLimit: number = 300\n): Promise<FormattedCode> {\n // Step 1: Beautify the file and get source map\n const beautifyResult = await ensureBeautified(filePath);\n const { code, rawMap } = beautifyResult;\n\n // Step 2: Truncate long strings\n const truncatedCode = truncateCodeHighPerf(code, charLimit);\n\n // Split into lines\n const lines = truncatedCode.split('\\n');\n const totalLines = lines.length;\n\n // Step 3: Adjust line range boundaries\n const effectiveStartLine = Math.max(1, Math.min(totalLines, startLine));\n const effectiveEndLine = Math.max(effectiveStartLine, Math.min(totalLines, endLine));\n\n // Step 4: Format each line with \"LineNo SourceLoc Code\" format\n const formattedLines: string[] = [];\n\n // Create source map consumer if available\n let consumer: SourceMapConsumer | null = null;\n if (rawMap && rawMap.sources && rawMap.names && rawMap.mappings) {\n consumer = new SourceMapConsumer({\n version: String(rawMap.version),\n sources: rawMap.sources,\n names: rawMap.names,\n mappings: rawMap.mappings,\n file: rawMap.file,\n sourceRoot: rawMap.sourceRoot,\n });\n }\n\n for (let lineNum = effectiveStartLine; lineNum <= effectiveEndLine; lineNum++) {\n const lineIndex = lineNum - 1;\n const lineContent = lines[lineIndex] ?? '';\n\n // Get original position from source map if available\n let sourcePos = '';\n if (consumer) {\n const originalPos = consumer.originalPositionFor({\n line: lineNum,\n column: 0,\n });\n sourcePos = formatSourcePosition(originalPos.line, originalPos.column);\n }\n \n formattedLines.push(formatCodeLine(lineNum, sourcePos, lineContent));\n }\n\n return {\n content: formattedLines.join('\\n'),\n totalLines,\n startLine: effectiveStartLine,\n endLine: effectiveEndLine,\n };\n}\n\n/**\n * \u683C\u5F0F\u5316\u6574\u4E2A\u6587\u4EF6\u4E3A LLM \u5206\u6790\u683C\u5F0F\n * \u683C\u5F0F: \"LineNo SourceLoc Code\"\n * \n * \u5904\u7406\u6D41\u7A0B\uFF1A\n * 1. \u8C03\u7528 ensureBeautified \u7F8E\u5316\u4EE3\u7801\n * 2. \u8C03\u7528 truncateCodeHighPerf \u622A\u65AD\u957F\u5B57\u7B26\u4E32\n * 3. \u4F7F\u7528 SourceMapConsumer \u83B7\u53D6\u539F\u59CB\u5750\u6807\n * 4. \u8FD4\u56DE\u683C\u5F0F\u5316\u540E\u7684\u884C\u6570\u7EC4\uFF08\u4FDD\u7559\u539F\u59CB\u884C\u53F7\uFF09\n * \n * @param filePath - Path to the JavaScript file\n * @param charLimit - Character limit for string truncation (default 300)\n * @returns FormattedFileResult with formatted lines array and metadata\n */\nexport async function formatEntireFile(\n filePath: string,\n charLimit: number = 300\n): Promise<FormattedFileResult> {\n // Step 1: Beautify the file and get source map\n const beautifyResult = await ensureBeautified(filePath);\n const { code, rawMap } = beautifyResult;\n\n // Step 2: Truncate long strings\n const truncatedCode = truncateCodeHighPerf(code, charLimit);\n\n // Split into lines\n const codeLines = truncatedCode.split('\\n');\n const totalLines = codeLines.length;\n\n // Step 3: Format each line with \"LineNo SourceLoc Code\" format\n const formattedLines: string[] = [];\n\n // Create source map consumer if available\n let consumer: SourceMapConsumer | null = null;\n if (rawMap && rawMap.sources && rawMap.names && rawMap.mappings) {\n consumer = new SourceMapConsumer({\n version: String(rawMap.version),\n sources: rawMap.sources,\n names: rawMap.names,\n mappings: rawMap.mappings,\n file: rawMap.file,\n sourceRoot: rawMap.sourceRoot,\n });\n }\n\n for (let lineNum = 1; lineNum <= totalLines; lineNum++) {\n const lineIndex = lineNum - 1;\n const lineContent = codeLines[lineIndex] ?? '';\n\n // Get original position from source map if available\n let sourcePos = '';\n if (consumer) {\n const originalPos = consumer.originalPositionFor({\n line: lineNum,\n column: 0,\n });\n sourcePos = formatSourcePosition(originalPos.line, originalPos.column);\n }\n \n formattedLines.push(formatCodeLine(lineNum, sourcePos, lineContent));\n }\n\n return {\n lines: formattedLines,\n totalLines,\n };\n}\n\n/**\n * Extract line number from a formatted code line\n * Format: \"LineNo SourceLoc Code\"\n * \n * @param formattedLine - A formatted code line\n * @returns The line number (1-based)\n */\nfunction extractLineNumber(formattedLine: string): number {\n const lineNumStr = formattedLine.substring(0, 5).trim();\n return parseInt(lineNumStr, 10);\n}\n\n/**\n * \u521B\u5EFA\u6279\u6B21\u7528\u4E8E\u5206\u6279\u5904\u7406\n * \u4F7F\u7528 tokenizer \u5206\u5272\u4EE3\u7801\uFF0C\u8BB0\u5F55\u6BCF\u4E2A\u6279\u6B21\u7684 startLine/endLine\n * \n * @param formattedLines - \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\u884C\u6570\u7EC4\n * @param maxTokensPerBatch - \u6BCF\u6279\u6B21\u6700\u5927 token \u6570\u91CF\n * @returns BatchInfo \u6570\u7EC4\n */\nexport function createBatches(\n formattedLines: string[],\n maxTokensPerBatch: number\n): BatchInfo[] {\n if (formattedLines.length === 0) {\n return [];\n }\n\n // Split lines into batches based on token limit\n const lineBatches = splitByTokenLimit(formattedLines, maxTokensPerBatch);\n \n const batches: BatchInfo[] = [];\n \n for (const batchLines of lineBatches) {\n if (batchLines.length === 0) continue;\n \n // Extract start and end line numbers from formatted lines\n const startLine = extractLineNumber(batchLines[0]);\n const endLine = extractLineNumber(batchLines[batchLines.length - 1]);\n \n // Join lines to create batch content\n const content = batchLines.join('\\n');\n \n // Calculate token count for this batch\n const tokenCount = countTokens(content);\n \n batches.push({\n startLine,\n endLine,\n content,\n tokenCount,\n });\n }\n \n return batches;\n}\n\n/**\n * Valid detection types for validation\n */\nconst VALID_DETECTION_TYPES: DetectionType[] = [\n \"If-Else Dispatcher\",\n \"Switch Dispatcher\",\n \"Instruction Array\"\n];\n\n/**\n * Valid confidence levels for validation\n */\nconst VALID_CONFIDENCE_LEVELS: ConfidenceLevel[] = [\n \"ultra_high\",\n \"high\",\n \"medium\",\n \"low\"\n];\n\n/**\n * Check if a value is a valid DetectionType\n */\nfunction isValidDetectionType(value: unknown): value is DetectionType {\n return VALID_DETECTION_TYPES.includes(value as DetectionType);\n}\n\n/**\n * Check if a value is a valid ConfidenceLevel\n */\nfunction isValidConfidenceLevel(value: unknown): value is ConfidenceLevel {\n return VALID_CONFIDENCE_LEVELS.includes(value as ConfidenceLevel);\n}\n\n/**\n * Parse VM component variable from LLM response\n */\nfunction parseVMComponentVariable(obj: Record<string, unknown>, fieldName: string): VMComponentVariable | null {\n const component = obj[fieldName] as Record<string, unknown> | undefined;\n if (!component || typeof component !== 'object') {\n return null;\n }\n \n const variableName = component.variable_name;\n const confidence = component.confidence;\n const reasoning = component.reasoning;\n \n if (typeof confidence !== 'string' || !isValidConfidenceLevel(confidence)) {\n return null;\n }\n \n return {\n variable_name: typeof variableName === 'string' ? variableName : null,\n confidence,\n reasoning: typeof reasoning === 'string' ? reasoning : '',\n };\n}\n\n/**\n * Parse VM components from LLM response\n */\nfunction parseVMComponents(obj: Record<string, unknown>): VMComponents | undefined {\n const vmComponents = obj.vm_components as Record<string, unknown> | undefined;\n if (!vmComponents || typeof vmComponents !== 'object') {\n return undefined;\n }\n \n const ip = parseVMComponentVariable(vmComponents, 'instruction_pointer');\n const sp = parseVMComponentVariable(vmComponents, 'stack_pointer');\n const stack = parseVMComponentVariable(vmComponents, 'virtual_stack');\n const bytecode = parseVMComponentVariable(vmComponents, 'bytecode_array');\n \n // Only return if at least one component is identified\n if (!ip && !sp && !stack && !bytecode) {\n return undefined;\n }\n \n return {\n instruction_pointer: ip ?? { variable_name: null, confidence: 'low', reasoning: '' },\n stack_pointer: sp ?? { variable_name: null, confidence: 'low', reasoning: '' },\n virtual_stack: stack ?? { variable_name: null, confidence: 'low', reasoning: '' },\n bytecode_array: bytecode ?? { variable_name: null, confidence: 'low', reasoning: '' },\n };\n}\n\n/**\n * Parse debugging entry point from LLM response\n */\nfunction parseDebuggingEntryPoint(obj: Record<string, unknown>): DebuggingEntryPoint | undefined {\n const entryPoint = obj.debugging_entry_point as Record<string, unknown> | undefined;\n if (!entryPoint || typeof entryPoint !== 'object') {\n return undefined;\n }\n \n const lineNumber = entryPoint.line_number;\n const description = entryPoint.description;\n \n if (typeof lineNumber !== 'number') {\n return undefined;\n }\n \n return {\n line_number: lineNumber,\n description: typeof description === 'string' ? description : '',\n };\n}\n\n/**\n * Parse and validate LLM detection result from JSON string\n * \n * Validates:\n * - JSON is parseable\n * - Required fields exist: summary, regions\n * - Each region has required fields: start/start_line, end/end_line, type, confidence, description\n * - Enum values are valid\n * - Supports both old and new JSON formats\n * \n * @param jsonString - JSON string from LLM response\n * @returns Parsed and validated DetectionResult\n * @throws Error if JSON is invalid or structure doesn't match expected format\n */\nexport function parseDetectionResult(jsonString: string): DetectionResult {\n // Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonString);\n } catch (error) {\n throw new Error(`\u65E0\u6CD5\u89E3\u6790 LLM \u54CD\u5E94: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Validate required top-level fields\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u671F\u671B\u5BF9\u8C61\u7C7B\u578B');\n }\n\n const obj = parsed as Record<string, unknown>;\n\n // Parse summary (support both old string format and new object format)\n let summary: string | DetectionSummary;\n if (typeof obj.summary === 'string') {\n summary = obj.summary;\n } else if (typeof obj.summary === 'object' && obj.summary !== null) {\n const summaryObj = obj.summary as Record<string, unknown>;\n if (typeof summaryObj.overall_description !== 'string' || typeof summaryObj.debugging_recommendation !== 'string') {\n throw new Error('LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Csummary \u5BF9\u8C61\u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5');\n }\n summary = {\n overall_description: summaryObj.overall_description,\n debugging_recommendation: summaryObj.debugging_recommendation,\n };\n } else {\n throw new Error('LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: summary');\n }\n\n if (!Array.isArray(obj.regions)) {\n throw new Error('LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: regions');\n }\n\n // Validate each region\n const validatedRegions: DetectionRegion[] = [];\n\n for (let i = 0; i < obj.regions.length; i++) {\n const region = obj.regions[i] as Record<string, unknown>;\n\n // Check region is an object\n if (typeof region !== 'object' || region === null) {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u4E0D\u662F\u5BF9\u8C61`);\n }\n\n // Support both old (start/end) and new (start_line/end_line) field names\n const startLine = region.start_line ?? region.start;\n const endLine = region.end_line ?? region.end;\n\n // Validate required fields exist and have correct types\n if (typeof startLine !== 'number') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: start_line \u6216 start`);\n }\n\n if (typeof endLine !== 'number') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: end_line \u6216 end`);\n }\n\n if (typeof region.type !== 'string') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: type`);\n }\n\n if (typeof region.confidence !== 'string') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: confidence`);\n }\n\n if (typeof region.description !== 'string') {\n throw new Error(`LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}] \u7F3A\u5C11\u5FC5\u9700\u5B57\u6BB5: description`);\n }\n\n // Validate enum values\n if (!isValidDetectionType(region.type)) {\n throw new Error(\n `LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}].type \u503C\u65E0\u6548: \"${region.type}\". ` +\n `\u6709\u6548\u503C: ${VALID_DETECTION_TYPES.join(', ')}`\n );\n }\n\n if (!isValidConfidenceLevel(region.confidence)) {\n throw new Error(\n `LLM \u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0Cregions[${i}].confidence \u503C\u65E0\u6548: \"${region.confidence}\". ` +\n `\u6709\u6548\u503C: ${VALID_CONFIDENCE_LEVELS.join(', ')}`\n );\n }\n\n // Parse optional VM components and debugging entry point\n const vmComponents = parseVMComponents(region);\n const debuggingEntryPoint = parseDebuggingEntryPoint(region);\n\n validatedRegions.push({\n start: startLine,\n end: endLine,\n type: region.type,\n confidence: region.confidence,\n description: region.description,\n ...(vmComponents && { vm_components: vmComponents }),\n ...(debuggingEntryPoint && { debugging_entry_point: debuggingEntryPoint }),\n });\n }\n\n return {\n summary,\n regions: validatedRegions,\n };\n}\n\n/**\n * Format detection result for display (enhanced with VM components)\n */\nfunction formatDetectionResultOutput(\n result: DetectionResult,\n filePath: string,\n totalLines: number,\n batchCount: number\n): string {\n const lines: string[] = [];\n \n lines.push('=== JSVMP Dispatcher Detection Result ===');\n lines.push(`File: ${filePath} (${totalLines} lines, ${batchCount} batch${batchCount > 1 ? 'es' : ''})`);\n lines.push('');\n \n // Format summary (support both old string format and new object format)\n if (typeof result.summary === 'string') {\n lines.push(`Summary: ${result.summary}`);\n } else {\n lines.push(`Summary: ${result.summary.overall_description}`);\n lines.push(`Recommendation: ${result.summary.debugging_recommendation}`);\n }\n lines.push('');\n \n if (result.regions.length > 0) {\n lines.push(`Detected Regions (${result.regions.length} JSVMP instance${result.regions.length > 1 ? 's' : ''}):`);\n lines.push('');\n \n for (let i = 0; i < result.regions.length; i++) {\n const region = result.regions[i];\n lines.push(`--- Instance ${i + 1} ---`);\n lines.push(`[${region.confidence}] Lines ${region.start}-${region.end}: ${region.type}`);\n lines.push(` ${region.description}`);\n \n // Format VM components if available\n if (region.vm_components) {\n lines.push(' VM Components:');\n const { instruction_pointer, stack_pointer, virtual_stack, bytecode_array } = region.vm_components;\n \n if (instruction_pointer.variable_name) {\n lines.push(` - Instruction Pointer: ${instruction_pointer.variable_name} [${instruction_pointer.confidence}]`);\n lines.push(` ${instruction_pointer.reasoning}`);\n }\n if (stack_pointer.variable_name) {\n lines.push(` - Stack Pointer: ${stack_pointer.variable_name} [${stack_pointer.confidence}]`);\n lines.push(` ${stack_pointer.reasoning}`);\n }\n if (virtual_stack.variable_name) {\n lines.push(` - Virtual Stack: ${virtual_stack.variable_name} [${virtual_stack.confidence}]`);\n lines.push(` ${virtual_stack.reasoning}`);\n }\n if (bytecode_array.variable_name) {\n lines.push(` - Bytecode Array: ${bytecode_array.variable_name} [${bytecode_array.confidence}]`);\n lines.push(` ${bytecode_array.reasoning}`);\n }\n }\n \n // Format debugging entry point if available\n if (region.debugging_entry_point) {\n lines.push(` Debugging Entry Point: Line ${region.debugging_entry_point.line_number}`);\n lines.push(` ${region.debugging_entry_point.description}`);\n }\n \n lines.push('');\n }\n } else {\n lines.push('No JSVMP dispatcher patterns detected.');\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Merge detection results from multiple batches\n * - Combines all regions from all batches\n * - Combines summaries from all batches\n * - Sorts regions by start line\n * - Deduplicates overlapping regions (keeps higher confidence)\n * \n * @param results - Array of DetectionResult from each batch\n * @returns Merged DetectionResult\n */\nexport function mergeDetectionResults(results: DetectionResult[]): DetectionResult {\n if (results.length === 0) {\n return { summary: '', regions: [] };\n }\n \n if (results.length === 1) {\n // Still need to sort and deduplicate regions for single result\n const sortedRegions = [...results[0].regions].sort((a, b) => a.start - b.start);\n return { summary: results[0].summary, regions: sortedRegions };\n }\n \n // Combine summaries (handle both string and object formats)\n const summaryParts: string[] = [];\n for (let i = 0; i < results.length; i++) {\n const summary = results[i].summary;\n if (typeof summary === 'string') {\n summaryParts.push(`[Batch ${i + 1}] ${summary}`);\n } else {\n summaryParts.push(`[Batch ${i + 1}] ${summary.overall_description}`);\n }\n }\n \n // For merged results, create a combined summary object\n const lastSummary = results[results.length - 1].summary;\n const combinedSummary: DetectionSummary = {\n overall_description: summaryParts.join('\\n'),\n debugging_recommendation: typeof lastSummary === 'string' \n ? '\u8BF7\u53C2\u8003\u5404\u6279\u6B21\u7684\u5206\u6790\u7ED3\u679C\u8FDB\u884C\u8C03\u8BD5\u3002'\n : lastSummary.debugging_recommendation,\n };\n \n // Collect all regions\n const allRegions: DetectionRegion[] = [];\n for (const result of results) {\n allRegions.push(...result.regions);\n }\n \n // Sort by start line\n allRegions.sort((a, b) => a.start - b.start);\n \n // Deduplicate overlapping regions (keep higher confidence)\n const confidenceOrder: Record<ConfidenceLevel, number> = {\n 'ultra_high': 4,\n 'high': 3,\n 'medium': 2,\n 'low': 1,\n };\n \n const deduplicatedRegions: DetectionRegion[] = [];\n for (const region of allRegions) {\n // Check if this region overlaps with any existing region\n let overlappingIndex = -1;\n for (let i = 0; i < deduplicatedRegions.length; i++) {\n const existing = deduplicatedRegions[i];\n // Check for overlap: regions overlap if one starts before the other ends\n if (region.start <= existing.end && region.end >= existing.start) {\n overlappingIndex = i;\n break;\n }\n }\n \n if (overlappingIndex === -1) {\n // No overlap, add the region\n deduplicatedRegions.push(region);\n } else {\n // Overlap found, keep the one with higher confidence\n const existing = deduplicatedRegions[overlappingIndex];\n if (confidenceOrder[region.confidence] > confidenceOrder[existing.confidence]) {\n deduplicatedRegions[overlappingIndex] = region;\n }\n // If equal confidence, keep the first one (existing)\n }\n }\n \n return {\n summary: combinedSummary,\n regions: deduplicatedRegions,\n };\n}\n\n/**\n * Process a single batch through LLM\n * \n * @param client - LLM client\n * @param batch - Batch information\n * @returns DetectionResult from LLM analysis\n */\nasync function processBatch(\n client: LLMClient,\n batch: BatchInfo\n): Promise<DetectionResult> {\n const llmResponse = await client.analyzeJSVMP(batch.content);\n return parseDetectionResult(llmResponse);\n}\n\n/**\n * Process batches with error handling\n * - Continues processing if some batches fail\n * - Collects partial results and error information\n * \n * @param client - LLM client\n * @param batches - Array of BatchInfo\n * @returns Object with successful results and error messages\n */\nexport async function processBatchesWithErrorHandling(\n client: LLMClient,\n batches: BatchInfo[]\n): Promise<{ results: DetectionResult[]; errors: string[] }> {\n const results: DetectionResult[] = [];\n const errors: string[] = [];\n \n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i];\n try {\n const result = await processBatch(client, batch);\n results.push(result);\n } catch (error) {\n const errorMsg = `Batch ${i + 1} (lines ${batch.startLine}-${batch.endLine}) failed: ${\n error instanceof Error ? error.message : String(error)\n }`;\n errors.push(errorMsg);\n }\n }\n \n return { results, errors };\n}\n\n/**\n * Find JSVMP dispatcher patterns in JavaScript code using LLM analysis\n * \n * @param filePath - Path to the JavaScript file to analyze\n * @param options - Optional configuration\n * @returns JsvmpDetectionResult with detection results or error\n */\nexport async function findJsvmpDispatcher(\n filePath: string,\n options?: JsvmpDetectionOptions\n): Promise<JsvmpDetectionResult> {\n const charLimit = options?.charLimit ?? 300;\n const maxTokensPerBatch = options?.maxTokensPerBatch ?? 8000;\n \n // Check LLM configuration\n const config = getLLMConfig();\n if (!config) {\n return {\n success: false,\n filePath,\n totalLines: 0,\n batchCount: 0,\n error: '\u672A\u914D\u7F6E LLM\u3002\u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF OPENAI_API_KEY \u4EE5\u542F\u7528 JSVMP dispatcher \u68C0\u6D4B\u529F\u80FD\u3002'\n };\n }\n \n // Check file exists\n if (!existsSync(filePath)) {\n return {\n success: false,\n filePath,\n totalLines: 0,\n batchCount: 0,\n error: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`\n };\n }\n \n try {\n // Format entire file for analysis\n const formattedCode = await formatEntireFile(filePath, charLimit);\n const totalLines = formattedCode.totalLines;\n \n // Create batches based on token limit\n const batches = createBatches(formattedCode.lines, maxTokensPerBatch);\n const batchCount = batches.length;\n \n // Create LLM client\n const client = createLLMClient(config);\n \n // Process batches with error handling\n const { results, errors } = await processBatchesWithErrorHandling(client, batches);\n \n // If all batches failed, return error\n if (results.length === 0) {\n return {\n success: false,\n filePath,\n totalLines,\n batchCount,\n error: `\u6240\u6709\u6279\u6B21\u5904\u7406\u5931\u8D25: ${errors.join('; ')}`,\n partialErrors: errors\n };\n }\n \n // Merge results from all successful batches\n const mergedResult = mergeDetectionResults(results);\n \n // Format output\n const formattedOutput = formatDetectionResultOutput(mergedResult, filePath, totalLines, batchCount);\n \n return {\n success: true,\n filePath,\n totalLines,\n batchCount,\n result: mergedResult,\n formattedOutput,\n partialErrors: errors.length > 0 ? errors : undefined\n };\n \n } catch (error) {\n return {\n success: false,\n filePath,\n totalLines: 0,\n batchCount: 0,\n error: error instanceof Error ? error.message : String(error)\n };\n }\n}\n", "/**\n * LLM Configuration Module\n * Handles reading and validating LLM configuration from environment variables\n */\n\nimport { generateText } from 'ai';\nimport { createOpenAI } from '@ai-sdk/openai';\nimport { createAnthropic } from '@ai-sdk/anthropic';\nimport { createGoogleGenerativeAI } from '@ai-sdk/google';\nimport type { LanguageModel } from 'ai';\n\n/**\n * Supported LLM providers\n */\nexport type LLMProvider = 'openai' | 'anthropic' | 'google';\n\n/**\n * Provider-specific default configurations\n */\nexport const PROVIDER_DEFAULTS: Record<LLMProvider, { model: string }> = {\n openai: { model: 'gpt-4.1-mini' },\n anthropic: { model: 'claude-haiku-4-5-20241022' },\n google: { model: 'gemini-2.5-flash-lite' },\n};\n\n/**\n * Environment variable names for each provider\n */\nexport const PROVIDER_ENV_KEYS: Record<LLMProvider, { \n apiKey: string; \n model: string; \n baseUrl: string;\n}> = {\n openai: { \n apiKey: 'OPENAI_API_KEY', \n model: 'OPENAI_MODEL', \n baseUrl: 'OPENAI_BASE_URL' \n },\n anthropic: { \n apiKey: 'ANTHROPIC_API_KEY', \n model: 'ANTHROPIC_MODEL',\n baseUrl: 'ANTHROPIC_BASE_URL'\n },\n google: { \n apiKey: 'GOOGLE_API_KEY', \n model: 'GOOGLE_MODEL',\n baseUrl: 'GOOGLE_BASE_URL'\n },\n};\n\n/**\n * Extended LLM configuration with provider information\n */\nexport interface LLMConfig {\n provider: LLMProvider;\n apiKey: string;\n model: string;\n baseUrl?: string; // Custom base URL for all providers\n}\n\n/**\n * Validates provider string against valid values\n * @param value - The provider string to validate\n * @returns The validated LLMProvider or null if invalid\n */\nexport function validateProvider(value: string | undefined): LLMProvider | null {\n if (value === undefined) return null;\n if (value === 'openai' || value === 'anthropic' || value === 'google') {\n return value;\n }\n return null;\n}\n\n/**\n * \u4ECE\u73AF\u5883\u53D8\u91CF\u8BFB\u53D6 LLM \u914D\u7F6E\n * @returns LLMConfig | null (null \u8868\u793A\u672A\u914D\u7F6E)\n */\nexport function getLLMConfig(): LLMConfig | null {\n // 1. Determine provider (default to 'openai')\n const providerEnv = process.env.LLM_PROVIDER?.toLowerCase();\n const provider = validateProvider(providerEnv);\n \n if (provider === null && providerEnv !== undefined) {\n // Invalid provider specified\n console.warn(`Invalid LLM_PROVIDER: ${providerEnv}. Valid values: openai, anthropic, google`);\n return null;\n }\n \n const effectiveProvider = provider ?? 'openai';\n \n // 2. Get provider-specific environment variable names\n const envKeys = PROVIDER_ENV_KEYS[effectiveProvider];\n \n // 3. Read API key (required)\n const apiKey = process.env[envKeys.apiKey];\n if (!apiKey) {\n return null;\n }\n \n // 4. Read model: LLM_MODEL > provider-specific > default\n const model = process.env.LLM_MODEL \n || process.env[envKeys.model] \n || PROVIDER_DEFAULTS[effectiveProvider].model;\n \n // 5. Read base URL: LLM_BASE_URL > provider-specific > undefined\n const baseUrl = process.env.LLM_BASE_URL || process.env[envKeys.baseUrl];\n \n return {\n provider: effectiveProvider,\n apiKey,\n model,\n baseUrl,\n };\n}\n\n/**\n * \u68C0\u67E5 LLM \u662F\u5426\u5DF2\u914D\u7F6E\n */\nexport function isLLMConfigured(): boolean {\n return getLLMConfig() !== null;\n}\n\n/**\n * LLM Client Interface\n */\nexport interface LLMClient {\n /**\n * \u53D1\u9001 JSVMP \u68C0\u6D4B\u8BF7\u6C42\u5230 LLM\n * @param formattedCode \u683C\u5F0F\u5316\u540E\u7684\u4EE3\u7801\n * @returns LLM \u8FD4\u56DE\u7684\u539F\u59CB JSON \u5B57\u7B26\u4E32\n */\n analyzeJSVMP(formattedCode: string): Promise<string>;\n}\n\n/**\n * \u6784\u5EFA JSVMP \u68C0\u6D4B\u7CFB\u7EDF\u63D0\u793A\u8BCD\n * \n * \u589E\u5F3A\u7248\u63D0\u793A\u8BCD\uFF0C\u652F\u6301\uFF1A\n * - \u591A\u4E2A\u72EC\u7ACB JSVMP \u5B9E\u4F8B\u8BC6\u522B\n * - VM \u7EC4\u4EF6\u53D8\u91CF\u8BC6\u522B\uFF08IP\u3001SP\u3001Stack\u3001Bytecode\uFF09\n * - \u8C03\u8BD5\u5165\u53E3\u70B9\u5B9A\u4F4D\n */\nfunction buildJSVMPSystemPrompt(): string {\n return `You are a Senior JavaScript Reverse Engineer and De-obfuscation Expert. Your specialty is analyzing **JSVMP (JavaScript Virtual Machine Protection)**.\n\n**Context: What is JSVMP?**\nJSVMP is a protection technique where original JavaScript code is compiled into custom **bytecode** and executed by a custom **interpreter** (virtual machine) written in JavaScript. A single JavaScript file may contain **multiple, independent JSVMP instances**.\n\nKey components of each JSVMP instance include:\n1. **The Bytecode Array:** A large array of integers representing the program logic for that specific VM.\n2. **The Virtual Stack:** A central array used to store operands and results for that VM.\n3. **The Dispatcher:** A control flow structure (e.g., a \\`while\\` loop with a \\`switch\\` or \\`if-else\\` chain) that reads an opcode and executes the corresponding logic for that VM.\n4. **Key State Variables:** The \"registers\" of a specific VM, such as its **Instruction Pointer (IP/PC)** and **Stack Pointer (SP)**.\n5. **Debugging Entry Point:** The single most critical line number within a specific dispatcher loop to set a breakpoint for observing that VM's state.\n\n**Task:**\nYour primary task is to analyze the provided JavaScript code snippet to identify **all independent JSVMP instances** and produce a comprehensive report for each one. You are NOT creating or analyzing any Intermediate Representation (IR). Your goal is to provide the necessary information for a subsequent tool to analyze each VM instance separately and create its IR and mappings.\n\nSpecifically, for **EACH** JSVMP instance you identify, you must:\n1. Define its location (**region**) and dispatcher type.\n2. Identify the specific **variables** that function as its core **Key State Variables** (Instruction Pointer, Stack Pointer, Virtual Stack, and Bytecode Array).\n3. Pinpoint the exact source code **line number** that serves as its optimal **Debugging Entry Point**.\n4. Summarize all findings in a single, structured JSON output.\n\n**Input Data Format:**\nThe code is provided in a simplified format: \\`LineNo SourceLoc Code\\`.\n* **Example:** \\`10 L234:56 var x = stack[p++];\\`\n* **Instruction:** Focus on the **LineNo** (1st column) and **Code** (3rd column onwards).\n\n**Detection Rules:**\n* **Region Identification:** An individual JSVMP instance is often characterized by a self-contained block containing a **Main Loop** + **Dispatcher** + **Stack Operations**.\n* **Instruction Pointer (IP) Identification:**\n * It is used as the **index for the Bytecode Array of its VM instance**.\n * It is **predictably incremented** in almost every loop iteration.\n * In some branches (jumps), it is **overwritten** with a new value.\n* **Stack Pointer (SP) Identification:**\n * It is used as the **index for the Virtual Stack array of its VM instance**.\n * Its value consistently **increments after a write** (push) and **decrements before a read** (pop).\n* **Debugging Entry Point Identification:**\n * This is the line **inside a specific dispatcher loop** but **before its \\`switch\\` or \\`if-else\\` chain begins**. It is typically located right after the \\`opcode\\` is read from the bytecode array.\n\n**Output Format:**\nReturn **ONLY valid JSON**. No markdown wrapper, no conversational text.\n\n**JSON Schema:**\n{\n \"summary\": {\n \"overall_description\": \"\u5BF9\u5728\u6587\u4EF6\u4E2D\u53D1\u73B0\u7684JSVMP\u5B9E\u4F8B\u6570\u91CF\u548C\u7C7B\u578B\u7684\u7B80\u8981\u4E2D\u6587\u603B\u7ED3\u3002\",\n \"debugging_recommendation\": \"\u4E3A\u4E0B\u4E00\u6B65\u5206\u6790\u63D0\u4F9B\u7684\u603B\u4F53\u4E2D\u6587\u5EFA\u8BAE\u3002\u4F8B\u5982\uFF1A'\u5DF2\u8BC6\u522B\u51FA N \u4E2A\u72EC\u7ACB\u7684JSVMP\u5B9E\u4F8B\u3002\u5EFA\u8BAE\u5BF9\u6BCF\u4E2A\u5B9E\u4F8B\u5206\u522B\u5728\u6307\u5B9A\u7684\"\u8C03\u8BD5\u5165\u53E3\u70B9\"\u8BBE\u7F6E\u6761\u4EF6\u65AD\u70B9\uFF0C\u5E76\u76D1\u63A7\u5176\u5404\u81EA\u7684\u7EC4\u4EF6\u53D8\u91CF\u3002'\"\n },\n \"regions\": [\n {\n \"start_line\": \"<start_line_integer>\",\n \"end_line\": \"<end_line_integer>\",\n \"type\": \"<If-Else Dispatcher | Switch Dispatcher | Instruction Array>\",\n \"confidence\": \"<ultra_high | high | medium | low>\",\n \"description\": \"\u5BF9\u8FD9\u4E2A\u7279\u5B9AJSVMP\u5B9E\u4F8B\u7684\u7B80\u8981\u4E2D\u6587\u63CF\u8FF0\u3002\",\n \"vm_components\": {\n \"instruction_pointer\": {\n \"variable_name\": \"<identified_variable_name | null>\",\n \"confidence\": \"<high | medium | low>\",\n \"reasoning\": \"Why this variable is the IP for THIS VM instance. E.g., 'Used as index for bytecode array _0x123 within this region.'\"\n },\n \"stack_pointer\": {\n \"variable_name\": \"<identified_variable_name | null>\",\n \"confidence\": \"<high | medium | low>\",\n \"reasoning\": \"Why this variable is the SP for THIS VM instance. E.g., 'Used as index for stack array _0x456.'\"\n },\n \"virtual_stack\": {\n \"variable_name\": \"<identified_array_name | null>\",\n \"confidence\": \"<high | medium | low>\",\n \"reasoning\": \"Why this array is the stack for THIS VM instance. E.g., 'Frequently accessed using its stack_pointer _0x789.'\"\n },\n \"bytecode_array\": {\n \"variable_name\": \"<identified_array_name | null>\",\n \"confidence\": \"<high | medium | low>\",\n \"reasoning\": \"Why this array is the bytecode for THIS VM instance. E.g., 'A large, static array indexed by its instruction_pointer _0x123.'\"\n }\n },\n \"debugging_entry_point\": {\n \"line_number\": \"<line_number_integer>\",\n \"description\": \"The optimal breakpoint line for THIS VM instance. E.g., 'This line is after the opcode is fetched and before this region's switch statement.'\"\n }\n }\n ]\n}`;\n}\n\n/**\n * Creates a provider-specific model instance using the AI SDK\n * @param config - The LLM configuration\n * @returns A LanguageModel instance for the configured provider\n */\nexport function createProviderModel(config: LLMConfig): LanguageModel {\n switch (config.provider) {\n case 'openai': {\n const openai = createOpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n return openai(config.model);\n }\n case 'anthropic': {\n const anthropic = createAnthropic({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n return anthropic(config.model);\n }\n case 'google': {\n const google = createGoogleGenerativeAI({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n });\n return google(config.model);\n }\n }\n}\n\n/**\n * \u521B\u5EFA LLM \u5BA2\u6237\u7AEF\u5B9E\u4F8B\n */\nexport function createLLMClient(config: LLMConfig): LLMClient {\n const model = createProviderModel(config);\n \n return {\n async analyzeJSVMP(formattedCode: string): Promise<string> {\n const systemPrompt = buildJSVMPSystemPrompt();\n \n try {\n const result = await generateText({\n model,\n system: systemPrompt,\n prompt: `\u8BF7\u5206\u6790\u4EE5\u4E0B\u4EE3\u7801\uFF0C\u8BC6\u522B JSVMP \u4FDD\u62A4\u7ED3\u6784\uFF1A\\n\\n${formattedCode}`,\n temperature: 0.1,\n });\n \n return result.text;\n } catch (error) {\n const providerName = config.provider.charAt(0).toUpperCase() + config.provider.slice(1);\n if (error instanceof Error) {\n throw new Error(`${providerName} LLM \u8BF7\u6C42\u5931\u8D25: ${error.message}`);\n }\n throw new Error(`${providerName} LLM \u8BF7\u6C42\u5931\u8D25: ${String(error)}`);\n }\n }\n };\n}\n", "/**\n * Tokenizer Module\n * Token counting and batch splitting utilities using tiktoken\n */\n\nimport { encoding_for_model, TiktokenModel } from 'tiktoken';\n\n/**\n * Default model for token counting\n */\nconst DEFAULT_MODEL: TiktokenModel = 'gpt-4o';\n\n/**\n * Calculate token count for text using tiktoken\n * \n * @param text - The text to count tokens for\n * @param model - Optional model name (default: gpt-4o)\n * @returns The number of tokens in the text\n */\nexport function countTokens(text: string, model?: string): number {\n const enc = encoding_for_model((model as TiktokenModel) ?? DEFAULT_MODEL);\n try {\n const tokens = enc.encode(text);\n return tokens.length;\n } finally {\n enc.free();\n }\n}\n\n/**\n * Split lines into batches based on token limit\n * Splits at line boundaries to preserve code structure\n * \n * @param lines - Array of code lines to split\n * @param maxTokens - Maximum tokens per batch\n * @param model - Optional model name (default: gpt-4o)\n * @returns Array of batches, where each batch is an array of lines\n */\nexport function splitByTokenLimit(\n lines: string[],\n maxTokens: number,\n model?: string\n): string[][] {\n if (lines.length === 0) {\n return [];\n }\n\n if (maxTokens <= 0) {\n throw new Error('maxTokens must be a positive number');\n }\n\n const batches: string[][] = [];\n let currentBatch: string[] = [];\n let currentTokenCount = 0;\n\n const enc = encoding_for_model((model as TiktokenModel) ?? DEFAULT_MODEL);\n \n try {\n for (const line of lines) {\n // Calculate tokens for this line (including newline)\n const lineWithNewline = line + '\\n';\n const lineTokens = enc.encode(lineWithNewline).length;\n\n // If a single line exceeds maxTokens, it goes in its own batch\n if (lineTokens > maxTokens) {\n // Flush current batch if not empty\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentTokenCount = 0;\n }\n // Add the oversized line as its own batch\n batches.push([line]);\n continue;\n }\n\n // Check if adding this line would exceed the limit\n if (currentTokenCount + lineTokens > maxTokens && currentBatch.length > 0) {\n // Flush current batch\n batches.push(currentBatch);\n currentBatch = [];\n currentTokenCount = 0;\n }\n\n // Add line to current batch\n currentBatch.push(line);\n currentTokenCount += lineTokens;\n }\n\n // Don't forget the last batch\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n } finally {\n enc.free();\n }\n}\n", "/**\n * Tool aggregation module\n * Collects all tool definitions and exports them as a unified array.\n */\n\nimport { findJsvmpDispatcherTool, FindJsvmpDispatcherInputSchema } from './findJsvmpDispatcherTool.js';\n\n/**\n * Array of all available MCP tool definitions.\n * To add a new tool:\n * 1. Create a new tool module in src/tools/\n * 2. Import it here\n * 3. Add it to this array\n */\nexport const tools = [\n findJsvmpDispatcherTool,\n] as const;\n\n// Re-export ToolDefinition interface and defineTool helper\nexport { ToolDefinition, defineTool } from './ToolDefinition.js';\n\n// Re-export tool and input schema\nexport { findJsvmpDispatcherTool, FindJsvmpDispatcherInputSchema };\n"],
5
+ "mappings": "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",
6
6
  "names": ["z", "z"]
7
7
  }
@@ -14,10 +14,12 @@ export declare const FindJsvmpDispatcherInputSchema: {
14
14
  *
15
15
  * JSVMP is a code protection technique that converts JavaScript to bytecode
16
16
  * executed by a virtual machine. This tool identifies:
17
+ * - Multiple independent JSVMP instances
17
18
  * - If-Else Dispatchers
18
19
  * - Switch Dispatchers
19
20
  * - Instruction Arrays
20
- * - Stack Operations
21
+ * - VM Components (IP, SP, Stack, Bytecode Array)
22
+ * - Debugging Entry Points
21
23
  *
22
24
  * Requires OPENAI_API_KEY environment variable to be set.
23
25
  */
@@ -1 +1 @@
1
- {"version":3,"file":"findJsvmpDispatcherTool.d.ts","sourceRoot":"","sources":["../../src/tools/findJsvmpDispatcherTool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;GAEG;AACH,eAAO,MAAM,8BAA8B;;;;CAI1C,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB;;;;EA8BlC,CAAC"}
1
+ {"version":3,"file":"findJsvmpDispatcherTool.d.ts","sourceRoot":"","sources":["../../src/tools/findJsvmpDispatcherTool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;GAEG;AACH,eAAO,MAAM,8BAA8B;;;;CAI1C,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,uBAAuB;;;;EA+BlC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reverse-craft/ai-tools",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "MCP server for AI-powered JSVMP detection - provides LLM-driven code analysis tools",
5
5
  "type": "module",
6
6
  "main": "dist/server.js",