@reverse-craft/ai-tools 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +130 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/jsvmpDetector.d.ts +98 -0
- package/dist/jsvmpDetector.d.ts.map +1 -0
- package/dist/jsvmpDetector.js +283 -0
- package/dist/jsvmpDetector.js.map +1 -0
- package/dist/llmConfig.d.ts +34 -0
- package/dist/llmConfig.d.ts.map +1 -0
- package/dist/llmConfig.js +133 -0
- package/dist/llmConfig.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 reverse-craft
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# @reverse-craft/ai-tools
|
|
2
|
+
|
|
3
|
+
AI-powered code analysis tools for smart-fs. Provides LLM-driven functionality including JSVMP (JavaScript Virtual Machine Protection) dispatcher detection.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **JSVMP Detection** - Detect VM protection patterns using LLM analysis
|
|
8
|
+
- **LLM Configuration** - Flexible OpenAI-compatible API configuration
|
|
9
|
+
- **Code Formatting** - Format code for LLM analysis with source map coordinates
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @reverse-craft/ai-tools
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
Set environment variables for LLM access:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Required
|
|
23
|
+
export OPENAI_API_KEY=your-api-key
|
|
24
|
+
|
|
25
|
+
# Optional (defaults shown)
|
|
26
|
+
export OPENAI_BASE_URL=https://api.openai.com/v1
|
|
27
|
+
export OPENAI_MODEL=gpt-4
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### JSVMP Dispatcher Detection
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { findJsvmpDispatcher } from '@reverse-craft/ai-tools';
|
|
36
|
+
|
|
37
|
+
const result = await findJsvmpDispatcher(
|
|
38
|
+
'./obfuscated.js',
|
|
39
|
+
1, // startLine
|
|
40
|
+
500, // endLine
|
|
41
|
+
{ charLimit: 300 }
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (result.success) {
|
|
45
|
+
console.log(result.formattedOutput);
|
|
46
|
+
// Detected regions with confidence levels
|
|
47
|
+
for (const region of result.result.regions) {
|
|
48
|
+
console.log(`[${region.confidence}] Lines ${region.start}-${region.end}: ${region.type}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### LLM Configuration
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { getLLMConfig, isLLMConfigured, createLLMClient } from '@reverse-craft/ai-tools';
|
|
57
|
+
|
|
58
|
+
// Check if LLM is configured
|
|
59
|
+
if (isLLMConfigured()) {
|
|
60
|
+
const config = getLLMConfig();
|
|
61
|
+
const client = createLLMClient(config);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Code Formatting for Analysis
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { formatCodeForAnalysis } from '@reverse-craft/ai-tools';
|
|
69
|
+
|
|
70
|
+
const formatted = await formatCodeForAnalysis(
|
|
71
|
+
'./app.min.js',
|
|
72
|
+
1, // startLine
|
|
73
|
+
100, // endLine
|
|
74
|
+
300 // charLimit
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
console.log(formatted.content);
|
|
78
|
+
// Output: "LineNo SourceLoc Code" format
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## API
|
|
82
|
+
|
|
83
|
+
### Types
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Detection types
|
|
87
|
+
type DetectionType =
|
|
88
|
+
| "If-Else Dispatcher"
|
|
89
|
+
| "Switch Dispatcher"
|
|
90
|
+
| "Instruction Array"
|
|
91
|
+
| "Stack Operation";
|
|
92
|
+
|
|
93
|
+
type ConfidenceLevel = "ultra_high" | "high" | "medium" | "low";
|
|
94
|
+
|
|
95
|
+
interface DetectionRegion {
|
|
96
|
+
start: number;
|
|
97
|
+
end: number;
|
|
98
|
+
type: DetectionType;
|
|
99
|
+
confidence: ConfidenceLevel;
|
|
100
|
+
description: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface JsvmpDetectionResult {
|
|
104
|
+
success: boolean;
|
|
105
|
+
filePath: string;
|
|
106
|
+
startLine: number;
|
|
107
|
+
endLine: number;
|
|
108
|
+
result?: DetectionResult;
|
|
109
|
+
formattedOutput?: string;
|
|
110
|
+
error?: string;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Functions
|
|
115
|
+
|
|
116
|
+
- `findJsvmpDispatcher(filePath, startLine, endLine, options?)` - Detect JSVMP patterns
|
|
117
|
+
- `formatCodeForAnalysis(filePath, startLine, endLine, charLimit?)` - Format code for LLM
|
|
118
|
+
- `parseDetectionResult(jsonString)` - Parse LLM response
|
|
119
|
+
- `getLLMConfig()` - Get LLM configuration from environment
|
|
120
|
+
- `isLLMConfigured()` - Check if LLM is configured
|
|
121
|
+
- `createLLMClient(config)` - Create LLM client instance
|
|
122
|
+
|
|
123
|
+
## Related Packages
|
|
124
|
+
|
|
125
|
+
- **[@reverse-craft/smart-fs](https://github.com/reverse-craft/smart-fs)** - Core library
|
|
126
|
+
- **[@reverse-craft/smart-fs-mcp](https://github.com/reverse-craft/smart-fs-mcp)** - MCP server
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Tools - AI-powered code analysis tools
|
|
3
|
+
*
|
|
4
|
+
* This package provides LLM-driven functionality for code analysis,
|
|
5
|
+
* including JSVMP (JavaScript Virtual Machine Protection) detection.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export { type LLMConfig, type LLMClient, getLLMConfig, isLLMConfigured, createLLMClient, } from './llmConfig.js';
|
|
10
|
+
export { type FormattedCode, type DetectionType, type ConfidenceLevel, type DetectionRegion, type DetectionResult, type JsvmpDetectionOptions, type JsvmpDetectionResult, formatCodeForAnalysis, parseDetectionResult, findJsvmpDispatcher, } from './jsvmpDetector.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,KAAK,SAAS,EACd,KAAK,SAAS,EACd,YAAY,EACZ,eAAe,EACf,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Tools - AI-powered code analysis tools
|
|
3
|
+
*
|
|
4
|
+
* This package provides LLM-driven functionality for code analysis,
|
|
5
|
+
* including JSVMP (JavaScript Virtual Machine Protection) detection.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
// LLM Configuration
|
|
10
|
+
export { getLLMConfig, isLLMConfigured, createLLMClient, } from './llmConfig.js';
|
|
11
|
+
// JSVMP Detector
|
|
12
|
+
export { formatCodeForAnalysis, parseDetectionResult, findJsvmpDispatcher, } from './jsvmpDetector.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oBAAoB;AACpB,OAAO,EAGL,YAAY,EACZ,eAAe,EACf,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,iBAAiB;AACjB,OAAO,EAQL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSVMP Detector Module
|
|
3
|
+
* AI-powered detection of JSVMP (JavaScript Virtual Machine Protection) patterns
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Formatted code result interface
|
|
7
|
+
*/
|
|
8
|
+
export interface FormattedCode {
|
|
9
|
+
content: string;
|
|
10
|
+
totalLines: number;
|
|
11
|
+
startLine: number;
|
|
12
|
+
endLine: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Detection type for JSVMP patterns
|
|
16
|
+
*/
|
|
17
|
+
export type DetectionType = "If-Else Dispatcher" | "Switch Dispatcher" | "Instruction Array" | "Stack Operation";
|
|
18
|
+
/**
|
|
19
|
+
* Confidence level for detection results
|
|
20
|
+
*/
|
|
21
|
+
export type ConfidenceLevel = "ultra_high" | "high" | "medium" | "low";
|
|
22
|
+
/**
|
|
23
|
+
* A detected region in the code
|
|
24
|
+
*/
|
|
25
|
+
export interface DetectionRegion {
|
|
26
|
+
start: number;
|
|
27
|
+
end: number;
|
|
28
|
+
type: DetectionType;
|
|
29
|
+
confidence: ConfidenceLevel;
|
|
30
|
+
description: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Complete detection result from LLM analysis
|
|
34
|
+
*/
|
|
35
|
+
export interface DetectionResult {
|
|
36
|
+
summary: string;
|
|
37
|
+
regions: DetectionRegion[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Options for JSVMP detection
|
|
41
|
+
*/
|
|
42
|
+
export interface JsvmpDetectionOptions {
|
|
43
|
+
charLimit?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Result from findJsvmpDispatcher function
|
|
47
|
+
*/
|
|
48
|
+
export interface JsvmpDetectionResult {
|
|
49
|
+
success: boolean;
|
|
50
|
+
filePath: string;
|
|
51
|
+
startLine: number;
|
|
52
|
+
endLine: number;
|
|
53
|
+
result?: DetectionResult;
|
|
54
|
+
formattedOutput?: string;
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 格式化代码为 LLM 分析格式
|
|
59
|
+
* 格式: "LineNo SourceLoc Code"
|
|
60
|
+
*
|
|
61
|
+
* 处理流程:
|
|
62
|
+
* 1. 调用 ensureBeautified 美化代码
|
|
63
|
+
* 2. 调用 truncateCodeHighPerf 截断长字符串
|
|
64
|
+
* 3. 使用 SourceMapConsumer 获取原始坐标
|
|
65
|
+
* 4. 格式化为 "LineNo SourceLoc Code" 格式
|
|
66
|
+
*
|
|
67
|
+
* @param filePath - Path to the JavaScript file
|
|
68
|
+
* @param startLine - Start line number (1-based)
|
|
69
|
+
* @param endLine - End line number (1-based)
|
|
70
|
+
* @param charLimit - Character limit for string truncation (default 300)
|
|
71
|
+
* @returns FormattedCode object with formatted content and metadata
|
|
72
|
+
*/
|
|
73
|
+
export declare function formatCodeForAnalysis(filePath: string, startLine: number, endLine: number, charLimit?: number): Promise<FormattedCode>;
|
|
74
|
+
/**
|
|
75
|
+
* Parse and validate LLM detection result from JSON string
|
|
76
|
+
*
|
|
77
|
+
* Validates:
|
|
78
|
+
* - JSON is parseable
|
|
79
|
+
* - Required fields exist: summary, regions
|
|
80
|
+
* - Each region has required fields: start, end, type, confidence, description
|
|
81
|
+
* - Enum values are valid
|
|
82
|
+
*
|
|
83
|
+
* @param jsonString - JSON string from LLM response
|
|
84
|
+
* @returns Parsed and validated DetectionResult
|
|
85
|
+
* @throws Error if JSON is invalid or structure doesn't match expected format
|
|
86
|
+
*/
|
|
87
|
+
export declare function parseDetectionResult(jsonString: string): DetectionResult;
|
|
88
|
+
/**
|
|
89
|
+
* Find JSVMP dispatcher patterns in JavaScript code using LLM analysis
|
|
90
|
+
*
|
|
91
|
+
* @param filePath - Path to the JavaScript file to analyze
|
|
92
|
+
* @param startLine - Start line number (1-based)
|
|
93
|
+
* @param endLine - End line number (1-based)
|
|
94
|
+
* @param options - Optional configuration
|
|
95
|
+
* @returns JsvmpDetectionResult with detection results or error
|
|
96
|
+
*/
|
|
97
|
+
export declare function findJsvmpDispatcher(filePath: string, startLine: number, endLine: number, options?: JsvmpDetectionOptions): Promise<JsvmpDetectionResult>;
|
|
98
|
+
//# sourceMappingURL=jsvmpDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsvmpDetector.d.ts","sourceRoot":"","sources":["../src/jsvmpDetector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,CAAC;AAEtB;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,eAAe,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAAY,GACtB,OAAO,CAAC,aAAa,CAAC,CAuDxB;AAoCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAoFxE;AAiCD;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CA+D/B"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSVMP Detector Module
|
|
3
|
+
* AI-powered detection of JSVMP (JavaScript Virtual Machine Protection) patterns
|
|
4
|
+
*/
|
|
5
|
+
import { SourceMapConsumer } from 'source-map-js';
|
|
6
|
+
import { ensureBeautified, truncateCodeHighPerf } from '@reverse-craft/smart-fs';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { getLLMConfig, createLLMClient } from './llmConfig.js';
|
|
9
|
+
/**
|
|
10
|
+
* Format source position as "L{line}:{column}" or empty placeholder
|
|
11
|
+
*/
|
|
12
|
+
function formatSourcePosition(line, column) {
|
|
13
|
+
if (line !== null && column !== null) {
|
|
14
|
+
return `L${line}:${column}`;
|
|
15
|
+
}
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Format a single code line with line number, source coordinates, and content
|
|
20
|
+
* Format: "LineNo SourceLoc Code"
|
|
21
|
+
*/
|
|
22
|
+
function formatCodeLine(lineNumber, sourcePos, code) {
|
|
23
|
+
const lineNumStr = String(lineNumber).padStart(5, ' ');
|
|
24
|
+
const srcPosPadded = sourcePos ? sourcePos.padEnd(10, ' ') : ' ';
|
|
25
|
+
return `${lineNumStr} ${srcPosPadded} ${code}`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 格式化代码为 LLM 分析格式
|
|
29
|
+
* 格式: "LineNo SourceLoc Code"
|
|
30
|
+
*
|
|
31
|
+
* 处理流程:
|
|
32
|
+
* 1. 调用 ensureBeautified 美化代码
|
|
33
|
+
* 2. 调用 truncateCodeHighPerf 截断长字符串
|
|
34
|
+
* 3. 使用 SourceMapConsumer 获取原始坐标
|
|
35
|
+
* 4. 格式化为 "LineNo SourceLoc Code" 格式
|
|
36
|
+
*
|
|
37
|
+
* @param filePath - Path to the JavaScript file
|
|
38
|
+
* @param startLine - Start line number (1-based)
|
|
39
|
+
* @param endLine - End line number (1-based)
|
|
40
|
+
* @param charLimit - Character limit for string truncation (default 300)
|
|
41
|
+
* @returns FormattedCode object with formatted content and metadata
|
|
42
|
+
*/
|
|
43
|
+
export async function formatCodeForAnalysis(filePath, startLine, endLine, charLimit = 300) {
|
|
44
|
+
// Step 1: Beautify the file and get source map
|
|
45
|
+
const beautifyResult = await ensureBeautified(filePath);
|
|
46
|
+
const { code, rawMap } = beautifyResult;
|
|
47
|
+
// Step 2: Truncate long strings
|
|
48
|
+
const truncatedCode = truncateCodeHighPerf(code, charLimit);
|
|
49
|
+
// Split into lines
|
|
50
|
+
const lines = truncatedCode.split('\n');
|
|
51
|
+
const totalLines = lines.length;
|
|
52
|
+
// Step 3: Adjust line range boundaries
|
|
53
|
+
const effectiveStartLine = Math.max(1, Math.min(totalLines, startLine));
|
|
54
|
+
const effectiveEndLine = Math.max(effectiveStartLine, Math.min(totalLines, endLine));
|
|
55
|
+
// Step 4: Format each line with "LineNo SourceLoc Code" format
|
|
56
|
+
const formattedLines = [];
|
|
57
|
+
// Create source map consumer if available
|
|
58
|
+
let consumer = null;
|
|
59
|
+
if (rawMap && rawMap.sources && rawMap.names && rawMap.mappings) {
|
|
60
|
+
consumer = new SourceMapConsumer({
|
|
61
|
+
version: String(rawMap.version),
|
|
62
|
+
sources: rawMap.sources,
|
|
63
|
+
names: rawMap.names,
|
|
64
|
+
mappings: rawMap.mappings,
|
|
65
|
+
file: rawMap.file,
|
|
66
|
+
sourceRoot: rawMap.sourceRoot,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
for (let lineNum = effectiveStartLine; lineNum <= effectiveEndLine; lineNum++) {
|
|
70
|
+
const lineIndex = lineNum - 1;
|
|
71
|
+
const lineContent = lines[lineIndex] ?? '';
|
|
72
|
+
// Get original position from source map if available
|
|
73
|
+
let sourcePos = '';
|
|
74
|
+
if (consumer) {
|
|
75
|
+
const originalPos = consumer.originalPositionFor({
|
|
76
|
+
line: lineNum,
|
|
77
|
+
column: 0,
|
|
78
|
+
});
|
|
79
|
+
sourcePos = formatSourcePosition(originalPos.line, originalPos.column);
|
|
80
|
+
}
|
|
81
|
+
formattedLines.push(formatCodeLine(lineNum, sourcePos, lineContent));
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
content: formattedLines.join('\n'),
|
|
85
|
+
totalLines,
|
|
86
|
+
startLine: effectiveStartLine,
|
|
87
|
+
endLine: effectiveEndLine,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Valid detection types for validation
|
|
92
|
+
*/
|
|
93
|
+
const VALID_DETECTION_TYPES = [
|
|
94
|
+
"If-Else Dispatcher",
|
|
95
|
+
"Switch Dispatcher",
|
|
96
|
+
"Instruction Array",
|
|
97
|
+
"Stack Operation"
|
|
98
|
+
];
|
|
99
|
+
/**
|
|
100
|
+
* Valid confidence levels for validation
|
|
101
|
+
*/
|
|
102
|
+
const VALID_CONFIDENCE_LEVELS = [
|
|
103
|
+
"ultra_high",
|
|
104
|
+
"high",
|
|
105
|
+
"medium",
|
|
106
|
+
"low"
|
|
107
|
+
];
|
|
108
|
+
/**
|
|
109
|
+
* Check if a value is a valid DetectionType
|
|
110
|
+
*/
|
|
111
|
+
function isValidDetectionType(value) {
|
|
112
|
+
return VALID_DETECTION_TYPES.includes(value);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if a value is a valid ConfidenceLevel
|
|
116
|
+
*/
|
|
117
|
+
function isValidConfidenceLevel(value) {
|
|
118
|
+
return VALID_CONFIDENCE_LEVELS.includes(value);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Parse and validate LLM detection result from JSON string
|
|
122
|
+
*
|
|
123
|
+
* Validates:
|
|
124
|
+
* - JSON is parseable
|
|
125
|
+
* - Required fields exist: summary, regions
|
|
126
|
+
* - Each region has required fields: start, end, type, confidence, description
|
|
127
|
+
* - Enum values are valid
|
|
128
|
+
*
|
|
129
|
+
* @param jsonString - JSON string from LLM response
|
|
130
|
+
* @returns Parsed and validated DetectionResult
|
|
131
|
+
* @throws Error if JSON is invalid or structure doesn't match expected format
|
|
132
|
+
*/
|
|
133
|
+
export function parseDetectionResult(jsonString) {
|
|
134
|
+
// Parse JSON
|
|
135
|
+
let parsed;
|
|
136
|
+
try {
|
|
137
|
+
parsed = JSON.parse(jsonString);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw new Error(`无法解析 LLM 响应: ${error instanceof Error ? error.message : String(error)}`);
|
|
141
|
+
}
|
|
142
|
+
// Validate required top-level fields
|
|
143
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
144
|
+
throw new Error('LLM 响应格式无效,期望对象类型');
|
|
145
|
+
}
|
|
146
|
+
const obj = parsed;
|
|
147
|
+
if (typeof obj.summary !== 'string') {
|
|
148
|
+
throw new Error('LLM 响应格式无效,缺少必需字段: summary');
|
|
149
|
+
}
|
|
150
|
+
if (!Array.isArray(obj.regions)) {
|
|
151
|
+
throw new Error('LLM 响应格式无效,缺少必需字段: regions');
|
|
152
|
+
}
|
|
153
|
+
// Validate each region
|
|
154
|
+
const validatedRegions = [];
|
|
155
|
+
for (let i = 0; i < obj.regions.length; i++) {
|
|
156
|
+
const region = obj.regions[i];
|
|
157
|
+
// Check region is an object
|
|
158
|
+
if (typeof region !== 'object' || region === null) {
|
|
159
|
+
throw new Error(`LLM 响应格式无效,regions[${i}] 不是对象`);
|
|
160
|
+
}
|
|
161
|
+
// Validate required fields exist and have correct types
|
|
162
|
+
if (typeof region.start !== 'number') {
|
|
163
|
+
throw new Error(`LLM 响应格式无效,regions[${i}] 缺少必需字段: start`);
|
|
164
|
+
}
|
|
165
|
+
if (typeof region.end !== 'number') {
|
|
166
|
+
throw new Error(`LLM 响应格式无效,regions[${i}] 缺少必需字段: end`);
|
|
167
|
+
}
|
|
168
|
+
if (typeof region.type !== 'string') {
|
|
169
|
+
throw new Error(`LLM 响应格式无效,regions[${i}] 缺少必需字段: type`);
|
|
170
|
+
}
|
|
171
|
+
if (typeof region.confidence !== 'string') {
|
|
172
|
+
throw new Error(`LLM 响应格式无效,regions[${i}] 缺少必需字段: confidence`);
|
|
173
|
+
}
|
|
174
|
+
if (typeof region.description !== 'string') {
|
|
175
|
+
throw new Error(`LLM 响应格式无效,regions[${i}] 缺少必需字段: description`);
|
|
176
|
+
}
|
|
177
|
+
// Validate enum values
|
|
178
|
+
if (!isValidDetectionType(region.type)) {
|
|
179
|
+
throw new Error(`LLM 响应格式无效,regions[${i}].type 值无效: "${region.type}". ` +
|
|
180
|
+
`有效值: ${VALID_DETECTION_TYPES.join(', ')}`);
|
|
181
|
+
}
|
|
182
|
+
if (!isValidConfidenceLevel(region.confidence)) {
|
|
183
|
+
throw new Error(`LLM 响应格式无效,regions[${i}].confidence 值无效: "${region.confidence}". ` +
|
|
184
|
+
`有效值: ${VALID_CONFIDENCE_LEVELS.join(', ')}`);
|
|
185
|
+
}
|
|
186
|
+
validatedRegions.push({
|
|
187
|
+
start: region.start,
|
|
188
|
+
end: region.end,
|
|
189
|
+
type: region.type,
|
|
190
|
+
confidence: region.confidence,
|
|
191
|
+
description: region.description,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
summary: obj.summary,
|
|
196
|
+
regions: validatedRegions,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Format detection result for display
|
|
201
|
+
*/
|
|
202
|
+
function formatDetectionResultOutput(result, filePath, startLine, endLine) {
|
|
203
|
+
const lines = [];
|
|
204
|
+
lines.push('=== JSVMP Dispatcher Detection Result ===');
|
|
205
|
+
lines.push(`File: ${filePath} (${startLine}-${endLine})`);
|
|
206
|
+
lines.push('');
|
|
207
|
+
lines.push(`Summary: ${result.summary}`);
|
|
208
|
+
lines.push('');
|
|
209
|
+
if (result.regions.length > 0) {
|
|
210
|
+
lines.push('Detected Regions:');
|
|
211
|
+
for (const region of result.regions) {
|
|
212
|
+
lines.push(`[${region.confidence}] Lines ${region.start}-${region.end}: ${region.type}`);
|
|
213
|
+
lines.push(` ${region.description}`);
|
|
214
|
+
lines.push('');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
lines.push('No JSVMP dispatcher patterns detected.');
|
|
219
|
+
}
|
|
220
|
+
return lines.join('\n');
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Find JSVMP dispatcher patterns in JavaScript code using LLM analysis
|
|
224
|
+
*
|
|
225
|
+
* @param filePath - Path to the JavaScript file to analyze
|
|
226
|
+
* @param startLine - Start line number (1-based)
|
|
227
|
+
* @param endLine - End line number (1-based)
|
|
228
|
+
* @param options - Optional configuration
|
|
229
|
+
* @returns JsvmpDetectionResult with detection results or error
|
|
230
|
+
*/
|
|
231
|
+
export async function findJsvmpDispatcher(filePath, startLine, endLine, options) {
|
|
232
|
+
const charLimit = options?.charLimit ?? 300;
|
|
233
|
+
// Check LLM configuration
|
|
234
|
+
const config = getLLMConfig();
|
|
235
|
+
if (!config) {
|
|
236
|
+
return {
|
|
237
|
+
success: false,
|
|
238
|
+
filePath,
|
|
239
|
+
startLine,
|
|
240
|
+
endLine,
|
|
241
|
+
error: '未配置 LLM。请设置环境变量 OPENAI_API_KEY 以启用 JSVMP dispatcher 检测功能。'
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// Check file exists
|
|
245
|
+
if (!existsSync(filePath)) {
|
|
246
|
+
return {
|
|
247
|
+
success: false,
|
|
248
|
+
filePath,
|
|
249
|
+
startLine,
|
|
250
|
+
endLine,
|
|
251
|
+
error: `文件不存在: ${filePath}`
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
// Format code for analysis
|
|
256
|
+
const formattedCode = await formatCodeForAnalysis(filePath, startLine, endLine, charLimit);
|
|
257
|
+
// Create LLM client and analyze
|
|
258
|
+
const client = createLLMClient(config);
|
|
259
|
+
const llmResponse = await client.analyzeJSVMP(formattedCode.content);
|
|
260
|
+
// Parse detection result
|
|
261
|
+
const result = parseDetectionResult(llmResponse);
|
|
262
|
+
// Format output
|
|
263
|
+
const formattedOutput = formatDetectionResultOutput(result, filePath, startLine, endLine);
|
|
264
|
+
return {
|
|
265
|
+
success: true,
|
|
266
|
+
filePath,
|
|
267
|
+
startLine: formattedCode.startLine,
|
|
268
|
+
endLine: formattedCode.endLine,
|
|
269
|
+
result,
|
|
270
|
+
formattedOutput
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
return {
|
|
275
|
+
success: false,
|
|
276
|
+
filePath,
|
|
277
|
+
startLine,
|
|
278
|
+
endLine,
|
|
279
|
+
error: error instanceof Error ? error.message : String(error)
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=jsvmpDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsvmpDetector.js","sourceRoot":"","sources":["../src/jsvmpDetector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Configuration Module
|
|
3
|
+
* Handles reading and validating LLM configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
export interface LLMConfig {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
model: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 从环境变量读取 LLM 配置
|
|
12
|
+
* @returns LLMConfig | null (null 表示未配置)
|
|
13
|
+
*/
|
|
14
|
+
export declare function getLLMConfig(): LLMConfig | null;
|
|
15
|
+
/**
|
|
16
|
+
* 检查 LLM 是否已配置
|
|
17
|
+
*/
|
|
18
|
+
export declare function isLLMConfigured(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* LLM Client Interface
|
|
21
|
+
*/
|
|
22
|
+
export interface LLMClient {
|
|
23
|
+
/**
|
|
24
|
+
* 发送 JSVMP 检测请求到 LLM
|
|
25
|
+
* @param formattedCode 格式化后的代码
|
|
26
|
+
* @returns LLM 返回的原始 JSON 字符串
|
|
27
|
+
*/
|
|
28
|
+
analyzeJSVMP(formattedCode: string): Promise<string>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 创建 LLM 客户端实例
|
|
32
|
+
*/
|
|
33
|
+
export declare function createLLMClient(config: LLMConfig): LLMClient;
|
|
34
|
+
//# sourceMappingURL=llmConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmConfig.d.ts","sourceRoot":"","sources":["../src/llmConfig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,SAAS,GAAG,IAAI,CAiB/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;AAoDD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAyD5D"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Configuration Module
|
|
3
|
+
* Handles reading and validating LLM configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 从环境变量读取 LLM 配置
|
|
7
|
+
* @returns LLMConfig | null (null 表示未配置)
|
|
8
|
+
*/
|
|
9
|
+
export function getLLMConfig() {
|
|
10
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
11
|
+
// API Key is required
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
// Use defaults for optional configuration
|
|
16
|
+
const baseUrl = process.env.OPENAI_BASE_URL || "https://api.openai.com/v1";
|
|
17
|
+
const model = process.env.OPENAI_MODEL || "gpt-4o-mini";
|
|
18
|
+
return {
|
|
19
|
+
apiKey,
|
|
20
|
+
baseUrl,
|
|
21
|
+
model
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 检查 LLM 是否已配置
|
|
26
|
+
*/
|
|
27
|
+
export function isLLMConfigured() {
|
|
28
|
+
return getLLMConfig() !== null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 构建 JSVMP 检测系统提示词
|
|
32
|
+
*/
|
|
33
|
+
function buildJSVMPSystemPrompt() {
|
|
34
|
+
return `你是一个专业的 JavaScript 逆向工程专家,专门识别 JSVMP(JavaScript Virtual Machine Protection)保护代码。
|
|
35
|
+
|
|
36
|
+
JSVMP 是一种代码保护技术,将 JavaScript 代码转换为字节码,并通过虚拟机执行。典型特征包括:
|
|
37
|
+
|
|
38
|
+
1. **虚拟栈(Virtual Stack)**:中央数组用于存储操作数和结果
|
|
39
|
+
2. **分发器(Dispatcher)**:大型 switch 语句或嵌套 if-else 链,根据指令码执行不同操作
|
|
40
|
+
3. **指令数组(Instruction Array)**:存储字节码指令的数组
|
|
41
|
+
4. **主循环(Main Loop)**:while 循环持续执行指令
|
|
42
|
+
|
|
43
|
+
检测规则:
|
|
44
|
+
|
|
45
|
+
**Ultra High 置信度**:
|
|
46
|
+
- 同时出现:主循环 + 分发器 + 栈操作
|
|
47
|
+
- 分发器有 >20 个 case 或 >10 层嵌套
|
|
48
|
+
- 明确的栈操作模式(push/pop/数组索引)
|
|
49
|
+
|
|
50
|
+
**High 置信度**:
|
|
51
|
+
- 独立的大型分发器结构(>20 case 的 switch 或 >10 层嵌套的 if-else)
|
|
52
|
+
- 明确的指令数组和程序计数器模式
|
|
53
|
+
|
|
54
|
+
**Medium 置信度**:
|
|
55
|
+
- 孤立的栈操作或可疑的 while 循环
|
|
56
|
+
- 部分 JSVMP 特征但不完整
|
|
57
|
+
|
|
58
|
+
**Low 置信度**:
|
|
59
|
+
- 通用混淆模式
|
|
60
|
+
- 可能相关但不确定的结构
|
|
61
|
+
|
|
62
|
+
请分析提供的代码,识别 JSVMP 相关区域。返回 JSON 格式:
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
"summary": "分析摘要(中文)",
|
|
66
|
+
"regions": [
|
|
67
|
+
{
|
|
68
|
+
"start": 起始行号,
|
|
69
|
+
"end": 结束行号,
|
|
70
|
+
"type": "If-Else Dispatcher" | "Switch Dispatcher" | "Instruction Array" | "Stack Operation",
|
|
71
|
+
"confidence": "ultra_high" | "high" | "medium" | "low",
|
|
72
|
+
"description": "详细描述(中文)"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
如果没有检测到 JSVMP 特征,返回空的 regions 数组。`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 创建 LLM 客户端实例
|
|
81
|
+
*/
|
|
82
|
+
export function createLLMClient(config) {
|
|
83
|
+
return {
|
|
84
|
+
async analyzeJSVMP(formattedCode) {
|
|
85
|
+
const systemPrompt = buildJSVMPSystemPrompt();
|
|
86
|
+
const requestBody = {
|
|
87
|
+
model: config.model,
|
|
88
|
+
messages: [
|
|
89
|
+
{
|
|
90
|
+
role: "system",
|
|
91
|
+
content: systemPrompt
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
role: "user",
|
|
95
|
+
content: `请分析以下代码,识别 JSVMP 保护结构:\n\n${formattedCode}`
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
temperature: 0.1,
|
|
99
|
+
response_format: { type: "json_object" }
|
|
100
|
+
};
|
|
101
|
+
try {
|
|
102
|
+
const response = await fetch(`${config.baseUrl}/chat/completions`, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: {
|
|
105
|
+
"Content-Type": "application/json",
|
|
106
|
+
"Authorization": `Bearer ${config.apiKey}`
|
|
107
|
+
},
|
|
108
|
+
body: JSON.stringify(requestBody)
|
|
109
|
+
});
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
const errorText = await response.text();
|
|
112
|
+
throw new Error(`API 请求失败 (${response.status}): ${errorText}`);
|
|
113
|
+
}
|
|
114
|
+
const data = await response.json();
|
|
115
|
+
if (!data.choices || !data.choices[0] || !data.choices[0].message) {
|
|
116
|
+
throw new Error("API 响应格式无效:缺少 choices 或 message 字段");
|
|
117
|
+
}
|
|
118
|
+
const content = data.choices[0].message.content;
|
|
119
|
+
if (typeof content !== "string") {
|
|
120
|
+
throw new Error("API 响应格式无效:message.content 不是字符串");
|
|
121
|
+
}
|
|
122
|
+
return content;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (error instanceof Error) {
|
|
126
|
+
throw new Error(`LLM 请求失败: ${error.message}`);
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`LLM 请求失败: ${String(error)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=llmConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmConfig.js","sourceRoot":"","sources":["../src/llmConfig.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reverse-craft/ai-tools",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI-powered code analysis tools - LLM-driven functionality for smart-fs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
17
|
+
"test": "vitest --run",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"ai",
|
|
22
|
+
"llm",
|
|
23
|
+
"openai",
|
|
24
|
+
"code-analysis",
|
|
25
|
+
"jsvmp",
|
|
26
|
+
"reverse-engineering",
|
|
27
|
+
"smart-fs"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/reverse-craft/ai-tools.git"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/reverse-craft/ai-tools#readme",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/reverse-craft/ai-tools/issues"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"source-map-js": "^1.2.1"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@reverse-craft/smart-fs": "^2.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@reverse-craft/smart-fs": "^2.0.0",
|
|
54
|
+
"@types/node": "^22.15.29",
|
|
55
|
+
"typescript": "^5.8.3",
|
|
56
|
+
"vitest": "^4.0.16"
|
|
57
|
+
}
|
|
58
|
+
}
|