@codesys/mcp-toolkit 1.5.8 → 2.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/CHANGELOG.md +153 -189
- package/LICENSE +21 -21
- package/README.md +269 -152
- package/dist/actions.d.ts +28 -0
- package/dist/actions.js +98 -0
- package/dist/actions.js.map +1 -0
- package/dist/bridge/bridge.d.ts +105 -0
- package/dist/bridge/bridge.js +400 -0
- package/dist/bridge/bridge.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/codesys/cache.d.ts +48 -0
- package/dist/codesys/cache.js +82 -0
- package/dist/codesys/cache.js.map +1 -0
- package/dist/codesys/changes.d.ts +57 -0
- package/dist/codesys/changes.js +133 -0
- package/dist/codesys/changes.js.map +1 -0
- package/dist/codesys/decl.d.ts +45 -0
- package/dist/codesys/decl.js +251 -0
- package/dist/codesys/decl.js.map +1 -0
- package/dist/codesys/devices.d.ts +34 -0
- package/dist/codesys/devices.js +82 -0
- package/dist/codesys/devices.js.map +1 -0
- package/dist/codesys/diff.d.ts +13 -0
- package/dist/codesys/diff.js +61 -0
- package/dist/codesys/diff.js.map +1 -0
- package/dist/codesys/install.d.ts +40 -0
- package/dist/codesys/install.js +144 -0
- package/dist/codesys/install.js.map +1 -0
- package/dist/codesys/library-browse.d.ts +19 -0
- package/dist/codesys/library-browse.js +57 -0
- package/dist/codesys/library-browse.js.map +1 -0
- package/dist/codesys/outline.d.ts +32 -0
- package/dist/codesys/outline.js +219 -0
- package/dist/codesys/outline.js.map +1 -0
- package/dist/codesys/simulation.d.ts +34 -0
- package/dist/codesys/simulation.js +57 -0
- package/dist/codesys/simulation.js.map +1 -0
- package/dist/codesys/st.d.ts +36 -0
- package/dist/codesys/st.js +69 -0
- package/dist/codesys/st.js.map +1 -0
- package/dist/daemon.d.ts +46 -0
- package/dist/daemon.js +173 -0
- package/dist/daemon.js.map +1 -0
- package/dist/driver.d.ts +25 -0
- package/dist/driver.js +33 -0
- package/dist/driver.js.map +1 -0
- package/dist/panel/sim-panel.html +357 -0
- package/dist/panel/viewer.html +126 -0
- package/dist/panel-types.d.ts +20 -0
- package/dist/panel-types.js +3 -0
- package/dist/panel-types.js.map +1 -0
- package/dist/panel.d.ts +27 -0
- package/dist/panel.js +208 -0
- package/dist/panel.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +33 -974
- package/dist/server.js.map +1 -0
- package/dist/tools.d.ts +103 -0
- package/dist/tools.js +793 -0
- package/dist/tools.js.map +1 -0
- package/dist/viewer.d.ts +14 -0
- package/dist/viewer.js +125 -0
- package/dist/viewer.js.map +1 -0
- package/package.json +66 -51
- package/watcher/mcp_compat.py +147 -0
- package/watcher/mcp_ops.py +1178 -0
- package/watcher/mcp_sim.py +246 -0
- package/watcher/watcher.py +255 -0
- package/.claude/settings.local.json +0 -29
- package/CLAUDE.md +0 -26
- package/CONTRIBUTING.md +0 -72
- package/README.md.enhanced +0 -155
- package/codesys-mcp-toolkit-1.2.0.tgz +0 -0
- package/codesys-mcp-toolkit-1.2.1.tgz +0 -0
- package/codesys-mcp-toolkit-1.5.7.tgz +0 -0
- package/codesys-mcp-toolkit-1.5.8.tgz +0 -0
- package/dist/bin.js +0 -75
- package/dist/check_session_paths.js +0 -149
- package/dist/codesys_interop.js +0 -435
- package/dist/direct_session_command.js +0 -293
- package/dist/scriptLoader.js +0 -165
- package/dist/scripts/check_status.py +0 -21
- package/dist/scripts/compile_project.py +0 -65
- package/dist/scripts/create_method.py +0 -80
- package/dist/scripts/create_pou.py +0 -102
- package/dist/scripts/create_project.py +0 -116
- package/dist/scripts/create_property.py +0 -78
- package/dist/scripts/ensure_project_open.py +0 -154
- package/dist/scripts/find_object_by_path.py +0 -111
- package/dist/scripts/get_pou_code.py +0 -91
- package/dist/scripts/get_project_structure.py +0 -72
- package/dist/scripts/open_project.py +0 -25
- package/dist/scripts/save_project.py +0 -29
- package/dist/scripts/session_status.py +0 -281
- package/dist/scripts/set_pou_code.py +0 -109
- package/dist/scripts/start_session.py +0 -809
- package/dist/scripts/stop_session.py +0 -324
- package/dist/sessionManager.js +0 -798
- package/docs/configuration.md +0 -141
- package/docs/index.md +0 -26
- package/docs/installation.md +0 -84
- package/docs/session_management.md +0 -110
- package/examples/README.md +0 -78
- package/examples/sample_config.json +0 -32
- package/replacements_session_status.txt +0 -16
- package/scriptDoc.txt +0 -8679
- package/scripts/build.js +0 -25
- package/scripts/fix_fstrings.py +0 -76
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Direct Session Command Tool
|
|
4
|
-
*
|
|
5
|
-
* This file provides functions to directly interact with a CODESYS session
|
|
6
|
-
* by writing to the command.json file and reading from the result.json file.
|
|
7
|
-
*
|
|
8
|
-
* This is an alternative approach to the standard session management.
|
|
9
|
-
*/
|
|
10
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
-
}
|
|
16
|
-
Object.defineProperty(o, k2, desc);
|
|
17
|
-
}) : (function(o, m, k, k2) {
|
|
18
|
-
if (k2 === undefined) k2 = k;
|
|
19
|
-
o[k2] = m[k];
|
|
20
|
-
}));
|
|
21
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
-
}) : function(o, v) {
|
|
24
|
-
o["default"] = v;
|
|
25
|
-
});
|
|
26
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
-
var ownKeys = function(o) {
|
|
28
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
-
var ar = [];
|
|
30
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
-
return ar;
|
|
32
|
-
};
|
|
33
|
-
return ownKeys(o);
|
|
34
|
-
};
|
|
35
|
-
return function (mod) {
|
|
36
|
-
if (mod && mod.__esModule) return mod;
|
|
37
|
-
var result = {};
|
|
38
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
-
__setModuleDefault(result, mod);
|
|
40
|
-
return result;
|
|
41
|
-
};
|
|
42
|
-
})();
|
|
43
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
44
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
45
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
46
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
47
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
48
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
49
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
-
exports.isSessionActive = isSessionActive;
|
|
54
|
-
exports.executeScriptDirect = executeScriptDirect;
|
|
55
|
-
exports.createProjectDirect = createProjectDirect;
|
|
56
|
-
const fs = __importStar(require("fs"));
|
|
57
|
-
const path = __importStar(require("path"));
|
|
58
|
-
const os = __importStar(require("os"));
|
|
59
|
-
const uuid_1 = require("uuid");
|
|
60
|
-
// Session directory and file names
|
|
61
|
-
const SESSION_DIR = path.join(os.tmpdir(), 'codesys_session');
|
|
62
|
-
const COMMAND_FILE = path.join(SESSION_DIR, 'command.json');
|
|
63
|
-
const RESULT_FILE = path.join(SESSION_DIR, 'result.json');
|
|
64
|
-
const SESSION_LOCK_FILE = path.join(SESSION_DIR, 'session.lock');
|
|
65
|
-
const STATE_FILE = path.join(SESSION_DIR, 'session_state.json');
|
|
66
|
-
/**
|
|
67
|
-
* Check if a session is active by looking for the lock file
|
|
68
|
-
* @returns True if a session appears to be active
|
|
69
|
-
*/
|
|
70
|
-
function isSessionActive() {
|
|
71
|
-
try {
|
|
72
|
-
// Log the paths we're checking to help with debugging
|
|
73
|
-
console.error(`DIRECT_SESSION: Checking for active session...`);
|
|
74
|
-
console.error(`DIRECT_SESSION: SESSION_DIR: ${SESSION_DIR}`);
|
|
75
|
-
console.error(`DIRECT_SESSION: SESSION_LOCK_FILE: ${SESSION_LOCK_FILE}`);
|
|
76
|
-
console.error(`DIRECT_SESSION: COMMAND_FILE: ${COMMAND_FILE}`);
|
|
77
|
-
// Check if session directory exists
|
|
78
|
-
if (!fs.existsSync(SESSION_DIR)) {
|
|
79
|
-
console.error(`DIRECT_SESSION: SESSION_DIR doesn't exist: ${SESSION_DIR}`);
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
// Check if lock file exists
|
|
83
|
-
if (!fs.existsSync(SESSION_LOCK_FILE)) {
|
|
84
|
-
console.error(`DIRECT_SESSION: SESSION_LOCK_FILE doesn't exist: ${SESSION_LOCK_FILE}`);
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
// Check if command file exists
|
|
88
|
-
if (!fs.existsSync(COMMAND_FILE)) {
|
|
89
|
-
console.error(`DIRECT_SESSION: COMMAND_FILE doesn't exist: ${COMMAND_FILE}`);
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
// Read the lock file to check age
|
|
93
|
-
const lockFileContent = fs.readFileSync(SESSION_LOCK_FILE, 'utf8');
|
|
94
|
-
const lockTime = parseFloat(lockFileContent);
|
|
95
|
-
const currentTime = Date.now() / 1000; // convert to seconds
|
|
96
|
-
const lockAgeSeconds = currentTime - lockTime;
|
|
97
|
-
console.error(`DIRECT_SESSION: Lock file age: ${lockAgeSeconds.toFixed(1)} seconds`);
|
|
98
|
-
// If lock is too old, session might be dead
|
|
99
|
-
if (lockAgeSeconds > 30) {
|
|
100
|
-
console.error(`DIRECT_SESSION: Session lock file is too old (${lockAgeSeconds.toFixed(1)} seconds)`);
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
// Try to read the command file to verify it's in the expected format
|
|
104
|
-
try {
|
|
105
|
-
const commandContent = fs.readFileSync(COMMAND_FILE, 'utf8');
|
|
106
|
-
const commandData = JSON.parse(commandContent);
|
|
107
|
-
console.error(`DIRECT_SESSION: Command file status: ${commandData.status}`);
|
|
108
|
-
}
|
|
109
|
-
catch (cmdError) {
|
|
110
|
-
console.error(`DIRECT_SESSION: Error parsing command file: ${cmdError}`);
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
console.error(`DIRECT_SESSION: Session appears to be active`);
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
console.error(`DIRECT_SESSION: Error checking session: ${error}`);
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Execute a script by directly writing to the command.json file
|
|
123
|
-
* @param scriptContent The Python script to execute
|
|
124
|
-
* @param timeoutMs Timeout in milliseconds
|
|
125
|
-
* @returns Promise that resolves to the script result
|
|
126
|
-
*/
|
|
127
|
-
function executeScriptDirect(scriptContent_1) {
|
|
128
|
-
return __awaiter(this, arguments, void 0, function* (scriptContent, timeoutMs = 60000) {
|
|
129
|
-
if (!isSessionActive()) {
|
|
130
|
-
throw new Error('No active session found');
|
|
131
|
-
}
|
|
132
|
-
// Generate a unique ID for this execution
|
|
133
|
-
const scriptId = (0, uuid_1.v4)();
|
|
134
|
-
// Create command data
|
|
135
|
-
const commandData = {
|
|
136
|
-
status: "pending",
|
|
137
|
-
command: {
|
|
138
|
-
id: scriptId,
|
|
139
|
-
type: "execute_script",
|
|
140
|
-
script: scriptContent,
|
|
141
|
-
timestamp: Date.now()
|
|
142
|
-
},
|
|
143
|
-
timestamp: Date.now()
|
|
144
|
-
};
|
|
145
|
-
console.error(`DIRECT_SESSION: Writing command to ${COMMAND_FILE}`);
|
|
146
|
-
console.error(`DIRECT_SESSION: Command data: ${JSON.stringify(commandData)}`);
|
|
147
|
-
try {
|
|
148
|
-
// Write command to file
|
|
149
|
-
fs.writeFileSync(COMMAND_FILE, JSON.stringify(commandData, null, 2));
|
|
150
|
-
console.error(`DIRECT_SESSION: Command written to file`);
|
|
151
|
-
// Verify the file was written correctly
|
|
152
|
-
try {
|
|
153
|
-
const verifyContent = fs.readFileSync(COMMAND_FILE, 'utf8');
|
|
154
|
-
console.error(`DIRECT_SESSION: Verification - Command file now contains: ${verifyContent.substring(0, 100)}...`);
|
|
155
|
-
}
|
|
156
|
-
catch (verifyErr) {
|
|
157
|
-
console.error(`DIRECT_SESSION: Verification failed - could not read command file: ${verifyErr}`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch (writeErr) {
|
|
161
|
-
console.error(`DIRECT_SESSION: ERROR writing command file: ${writeErr}`);
|
|
162
|
-
throw writeErr; // Re-throw to propagate the error
|
|
163
|
-
}
|
|
164
|
-
// Poll for result
|
|
165
|
-
return new Promise((resolve, reject) => {
|
|
166
|
-
let pollCount = 0;
|
|
167
|
-
const pollInterval = setInterval(() => {
|
|
168
|
-
pollCount++;
|
|
169
|
-
try {
|
|
170
|
-
// Check if result file exists
|
|
171
|
-
if (!fs.existsSync(RESULT_FILE)) {
|
|
172
|
-
if (pollCount % 10 === 0) {
|
|
173
|
-
console.error(`DIRECT_SESSION: Result file not found at ${RESULT_FILE} (poll ${pollCount})`);
|
|
174
|
-
}
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
// Read result file
|
|
178
|
-
const resultContent = fs.readFileSync(RESULT_FILE, 'utf8');
|
|
179
|
-
try {
|
|
180
|
-
const resultData = JSON.parse(resultContent);
|
|
181
|
-
// Check if the result is complete and for our script
|
|
182
|
-
if (resultData.status === 'complete' && resultData.result) {
|
|
183
|
-
const result = resultData.result;
|
|
184
|
-
if (result.id === scriptId) {
|
|
185
|
-
console.error(`DIRECT_SESSION: Found result for script ${scriptId}`);
|
|
186
|
-
// Clear interval
|
|
187
|
-
clearInterval(pollInterval);
|
|
188
|
-
// Resolve with the result
|
|
189
|
-
resolve({
|
|
190
|
-
success: result.success,
|
|
191
|
-
output: result.output
|
|
192
|
-
});
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
catch (parseError) {
|
|
198
|
-
console.error(`DIRECT_SESSION: Error parsing result data: ${parseError}`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
console.error(`DIRECT_SESSION: Error reading result file: ${error}`);
|
|
203
|
-
}
|
|
204
|
-
}, 100);
|
|
205
|
-
// Set timeout
|
|
206
|
-
setTimeout(() => {
|
|
207
|
-
clearInterval(pollInterval);
|
|
208
|
-
reject(new Error(`Script execution timed out after ${timeoutMs}ms`));
|
|
209
|
-
}, timeoutMs);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Create a project using a session
|
|
215
|
-
* @param targetProjectPath Full path to the project to create
|
|
216
|
-
* @param templateProjectPath Path to the template project
|
|
217
|
-
* @returns Promise that resolves when the project is created
|
|
218
|
-
*/
|
|
219
|
-
function createProjectDirect(targetProjectPath, templateProjectPath) {
|
|
220
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
221
|
-
try {
|
|
222
|
-
if (!isSessionActive()) {
|
|
223
|
-
throw new Error('No active session found');
|
|
224
|
-
}
|
|
225
|
-
// Normalize paths for cross-platform compatibility
|
|
226
|
-
const normalizedTargetPath = targetProjectPath.replace(/\\/g, '/');
|
|
227
|
-
const normalizedTemplatePath = templateProjectPath.replace(/\\/g, '/');
|
|
228
|
-
// Create a simplified project creation script that only copies the file and doesn't try to open it
|
|
229
|
-
const simpleProjectCreationScript = `
|
|
230
|
-
import sys, os, shutil, time, traceback
|
|
231
|
-
|
|
232
|
-
TEMPLATE_PROJECT_PATH = '${normalizedTemplatePath}'
|
|
233
|
-
PROJECT_FILE_PATH = '${normalizedTargetPath}'
|
|
234
|
-
|
|
235
|
-
print("Direct project creation script")
|
|
236
|
-
print(" Template: %s" % TEMPLATE_PROJECT_PATH)
|
|
237
|
-
print(" Target: %s" % PROJECT_FILE_PATH)
|
|
238
|
-
|
|
239
|
-
try:
|
|
240
|
-
# Ensure the target directory exists
|
|
241
|
-
target_dir = os.path.dirname(PROJECT_FILE_PATH)
|
|
242
|
-
if not os.path.exists(target_dir):
|
|
243
|
-
print("Creating target directory: %s" % target_dir)
|
|
244
|
-
os.makedirs(target_dir)
|
|
245
|
-
|
|
246
|
-
# Check if template exists
|
|
247
|
-
if not os.path.exists(TEMPLATE_PROJECT_PATH):
|
|
248
|
-
print("ERROR: Template project not found: %s" % TEMPLATE_PROJECT_PATH)
|
|
249
|
-
print("SCRIPT_ERROR: Template project not found")
|
|
250
|
-
sys.exit(1)
|
|
251
|
-
|
|
252
|
-
# Copy the template to the target
|
|
253
|
-
print("Copying template to target...")
|
|
254
|
-
shutil.copy2(TEMPLATE_PROJECT_PATH, PROJECT_FILE_PATH)
|
|
255
|
-
|
|
256
|
-
# Verify the file was created
|
|
257
|
-
if os.path.exists(PROJECT_FILE_PATH):
|
|
258
|
-
print("Project file created successfully: %s" % PROJECT_FILE_PATH)
|
|
259
|
-
print("File size: %d bytes" % os.path.getsize(PROJECT_FILE_PATH))
|
|
260
|
-
print("SCRIPT_SUCCESS: Project file created successfully")
|
|
261
|
-
else:
|
|
262
|
-
print("ERROR: Failed to create project file")
|
|
263
|
-
print("SCRIPT_ERROR: Failed to create project file")
|
|
264
|
-
sys.exit(1)
|
|
265
|
-
except Exception as e:
|
|
266
|
-
print("ERROR: %s" % e)
|
|
267
|
-
traceback.print_exc()
|
|
268
|
-
print("SCRIPT_ERROR: %s" % e)
|
|
269
|
-
sys.exit(1)
|
|
270
|
-
`;
|
|
271
|
-
// Execute the script directly
|
|
272
|
-
const result = yield executeScriptDirect(simpleProjectCreationScript, 120000);
|
|
273
|
-
if (result.success) {
|
|
274
|
-
return {
|
|
275
|
-
success: true,
|
|
276
|
-
message: `Project created successfully at ${targetProjectPath}`
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
return {
|
|
281
|
-
success: false,
|
|
282
|
-
message: `Failed to create project: ${result.output}`
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
catch (error) {
|
|
287
|
-
return {
|
|
288
|
-
success: false,
|
|
289
|
-
message: `Error: ${error.message}`
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
}
|
package/dist/scriptLoader.js
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
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
|
-
// Get the escaped value, handling special characters
|
|
125
|
-
// Note: We've changed our approach to use forward slashes everywhere
|
|
126
|
-
// and handle the path normalization in each script instead of using r-strings
|
|
127
|
-
let escapedValue = String(value);
|
|
128
|
-
// If value has single quotes, escape them
|
|
129
|
-
if (escapedValue.includes("'")) {
|
|
130
|
-
escapedValue = escapedValue.replace(/'/g, "\\'");
|
|
131
|
-
console.error(`SCRIPT_LOADER: Escaped single quotes in value: ${escapedValue}`);
|
|
132
|
-
}
|
|
133
|
-
// Replace {PARAM_NAME} with the escaped value
|
|
134
|
-
const paramPattern = new RegExp(`\\{${key}\\}`, 'g');
|
|
135
|
-
result = result.replace(paramPattern, escapedValue);
|
|
136
|
-
}
|
|
137
|
-
return result;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Combines multiple script fragments with proper indentation
|
|
141
|
-
* @param scripts Object containing named script fragments
|
|
142
|
-
* @returns Combined script content
|
|
143
|
-
*/
|
|
144
|
-
function combineScripts(scripts) {
|
|
145
|
-
return Object.values(scripts).join('\n\n');
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Load all script templates from the scripts directory
|
|
149
|
-
* This is useful during development to preload the cache
|
|
150
|
-
*/
|
|
151
|
-
function preloadAllScriptTemplates() {
|
|
152
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
153
|
-
try {
|
|
154
|
-
const files = fs.readdirSync(SCRIPTS_DIR);
|
|
155
|
-
for (const file of files) {
|
|
156
|
-
if (file.endsWith('.py')) {
|
|
157
|
-
yield loadScriptTemplate(file);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
console.error(`Failed to preload script templates: ${error.message}`);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import sys, scriptengine as script_engine, os, traceback
|
|
2
|
-
project_open = False; project_name = "No project open"; project_path = "N/A"; scripting_ok = False
|
|
3
|
-
try:
|
|
4
|
-
scripting_ok = True; primary_project = script_engine.projects.primary
|
|
5
|
-
if primary_project:
|
|
6
|
-
project_open = True
|
|
7
|
-
try:
|
|
8
|
-
project_path = os.path.normcase(os.path.abspath(primary_project.path))
|
|
9
|
-
try:
|
|
10
|
-
project_name = primary_project.get_name() # Might fail
|
|
11
|
-
if not project_name: project_name = "Unnamed (path: %s)" % os.path.basename(project_path)
|
|
12
|
-
except: project_name = "Unnamed (path: %s)" % os.path.basename(project_path)
|
|
13
|
-
except Exception as e_path: project_path = "N/A (Error: %s)" % e_path; project_name = "Unnamed (Path Error)"
|
|
14
|
-
print("Project Open: %s" % project_open); print("Project Name: %s" % project_name)
|
|
15
|
-
print("Project Path: %s" % project_path); print("Scripting OK: %s" % scripting_ok)
|
|
16
|
-
print("SCRIPT_SUCCESS: Status check complete."); sys.exit(0)
|
|
17
|
-
except Exception as e:
|
|
18
|
-
error_message = "Error during status check: %s" % e
|
|
19
|
-
print(error_message); print("Scripting OK: False")
|
|
20
|
-
# traceback.print_exc() # Optional traceback
|
|
21
|
-
print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import sys, scriptengine as script_engine, os, traceback
|
|
2
|
-
|
|
3
|
-
# Import ensure_project_open function from the template
|
|
4
|
-
# This will be prepended by the script loader
|
|
5
|
-
def ensure_project_open(target_project_path):
|
|
6
|
-
# Function implementation will be included from ensure_project_open.py
|
|
7
|
-
pass
|
|
8
|
-
|
|
9
|
-
try:
|
|
10
|
-
print("DEBUG: compile_project script: Project='%s'" % PROJECT_FILE_PATH)
|
|
11
|
-
primary_project = ensure_project_open(PROJECT_FILE_PATH)
|
|
12
|
-
project_name = os.path.basename(PROJECT_FILE_PATH)
|
|
13
|
-
target_app = None
|
|
14
|
-
app_name = "N/A"
|
|
15
|
-
|
|
16
|
-
# Try getting active application first
|
|
17
|
-
try:
|
|
18
|
-
target_app = primary_project.active_application
|
|
19
|
-
if target_app:
|
|
20
|
-
app_name = getattr(target_app, 'get_name', lambda: "Unnamed App (Active)")()
|
|
21
|
-
print("DEBUG: Found active application: %s" % app_name)
|
|
22
|
-
except Exception as active_err:
|
|
23
|
-
print("WARN: Could not get active application: %s. Searching..." % active_err)
|
|
24
|
-
|
|
25
|
-
# If no active app, search for the first one
|
|
26
|
-
if not target_app:
|
|
27
|
-
print("DEBUG: Searching for first compilable application...")
|
|
28
|
-
apps = []
|
|
29
|
-
try:
|
|
30
|
-
# Search recursively through all project objects
|
|
31
|
-
all_children = primary_project.get_children(True)
|
|
32
|
-
for child in all_children:
|
|
33
|
-
# Check using the marker property and if build method exists
|
|
34
|
-
if hasattr(child, 'is_application') and child.is_application and hasattr(child, 'build'):
|
|
35
|
-
app_name_found = getattr(child, 'get_name', lambda: "Unnamed App")()
|
|
36
|
-
print("DEBUG: Found potential application object: %s" % app_name_found)
|
|
37
|
-
apps.append(child)
|
|
38
|
-
break # Take the first one found
|
|
39
|
-
except Exception as find_err: print("WARN: Error finding application object: %s" % find_err)
|
|
40
|
-
|
|
41
|
-
if not apps: raise RuntimeError("No compilable application found in project '%s'" % project_name)
|
|
42
|
-
target_app = apps[0]
|
|
43
|
-
app_name = getattr(target_app, 'get_name', lambda: "Unnamed App (First Found)")()
|
|
44
|
-
print("WARN: Compiling first found application: %s" % app_name)
|
|
45
|
-
|
|
46
|
-
print("DEBUG: Calling build() on app '%s'..." % app_name)
|
|
47
|
-
if not hasattr(target_app, 'build'):
|
|
48
|
-
raise TypeError("Selected object '%s' is not an application or doesn't support build()." % app_name)
|
|
49
|
-
|
|
50
|
-
# Execute the build
|
|
51
|
-
target_app.build();
|
|
52
|
-
print("DEBUG: Build command executed for application '%s'." % app_name)
|
|
53
|
-
|
|
54
|
-
# Check messages is harder without direct access to message store from script.
|
|
55
|
-
# Rely on CODESYS UI or log output for now.
|
|
56
|
-
print("Compile Initiated For Application: %s" % app_name)
|
|
57
|
-
print("In Project: %s" % project_name)
|
|
58
|
-
print("SCRIPT_SUCCESS: Application compilation initiated.")
|
|
59
|
-
sys.exit(0)
|
|
60
|
-
except Exception as e:
|
|
61
|
-
detailed_error = traceback.format_exc()
|
|
62
|
-
error_message = "Error initiating compilation for project %s: %s\\n%s" % (PROJECT_FILE_PATH, e, detailed_error)
|
|
63
|
-
print(error_message)
|
|
64
|
-
print("SCRIPT_ERROR: %s" % error_message)
|
|
65
|
-
sys.exit(1)
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import sys, scriptengine as script_engine, os, traceback
|
|
2
|
-
|
|
3
|
-
# Import ensure_project_open function from the template
|
|
4
|
-
# This will be prepended by the script loader
|
|
5
|
-
def ensure_project_open(target_project_path):
|
|
6
|
-
# Function implementation will be included from ensure_project_open.py
|
|
7
|
-
pass
|
|
8
|
-
|
|
9
|
-
# Import find_object_by_path function from the template
|
|
10
|
-
# This will be prepended by the script loader
|
|
11
|
-
def find_object_by_path_robust(start_node, full_path, target_type_name="object"):
|
|
12
|
-
# Function implementation will be included from find_object_by_path.py
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
PARENT_POU_FULL_PATH = "{PARENT_POU_FULL_PATH}" # e.g., "Application/MyFB"
|
|
16
|
-
METHOD_NAME = "{METHOD_NAME}"
|
|
17
|
-
RETURN_TYPE = "{RETURN_TYPE}" # Can be empty string for no return type
|
|
18
|
-
# Optional: Language
|
|
19
|
-
# LANG_GUID_STR = "{LANG_GUID_STR}" # Example if needed
|
|
20
|
-
|
|
21
|
-
try:
|
|
22
|
-
print("DEBUG: create_method script: ParentPOU='%s', Name='%s', ReturnType='%s', Project='%s'" % (PARENT_POU_FULL_PATH, METHOD_NAME, RETURN_TYPE, PROJECT_FILE_PATH))
|
|
23
|
-
primary_project = ensure_project_open(PROJECT_FILE_PATH)
|
|
24
|
-
if not PARENT_POU_FULL_PATH: raise ValueError("Parent POU full path empty.")
|
|
25
|
-
if not METHOD_NAME: raise ValueError("Method name empty.")
|
|
26
|
-
# RETURN_TYPE can be empty
|
|
27
|
-
|
|
28
|
-
# Find the parent POU object
|
|
29
|
-
parent_pou_object = find_object_by_path_robust(primary_project, PARENT_POU_FULL_PATH, "parent POU")
|
|
30
|
-
if not parent_pou_object: raise ValueError("Parent POU object not found: %s" % PARENT_POU_FULL_PATH)
|
|
31
|
-
|
|
32
|
-
parent_pou_name = getattr(parent_pou_object, 'get_name', lambda: PARENT_POU_FULL_PATH)()
|
|
33
|
-
print("DEBUG: Found Parent POU object: %s" % parent_pou_name)
|
|
34
|
-
|
|
35
|
-
# Check if parent object supports creating methods (should implement ScriptIecLanguageMemberContainer)
|
|
36
|
-
if not hasattr(parent_pou_object, 'create_method'):
|
|
37
|
-
raise TypeError("Parent object '%s' of type %s does not support create_method." % (parent_pou_name, type(parent_pou_object).__name__))
|
|
38
|
-
|
|
39
|
-
# Default language to None (usually ST)
|
|
40
|
-
lang_guid = None
|
|
41
|
-
# Use None if RETURN_TYPE is empty string, otherwise use the string
|
|
42
|
-
actual_return_type = RETURN_TYPE if RETURN_TYPE else None
|
|
43
|
-
print("DEBUG: Calling create_method: Name='%s', ReturnType=%s, Lang=%s" % (METHOD_NAME, actual_return_type, lang_guid))
|
|
44
|
-
|
|
45
|
-
# Call the create_method method ON THE PARENT POU
|
|
46
|
-
new_method_object = parent_pou_object.create_method(
|
|
47
|
-
name=METHOD_NAME,
|
|
48
|
-
return_type=actual_return_type,
|
|
49
|
-
language=lang_guid # Pass None to use default
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
if new_method_object:
|
|
53
|
-
new_meth_name = getattr(new_method_object, 'get_name', lambda: METHOD_NAME)()
|
|
54
|
-
print("DEBUG: Method object created: %s" % new_meth_name)
|
|
55
|
-
|
|
56
|
-
# --- SAVE THE PROJECT TO PERSIST THE NEW METHOD OBJECT ---
|
|
57
|
-
try:
|
|
58
|
-
print("DEBUG: Saving Project (after method creation)...")
|
|
59
|
-
primary_project.save()
|
|
60
|
-
print("DEBUG: Project saved successfully after method creation.")
|
|
61
|
-
except Exception as save_err:
|
|
62
|
-
print("ERROR: Failed to save Project after creating method: %s" % save_err)
|
|
63
|
-
detailed_error = traceback.format_exc()
|
|
64
|
-
error_message = "Error saving Project after creating method '%s': %s\\n%s" % (METHOD_NAME, save_err, detailed_error)
|
|
65
|
-
print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
|
|
66
|
-
# --- END SAVING ---
|
|
67
|
-
|
|
68
|
-
print("Method Created: %s" % new_meth_name)
|
|
69
|
-
print("Parent POU: %s" % PARENT_POU_FULL_PATH)
|
|
70
|
-
print("Return Type: %s" % (RETURN_TYPE if RETURN_TYPE else "(None)"))
|
|
71
|
-
print("SCRIPT_SUCCESS: Method created successfully.")
|
|
72
|
-
sys.exit(0)
|
|
73
|
-
else:
|
|
74
|
-
error_message = "Failed to create method '%s' under '%s'. create_method returned None." % (METHOD_NAME, parent_pou_name)
|
|
75
|
-
print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
|
|
76
|
-
|
|
77
|
-
except Exception as e:
|
|
78
|
-
detailed_error = traceback.format_exc()
|
|
79
|
-
error_message = "Error creating method '%s' under POU '%s' in project '%s': %s\\n%s" % (METHOD_NAME, PARENT_POU_FULL_PATH, PROJECT_FILE_PATH, e, detailed_error)
|
|
80
|
-
print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
|