@codesys/mcp-toolkit 1.1.6 → 1.1.8
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 +13 -0
- package/dist/scriptLoader.js +18 -1
- package/dist/scripts/check_status.py +21 -0
- package/dist/scripts/compile_project.py +65 -0
- package/dist/scripts/create_method.py +80 -0
- package/dist/scripts/create_pou.py +139 -0
- package/dist/scripts/create_project.py +54 -0
- package/dist/scripts/create_property.py +78 -0
- package/dist/scripts/ensure_project_open.py +154 -0
- package/dist/scripts/find_object_by_path.py +111 -0
- package/dist/scripts/get_pou_code.py +91 -0
- package/dist/scripts/get_project_structure.py +72 -0
- package/dist/scripts/open_project.py +25 -0
- package/dist/scripts/save_project.py +29 -0
- package/dist/scripts/set_pou_code.py +104 -0
- package/package.json +14 -2
- package/src/scripts/check_status.py +21 -0
- package/src/scripts/compile_project.py +65 -0
- package/src/scripts/create_method.py +80 -0
- package/src/scripts/create_pou.py +139 -0
- package/src/scripts/create_project.py +54 -0
- package/src/scripts/create_property.py +78 -0
- package/src/scripts/ensure_project_open.py +154 -0
- package/src/scripts/find_object_by_path.py +111 -0
- package/src/scripts/get_pou_code.py +91 -0
- package/src/scripts/get_project_structure.py +72 -0
- package/src/scripts/open_project.py +25 -0
- package/src/scripts/save_project.py +29 -0
- package/src/scripts/set_pou_code.py +104 -0
- package/.claude/settings.local.json +0 -10
- package/CONTRIBUTING.md +0 -72
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
def get_object_structure(obj, indent=0, max_depth=10): # Add max_depth
|
|
10
|
+
lines = []; indent_str = " " * indent
|
|
11
|
+
if indent > max_depth:
|
|
12
|
+
lines.append("%s- Max recursion depth reached." % indent_str)
|
|
13
|
+
return lines
|
|
14
|
+
try:
|
|
15
|
+
name = "Unnamed"; obj_type = type(obj).__name__
|
|
16
|
+
guid_str = ""
|
|
17
|
+
folder_str = ""
|
|
18
|
+
try:
|
|
19
|
+
name = getattr(obj, 'get_name', lambda: "Unnamed")() or "Unnamed" # Safer get_name
|
|
20
|
+
if hasattr(obj, 'guid'): guid_str = " {%s}" % obj.guid
|
|
21
|
+
if hasattr(obj, 'is_folder') and obj.is_folder: folder_str = " [Folder]"
|
|
22
|
+
except Exception as name_err:
|
|
23
|
+
print("WARN: Error getting name/guid/folder status for an object: %s" % name_err)
|
|
24
|
+
name = "!!! Error Getting Name !!!"
|
|
25
|
+
|
|
26
|
+
lines.append("%s- %s (%s)%s%s" % (indent_str, name, obj_type, folder_str, guid_str))
|
|
27
|
+
|
|
28
|
+
# Get children only if the object potentially has them
|
|
29
|
+
children = []
|
|
30
|
+
can_have_children = hasattr(obj, 'get_children') and (
|
|
31
|
+
not hasattr(obj, 'is_folder') or # If it's not clear if it's a folder (e.g., project root)
|
|
32
|
+
(hasattr(obj, 'is_folder') and obj.is_folder) or # If it is a folder
|
|
33
|
+
# Add known container types explicitly, check marker interfaces too
|
|
34
|
+
hasattr(obj, 'is_project') or hasattr(obj, 'is_application') or hasattr(obj, 'is_device') or hasattr(obj,'is_pou')
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if can_have_children:
|
|
38
|
+
try:
|
|
39
|
+
children = obj.get_children(False)
|
|
40
|
+
# print("DEBUG: %s has %d children" % (name, len(children))) # Verbose
|
|
41
|
+
except Exception as get_child_err:
|
|
42
|
+
lines.append("%s ERROR getting children: %s" % (indent_str, get_child_err))
|
|
43
|
+
# traceback.print_exc() # Optional
|
|
44
|
+
|
|
45
|
+
for child in children:
|
|
46
|
+
lines.extend(get_object_structure(child, indent + 1, max_depth)) # Recurse
|
|
47
|
+
|
|
48
|
+
except Exception as e:
|
|
49
|
+
lines.append("%s- Error processing node: %s" % (indent_str, e))
|
|
50
|
+
traceback.print_exc() # Print detailed error for this node
|
|
51
|
+
return lines
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
print("DEBUG: Getting structure for: %s" % PROJECT_FILE_PATH)
|
|
55
|
+
primary_project = ensure_project_open(PROJECT_FILE_PATH)
|
|
56
|
+
project_name = os.path.basename(PROJECT_FILE_PATH)
|
|
57
|
+
print("DEBUG: Getting structure for project: %s" % project_name)
|
|
58
|
+
# Use the project object obtained from ensure_project_open
|
|
59
|
+
structure_list = get_object_structure(primary_project, max_depth=15) # Set a reasonable depth
|
|
60
|
+
structure_output = "\\n".join(structure_list)
|
|
61
|
+
# Ensure markers are printed distinctly
|
|
62
|
+
print("\\n--- PROJECT STRUCTURE START ---")
|
|
63
|
+
print(structure_output)
|
|
64
|
+
print("--- PROJECT STRUCTURE END ---\\n")
|
|
65
|
+
print("SCRIPT_SUCCESS: Project structure retrieved.")
|
|
66
|
+
sys.exit(0)
|
|
67
|
+
except Exception as e:
|
|
68
|
+
detailed_error = traceback.format_exc()
|
|
69
|
+
error_message = "Error getting structure for %s: %s\\n%s" % (PROJECT_FILE_PATH, e, detailed_error)
|
|
70
|
+
print(error_message)
|
|
71
|
+
print("SCRIPT_ERROR: %s" % error_message)
|
|
72
|
+
sys.exit(1)
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
project = ensure_project_open(PROJECT_FILE_PATH)
|
|
11
|
+
# Get name from object if possible, otherwise use path basename
|
|
12
|
+
proj_name = "Unknown"
|
|
13
|
+
try:
|
|
14
|
+
if project: proj_name = project.get_name() or os.path.basename(PROJECT_FILE_PATH)
|
|
15
|
+
else: proj_name = os.path.basename(PROJECT_FILE_PATH) + " (ensure_project_open returned None?)"
|
|
16
|
+
except Exception:
|
|
17
|
+
proj_name = os.path.basename(PROJECT_FILE_PATH) + " (name retrieval failed)"
|
|
18
|
+
print("Project Opened: %s" % proj_name)
|
|
19
|
+
print("SCRIPT_SUCCESS: Project opened successfully.")
|
|
20
|
+
sys.exit(0)
|
|
21
|
+
except Exception as e:
|
|
22
|
+
error_message = "Error opening project %s: %s" % (PROJECT_FILE_PATH, e)
|
|
23
|
+
print(error_message)
|
|
24
|
+
traceback.print_exc()
|
|
25
|
+
print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
primary_project = ensure_project_open(PROJECT_FILE_PATH)
|
|
11
|
+
# Get name from object if possible, otherwise use path basename
|
|
12
|
+
project_name = "Unknown"
|
|
13
|
+
try:
|
|
14
|
+
if primary_project: project_name = primary_project.get_name() or os.path.basename(PROJECT_FILE_PATH)
|
|
15
|
+
else: project_name = os.path.basename(PROJECT_FILE_PATH) + " (ensure_project_open returned None?)"
|
|
16
|
+
except Exception:
|
|
17
|
+
project_name = os.path.basename(PROJECT_FILE_PATH) + " (name retrieval failed)"
|
|
18
|
+
|
|
19
|
+
print("DEBUG: Saving project: %s (%s)" % (project_name, PROJECT_FILE_PATH))
|
|
20
|
+
primary_project.save()
|
|
21
|
+
print("DEBUG: project.save() executed.")
|
|
22
|
+
print("Project Saved: %s" % project_name)
|
|
23
|
+
print("SCRIPT_SUCCESS: Project saved successfully.")
|
|
24
|
+
sys.exit(0)
|
|
25
|
+
except Exception as e:
|
|
26
|
+
error_message = "Error saving project %s: %s" % (PROJECT_FILE_PATH, e)
|
|
27
|
+
print(error_message)
|
|
28
|
+
traceback.print_exc()
|
|
29
|
+
print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
|
|
@@ -0,0 +1,104 @@
|
|
|
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
|
+
POU_FULL_PATH = "{POU_FULL_PATH}" # Expecting format like "Application/MyPOU" or "Folder/SubFolder/MyPOU"
|
|
16
|
+
DECLARATION_CONTENT = """{DECLARATION_CONTENT}"""
|
|
17
|
+
IMPLEMENTATION_CONTENT = """{IMPLEMENTATION_CONTENT}"""
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
print("DEBUG: set_pou_code script: POU_FULL_PATH='%s', Project='%s'" % (POU_FULL_PATH, PROJECT_FILE_PATH))
|
|
21
|
+
primary_project = ensure_project_open(PROJECT_FILE_PATH)
|
|
22
|
+
if not POU_FULL_PATH: raise ValueError("POU full path empty.")
|
|
23
|
+
|
|
24
|
+
# Find the target POU/Method/Property object
|
|
25
|
+
target_object = find_object_by_path_robust(primary_project, POU_FULL_PATH, "target object")
|
|
26
|
+
if not target_object: raise ValueError("Target object not found using path: %s" % POU_FULL_PATH)
|
|
27
|
+
|
|
28
|
+
target_name = getattr(target_object, 'get_name', lambda: POU_FULL_PATH)()
|
|
29
|
+
print("DEBUG: Found target object: %s" % target_name)
|
|
30
|
+
|
|
31
|
+
# --- Set Declaration Part ---
|
|
32
|
+
declaration_updated = False
|
|
33
|
+
# Check if the content is actually provided (might be None/empty if only impl is set)
|
|
34
|
+
has_declaration_content = 'DECLARATION_CONTENT' in locals() or 'DECLARATION_CONTENT' in globals()
|
|
35
|
+
if has_declaration_content and DECLARATION_CONTENT is not None: # Check not None
|
|
36
|
+
if hasattr(target_object, 'textual_declaration'):
|
|
37
|
+
decl_obj = target_object.textual_declaration
|
|
38
|
+
if decl_obj and hasattr(decl_obj, 'replace'):
|
|
39
|
+
try:
|
|
40
|
+
print("DEBUG: Accessing textual_declaration...")
|
|
41
|
+
decl_obj.replace(DECLARATION_CONTENT)
|
|
42
|
+
print("DEBUG: Set declaration text using replace().")
|
|
43
|
+
declaration_updated = True
|
|
44
|
+
except Exception as decl_err:
|
|
45
|
+
print("ERROR: Failed to set declaration text: %s" % decl_err)
|
|
46
|
+
traceback.print_exc() # Print stack trace for detailed error
|
|
47
|
+
else:
|
|
48
|
+
print("WARN: Target '%s' textual_declaration attribute is None or does not have replace(). Skipping declaration update." % target_name)
|
|
49
|
+
else:
|
|
50
|
+
print("WARN: Target '%s' does not have textual_declaration attribute. Skipping declaration update." % target_name)
|
|
51
|
+
else:
|
|
52
|
+
print("DEBUG: Declaration content not provided or is None. Skipping declaration update.")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# --- Set Implementation Part ---
|
|
56
|
+
implementation_updated = False
|
|
57
|
+
has_implementation_content = 'IMPLEMENTATION_CONTENT' in locals() or 'IMPLEMENTATION_CONTENT' in globals()
|
|
58
|
+
if has_implementation_content and IMPLEMENTATION_CONTENT is not None: # Check not None
|
|
59
|
+
if hasattr(target_object, 'textual_implementation'):
|
|
60
|
+
impl_obj = target_object.textual_implementation
|
|
61
|
+
if impl_obj and hasattr(impl_obj, 'replace'):
|
|
62
|
+
try:
|
|
63
|
+
print("DEBUG: Accessing textual_implementation...")
|
|
64
|
+
impl_obj.replace(IMPLEMENTATION_CONTENT)
|
|
65
|
+
print("DEBUG: Set implementation text using replace().")
|
|
66
|
+
implementation_updated = True
|
|
67
|
+
except Exception as impl_err:
|
|
68
|
+
print("ERROR: Failed to set implementation text: %s" % impl_err)
|
|
69
|
+
traceback.print_exc() # Print stack trace for detailed error
|
|
70
|
+
else:
|
|
71
|
+
print("WARN: Target '%s' textual_implementation attribute is None or does not have replace(). Skipping implementation update." % target_name)
|
|
72
|
+
else:
|
|
73
|
+
print("WARN: Target '%s' does not have textual_implementation attribute. Skipping implementation update." % target_name)
|
|
74
|
+
else:
|
|
75
|
+
print("DEBUG: Implementation content not provided or is None. Skipping implementation update.")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# --- SAVE THE PROJECT TO PERSIST THE CODE CHANGE ---
|
|
79
|
+
# Only save if something was actually updated to avoid unnecessary saves
|
|
80
|
+
if declaration_updated or implementation_updated:
|
|
81
|
+
try:
|
|
82
|
+
print("DEBUG: Saving Project (after code change)...")
|
|
83
|
+
primary_project.save() # Save the overall project file
|
|
84
|
+
print("DEBUG: Project saved successfully after code change.")
|
|
85
|
+
except Exception as save_err:
|
|
86
|
+
print("ERROR: Failed to save Project after setting code: %s" % save_err)
|
|
87
|
+
detailed_error = traceback.format_exc()
|
|
88
|
+
error_message = "Error saving Project after code change for '%s': %s\\n%s" % (target_name, save_err, detailed_error)
|
|
89
|
+
print(error_message); print("SCRIPT_ERROR: %s" % error_message); sys.exit(1)
|
|
90
|
+
else:
|
|
91
|
+
print("DEBUG: No code parts were updated, skipping project save.")
|
|
92
|
+
# --- END SAVING ---
|
|
93
|
+
|
|
94
|
+
print("Code Set For: %s" % target_name)
|
|
95
|
+
print("Path: %s" % POU_FULL_PATH)
|
|
96
|
+
print("SCRIPT_SUCCESS: Declaration and/or implementation set successfully.")
|
|
97
|
+
sys.exit(0)
|
|
98
|
+
|
|
99
|
+
except Exception as e:
|
|
100
|
+
detailed_error = traceback.format_exc()
|
|
101
|
+
error_message = "Error setting code for object '%s' in project '%s': %s\\n%s" % (POU_FULL_PATH, PROJECT_FILE_PATH, e, detailed_error)
|
|
102
|
+
print(error_message)
|
|
103
|
+
print("SCRIPT_ERROR: %s" % error_message)
|
|
104
|
+
sys.exit(1)
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# Contributing to @codesys/mcp-toolkit
|
|
2
|
-
|
|
3
|
-
Thank you for considering contributing to the CODESYS MCP Toolkit! This document provides guidelines and steps for contributing.
|
|
4
|
-
|
|
5
|
-
## Code of Conduct
|
|
6
|
-
|
|
7
|
-
Please be respectful and considerate of others when contributing to this project. We aim to foster an inclusive and welcoming community.
|
|
8
|
-
|
|
9
|
-
## How Can I Contribute?
|
|
10
|
-
|
|
11
|
-
### Reporting Bugs
|
|
12
|
-
|
|
13
|
-
Bug reports help improve the project! When reporting bugs:
|
|
14
|
-
|
|
15
|
-
1. Check if the bug has already been reported
|
|
16
|
-
2. Use the bug report template
|
|
17
|
-
3. Include detailed steps to reproduce the issue
|
|
18
|
-
4. Describe the expected vs. actual behavior
|
|
19
|
-
5. Include screenshots if applicable
|
|
20
|
-
6. Provide environment details (OS, Node.js version, etc.)
|
|
21
|
-
|
|
22
|
-
### Suggesting Features
|
|
23
|
-
|
|
24
|
-
We welcome feature suggestions! When suggesting features:
|
|
25
|
-
|
|
26
|
-
1. Describe the problem your feature would solve
|
|
27
|
-
2. Explain how your feature would work
|
|
28
|
-
3. Consider potential alternatives
|
|
29
|
-
4. Provide examples of similar features in other projects (if applicable)
|
|
30
|
-
|
|
31
|
-
### Pull Requests
|
|
32
|
-
|
|
33
|
-
1. Fork the repository
|
|
34
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
35
|
-
3. Make your changes
|
|
36
|
-
4. Run tests and ensure they pass
|
|
37
|
-
5. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
38
|
-
6. Push to your branch (`git push origin feature/amazing-feature`)
|
|
39
|
-
7. Open a Pull Request
|
|
40
|
-
|
|
41
|
-
## Development Setup
|
|
42
|
-
|
|
43
|
-
1. Clone the repository
|
|
44
|
-
```bash
|
|
45
|
-
git clone https://github.com/yourusername/codesys-mcp-toolkit.git
|
|
46
|
-
cd codesys-mcp-toolkit
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
2. Install dependencies
|
|
50
|
-
```bash
|
|
51
|
-
npm install
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
3. Build the project
|
|
55
|
-
```bash
|
|
56
|
-
npm run build
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Style Guidelines
|
|
60
|
-
|
|
61
|
-
- Follow existing code formatting patterns
|
|
62
|
-
- Use meaningful variable and function names
|
|
63
|
-
- Add comments where necessary to explain complex logic
|
|
64
|
-
- Update documentation when changing functionality
|
|
65
|
-
|
|
66
|
-
## Testing
|
|
67
|
-
|
|
68
|
-
- Add tests for new features
|
|
69
|
-
- Ensure all tests pass before submitting a PR
|
|
70
|
-
- Consider edge cases in your tests
|
|
71
|
-
|
|
72
|
-
Thank you for contributing!
|