@codesys/mcp-toolkit 1.1.3 → 1.2.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/.claude/settings.local.json +23 -0
- package/CHANGELOG.md +32 -26
- package/CLAUDE.md +26 -0
- package/CONTRIBUTING.md +72 -72
- package/LICENSE +21 -21
- package/README.md +152 -145
- package/README.md.enhanced +155 -155
- package/codesys-mcp-toolkit-1.2.0.tgz +0 -0
- package/dist/codesys_interop.js +29 -2
- package/dist/scriptLoader.js +158 -0
- package/dist/server.js +365 -1039
- package/dist/sessionManager.js +401 -0
- package/docs/index.md +26 -26
- package/docs/installation.md +84 -84
- package/docs/session_management.md +84 -0
- package/examples/README.md +78 -78
- package/examples/sample_config.json +32 -32
- package/package.json +50 -48
- package/scriptDoc.txt +8679 -8679
package/README.md.enhanced
CHANGED
|
@@ -1,155 +1,155 @@
|
|
|
1
|
-
# @codesys/mcp-toolkit
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-
|
|
6
|
-
A Model Context Protocol (MCP) server for CODESYS V3 programming environments. This toolkit enables seamless interaction between MCP clients (like Claude Desktop) and CODESYS, allowing automation of project management, POU creation, code editing, and compilation tasks.
|
|
7
|
-
|
|
8
|
-
<p align="center">
|
|
9
|
-
<img src="https://github.com/yourusername/codesys-mcp-toolkit/raw/main/docs/assets/diagram.png" alt="CODESYS MCP Toolkit Architecture" width="600">
|
|
10
|
-
</p>
|
|
11
|
-
|
|
12
|
-
## 🌟 Features
|
|
13
|
-
|
|
14
|
-
- **Project Management**
|
|
15
|
-
- Open existing CODESYS projects
|
|
16
|
-
- Create new projects from templates
|
|
17
|
-
- Save project changes
|
|
18
|
-
|
|
19
|
-
- **POU Management**
|
|
20
|
-
- Create Programs, Function Blocks, and Functions
|
|
21
|
-
- Set declaration and implementation code
|
|
22
|
-
- Create properties and methods for Function Blocks
|
|
23
|
-
- Compile projects
|
|
24
|
-
|
|
25
|
-
- **MCP Resources**
|
|
26
|
-
- `codesys://project/status`: Check scripting status and project state
|
|
27
|
-
- `codesys://project/{+project_path}/structure`: Retrieve project structure
|
|
28
|
-
- `codesys://project/{+project_path}/pou/{+pou_path}/code`: Read POU code
|
|
29
|
-
|
|
30
|
-
- **MCP Tools**
|
|
31
|
-
- `open_project`: Open specified CODESYS project
|
|
32
|
-
- `create_project`: Create new CODESYS project
|
|
33
|
-
- `save_project`: Save currently open project
|
|
34
|
-
- `create_pou`: Create new Program, Function Block, or Function
|
|
35
|
-
- `set_pou_code`: Update code for a specified POU
|
|
36
|
-
- `create_property`: Create property in a Function Block
|
|
37
|
-
- `create_method`: Create method in a Function Block
|
|
38
|
-
- `compile_project`: Compile the open project
|
|
39
|
-
|
|
40
|
-
## 📋 Prerequisites
|
|
41
|
-
|
|
42
|
-
- **CODESYS V3**: A working CODESYS V3 installation (tested with 3.5 SP21) with **Scripting Engine** component enabled
|
|
43
|
-
- **Node.js**: Version 18 or later required
|
|
44
|
-
- **MCP Client**: An MCP-enabled application (e.g., Claude Desktop)
|
|
45
|
-
|
|
46
|
-
## 🚀 Installation
|
|
47
|
-
|
|
48
|
-
### Option 1: Install from npm (Recommended)
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
npm install -g @codesys/mcp-toolkit
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
This installs the package globally, making the `codesys-mcp-toolkit` command available in your terminal.
|
|
55
|
-
|
|
56
|
-
### Option 2: Install from Source
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
# Clone the repository
|
|
60
|
-
git clone https://github.com/yourusername/codesys-mcp-toolkit.git
|
|
61
|
-
cd codesys-mcp-toolkit
|
|
62
|
-
|
|
63
|
-
# Install dependencies
|
|
64
|
-
npm install
|
|
65
|
-
|
|
66
|
-
# Build the project
|
|
67
|
-
npm run build
|
|
68
|
-
|
|
69
|
-
# Install globally
|
|
70
|
-
npm install -g .
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## 🔧 Configuration
|
|
74
|
-
|
|
75
|
-
### Claude Desktop Configuration
|
|
76
|
-
|
|
77
|
-
1. Locate your Claude Desktop configuration file:
|
|
78
|
-
- Windows: `C:\Users\<YourUsername>\AppData\Roaming\Claude\claude_desktop_config.json`
|
|
79
|
-
|
|
80
|
-
2. Add the CODESYS MCP server entry:
|
|
81
|
-
|
|
82
|
-
```json
|
|
83
|
-
{
|
|
84
|
-
"mcpServers": {
|
|
85
|
-
"codesys_local": {
|
|
86
|
-
"command": "npx",
|
|
87
|
-
"args": [
|
|
88
|
-
"-y",
|
|
89
|
-
"@codesys/mcp-toolkit",
|
|
90
|
-
"--codesys-path", "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\Common\\CODESYS.exe",
|
|
91
|
-
"--codesys-profile", "CODESYS V3.5 SP21"
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
3. Customize the paths to match your CODESYS installation:
|
|
99
|
-
- `--codesys-path`: Path to your CODESYS.exe
|
|
100
|
-
- `--codesys-profile`: Your CODESYS profile name
|
|
101
|
-
|
|
102
|
-
4. Restart Claude Desktop to apply the changes
|
|
103
|
-
|
|
104
|
-
## 🛠️ Usage Examples
|
|
105
|
-
|
|
106
|
-
### Creating a Function Block with Properties
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
Ask Claude: "Using the CODESYS Local server, please create a Motor Controller function block with Start and Stop methods, plus CurrentSpeed property."
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Claude will execute these MCP tool calls:
|
|
113
|
-
1. `create_pou` to create the MotorController Function Block
|
|
114
|
-
2. `create_property` to add the CurrentSpeed property
|
|
115
|
-
3. `create_method` to add Start and Stop methods
|
|
116
|
-
4. `set_pou_code` to implement each method and property
|
|
117
|
-
|
|
118
|
-
### Opening and Compiling a Project
|
|
119
|
-
|
|
120
|
-
```
|
|
121
|
-
Ask Claude: "Can you open the project at C:/MyProjects/TestProject.project using CODESYS Local and compile it?"
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Claude will:
|
|
125
|
-
1. Use `open_project` to open the specified file
|
|
126
|
-
2. Use `compile_project` to build the application
|
|
127
|
-
|
|
128
|
-
## 🔍 Troubleshooting
|
|
129
|
-
|
|
130
|
-
### Common Issues
|
|
131
|
-
|
|
132
|
-
- **Connection Failures**: Check Claude Desktop logs for error messages
|
|
133
|
-
- **Path Issues**: Ensure CODESYS executable path is correct
|
|
134
|
-
- **Profile Mismatch**: Verify profile name matches exactly
|
|
135
|
-
- **Permission Problems**: Ensure Claude has appropriate permissions
|
|
136
|
-
- **CODESYS Already Running**: Close other CODESYS instances
|
|
137
|
-
|
|
138
|
-
### Debug Logs
|
|
139
|
-
|
|
140
|
-
Check logs at:
|
|
141
|
-
- Windows: `C:\Users\<YourUsername>\AppData\Roaming\Claude\logs\`
|
|
142
|
-
|
|
143
|
-
## 🤝 Contributing
|
|
144
|
-
|
|
145
|
-
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
146
|
-
|
|
147
|
-
## 📝 License
|
|
148
|
-
|
|
149
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
150
|
-
|
|
151
|
-
## 🙏 Acknowledgements
|
|
152
|
-
|
|
153
|
-
- The [CODESYS](https://www.codesys.com/) team for their scripting engine
|
|
154
|
-
- [Model Context Protocol](https://github.com/m-ld/model-context-protocol) project
|
|
155
|
-
- All contributors who have helped improve this toolkit
|
|
1
|
+
# @codesys/mcp-toolkit
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
A Model Context Protocol (MCP) server for CODESYS V3 programming environments. This toolkit enables seamless interaction between MCP clients (like Claude Desktop) and CODESYS, allowing automation of project management, POU creation, code editing, and compilation tasks.
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<img src="https://github.com/yourusername/codesys-mcp-toolkit/raw/main/docs/assets/diagram.png" alt="CODESYS MCP Toolkit Architecture" width="600">
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
## 🌟 Features
|
|
13
|
+
|
|
14
|
+
- **Project Management**
|
|
15
|
+
- Open existing CODESYS projects
|
|
16
|
+
- Create new projects from templates
|
|
17
|
+
- Save project changes
|
|
18
|
+
|
|
19
|
+
- **POU Management**
|
|
20
|
+
- Create Programs, Function Blocks, and Functions
|
|
21
|
+
- Set declaration and implementation code
|
|
22
|
+
- Create properties and methods for Function Blocks
|
|
23
|
+
- Compile projects
|
|
24
|
+
|
|
25
|
+
- **MCP Resources**
|
|
26
|
+
- `codesys://project/status`: Check scripting status and project state
|
|
27
|
+
- `codesys://project/{+project_path}/structure`: Retrieve project structure
|
|
28
|
+
- `codesys://project/{+project_path}/pou/{+pou_path}/code`: Read POU code
|
|
29
|
+
|
|
30
|
+
- **MCP Tools**
|
|
31
|
+
- `open_project`: Open specified CODESYS project
|
|
32
|
+
- `create_project`: Create new CODESYS project
|
|
33
|
+
- `save_project`: Save currently open project
|
|
34
|
+
- `create_pou`: Create new Program, Function Block, or Function
|
|
35
|
+
- `set_pou_code`: Update code for a specified POU
|
|
36
|
+
- `create_property`: Create property in a Function Block
|
|
37
|
+
- `create_method`: Create method in a Function Block
|
|
38
|
+
- `compile_project`: Compile the open project
|
|
39
|
+
|
|
40
|
+
## 📋 Prerequisites
|
|
41
|
+
|
|
42
|
+
- **CODESYS V3**: A working CODESYS V3 installation (tested with 3.5 SP21) with **Scripting Engine** component enabled
|
|
43
|
+
- **Node.js**: Version 18 or later required
|
|
44
|
+
- **MCP Client**: An MCP-enabled application (e.g., Claude Desktop)
|
|
45
|
+
|
|
46
|
+
## 🚀 Installation
|
|
47
|
+
|
|
48
|
+
### Option 1: Install from npm (Recommended)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g @codesys/mcp-toolkit
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This installs the package globally, making the `codesys-mcp-toolkit` command available in your terminal.
|
|
55
|
+
|
|
56
|
+
### Option 2: Install from Source
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Clone the repository
|
|
60
|
+
git clone https://github.com/yourusername/codesys-mcp-toolkit.git
|
|
61
|
+
cd codesys-mcp-toolkit
|
|
62
|
+
|
|
63
|
+
# Install dependencies
|
|
64
|
+
npm install
|
|
65
|
+
|
|
66
|
+
# Build the project
|
|
67
|
+
npm run build
|
|
68
|
+
|
|
69
|
+
# Install globally
|
|
70
|
+
npm install -g .
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 🔧 Configuration
|
|
74
|
+
|
|
75
|
+
### Claude Desktop Configuration
|
|
76
|
+
|
|
77
|
+
1. Locate your Claude Desktop configuration file:
|
|
78
|
+
- Windows: `C:\Users\<YourUsername>\AppData\Roaming\Claude\claude_desktop_config.json`
|
|
79
|
+
|
|
80
|
+
2. Add the CODESYS MCP server entry:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"mcpServers": {
|
|
85
|
+
"codesys_local": {
|
|
86
|
+
"command": "npx",
|
|
87
|
+
"args": [
|
|
88
|
+
"-y",
|
|
89
|
+
"@codesys/mcp-toolkit",
|
|
90
|
+
"--codesys-path", "C:\\Program Files\\CODESYS 3.5.21.0\\CODESYS\\Common\\CODESYS.exe",
|
|
91
|
+
"--codesys-profile", "CODESYS V3.5 SP21"
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
3. Customize the paths to match your CODESYS installation:
|
|
99
|
+
- `--codesys-path`: Path to your CODESYS.exe
|
|
100
|
+
- `--codesys-profile`: Your CODESYS profile name
|
|
101
|
+
|
|
102
|
+
4. Restart Claude Desktop to apply the changes
|
|
103
|
+
|
|
104
|
+
## 🛠️ Usage Examples
|
|
105
|
+
|
|
106
|
+
### Creating a Function Block with Properties
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Ask Claude: "Using the CODESYS Local server, please create a Motor Controller function block with Start and Stop methods, plus CurrentSpeed property."
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Claude will execute these MCP tool calls:
|
|
113
|
+
1. `create_pou` to create the MotorController Function Block
|
|
114
|
+
2. `create_property` to add the CurrentSpeed property
|
|
115
|
+
3. `create_method` to add Start and Stop methods
|
|
116
|
+
4. `set_pou_code` to implement each method and property
|
|
117
|
+
|
|
118
|
+
### Opening and Compiling a Project
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Ask Claude: "Can you open the project at C:/MyProjects/TestProject.project using CODESYS Local and compile it?"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Claude will:
|
|
125
|
+
1. Use `open_project` to open the specified file
|
|
126
|
+
2. Use `compile_project` to build the application
|
|
127
|
+
|
|
128
|
+
## 🔍 Troubleshooting
|
|
129
|
+
|
|
130
|
+
### Common Issues
|
|
131
|
+
|
|
132
|
+
- **Connection Failures**: Check Claude Desktop logs for error messages
|
|
133
|
+
- **Path Issues**: Ensure CODESYS executable path is correct
|
|
134
|
+
- **Profile Mismatch**: Verify profile name matches exactly
|
|
135
|
+
- **Permission Problems**: Ensure Claude has appropriate permissions
|
|
136
|
+
- **CODESYS Already Running**: Close other CODESYS instances
|
|
137
|
+
|
|
138
|
+
### Debug Logs
|
|
139
|
+
|
|
140
|
+
Check logs at:
|
|
141
|
+
- Windows: `C:\Users\<YourUsername>\AppData\Roaming\Claude\logs\`
|
|
142
|
+
|
|
143
|
+
## 🤝 Contributing
|
|
144
|
+
|
|
145
|
+
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
146
|
+
|
|
147
|
+
## 📝 License
|
|
148
|
+
|
|
149
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
150
|
+
|
|
151
|
+
## 🙏 Acknowledgements
|
|
152
|
+
|
|
153
|
+
- The [CODESYS](https://www.codesys.com/) team for their scripting engine
|
|
154
|
+
- [Model Context Protocol](https://github.com/m-ld/model-context-protocol) project
|
|
155
|
+
- All contributors who have helped improve this toolkit
|
|
Binary file
|
package/dist/codesys_interop.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - Creating temporary Python script files
|
|
8
8
|
* - Executing them via CODESYS's scripting engine
|
|
9
9
|
* - Capturing and processing results
|
|
10
|
+
* - Supporting both one-off script execution and persistent sessions
|
|
10
11
|
*
|
|
11
12
|
* IMPORTANT: Path handling for Windows is critical - paths with spaces require
|
|
12
13
|
* special handling to avoid the 'C:\Program' not recognized error.
|
|
@@ -60,6 +61,8 @@ const promises_1 = require("fs/promises");
|
|
|
60
61
|
const path = __importStar(require("path"));
|
|
61
62
|
const os = __importStar(require("os"));
|
|
62
63
|
const fs = __importStar(require("fs")); // Import fs for existsSync check
|
|
64
|
+
// Optional import for session manager
|
|
65
|
+
const sessionManager_1 = require("./sessionManager");
|
|
63
66
|
// Define expected success/error markers from the Python scripts
|
|
64
67
|
const SCRIPT_SUCCESS_MARKER = 'SCRIPT_SUCCESS';
|
|
65
68
|
const SCRIPT_ERROR_MARKER = 'SCRIPT_ERROR';
|
|
@@ -69,12 +72,13 @@ const SCRIPT_ERROR_MARKER = 'SCRIPT_ERROR';
|
|
|
69
72
|
* @param scriptContent The Python script code to execute.
|
|
70
73
|
* @param codesysExePath The full path to the CODESYS.exe executable (can contain spaces).
|
|
71
74
|
* @param codesysProfileName The name of the CODESYS profile to use for scripting.
|
|
75
|
+
* @param sessionManager Optional session manager for persistent session execution
|
|
72
76
|
* @returns A promise resolving to an object containing the success status and the script's output.
|
|
73
77
|
*
|
|
74
78
|
* NOTE: Using shell: true with careful command string quoting to handle
|
|
75
79
|
* CODESYS argument parsing quirks when launched non-interactively.
|
|
76
80
|
*/
|
|
77
|
-
function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName) {
|
|
81
|
+
function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName, sessionManager) {
|
|
78
82
|
return __awaiter(this, void 0, void 0, function* () {
|
|
79
83
|
// --- Pre-checks ---
|
|
80
84
|
if (!codesysExePath)
|
|
@@ -84,6 +88,29 @@ function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName)
|
|
|
84
88
|
if (!fs.existsSync(codesysExePath))
|
|
85
89
|
throw new Error(`CODESYS executable not found at provided path: ${codesysExePath}`);
|
|
86
90
|
// --- End Pre-checks ---
|
|
91
|
+
// --- Check if we should use the persistent session ---
|
|
92
|
+
if (sessionManager) {
|
|
93
|
+
const sessionState = sessionManager.getState();
|
|
94
|
+
if (sessionState === sessionManager_1.SessionState.RUNNING || sessionState === sessionManager_1.SessionState.BUSY) {
|
|
95
|
+
process.stderr.write(`INTEROP: Using persistent session for script execution\n`);
|
|
96
|
+
try {
|
|
97
|
+
const result = yield sessionManager.executeScript(scriptContent);
|
|
98
|
+
return {
|
|
99
|
+
success: result.success,
|
|
100
|
+
output: result.output
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
process.stderr.write(`INTEROP: Error executing script in persistent session: ${error.message}\n`);
|
|
105
|
+
process.stderr.write(`INTEROP: Falling back to one-time execution mode\n`);
|
|
106
|
+
// Continue with the non-persistent approach as fallback
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
process.stderr.write(`INTEROP: Session not in RUNNING/BUSY state (current: ${sessionState}). Using one-time execution.\n`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// --- Standard one-time script execution ---
|
|
87
114
|
const tempDir = os.tmpdir();
|
|
88
115
|
const tempFileName = `codesys_script_${Date.now()}_${Math.random().toString(36).substring(2, 9)}.py`;
|
|
89
116
|
const tempFilePath = path.join(tempDir, tempFileName); // Path module uses OS-specific separators ('\' on Windows)
|
|
@@ -118,7 +145,7 @@ function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName)
|
|
|
118
145
|
process.stderr.write(`INTEROP ENV: Forcing CWD for spawn: ${codesysDir}\n`); // Re-enabled CWD change
|
|
119
146
|
// --- Create modified environment (Re-enabled) ---
|
|
120
147
|
const spawnEnv = Object.assign({}, process.env);
|
|
121
|
-
const pathSeparator = ';'
|
|
148
|
+
const pathSeparator = os.platform() === 'win32' ? ';' : ':';
|
|
122
149
|
const originalPath = spawnEnv.PATH || '';
|
|
123
150
|
spawnEnv.PATH = `${codesysDir}${pathSeparator}${originalPath}`; // Prepend CODESYS dir to PATH
|
|
124
151
|
process.stderr.write(`INTEROP ENV: MODIFIED PATH for spawn (prepended): ${spawnEnv.PATH.substring(0, 100)}...\n`); // Re-enabled ENV change
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Script Loader Module
|
|
4
|
+
* Centralizes loading and management of Python script templates
|
|
5
|
+
*
|
|
6
|
+
* This module:
|
|
7
|
+
* - Loads script templates from the /scripts directory
|
|
8
|
+
* - Provides script template interpolation functions
|
|
9
|
+
* - Manages script parameter substitution
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
45
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
46
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
47
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
48
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
49
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
50
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.loadScriptTemplate = loadScriptTemplate;
|
|
55
|
+
exports.loadScriptTemplateSync = loadScriptTemplateSync;
|
|
56
|
+
exports.interpolateScript = interpolateScript;
|
|
57
|
+
exports.combineScripts = combineScripts;
|
|
58
|
+
exports.preloadAllScriptTemplates = preloadAllScriptTemplates;
|
|
59
|
+
const fs = __importStar(require("fs"));
|
|
60
|
+
const path = __importStar(require("path"));
|
|
61
|
+
const util_1 = require("util");
|
|
62
|
+
const readFileAsync = (0, util_1.promisify)(fs.readFile);
|
|
63
|
+
const SCRIPTS_DIR = path.join(__dirname, 'scripts');
|
|
64
|
+
// Cache for loaded scripts to avoid repeated file system access
|
|
65
|
+
const scriptCache = {};
|
|
66
|
+
/**
|
|
67
|
+
* Loads a script template from the scripts directory
|
|
68
|
+
* @param scriptName The name of the script file (without .py extension)
|
|
69
|
+
* @returns The script content as a string
|
|
70
|
+
*/
|
|
71
|
+
function loadScriptTemplate(scriptName) {
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
// Add .py extension if not provided
|
|
74
|
+
const fileName = scriptName.endsWith('.py') ? scriptName : `${scriptName}.py`;
|
|
75
|
+
const filePath = path.join(SCRIPTS_DIR, fileName);
|
|
76
|
+
// Return from cache if available
|
|
77
|
+
if (scriptCache[fileName]) {
|
|
78
|
+
return scriptCache[fileName];
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const content = yield readFileAsync(filePath, 'utf8');
|
|
82
|
+
// Store in cache for future use
|
|
83
|
+
scriptCache[fileName] = content;
|
|
84
|
+
return content;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw new Error(`Failed to load script template '${fileName}': ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Loads a script template synchronously (for use during startup)
|
|
93
|
+
* @param scriptName The name of the script file (without .py extension)
|
|
94
|
+
* @returns The script content as a string
|
|
95
|
+
*/
|
|
96
|
+
function loadScriptTemplateSync(scriptName) {
|
|
97
|
+
// Add .py extension if not provided
|
|
98
|
+
const fileName = scriptName.endsWith('.py') ? scriptName : `${scriptName}.py`;
|
|
99
|
+
const filePath = path.join(SCRIPTS_DIR, fileName);
|
|
100
|
+
// Return from cache if available
|
|
101
|
+
if (scriptCache[fileName]) {
|
|
102
|
+
return scriptCache[fileName];
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
106
|
+
// Store in cache for future use
|
|
107
|
+
scriptCache[fileName] = content;
|
|
108
|
+
return content;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
throw new Error(`Failed to load script template '${fileName}': ${error.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Interpolates parameters into a script template
|
|
116
|
+
* @param template The script template string
|
|
117
|
+
* @param params Object containing parameter names and values
|
|
118
|
+
* @returns The script with parameter values substituted
|
|
119
|
+
*/
|
|
120
|
+
function interpolateScript(template, params) {
|
|
121
|
+
let result = template;
|
|
122
|
+
// Replace each parameter in the template
|
|
123
|
+
for (const [key, value] of Object.entries(params)) {
|
|
124
|
+
// Convert value to string and escape backslashes for Python
|
|
125
|
+
const escapedValue = String(value).replace(/\\/g, '\\\\');
|
|
126
|
+
// Replace {PARAM_NAME} with the escaped value
|
|
127
|
+
const paramPattern = new RegExp(`\\{${key}\\}`, 'g');
|
|
128
|
+
result = result.replace(paramPattern, escapedValue);
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Combines multiple script fragments with proper indentation
|
|
134
|
+
* @param scripts Object containing named script fragments
|
|
135
|
+
* @returns Combined script content
|
|
136
|
+
*/
|
|
137
|
+
function combineScripts(scripts) {
|
|
138
|
+
return Object.values(scripts).join('\n\n');
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Load all script templates from the scripts directory
|
|
142
|
+
* This is useful during development to preload the cache
|
|
143
|
+
*/
|
|
144
|
+
function preloadAllScriptTemplates() {
|
|
145
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
try {
|
|
147
|
+
const files = fs.readdirSync(SCRIPTS_DIR);
|
|
148
|
+
for (const file of files) {
|
|
149
|
+
if (file.endsWith('.py')) {
|
|
150
|
+
yield loadScriptTemplate(file);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
console.error(`Failed to preload script templates: ${error.message}`);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|