claudemol 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl
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.
- claudemol/__init__.py +1 -1
- claudemol/cli.py +130 -17
- {claudemol-0.3.0.dist-info → claudemol-0.4.0.dist-info}/METADATA +1 -1
- claudemol-0.4.0.dist-info/RECORD +11 -0
- {claudemol-0.3.0.dist-info → claudemol-0.4.0.dist-info}/WHEEL +1 -1
- claudemol-0.3.0.dist-info/RECORD +0 -11
- {claudemol-0.3.0.dist-info → claudemol-0.4.0.dist-info}/entry_points.txt +0 -0
- {claudemol-0.3.0.dist-info → claudemol-0.4.0.dist-info}/licenses/LICENSE +0 -0
claudemol/__init__.py
CHANGED
claudemol/cli.py
CHANGED
|
@@ -5,9 +5,14 @@ Usage:
|
|
|
5
5
|
claudemol setup # Configure PyMOL to auto-load the socket plugin
|
|
6
6
|
claudemol status # Check if PyMOL is running and connected
|
|
7
7
|
claudemol test # Test the connection
|
|
8
|
+
claudemol info # Show installation info
|
|
9
|
+
claudemol launch # Launch PyMOL or connect to existing instance
|
|
10
|
+
claudemol exec # Execute code in PyMOL
|
|
8
11
|
"""
|
|
9
12
|
|
|
10
13
|
import argparse
|
|
14
|
+
import os
|
|
15
|
+
import stat
|
|
11
16
|
import sys
|
|
12
17
|
from pathlib import Path
|
|
13
18
|
|
|
@@ -15,6 +20,7 @@ from claudemol.connection import (
|
|
|
15
20
|
CONFIG_FILE,
|
|
16
21
|
PyMOLConnection,
|
|
17
22
|
check_pymol_installed,
|
|
23
|
+
connect_or_launch,
|
|
18
24
|
find_pymol_command,
|
|
19
25
|
get_config,
|
|
20
26
|
get_configured_python,
|
|
@@ -22,6 +28,23 @@ from claudemol.connection import (
|
|
|
22
28
|
save_config,
|
|
23
29
|
)
|
|
24
30
|
|
|
31
|
+
WRAPPER_DIR = Path.home() / ".claudemol" / "bin"
|
|
32
|
+
WRAPPER_PATH = WRAPPER_DIR / "claudemol"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _create_wrapper_script():
|
|
36
|
+
"""Create ~/.claudemol/bin/claudemol shell wrapper with baked Python path."""
|
|
37
|
+
WRAPPER_DIR.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
python_path = sys.executable
|
|
39
|
+
script = f"""#!/bin/bash
|
|
40
|
+
exec "{python_path}" -m claudemol.cli "$@"
|
|
41
|
+
"""
|
|
42
|
+
WRAPPER_PATH.write_text(script)
|
|
43
|
+
WRAPPER_PATH.chmod(
|
|
44
|
+
WRAPPER_PATH.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
|
45
|
+
)
|
|
46
|
+
return python_path
|
|
47
|
+
|
|
25
48
|
|
|
26
49
|
def setup_pymol():
|
|
27
50
|
"""Configure PyMOL to auto-load the socket plugin."""
|
|
@@ -41,6 +64,9 @@ def setup_pymol():
|
|
|
41
64
|
# Still save config (in case Python path changed)
|
|
42
65
|
save_config({"python_path": sys.executable})
|
|
43
66
|
print(f"Saved Python path: {sys.executable}")
|
|
67
|
+
# Create/update wrapper script
|
|
68
|
+
_create_wrapper_script()
|
|
69
|
+
print(f"Wrapper script: {WRAPPER_PATH}")
|
|
44
70
|
return 0
|
|
45
71
|
|
|
46
72
|
# Add to .pymolrc
|
|
@@ -69,6 +95,10 @@ def setup_pymol():
|
|
|
69
95
|
save_config({"python_path": sys.executable})
|
|
70
96
|
print(f"Saved Python path: {sys.executable}")
|
|
71
97
|
|
|
98
|
+
# Create wrapper script
|
|
99
|
+
_create_wrapper_script()
|
|
100
|
+
print(f"Wrapper script: {WRAPPER_PATH}")
|
|
101
|
+
|
|
72
102
|
return 0
|
|
73
103
|
|
|
74
104
|
|
|
@@ -149,34 +179,113 @@ def show_info():
|
|
|
149
179
|
else:
|
|
150
180
|
print(" Config: not set (run 'claudemol setup' to configure)")
|
|
151
181
|
|
|
182
|
+
print(f" Wrapper script: {WRAPPER_PATH}")
|
|
183
|
+
print(f" Wrapper exists: {WRAPPER_PATH.exists()}")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def do_launch(args):
|
|
187
|
+
"""Launch PyMOL or connect to existing instance."""
|
|
188
|
+
file_path = getattr(args, "file", None)
|
|
189
|
+
try:
|
|
190
|
+
conn, process = connect_or_launch(file_path=file_path)
|
|
191
|
+
if process:
|
|
192
|
+
print(f"Launched PyMOL (pid {process.pid})")
|
|
193
|
+
else:
|
|
194
|
+
print("Connected to existing PyMOL instance")
|
|
195
|
+
conn.disconnect()
|
|
196
|
+
return 0
|
|
197
|
+
except Exception as e:
|
|
198
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
199
|
+
return 1
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def do_exec(args):
|
|
203
|
+
"""Execute code in PyMOL."""
|
|
204
|
+
code = getattr(args, "code", None)
|
|
205
|
+
|
|
206
|
+
# Read from positional arg or stdin
|
|
207
|
+
if code:
|
|
208
|
+
code = code
|
|
209
|
+
elif not os.isatty(sys.stdin.fileno()):
|
|
210
|
+
code = sys.stdin.read()
|
|
211
|
+
else:
|
|
212
|
+
print(
|
|
213
|
+
"Error: No code provided. Pass as argument or pipe via stdin.",
|
|
214
|
+
file=sys.stderr,
|
|
215
|
+
)
|
|
216
|
+
print(" claudemol exec \"cmd.fetch('1ubq')\"", file=sys.stderr)
|
|
217
|
+
print(" echo \"cmd.fetch('1ubq')\" | claudemol exec", file=sys.stderr)
|
|
218
|
+
return 1
|
|
219
|
+
|
|
220
|
+
if not code.strip():
|
|
221
|
+
print("Error: Empty code.", file=sys.stderr)
|
|
222
|
+
return 1
|
|
223
|
+
|
|
224
|
+
conn = PyMOLConnection()
|
|
225
|
+
try:
|
|
226
|
+
conn.connect(timeout=2.0)
|
|
227
|
+
except ConnectionError:
|
|
228
|
+
print("Error: Cannot connect to PyMOL. Is it running?", file=sys.stderr)
|
|
229
|
+
print(" Run: claudemol launch", file=sys.stderr)
|
|
230
|
+
return 1
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
result = conn.execute(code)
|
|
234
|
+
if result:
|
|
235
|
+
print(result, end="" if result.endswith("\n") else "\n")
|
|
236
|
+
conn.disconnect()
|
|
237
|
+
return 0
|
|
238
|
+
except Exception as e:
|
|
239
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
240
|
+
conn.disconnect()
|
|
241
|
+
return 1
|
|
242
|
+
|
|
152
243
|
|
|
153
244
|
def main():
|
|
154
245
|
parser = argparse.ArgumentParser(
|
|
155
246
|
description="claudemol: PyMOL integration for Claude Code",
|
|
156
247
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
157
|
-
epilog="""
|
|
158
|
-
Commands:
|
|
159
|
-
setup Configure PyMOL to auto-load the socket plugin
|
|
160
|
-
status Check if PyMOL is running and connected
|
|
161
|
-
test Test the connection with a simple command
|
|
162
|
-
info Show installation info
|
|
163
|
-
|
|
164
|
-
For Claude Code skills, install the claudemol-skills plugin:
|
|
165
|
-
/plugin marketplace add ANaka/claudemol?path=claude-plugin
|
|
166
|
-
/plugin install claudemol-skills
|
|
167
|
-
""",
|
|
168
248
|
)
|
|
169
|
-
|
|
170
|
-
|
|
249
|
+
|
|
250
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
251
|
+
|
|
252
|
+
# setup
|
|
253
|
+
subparsers.add_parser(
|
|
254
|
+
"setup", help="Configure PyMOL to auto-load the socket plugin"
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# status
|
|
258
|
+
subparsers.add_parser("status", help="Check if PyMOL is running and connected")
|
|
259
|
+
|
|
260
|
+
# test
|
|
261
|
+
subparsers.add_parser("test", help="Test the connection with a simple command")
|
|
262
|
+
|
|
263
|
+
# info
|
|
264
|
+
subparsers.add_parser("info", help="Show installation info")
|
|
265
|
+
|
|
266
|
+
# launch
|
|
267
|
+
launch_parser = subparsers.add_parser(
|
|
268
|
+
"launch", help="Launch PyMOL or connect to existing instance"
|
|
269
|
+
)
|
|
270
|
+
launch_parser.add_argument(
|
|
271
|
+
"file", nargs="?", default=None, help="File to open (e.g., .pdb, .cif)"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# exec
|
|
275
|
+
exec_parser = subparsers.add_parser("exec", help="Execute code in PyMOL")
|
|
276
|
+
exec_parser.add_argument(
|
|
277
|
+
"code",
|
|
171
278
|
nargs="?",
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
help="Command to run",
|
|
279
|
+
default=None,
|
|
280
|
+
help="Python code to execute (or pipe via stdin)",
|
|
175
281
|
)
|
|
176
282
|
|
|
177
283
|
args = parser.parse_args()
|
|
178
284
|
|
|
179
|
-
if args.command
|
|
285
|
+
if args.command is None:
|
|
286
|
+
show_info()
|
|
287
|
+
return 0
|
|
288
|
+
elif args.command == "setup":
|
|
180
289
|
return setup_pymol()
|
|
181
290
|
elif args.command == "status":
|
|
182
291
|
return check_status()
|
|
@@ -185,6 +294,10 @@ For Claude Code skills, install the claudemol-skills plugin:
|
|
|
185
294
|
elif args.command == "info":
|
|
186
295
|
show_info()
|
|
187
296
|
return 0
|
|
297
|
+
elif args.command == "launch":
|
|
298
|
+
return do_launch(args)
|
|
299
|
+
elif args.command == "exec":
|
|
300
|
+
return do_exec(args)
|
|
188
301
|
|
|
189
302
|
|
|
190
303
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claudemol
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: PyMOL integration for Claude Code - control molecular visualization via natural language
|
|
5
5
|
Project-URL: Homepage, https://github.com/ANaka/claudemol
|
|
6
6
|
Project-URL: Repository, https://github.com/ANaka/claudemol
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
claudemol/__init__.py,sha256=JPTUCYrIbuBw8Om4QKJre3KG0HZg4mcm91HsnSBnqls,744
|
|
2
|
+
claudemol/cli.py,sha256=9gVAY-MfrKFv4me9QKTuHHi_EeJEz54rA2UpRMUBhhY,9175
|
|
3
|
+
claudemol/connection.py,sha256=pJXO5eBXir8NHXohOl5gk3YSE5bv0zggDK9cfnP0hE0,8333
|
|
4
|
+
claudemol/plugin.py,sha256=xRqpd9Ncn2vDZnmZsKHcFrhISJng38FAZv_0Thy-axc,5513
|
|
5
|
+
claudemol/session.py,sha256=BtaIx9UalvnnlmQ1Zr9HFAlvt_0HzrAnT952HPpFG4w,8258
|
|
6
|
+
claudemol/view.py,sha256=k5wzx2jOeYgZKJKNJfk-3Aat3iDvKU-8y9dMAjb4E-A,4103
|
|
7
|
+
claudemol-0.4.0.dist-info/METADATA,sha256=p6E78_QKolJyxD2mXhCeE1mxSd4gQ2J59O9EM73e7V0,6593
|
|
8
|
+
claudemol-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
9
|
+
claudemol-0.4.0.dist-info/entry_points.txt,sha256=zHSqaPcqaXWoGEavppdq_zTrMARmjjrTqLHa5KEBchw,49
|
|
10
|
+
claudemol-0.4.0.dist-info/licenses/LICENSE,sha256=sZWsSm99w9tlHsmCnA7_6KzEAqQaD7nSQlgYesvvWMQ,1075
|
|
11
|
+
claudemol-0.4.0.dist-info/RECORD,,
|
claudemol-0.3.0.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
claudemol/__init__.py,sha256=SaNeozowULmMoX3-9qAlG9sNk--xgkreurxppLkVE4A,744
|
|
2
|
-
claudemol/cli.py,sha256=fF3hfDLZVx5W6LYO2OOoPGnkvTHbQqF1H6FX1pIfMeQ,5850
|
|
3
|
-
claudemol/connection.py,sha256=pJXO5eBXir8NHXohOl5gk3YSE5bv0zggDK9cfnP0hE0,8333
|
|
4
|
-
claudemol/plugin.py,sha256=xRqpd9Ncn2vDZnmZsKHcFrhISJng38FAZv_0Thy-axc,5513
|
|
5
|
-
claudemol/session.py,sha256=BtaIx9UalvnnlmQ1Zr9HFAlvt_0HzrAnT952HPpFG4w,8258
|
|
6
|
-
claudemol/view.py,sha256=k5wzx2jOeYgZKJKNJfk-3Aat3iDvKU-8y9dMAjb4E-A,4103
|
|
7
|
-
claudemol-0.3.0.dist-info/METADATA,sha256=qv5TatSb0fhnNjx30iqiuvmiyUR6gX_Va6E7IpWdJLY,6593
|
|
8
|
-
claudemol-0.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
9
|
-
claudemol-0.3.0.dist-info/entry_points.txt,sha256=zHSqaPcqaXWoGEavppdq_zTrMARmjjrTqLHa5KEBchw,49
|
|
10
|
-
claudemol-0.3.0.dist-info/licenses/LICENSE,sha256=sZWsSm99w9tlHsmCnA7_6KzEAqQaD7nSQlgYesvvWMQ,1075
|
|
11
|
-
claudemol-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|