codesysultra 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,332 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.registerTools = registerTools;
46
+ const zod_1 = require("zod");
47
+ const path = __importStar(require("path"));
48
+ const types_1 = require("../types");
49
+ const codesys_interop_1 = require("../codesys_interop");
50
+ const utils_1 = require("../utils");
51
+ const templates_1 = require("../templates");
52
+ function registerTools(server, config) {
53
+ const WORKSPACE_DIR = config.workspaceDir;
54
+ const codesysExePath = config.codesysPath;
55
+ const codesysProfileName = config.profileName;
56
+ console.error("HANDLERS: Registering Tools...");
57
+ // --- Tools ---
58
+ server.tool("open_project", // Tool Name
59
+ "Opens an existing CODESYS project file.", // Tool Description
60
+ {
61
+ filePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project' or '/Users/user/projects/my_project.project').")
62
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
63
+ const { filePath } = args;
64
+ let absPath = path.normalize(path.isAbsolute(filePath) ? filePath : path.join(WORKSPACE_DIR, filePath));
65
+ console.error(`Tool call: open_project: ${absPath}`);
66
+ try {
67
+ const escapedPath = absPath.replace(/\\/g, '\\\\');
68
+ const script = templates_1.OPEN_PROJECT_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escapedPath);
69
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
70
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
71
+ return { content: [{ type: "text", text: success ? `Project opened: ${absPath}` : `Failed open project ${absPath}. Output:\n${result.output}` }], isError: !success };
72
+ }
73
+ catch (e) {
74
+ console.error(`Error open_project ${absPath}: ${e}`);
75
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
76
+ }
77
+ }));
78
+ server.tool("create_project", // Tool Name
79
+ "Creates a new CODESYS project from the standard template.", // Tool Description
80
+ {
81
+ filePath: zod_1.z.string().describe("Path where the new project file should be created (e.g., 'C:/Projects/NewPLC.project' or '/Users/user/projects/new_project.project').")
82
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
83
+ const { filePath } = args;
84
+ let absPath = path.normalize(path.isAbsolute(filePath) ? filePath : path.join(WORKSPACE_DIR, filePath));
85
+ console.error(`Tool call: create_project (copy template): ${absPath}`);
86
+ let templatePath = "";
87
+ try {
88
+ // Template finding logic (same as before)
89
+ const baseDir = path.dirname(path.dirname(codesysExePath));
90
+ templatePath = path.normalize(path.join(baseDir, 'Templates', 'Standard.project'));
91
+ if (!(yield (0, utils_1.fileExists)(templatePath))) {
92
+ console.error(`WARN: Template not found relative to exe: ${templatePath}. Trying ProgramData...`);
93
+ const programData = process.env.ALLUSERSPROFILE || process.env.ProgramData || 'C:\\ProgramData';
94
+ const possibleTemplateDir = path.join(programData, 'CODESYS', 'CODESYS', codesysProfileName, 'Templates');
95
+ let potentialTemplatePath = path.normalize(path.join(possibleTemplateDir, 'Standard.project'));
96
+ if (yield (0, utils_1.fileExists)(potentialTemplatePath)) {
97
+ templatePath = potentialTemplatePath;
98
+ console.error(`DEBUG: Found template in ProgramData: ${templatePath}`);
99
+ }
100
+ else {
101
+ const alternativeTemplateDir = path.join(programData, 'CODESYS', 'Templates');
102
+ potentialTemplatePath = path.normalize(path.join(alternativeTemplateDir, 'Standard.project'));
103
+ if (yield (0, utils_1.fileExists)(potentialTemplatePath)) {
104
+ templatePath = potentialTemplatePath;
105
+ console.error(`DEBUG: Found template in ProgramData (alternative): ${templatePath}`);
106
+ }
107
+ else {
108
+ throw new Error(`Standard template project file not found at relative path or ProgramData locations.`);
109
+ }
110
+ }
111
+ }
112
+ else {
113
+ console.error(`DEBUG: Found template relative to exe: ${templatePath}`);
114
+ }
115
+ // *** END TEMPLATE FINDING ***
116
+ }
117
+ catch (e) {
118
+ console.error(`Template Error: ${e.message}`);
119
+ return { content: [{ type: "text", text: `Template Error: ${e.message}` }], isError: true };
120
+ }
121
+ try {
122
+ const escProjPath = absPath.replace(/\\/g, '\\\\');
123
+ const escTmplPath = templatePath.replace(/\\/g, '\\\\');
124
+ const script = templates_1.CREATE_PROJECT_SCRIPT_TEMPLATE
125
+ .replace("{PROJECT_FILE_PATH}", escProjPath)
126
+ .replace("{TEMPLATE_PROJECT_PATH}", escTmplPath);
127
+ console.error(">>> create_project (copy-then-open): PREPARED SCRIPT:", script.substring(0, 500) + "...");
128
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
129
+ console.error(">>> create_project (copy-then-open): EXECUTION RESULT:", JSON.stringify(result));
130
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
131
+ return { content: [{ type: "text", text: success ? `Project created from template: ${absPath}` : `Failed create project ${absPath} from template. Output:\n${result.output}` }], isError: !success };
132
+ }
133
+ catch (e) {
134
+ console.error(`Error create_project ${absPath}: ${e}`);
135
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
136
+ }
137
+ }));
138
+ server.tool("save_project", // Tool Name
139
+ "Saves the currently open CODESYS project.", // Tool Description
140
+ {
141
+ projectFilePath: zod_1.z.string().describe("Path to the project file to ensure is open before saving (e.g., 'C:/Projects/MyPLC.project').")
142
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
143
+ const { projectFilePath } = args;
144
+ let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
145
+ console.error(`Tool call: save_project: ${absPath}`);
146
+ try {
147
+ const escapedPath = absPath.replace(/\\/g, '\\\\');
148
+ const script = templates_1.SAVE_PROJECT_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escapedPath);
149
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
150
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
151
+ return { content: [{ type: "text", text: success ? `Project saved: ${absPath}` : `Failed save project ${absPath}. Output:\n${result.output}` }], isError: !success };
152
+ }
153
+ catch (e) {
154
+ console.error(`Error save_project ${absPath}: ${e}`);
155
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
156
+ }
157
+ }));
158
+ server.tool("create_pou", // Tool Name
159
+ "Creates a new Program, Function Block, or Function POU within the specified CODESYS project.", // Tool Description
160
+ {
161
+ projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
162
+ name: zod_1.z.string().describe("Name for the new POU (must be a valid IEC identifier)."),
163
+ type: types_1.PouTypeEnum.describe("Type of POU (Program, FunctionBlock, Function)."),
164
+ language: types_1.ImplementationLanguageEnum.describe("Implementation language (ST, LD, FBD, etc.). CODESYS default will be used if specific language is not set or directly supported by scripting for this POU type."),
165
+ parentPath: zod_1.z.string().describe("Relative path under project root or application where the POU should be created (e.g., 'Application' or 'MyFolder/SubFolder').")
166
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
167
+ const { projectFilePath, name, type, language, parentPath } = args;
168
+ let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
169
+ const sanParentPath = parentPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
170
+ const sanName = name.trim();
171
+ console.error(`Tool call: create_pou: Name='${sanName}', Type='${type}', Lang='${language}', Parent='${sanParentPath}', Project='${absPath}'`);
172
+ try {
173
+ const escProjPath = absPath.replace(/\\/g, '\\\\');
174
+ let script = templates_1.CREATE_POU_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
175
+ script = script.replace("{POU_NAME}", sanName);
176
+ script = script.replace("{POU_TYPE_STR}", type);
177
+ script = script.replace("{IMPL_LANGUAGE_STR}", language);
178
+ script = script.replace("{PARENT_PATH}", sanParentPath);
179
+ console.error(">>> create_pou: PREPARED SCRIPT:", script.substring(0, 500) + "...");
180
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
181
+ console.error(">>> create_pou: EXECUTION RESULT:", JSON.stringify(result));
182
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
183
+ return { content: [{ type: "text", text: success ? `POU '${sanName}' created in '${sanParentPath}' of ${absPath}. Project saved.` : `Failed create POU '${sanName}'. Output:\n${result.output}` }], isError: !success };
184
+ }
185
+ catch (e) {
186
+ console.error(`Error create_pou ${sanName} in ${absPath}: ${e}`);
187
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
188
+ }
189
+ }));
190
+ server.tool("set_pou_code", // Tool Name
191
+ "Sets the declaration and/or implementation code for a specific POU, Method, or Property.", // Tool Description
192
+ {
193
+ projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
194
+ pouPath: zod_1.z.string().describe("Full relative path to the target object (e.g., 'Application/MyPOU', 'MyFolder/MyFB/MyMethod', 'MyFolder/MyFB/MyProperty')."),
195
+ declarationCode: zod_1.z.string().describe("Code for the declaration part (VAR...END_VAR). If omitted, the declaration is not changed.").optional(),
196
+ implementationCode: zod_1.z.string().describe("Code for the implementation logic part. If omitted, the implementation is not changed.").optional()
197
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
198
+ const { projectFilePath, pouPath, declarationCode, implementationCode } = args;
199
+ if (declarationCode === undefined && implementationCode === undefined) {
200
+ return { content: [{ type: "text", text: "Error: At least one of declarationCode or implementationCode must be provided." }], isError: true };
201
+ }
202
+ let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
203
+ const sanPouPath = pouPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
204
+ console.error(`Tool call: set_pou_code: Target='${sanPouPath}', Project='${absPath}'`);
205
+ try {
206
+ const escProjPath = absPath.replace(/\\/g, '\\\\');
207
+ // Escape content for Python triple-quoted strings
208
+ const sanDeclCode = (declarationCode !== null && declarationCode !== void 0 ? declarationCode : "").replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"');
209
+ const sanImplCode = (implementationCode !== null && implementationCode !== void 0 ? implementationCode : "").replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"');
210
+ let script = templates_1.SET_POU_CODE_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
211
+ script = script.replace("{POU_FULL_PATH}", sanPouPath);
212
+ script = script.replace("{DECLARATION_CONTENT}", sanDeclCode);
213
+ script = script.replace("{IMPLEMENTATION_CONTENT}", sanImplCode);
214
+ console.error(">>> set_pou_code: PREPARED SCRIPT:", script.substring(0, 500) + "...");
215
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
216
+ console.error(">>> set_pou_code: EXECUTION RESULT:", JSON.stringify(result));
217
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
218
+ return { content: [{ type: "text", text: success ? `Code set for '${sanPouPath}' in ${absPath}. Project saved.` : `Failed set code for '${sanPouPath}'. Output:\n${result.output}` }], isError: !success };
219
+ }
220
+ catch (e) {
221
+ console.error(`Error set_pou_code ${sanPouPath} in ${absPath}: ${e}`);
222
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
223
+ }
224
+ }));
225
+ server.tool("create_property", // Tool Name
226
+ "Creates a new Property within a specific Function Block POU.", // Tool Description
227
+ {
228
+ projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
229
+ // Assuming properties can only be added to FBs in standard CODESYS scripting
230
+ parentPouPath: zod_1.z.string().describe("Relative path to the parent Function Block POU (e.g., 'Application/MyFB')."),
231
+ propertyName: zod_1.z.string().describe("Name for the new property (must be a valid IEC identifier)."),
232
+ propertyType: zod_1.z.string().describe("Data type of the property (e.g., 'BOOL', 'INT', 'MyDUT').")
233
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
234
+ const { projectFilePath, parentPouPath, propertyName, propertyType } = args;
235
+ let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
236
+ const sanParentPath = parentPouPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
237
+ const sanPropName = propertyName.trim();
238
+ const sanPropType = propertyType.trim();
239
+ console.error(`Tool call: create_property: Name='${sanPropName}', Type='${sanPropType}', ParentPOU='${sanParentPath}', Project='${absPath}'`);
240
+ if (!sanPropName || !sanPropType) {
241
+ return { content: [{ type: "text", text: `Error: Property name and type cannot be empty.` }], isError: true };
242
+ }
243
+ try {
244
+ const escProjPath = absPath.replace(/\\/g, '\\\\');
245
+ let script = templates_1.CREATE_PROPERTY_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
246
+ script = script.replace("{PARENT_POU_FULL_PATH}", sanParentPath);
247
+ script = script.replace("{PROPERTY_NAME}", sanPropName);
248
+ script = script.replace("{PROPERTY_TYPE}", sanPropType);
249
+ console.error(">>> create_property: PREPARED SCRIPT:", script.substring(0, 500) + "...");
250
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
251
+ console.error(">>> create_property: EXECUTION RESULT:", JSON.stringify(result));
252
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
253
+ return {
254
+ content: [{ type: "text", text: success ? `Property '${sanPropName}' created under '${sanParentPath}' in ${absPath}. Project saved.` : `Failed to create property '${sanPropName}'. Output:\n${result.output}` }],
255
+ isError: !success
256
+ };
257
+ }
258
+ catch (e) {
259
+ console.error(`Error create_property ${sanPropName} in ${absPath}: ${e}`);
260
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
261
+ }
262
+ }));
263
+ server.tool("create_method", // Tool Name
264
+ "Creates a new Method within a specific Function Block POU.", // Tool Description
265
+ {
266
+ projectFilePath: zod_1.z.string().describe("Path to the project file (e.g., 'C:/Projects/MyPLC.project')."),
267
+ // Assuming methods can typically only be added to FBs in standard CODESYS scripting
268
+ parentPouPath: zod_1.z.string().describe("Relative path to the parent Function Block POU (e.g., 'Application/MyFB')."),
269
+ methodName: zod_1.z.string().describe("Name of the new method (must be a valid IEC identifier)."),
270
+ returnType: zod_1.z.string().optional().describe("Return type (e.g., 'BOOL', 'INT'). Leave empty or omit for no return value (PROCEDURE)."),
271
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
272
+ const { projectFilePath, parentPouPath, methodName, returnType } = args;
273
+ let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
274
+ const sanParentPath = parentPouPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
275
+ const sanMethName = methodName.trim();
276
+ const sanReturnType = (returnType !== null && returnType !== void 0 ? returnType : "").trim();
277
+ console.error(`Tool call: create_method: Name='${sanMethName}', Return='${sanReturnType}', ParentPOU='${sanParentPath}', Project='${absPath}'`);
278
+ if (!sanMethName) {
279
+ return { content: [{ type: "text", text: `Error: Method name cannot be empty.` }], isError: true };
280
+ }
281
+ try {
282
+ const escProjPath = absPath.replace(/\\/g, '\\\\');
283
+ let script = templates_1.CREATE_METHOD_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escProjPath);
284
+ script = script.replace("{PARENT_POU_FULL_PATH}", sanParentPath);
285
+ script = script.replace("{METHOD_NAME}", sanMethName);
286
+ script = script.replace("{RETURN_TYPE}", sanReturnType);
287
+ console.error(">>> create_method: PREPARED SCRIPT:", script.substring(0, 500) + "...");
288
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
289
+ console.error(">>> create_method: EXECUTION RESULT:", JSON.stringify(result));
290
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
291
+ return {
292
+ content: [{ type: "text", text: success ? `Method '${sanMethName}' created under '${sanParentPath}' in ${absPath}. Project saved.` : `Failed to create method '${sanMethName}'. Output:\n${result.output}` }],
293
+ isError: !success
294
+ };
295
+ }
296
+ catch (e) {
297
+ console.error(`Error create_method ${sanMethName} in ${absPath}: ${e}`);
298
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
299
+ }
300
+ }));
301
+ server.tool("compile_project", // Tool Name
302
+ "Compiles (Builds) the primary application within a CODESYS project.", // Tool Description
303
+ {
304
+ projectFilePath: zod_1.z.string().describe("Path to the project file containing the application to compile (e.g., 'C:/Projects/MyPLC.project').")
305
+ }, (args) => __awaiter(this, void 0, void 0, function* () {
306
+ const { projectFilePath } = args;
307
+ let absPath = path.normalize(path.isAbsolute(projectFilePath) ? projectFilePath : path.join(WORKSPACE_DIR, projectFilePath));
308
+ console.error(`Tool call: compile_project: ${absPath}`);
309
+ try {
310
+ const escapedPath = absPath.replace(/\\/g, '\\\\');
311
+ const script = templates_1.COMPILE_PROJECT_SCRIPT_TEMPLATE.replace("{PROJECT_FILE_PATH}", escapedPath);
312
+ const result = yield (0, codesys_interop_1.executeCodesysScript)(script, codesysExePath, codesysProfileName);
313
+ const success = result.success && result.output.includes("SCRIPT_SUCCESS");
314
+ // Check for actual compile errors in the output log
315
+ const hasCompileErrors = result.output.includes("Compile complete --") && !/ 0 error\(s\),/.test(result.output);
316
+ let message = success ? `Compilation initiated for application in ${absPath}. Check CODESYS messages for results.` : `Failed initiating compilation for ${absPath}. Output:\n${result.output}`;
317
+ let isError = !success; // Base error status on script success
318
+ if (success && hasCompileErrors) {
319
+ message += " WARNING: Build command reported errors in the output log.";
320
+ console.warn("Compile project reported build errors in the output.");
321
+ // Report as error if compile fails, even if script technically succeeded
322
+ isError = true;
323
+ }
324
+ return { content: [{ type: "text", text: message }], isError: isError };
325
+ }
326
+ catch (e) {
327
+ console.error(`Error compile_project ${absPath}: ${e}`);
328
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
329
+ }
330
+ }));
331
+ // --- End Tools ---
332
+ }
package/dist/server.js ADDED
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ /**
3
+ * server.ts
4
+ * MCP Server for interacting with CODESYS via Python scripting.
5
+ * Refactored to be modular.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
41
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
42
+ return new (P || (P = Promise))(function (resolve, reject) {
43
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
44
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
45
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
46
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
47
+ });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.startMcpServer = startMcpServer;
51
+ const os = __importStar(require("os"));
52
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
53
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
54
+ const resources_1 = require("./handlers/resources");
55
+ const tools_1 = require("./handlers/tools");
56
+ const fs = __importStar(require("fs"));
57
+ // --- STARTUP LOG ---
58
+ console.error(`>>> SERVER.TS TOP LEVEL EXECUTION @ ${new Date().toISOString()} <<<`);
59
+ console.error(`>>> Node: ${process.version}, Platform: ${os.platform()}, Arch: ${os.arch()}`);
60
+ console.error(`>>> Initial CWD: ${process.cwd()}`);
61
+ // --- End Startup Log ---
62
+ function startMcpServer(config) {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ console.error(`>>> SERVER.TS startMcpServer() CALLED @ ${new Date().toISOString()} <<<`);
65
+ console.error(`>>> Config Received: ${JSON.stringify(config)}`);
66
+ const codesysExePath = config.codesysPath;
67
+ console.error(`SERVER.TS: Checking existence of CODESYS executable: ${codesysExePath}`);
68
+ try {
69
+ if (!fs.existsSync(codesysExePath)) {
70
+ console.error(`SERVER.TS ERROR: Determined CODESYS executable path does not exist: ${codesysExePath}`);
71
+ throw new Error(`CODESYS executable not found at specified path: ${codesysExePath}`);
72
+ }
73
+ else {
74
+ console.error(`SERVER.TS: Confirmed CODESYS executable exists.`);
75
+ }
76
+ }
77
+ catch (err) {
78
+ console.error(`SERVER.TS ERROR: Error checking CODESYS path existence: ${err.message}`);
79
+ throw err;
80
+ }
81
+ console.error("SERVER.TS: Initializing McpServer...");
82
+ const server = new mcp_js_1.McpServer({
83
+ name: "CODESYS Control MCP Server",
84
+ version: "1.7.1"
85
+ }, {
86
+ capabilities: {
87
+ resources: { listChanged: true },
88
+ tools: { listChanged: true }
89
+ }
90
+ });
91
+ console.error("SERVER.TS: McpServer instance created.");
92
+ // Register Resources and Tools
93
+ (0, resources_1.registerResources)(server, config);
94
+ (0, tools_1.registerTools)(server, config);
95
+ console.error("SERVER.TS: Resources and Tools registered.");
96
+ console.error("SERVER.TS: startServer() internal logic executing.");
97
+ try {
98
+ const transport = new stdio_js_1.StdioServerTransport();
99
+ console.error("SERVER.TS: Connecting MCP server via stdio...");
100
+ server.connect(transport);
101
+ console.error("SERVER.TS: MCP Server connection initiated via stdio.");
102
+ }
103
+ catch (error) {
104
+ console.error("FATAL: Failed to initiate MCP server connection:", error);
105
+ throw error;
106
+ }
107
+ });
108
+ }
109
+ // --- Graceful Shutdown / Unhandled Rejection ---
110
+ process.on('SIGINT', () => {
111
+ console.error('\nSERVER.TS: SIGINT received, shutting down...');
112
+ process.exit(0);
113
+ });
114
+ process.on('SIGTERM', () => {
115
+ console.error('\nSERVER.TS: SIGTERM received, shutting down...');
116
+ process.exit(0);
117
+ });
118
+ process.on('unhandledRejection', (reason, promise) => {
119
+ console.error('SERVER.TS: Unhandled Rejection at:', promise, 'reason:', reason);
120
+ });
121
+ // --- End Graceful Shutdown / Unhandled Rejection ---
122
+ console.error(">>> SERVER.TS Module Parsed <<<");
@@ -0,0 +1,21 @@
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)
@@ -0,0 +1,55 @@
1
+ import sys, scriptengine as script_engine, os, traceback
2
+ {{ENSURE_PROJECT_OPEN_PYTHON_SNIPPET}}
3
+ try:
4
+ print("DEBUG: compile_project script: Project='%s'" % PROJECT_FILE_PATH)
5
+ primary_project = ensure_project_open(PROJECT_FILE_PATH)
6
+ project_name = os.path.basename(PROJECT_FILE_PATH)
7
+ target_app = None
8
+ app_name = "N/A"
9
+
10
+ # Try getting active application first
11
+ try:
12
+ target_app = primary_project.active_application
13
+ if target_app:
14
+ app_name = getattr(target_app, 'get_name', lambda: "Unnamed App (Active)")()
15
+ print("DEBUG: Found active application: %s" % app_name)
16
+ except Exception as active_err:
17
+ print("WARN: Could not get active application: %s. Searching..." % active_err)
18
+
19
+ # If no active app, search for the first one
20
+ if not target_app:
21
+ print("DEBUG: Searching for first compilable application...")
22
+ apps = []
23
+ try:
24
+ # Search recursively through all project objects
25
+ all_children = primary_project.get_children(True)
26
+ for child in all_children:
27
+ # Check using the marker property and if build method exists
28
+ if hasattr(child, 'is_application') and child.is_application and hasattr(child, 'build'):
29
+ app_name_found = getattr(child, 'get_name', lambda: "Unnamed App")()
30
+ print("DEBUG: Found potential application object: %s" % app_name_found)
31
+ apps.append(child)
32
+ break # Take the first one found
33
+ except Exception as find_err: print("WARN: Error finding application object: %s" % find_err)
34
+
35
+ if not apps: raise RuntimeError("No compilable application found in project '%s'" % project_name)
36
+ target_app = apps[0]
37
+ app_name = getattr(target_app, 'get_name', lambda: "Unnamed App (First Found)")()
38
+ print("WARN: Compiling first found application: %s" % app_name)
39
+
40
+ print("DEBUG: Calling build() on app '%s'..." % app_name)
41
+ if not hasattr(target_app, 'build'):
42
+ raise TypeError("Selected object '%s' is not an application or doesn't support build()." % app_name)
43
+
44
+ # Execute the build
45
+ target_app.build();
46
+ print("DEBUG: Build command executed for application '%s'." % app_name)
47
+
48
+ # Check messages is harder without direct access to message store from script.
49
+ # Rely on CODESYS UI or log output for now.
50
+ print("Compile Initiated For Application: %s" % app_name); print("In Project: %s" % project_name)
51
+ print("SCRIPT_SUCCESS: Application compilation initiated."); sys.exit(0)
52
+ except Exception as e:
53
+ detailed_error = traceback.format_exc()
54
+ error_message = "Error initiating compilation for project %s: %s\\n%s" % (PROJECT_FILE_PATH, e, detailed_error)
55
+ print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
@@ -0,0 +1,68 @@
1
+ import sys, scriptengine as script_engine, os, traceback
2
+ {{ENSURE_PROJECT_OPEN_PYTHON_SNIPPET}}
3
+ {{FIND_OBJECT_BY_PATH_PYTHON_SNIPPET}}
4
+ PARENT_POU_FULL_PATH = "{PARENT_POU_FULL_PATH}" # e.g., "Application/MyFB"
5
+ METHOD_NAME = "{METHOD_NAME}"
6
+ RETURN_TYPE = "{RETURN_TYPE}" # Can be empty string for no return type
7
+ # Optional: Language
8
+ # LANG_GUID_STR = "{LANG_GUID_STR}" # Example if needed
9
+
10
+ try:
11
+ print("DEBUG: create_method script: ParentPOU='%s', Name='%s', ReturnType='%s', Project='%s'" % (PARENT_POU_FULL_PATH, METHOD_NAME, RETURN_TYPE, PROJECT_FILE_PATH))
12
+ primary_project = ensure_project_open(PROJECT_FILE_PATH)
13
+ if not PARENT_POU_FULL_PATH: raise ValueError("Parent POU full path empty.")
14
+ if not METHOD_NAME: raise ValueError("Method name empty.")
15
+ # RETURN_TYPE can be empty
16
+
17
+ # Find the parent POU object
18
+ parent_pou_object = find_object_by_path_robust(primary_project, PARENT_POU_FULL_PATH, "parent POU")
19
+ if not parent_pou_object: raise ValueError("Parent POU object not found: %s" % PARENT_POU_FULL_PATH)
20
+
21
+ parent_pou_name = getattr(parent_pou_object, 'get_name', lambda: PARENT_POU_FULL_PATH)()
22
+ print("DEBUG: Found Parent POU object: %s" % parent_pou_name)
23
+
24
+ # Check if parent object supports creating methods (should implement ScriptIecLanguageMemberContainer)
25
+ if not hasattr(parent_pou_object, 'create_method'):
26
+ raise TypeError("Parent object '%s' of type %s does not support create_method." % (parent_pou_name, type(parent_pou_object).__name__))
27
+
28
+ # Default language to None (usually ST)
29
+ lang_guid = None
30
+ # Use None if RETURN_TYPE is empty string, otherwise use the string
31
+ actual_return_type = RETURN_TYPE if RETURN_TYPE else None
32
+ print("DEBUG: Calling create_method: Name='%s', ReturnType=%s, Lang=%s" % (METHOD_NAME, actual_return_type, lang_guid))
33
+
34
+ # Call the create_method method ON THE PARENT POU
35
+ new_method_object = parent_pou_object.create_method(
36
+ name=METHOD_NAME,
37
+ return_type=actual_return_type,
38
+ language=lang_guid # Pass None to use default
39
+ )
40
+
41
+ if new_method_object:
42
+ new_meth_name = getattr(new_method_object, 'get_name', lambda: METHOD_NAME)()
43
+ print("DEBUG: Method object created: %s" % new_meth_name)
44
+
45
+ # --- SAVE THE PROJECT TO PERSIST THE NEW METHOD OBJECT ---
46
+ try:
47
+ print("DEBUG: Saving Project (after method creation)...")
48
+ primary_project.save()
49
+ print("DEBUG: Project saved successfully after method creation.")
50
+ except Exception as save_err:
51
+ print("ERROR: Failed to save Project after creating method: %s" % save_err)
52
+ detailed_error = traceback.format_exc()
53
+ error_message = "Error saving Project after creating method '%s': %s\\n%s" % (METHOD_NAME, save_err, detailed_error)
54
+ print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
55
+ # --- END SAVING ---
56
+
57
+ print("Method Created: %s" % new_meth_name)
58
+ print("Parent POU: %s" % PARENT_POU_FULL_PATH)
59
+ print("Return Type: %s" % (RETURN_TYPE if RETURN_TYPE else "(None)"))
60
+ print("SCRIPT_SUCCESS: Method created successfully."); sys.exit(0)
61
+ else:
62
+ error_message = "Failed to create method '%s' under '%s'. create_method returned None." % (METHOD_NAME, parent_pou_name)
63
+ print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
64
+
65
+ except Exception as e:
66
+ detailed_error = traceback.format_exc()
67
+ 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)
68
+ print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)