@codesys/mcp-toolkit 1.5.1 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +3 -1
- package/CHANGELOG.md +12 -0
- package/dist/check_session_paths.js +149 -0
- package/dist/codesys_interop.js +2 -2
- package/dist/direct_session_command.js +22 -5
- package/dist/scripts/create_pou.py +6 -0
- package/dist/scripts/create_project.py +5 -0
- package/dist/scripts/set_pou_code.py +5 -0
- package/dist/server.js +18 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.5.3] - 2025-05-02
|
|
9
|
+
### Fixed
|
|
10
|
+
- Added automatic session startup when server starts
|
|
11
|
+
- Improved session detection with better diagnostics
|
|
12
|
+
- Enhanced logging for session command status
|
|
13
|
+
|
|
14
|
+
## [1.5.2] - 2025-05-02
|
|
15
|
+
### Fixed
|
|
16
|
+
- Re-enabled session management feature that was disabled for debugging
|
|
17
|
+
- Fixed project path handling between scripts for more reliable project creation
|
|
18
|
+
- Fixed create_pou.py and set_pou_code.py to properly handle project paths when embedded in other scripts
|
|
19
|
+
|
|
8
20
|
## [1.5.1] - 2025-05-02
|
|
9
21
|
### Added
|
|
10
22
|
- Implemented direct session command handling for project creation
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Session Path Diagnostic Tool
|
|
4
|
+
* This script checks the consistency of paths used in the session management system.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const os = __importStar(require("os"));
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
// Session directory paths from direct_session_command.ts
|
|
44
|
+
const DIRECT_SESSION_DIR = path.join(os.tmpdir(), 'codesys_session');
|
|
45
|
+
const DIRECT_COMMAND_FILE = path.join(DIRECT_SESSION_DIR, 'command.json');
|
|
46
|
+
const DIRECT_RESULT_FILE = path.join(DIRECT_SESSION_DIR, 'result.json');
|
|
47
|
+
const DIRECT_SESSION_LOCK_FILE = path.join(DIRECT_SESSION_DIR, 'session.lock');
|
|
48
|
+
const DIRECT_STATE_FILE = path.join(DIRECT_SESSION_DIR, 'session_state.json');
|
|
49
|
+
// Constants from sessionManager.ts
|
|
50
|
+
const SESSION_DIR = path.join(os.tmpdir(), 'codesys_session');
|
|
51
|
+
const COMMAND_FILE = 'command.json';
|
|
52
|
+
const RESULT_FILE = 'result.json';
|
|
53
|
+
const STATE_FILE = 'session_state.json';
|
|
54
|
+
const SESSION_LOCK_FILE = 'session.lock';
|
|
55
|
+
console.log("==== Session Path Diagnostics ====");
|
|
56
|
+
console.log("\nBase session directory check:");
|
|
57
|
+
console.log(`- DIRECT_SESSION_DIR: ${DIRECT_SESSION_DIR}`);
|
|
58
|
+
console.log(`- SESSION_DIR: ${SESSION_DIR}`);
|
|
59
|
+
console.log(` Direct and manager directories match: ${DIRECT_SESSION_DIR === SESSION_DIR}`);
|
|
60
|
+
console.log("\nExpected file paths in direct_session_command.ts:");
|
|
61
|
+
console.log(`- Command file: ${DIRECT_COMMAND_FILE}`);
|
|
62
|
+
console.log(`- Result file: ${DIRECT_RESULT_FILE}`);
|
|
63
|
+
console.log(`- Lock file: ${DIRECT_SESSION_LOCK_FILE}`);
|
|
64
|
+
console.log(`- State file: ${DIRECT_STATE_FILE}`);
|
|
65
|
+
console.log("\nFile names in sessionManager.ts:");
|
|
66
|
+
console.log(`- Command file: ${COMMAND_FILE}`);
|
|
67
|
+
console.log(`- Result file: ${RESULT_FILE}`);
|
|
68
|
+
console.log(`- Lock file: ${SESSION_LOCK_FILE}`);
|
|
69
|
+
console.log(`- State file: ${STATE_FILE}`);
|
|
70
|
+
console.log("\nFile existence checks:");
|
|
71
|
+
console.log(`- Base session directory exists: ${fs.existsSync(SESSION_DIR)}`);
|
|
72
|
+
if (fs.existsSync(SESSION_DIR)) {
|
|
73
|
+
console.log(`- Command file exists: ${fs.existsSync(DIRECT_COMMAND_FILE)}`);
|
|
74
|
+
console.log(`- Result file exists: ${fs.existsSync(DIRECT_RESULT_FILE)}`);
|
|
75
|
+
console.log(`- Lock file exists: ${fs.existsSync(DIRECT_SESSION_LOCK_FILE)}`);
|
|
76
|
+
console.log(`- State file exists: ${fs.existsSync(DIRECT_STATE_FILE)}`);
|
|
77
|
+
console.log("\nContent checks (if files exist):");
|
|
78
|
+
if (fs.existsSync(DIRECT_COMMAND_FILE)) {
|
|
79
|
+
try {
|
|
80
|
+
const commandContent = fs.readFileSync(DIRECT_COMMAND_FILE, 'utf8');
|
|
81
|
+
console.log(`- Command file content: ${commandContent.substring(0, 150)}...`);
|
|
82
|
+
try {
|
|
83
|
+
const commandJson = JSON.parse(commandContent);
|
|
84
|
+
console.log(` Status: ${commandJson.status}`);
|
|
85
|
+
console.log(` Has command object: ${commandJson.command !== null}`);
|
|
86
|
+
if (commandJson.command) {
|
|
87
|
+
console.log(` Command type: ${commandJson.command.type}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
console.log(` Error parsing command file JSON: ${e}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
console.log(`- Error reading command file: ${e}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (fs.existsSync(DIRECT_RESULT_FILE)) {
|
|
99
|
+
try {
|
|
100
|
+
const resultContent = fs.readFileSync(DIRECT_RESULT_FILE, 'utf8');
|
|
101
|
+
console.log(`- Result file content: ${resultContent.substring(0, 150)}...`);
|
|
102
|
+
try {
|
|
103
|
+
const resultJson = JSON.parse(resultContent);
|
|
104
|
+
console.log(` Status: ${resultJson.status}`);
|
|
105
|
+
console.log(` Has result object: ${resultJson.result !== null}`);
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
console.log(` Error parsing result file JSON: ${e}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
console.log(`- Error reading result file: ${e}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (fs.existsSync(DIRECT_SESSION_LOCK_FILE)) {
|
|
116
|
+
try {
|
|
117
|
+
const lockContent = fs.readFileSync(DIRECT_SESSION_LOCK_FILE, 'utf8');
|
|
118
|
+
console.log(`- Lock file content: ${lockContent}`);
|
|
119
|
+
const lockTime = parseFloat(lockContent);
|
|
120
|
+
const currentTime = Date.now() / 1000; // convert to seconds
|
|
121
|
+
const lockAgeSeconds = currentTime - lockTime;
|
|
122
|
+
console.log(` Lock age: ${lockAgeSeconds.toFixed(1)} seconds`);
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
console.log(`- Error reading lock file: ${e}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (fs.existsSync(DIRECT_STATE_FILE)) {
|
|
129
|
+
try {
|
|
130
|
+
const stateContent = fs.readFileSync(DIRECT_STATE_FILE, 'utf8');
|
|
131
|
+
console.log(`- State file content: ${stateContent.substring(0, 150)}...`);
|
|
132
|
+
try {
|
|
133
|
+
const stateJson = JSON.parse(stateContent);
|
|
134
|
+
console.log(` Session ID: ${stateJson.sessionId || stateJson.session_id}`);
|
|
135
|
+
console.log(` Status: ${stateJson.status}`);
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
console.log(` Error parsing state file JSON: ${e}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
console.log(`- Error reading state file: ${e}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log(" Cannot check files as base directory does not exist");
|
|
148
|
+
}
|
|
149
|
+
console.log("\n==== End of Session Path Diagnostics ====");
|
package/dist/codesys_interop.js
CHANGED
|
@@ -91,8 +91,8 @@ function executeCodesysScript(scriptContent, codesysExePath, codesysProfileName,
|
|
|
91
91
|
if (!fs.existsSync(codesysExePath))
|
|
92
92
|
throw new Error(`CODESYS executable not found at provided path: ${codesysExePath}`);
|
|
93
93
|
// --- End Pre-checks ---
|
|
94
|
-
// Session management feature control
|
|
95
|
-
const SESSION_FEATURE_DISABLED =
|
|
94
|
+
// Session management feature control
|
|
95
|
+
const SESSION_FEATURE_DISABLED = false; // Session feature enabled
|
|
96
96
|
// --- Check if we should use the persistent session ---
|
|
97
97
|
if (!SESSION_FEATURE_DISABLED && sessionManager) {
|
|
98
98
|
const sessionState = sessionManager.getState();
|
|
@@ -69,19 +69,24 @@ const STATE_FILE = path.join(SESSION_DIR, 'session_state.json');
|
|
|
69
69
|
*/
|
|
70
70
|
function isSessionActive() {
|
|
71
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}`);
|
|
72
77
|
// Check if session directory exists
|
|
73
78
|
if (!fs.existsSync(SESSION_DIR)) {
|
|
74
|
-
console.error(`SESSION_DIR doesn't exist: ${SESSION_DIR}`);
|
|
79
|
+
console.error(`DIRECT_SESSION: SESSION_DIR doesn't exist: ${SESSION_DIR}`);
|
|
75
80
|
return false;
|
|
76
81
|
}
|
|
77
82
|
// Check if lock file exists
|
|
78
83
|
if (!fs.existsSync(SESSION_LOCK_FILE)) {
|
|
79
|
-
console.error(`SESSION_LOCK_FILE doesn't exist: ${SESSION_LOCK_FILE}`);
|
|
84
|
+
console.error(`DIRECT_SESSION: SESSION_LOCK_FILE doesn't exist: ${SESSION_LOCK_FILE}`);
|
|
80
85
|
return false;
|
|
81
86
|
}
|
|
82
87
|
// Check if command file exists
|
|
83
88
|
if (!fs.existsSync(COMMAND_FILE)) {
|
|
84
|
-
console.error(`COMMAND_FILE doesn't exist: ${COMMAND_FILE}`);
|
|
89
|
+
console.error(`DIRECT_SESSION: COMMAND_FILE doesn't exist: ${COMMAND_FILE}`);
|
|
85
90
|
return false;
|
|
86
91
|
}
|
|
87
92
|
// Read the lock file to check age
|
|
@@ -89,15 +94,27 @@ function isSessionActive() {
|
|
|
89
94
|
const lockTime = parseFloat(lockFileContent);
|
|
90
95
|
const currentTime = Date.now() / 1000; // convert to seconds
|
|
91
96
|
const lockAgeSeconds = currentTime - lockTime;
|
|
97
|
+
console.error(`DIRECT_SESSION: Lock file age: ${lockAgeSeconds.toFixed(1)} seconds`);
|
|
92
98
|
// If lock is too old, session might be dead
|
|
93
99
|
if (lockAgeSeconds > 30) {
|
|
94
|
-
console.error(`Session lock file is too old (${lockAgeSeconds.toFixed(1)} seconds)`);
|
|
100
|
+
console.error(`DIRECT_SESSION: Session lock file is too old (${lockAgeSeconds.toFixed(1)} seconds)`);
|
|
95
101
|
return false;
|
|
96
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`);
|
|
97
114
|
return true;
|
|
98
115
|
}
|
|
99
116
|
catch (error) {
|
|
100
|
-
console.error(`Error checking session: ${error}`);
|
|
117
|
+
console.error(`DIRECT_SESSION: Error checking session: ${error}`);
|
|
101
118
|
return false;
|
|
102
119
|
}
|
|
103
120
|
}
|
|
@@ -12,11 +12,17 @@ def find_object_by_path_robust(start_node, full_path, target_type_name="object")
|
|
|
12
12
|
# Function implementation will be included from find_object_by_path.py
|
|
13
13
|
pass
|
|
14
14
|
|
|
15
|
+
# Define required parameters
|
|
15
16
|
POU_NAME = "{POU_NAME}"
|
|
16
17
|
POU_TYPE_STR = "{POU_TYPE_STR}"
|
|
17
18
|
IMPL_LANGUAGE_STR = "{IMPL_LANGUAGE_STR}"
|
|
18
19
|
PARENT_PATH_REL = "{PARENT_PATH}"
|
|
19
20
|
|
|
21
|
+
# Define the global PROJECT_FILE_PATH for compatibility with ensure_project_open
|
|
22
|
+
# When this script is embedded in other scripts
|
|
23
|
+
if 'PROJECT_FILE_PATH' not in globals():
|
|
24
|
+
PROJECT_FILE_PATH = "{PROJECT_FILE_PATH}"
|
|
25
|
+
|
|
20
26
|
pou_type_map = {
|
|
21
27
|
"Program": script_engine.PouType.Program,
|
|
22
28
|
"FunctionBlock": script_engine.PouType.FunctionBlock,
|
|
@@ -7,6 +7,11 @@ PROJECT_FILE_PATH = '{PROJECT_FILE_PATH}'
|
|
|
7
7
|
# Optional flag to skip opening the project after creation (useful for sessions)
|
|
8
8
|
SKIP_OPEN = '{SKIP_OPEN}' == 'true'
|
|
9
9
|
|
|
10
|
+
# Define the global PROJECT_FILE_PATH for compatibility with ensure_project_open
|
|
11
|
+
# This is used by some scripts that check the project status
|
|
12
|
+
if 'PROJECT_FILE_PATH' not in globals():
|
|
13
|
+
globals()['PROJECT_FILE_PATH'] = PROJECT_FILE_PATH
|
|
14
|
+
|
|
10
15
|
# Print raw paths for debugging
|
|
11
16
|
print("DEBUG: Template path (raw): %s" % repr(TEMPLATE_PROJECT_PATH))
|
|
12
17
|
print("DEBUG: Project path (raw): %s" % repr(PROJECT_FILE_PATH))
|
|
@@ -16,6 +16,11 @@ POU_FULL_PATH = "{POU_FULL_PATH}" # Expecting format like "Application/MyPOU" or
|
|
|
16
16
|
DECLARATION_CONTENT = """{DECLARATION_CONTENT}"""
|
|
17
17
|
IMPLEMENTATION_CONTENT = """{IMPLEMENTATION_CONTENT}"""
|
|
18
18
|
|
|
19
|
+
# Define the global PROJECT_FILE_PATH for compatibility with ensure_project_open
|
|
20
|
+
# When this script is embedded in other scripts
|
|
21
|
+
if 'PROJECT_FILE_PATH' not in globals():
|
|
22
|
+
PROJECT_FILE_PATH = "{PROJECT_FILE_PATH}"
|
|
23
|
+
|
|
19
24
|
try:
|
|
20
25
|
print("DEBUG: set_pou_code script: POU_FULL_PATH='%s', Project='%s'" % (POU_FULL_PATH, PROJECT_FILE_PATH))
|
|
21
26
|
primary_project = ensure_project_open(PROJECT_FILE_PATH)
|
package/dist/server.js
CHANGED
|
@@ -119,6 +119,24 @@ function startMcpServer(config) {
|
|
|
119
119
|
// --- Initialize Session Manager ---
|
|
120
120
|
const sessionManager = new sessionManager_1.CodesysSessionManager(codesysExePath, codesysProfileName);
|
|
121
121
|
console.error('SERVER.TS: Session manager initialized');
|
|
122
|
+
// Explicitly start the session when server starts
|
|
123
|
+
try {
|
|
124
|
+
// Check if session is already active
|
|
125
|
+
console.error('SERVER.TS: Checking if session is already active...');
|
|
126
|
+
const isActive = (0, direct_session_command_1.isSessionActive)();
|
|
127
|
+
if (isActive) {
|
|
128
|
+
console.error('SERVER.TS: Session is already active');
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.error('SERVER.TS: Session not active, starting new session...');
|
|
132
|
+
yield sessionManager.startSession();
|
|
133
|
+
console.error('SERVER.TS: Session start initiated');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
console.error(`SERVER.TS: Error starting session: ${error.message}`);
|
|
138
|
+
// Continue without session, will fallback to one-time execution
|
|
139
|
+
}
|
|
122
140
|
// --- End Session Manager Initialization ---
|
|
123
141
|
// --- Preload script templates ---
|
|
124
142
|
try {
|