@codesys/mcp-toolkit 1.5.7 → 2.0.0-alpha.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.
Files changed (109) hide show
  1. package/CHANGELOG.md +153 -183
  2. package/LICENSE +21 -21
  3. package/README.md +224 -107
  4. package/dist/actions.d.ts +28 -0
  5. package/dist/actions.js +98 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/bridge/bridge.d.ts +105 -0
  8. package/dist/bridge/bridge.js +400 -0
  9. package/dist/bridge/bridge.js.map +1 -0
  10. package/dist/cli.d.ts +2 -0
  11. package/dist/cli.js +196 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/codesys/cache.d.ts +48 -0
  14. package/dist/codesys/cache.js +82 -0
  15. package/dist/codesys/cache.js.map +1 -0
  16. package/dist/codesys/changes.d.ts +57 -0
  17. package/dist/codesys/changes.js +133 -0
  18. package/dist/codesys/changes.js.map +1 -0
  19. package/dist/codesys/decl.d.ts +45 -0
  20. package/dist/codesys/decl.js +251 -0
  21. package/dist/codesys/decl.js.map +1 -0
  22. package/dist/codesys/devices.d.ts +34 -0
  23. package/dist/codesys/devices.js +82 -0
  24. package/dist/codesys/devices.js.map +1 -0
  25. package/dist/codesys/diff.d.ts +13 -0
  26. package/dist/codesys/diff.js +61 -0
  27. package/dist/codesys/diff.js.map +1 -0
  28. package/dist/codesys/install.d.ts +40 -0
  29. package/dist/codesys/install.js +144 -0
  30. package/dist/codesys/install.js.map +1 -0
  31. package/dist/codesys/library-browse.d.ts +19 -0
  32. package/dist/codesys/library-browse.js +57 -0
  33. package/dist/codesys/library-browse.js.map +1 -0
  34. package/dist/codesys/outline.d.ts +32 -0
  35. package/dist/codesys/outline.js +219 -0
  36. package/dist/codesys/outline.js.map +1 -0
  37. package/dist/codesys/simulation.d.ts +34 -0
  38. package/dist/codesys/simulation.js +57 -0
  39. package/dist/codesys/simulation.js.map +1 -0
  40. package/dist/codesys/st.d.ts +36 -0
  41. package/dist/codesys/st.js +69 -0
  42. package/dist/codesys/st.js.map +1 -0
  43. package/dist/daemon.d.ts +46 -0
  44. package/dist/daemon.js +173 -0
  45. package/dist/daemon.js.map +1 -0
  46. package/dist/driver.d.ts +25 -0
  47. package/dist/driver.js +33 -0
  48. package/dist/driver.js.map +1 -0
  49. package/dist/panel/sim-panel.html +357 -0
  50. package/dist/panel/viewer.html +126 -0
  51. package/dist/panel-types.d.ts +20 -0
  52. package/dist/panel-types.js +3 -0
  53. package/dist/panel-types.js.map +1 -0
  54. package/dist/panel.d.ts +27 -0
  55. package/dist/panel.js +208 -0
  56. package/dist/panel.js.map +1 -0
  57. package/dist/server.d.ts +5 -0
  58. package/dist/server.js +33 -941
  59. package/dist/server.js.map +1 -0
  60. package/dist/tools.d.ts +103 -0
  61. package/dist/tools.js +793 -0
  62. package/dist/tools.js.map +1 -0
  63. package/dist/viewer.d.ts +14 -0
  64. package/dist/viewer.js +125 -0
  65. package/dist/viewer.js.map +1 -0
  66. package/package.json +37 -21
  67. package/watcher/mcp_compat.py +147 -0
  68. package/watcher/mcp_ops.py +1178 -0
  69. package/watcher/mcp_sim.py +246 -0
  70. package/watcher/watcher.py +255 -0
  71. package/.claude/settings.local.json +0 -29
  72. package/CLAUDE.md +0 -26
  73. package/CONTRIBUTING.md +0 -72
  74. package/README.md.enhanced +0 -155
  75. package/codesys-mcp-toolkit-1.2.0.tgz +0 -0
  76. package/codesys-mcp-toolkit-1.2.1.tgz +0 -0
  77. package/codesys-mcp-toolkit-1.5.7.tgz +0 -0
  78. package/dist/bin.js +0 -75
  79. package/dist/check_session_paths.js +0 -149
  80. package/dist/codesys_interop.js +0 -435
  81. package/dist/direct_session_command.js +0 -293
  82. package/dist/scriptLoader.js +0 -165
  83. package/dist/scripts/check_status.py +0 -21
  84. package/dist/scripts/compile_project.py +0 -65
  85. package/dist/scripts/create_method.py +0 -80
  86. package/dist/scripts/create_pou.py +0 -102
  87. package/dist/scripts/create_project.py +0 -116
  88. package/dist/scripts/create_property.py +0 -78
  89. package/dist/scripts/ensure_project_open.py +0 -154
  90. package/dist/scripts/find_object_by_path.py +0 -111
  91. package/dist/scripts/get_pou_code.py +0 -91
  92. package/dist/scripts/get_project_structure.py +0 -72
  93. package/dist/scripts/open_project.py +0 -25
  94. package/dist/scripts/save_project.py +0 -29
  95. package/dist/scripts/session_status.py +0 -281
  96. package/dist/scripts/set_pou_code.py +0 -109
  97. package/dist/scripts/start_session.py +0 -809
  98. package/dist/scripts/stop_session.py +0 -324
  99. package/dist/sessionManager.js +0 -798
  100. package/docs/configuration.md +0 -141
  101. package/docs/index.md +0 -26
  102. package/docs/installation.md +0 -84
  103. package/docs/session_management.md +0 -110
  104. package/examples/README.md +0 -78
  105. package/examples/sample_config.json +0 -32
  106. package/replacements_session_status.txt +0 -16
  107. package/scriptDoc.txt +0 -8679
  108. package/scripts/build.js +0 -25
  109. 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
- }
@@ -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)