clipsy 1.5.0__py3-none-any.whl → 1.7.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.
clipsy/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "1.5.0"
1
+ __version__ = "1.7.0"
2
2
  __app_name__ = "Clipsy"
clipsy/__main__.py CHANGED
@@ -1,11 +1,136 @@
1
+ import argparse
1
2
  import logging
3
+ import os
4
+ import subprocess
2
5
  import sys
6
+ from pathlib import Path
3
7
 
4
8
  from clipsy.config import LOG_PATH
5
9
  from clipsy.utils import ensure_dirs
6
10
 
11
+ PLIST_NAME = "com.clipsy.app.plist"
12
+ LAUNCHAGENT_DIR = Path.home() / "Library" / "LaunchAgents"
13
+ PLIST_PATH = LAUNCHAGENT_DIR / PLIST_NAME
7
14
 
8
- def main():
15
+
16
+ def get_clipsy_path() -> str:
17
+ """Get the path to the clipsy executable."""
18
+ import shutil
19
+
20
+ # Check if we're running from an installed location
21
+ clipsy_path = shutil.which("clipsy")
22
+ if clipsy_path:
23
+ return clipsy_path
24
+ # Fallback to current Python module
25
+ return f"{sys.executable} -m clipsy"
26
+
27
+
28
+ def create_plist(clipsy_path: str) -> str:
29
+ """Generate the LaunchAgent plist content."""
30
+ data_dir = Path.home() / ".local" / "share" / "clipsy"
31
+ return f"""<?xml version="1.0" encoding="UTF-8"?>
32
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
+ <plist version="1.0">
34
+ <dict>
35
+ <key>Label</key>
36
+ <string>com.clipsy.app</string>
37
+ <key>ProgramArguments</key>
38
+ <array>
39
+ <string>{clipsy_path}</string>
40
+ </array>
41
+ <key>RunAtLoad</key>
42
+ <true/>
43
+ <key>KeepAlive</key>
44
+ <true/>
45
+ <key>StandardOutPath</key>
46
+ <string>{data_dir}/clipsy.log</string>
47
+ <key>StandardErrorPath</key>
48
+ <string>{data_dir}/clipsy.log</string>
49
+ </dict>
50
+ </plist>
51
+ """
52
+
53
+
54
+ def install_launchagent() -> int:
55
+ """Install and start the LaunchAgent."""
56
+ ensure_dirs()
57
+
58
+ clipsy_path = get_clipsy_path()
59
+ print(f"Installing LaunchAgent for: {clipsy_path}")
60
+
61
+ # Create LaunchAgents directory if needed
62
+ LAUNCHAGENT_DIR.mkdir(parents=True, exist_ok=True)
63
+
64
+ # Unload existing if present
65
+ if PLIST_PATH.exists():
66
+ subprocess.run(
67
+ ["launchctl", "unload", str(PLIST_PATH)],
68
+ capture_output=True,
69
+ )
70
+
71
+ # Write plist
72
+ PLIST_PATH.write_text(create_plist(clipsy_path))
73
+ print(f"Created: {PLIST_PATH}")
74
+
75
+ # Load the agent
76
+ result = subprocess.run(
77
+ ["launchctl", "load", str(PLIST_PATH)],
78
+ capture_output=True,
79
+ text=True,
80
+ )
81
+
82
+ if result.returncode == 0:
83
+ print("Clipsy is now running in the background.")
84
+ print("It will start automatically on login.")
85
+ return 0
86
+ else:
87
+ print(f"Failed to load LaunchAgent: {result.stderr}")
88
+ return 1
89
+
90
+
91
+ def uninstall_launchagent() -> int:
92
+ """Stop and remove the LaunchAgent."""
93
+ if not PLIST_PATH.exists():
94
+ print("LaunchAgent not installed.")
95
+ return 0
96
+
97
+ # Unload
98
+ subprocess.run(
99
+ ["launchctl", "unload", str(PLIST_PATH)],
100
+ capture_output=True,
101
+ )
102
+
103
+ # Remove plist
104
+ PLIST_PATH.unlink()
105
+ print("LaunchAgent uninstalled.")
106
+ print("Clipsy will no longer start on login.")
107
+ return 0
108
+
109
+
110
+ def check_status() -> int:
111
+ """Check if Clipsy is running."""
112
+ result = subprocess.run(
113
+ ["launchctl", "list", "com.clipsy.app"],
114
+ capture_output=True,
115
+ text=True,
116
+ )
117
+
118
+ if result.returncode == 0:
119
+ print("Clipsy is running.")
120
+ if PLIST_PATH.exists():
121
+ print(f"LaunchAgent: {PLIST_PATH}")
122
+ return 0
123
+ else:
124
+ print("Clipsy is not running.")
125
+ if PLIST_PATH.exists():
126
+ print(f"LaunchAgent installed but not loaded: {PLIST_PATH}")
127
+ else:
128
+ print("LaunchAgent not installed. Run: clipsy install")
129
+ return 1
130
+
131
+
132
+ def run_app():
133
+ """Run the Clipsy application."""
9
134
  ensure_dirs()
10
135
 
11
136
  logging.basicConfig(
@@ -18,9 +143,48 @@ def main():
18
143
  )
19
144
 
20
145
  from clipsy.app import ClipsyApp
146
+
21
147
  app = ClipsyApp()
22
148
  app.run()
23
149
 
24
150
 
151
+ def main():
152
+ parser = argparse.ArgumentParser(
153
+ description="Clipsy - Clipboard history manager for macOS",
154
+ formatter_class=argparse.RawDescriptionHelpFormatter,
155
+ epilog="""
156
+ Commands:
157
+ (none) Install and run as background service (default)
158
+ uninstall Remove LaunchAgent
159
+ status Check if Clipsy is running
160
+ run Run in foreground (for debugging)
161
+
162
+ Examples:
163
+ clipsy # Install and start as background service
164
+ clipsy status # Check if running
165
+ clipsy uninstall # Stop and remove from login items
166
+ clipsy run # Run in foreground (debugging)
167
+ """,
168
+ )
169
+ parser.add_argument(
170
+ "command",
171
+ nargs="?",
172
+ choices=["uninstall", "status", "run"],
173
+ help="Command to run",
174
+ )
175
+
176
+ args = parser.parse_args()
177
+
178
+ if args.command == "uninstall":
179
+ sys.exit(uninstall_launchagent())
180
+ elif args.command == "status":
181
+ sys.exit(check_status())
182
+ elif args.command == "run":
183
+ run_app()
184
+ else:
185
+ # Default: install and start as background service
186
+ sys.exit(install_launchagent())
187
+
188
+
25
189
  if __name__ == "__main__":
26
190
  main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clipsy
3
- Version: 1.5.0
3
+ Version: 1.7.0
4
4
  Summary: Lightweight clipboard history manager for macOS
5
5
  Author-email: Brendan Conrad <brendan.conrad@gmail.com>
6
6
  License: MIT
@@ -59,10 +59,19 @@ A lightweight clipboard history manager for macOS. Runs as a menu bar icon — n
59
59
 
60
60
  ## Installation
61
61
 
62
- ### Via pip (recommended)
62
+ ### Via pipx (recommended)
63
+
64
+ ```bash
65
+ brew install pipx
66
+ pipx install clipsy
67
+ clipsy
68
+ ```
69
+
70
+ ### Via pip
63
71
 
64
72
  ```bash
65
73
  pip install clipsy
74
+ clipsy
66
75
  ```
67
76
 
68
77
  ### From source
@@ -72,14 +81,12 @@ git clone https://github.com/brencon/clipsy.git
72
81
  cd clipsy
73
82
  python3 -m venv .venv
74
83
  .venv/bin/pip install -e .
84
+ .venv/bin/clipsy
75
85
  ```
76
86
 
77
87
  ## Usage
78
88
 
79
- ```bash
80
- # Run clipsy (a scissors icon appears in your menu bar)
81
- clipsy
82
- ```
89
+ After running `clipsy`, the app installs as a background service and starts automatically on login. A scissors icon (✂️) appears in your menu bar.
83
90
 
84
91
  Then just use your Mac normally. Every time you copy something, it shows up in the Clipsy menu:
85
92
 
@@ -102,19 +109,13 @@ Then just use your Mac normally. Every time you copy something, it shows up in t
102
109
  └── Quit Clipsy
103
110
  ```
104
111
 
105
- ## Auto-Start on Login
106
-
107
- Run clipsy automatically when you log in — no terminal needed:
112
+ ## Commands
108
113
 
109
114
  ```bash
110
- # Install as a LaunchAgent
111
- scripts/install_launchagent.sh install
112
-
113
- # Check status
114
- scripts/install_launchagent.sh status
115
-
116
- # Remove auto-start
117
- scripts/install_launchagent.sh uninstall
115
+ clipsy # Install and start as background service (default)
116
+ clipsy status # Check if running
117
+ clipsy uninstall # Remove from login items
118
+ clipsy run # Run in foreground (for debugging)
118
119
  ```
119
120
 
120
121
  ## Data Storage
@@ -1,5 +1,5 @@
1
- clipsy/__init__.py,sha256=RfTNMAT90hngQkclaI0i0rdsR5s2s2IFJWzExWhvwjU,46
2
- clipsy/__main__.py,sha256=vCWOKz08ZY3Uc5orHOMND0sEgBnyvD0WkD4o6b4_6Mw,493
1
+ clipsy/__init__.py,sha256=5B_3MB6DYDXcJfVxDSzafJY1_-IM-eLcNadIWCMyJTc,46
2
+ clipsy/__main__.py,sha256=Ipb_HlLKeG5TPKdaAd4FALgrvCX9PPw9TuMF1BH0AAQ,4962
3
3
  clipsy/app.py,sha256=_IKuZgA-DvAE3KDsDN00S0aaMIxwBpiv_P1fpzwQFqU,7299
4
4
  clipsy/config.py,sha256=E9NCsGMeT2H0YXYCq5xYwbd27VkksV4S9txZSMX0RmE,672
5
5
  clipsy/models.py,sha256=i3KjD4Dcp7y_gTXkIBr2xZxFIIC6kHaMWmv6cSIDABM,563
@@ -7,9 +7,9 @@ clipsy/monitor.py,sha256=UUKZToYcZ5pzu7LfiuJ_nnE4AA-d3uLW-WdQU_XrDME,6288
7
7
  clipsy/redact.py,sha256=EU2nq8oEDYLZ_I_9tX2bXACIF971a0V_ApKdvpN4VGY,7284
8
8
  clipsy/storage.py,sha256=QNox2-spkVx_gMPSWqKgF_yj-SMpRJ4UAT6yd9l6rVY,9794
9
9
  clipsy/utils.py,sha256=rztT20cXYJ7633q3oLwt6Fv0Ubq9hm5bPPKDkWyvxdI,2208
10
- clipsy-1.5.0.dist-info/licenses/LICENSE,sha256=bZ7uVihgPnLGryi5ugUgkVrEoho0_hFAd3bVdhYXGqs,1071
11
- clipsy-1.5.0.dist-info/METADATA,sha256=7lAWnXyqO69PZSLoFjOZKU1WuXaaykI0a3V-dUSRkUE,5693
12
- clipsy-1.5.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
13
- clipsy-1.5.0.dist-info/entry_points.txt,sha256=ISIoWU3Zj-4NEuj2pJW96LxpsvjRJJH73otv9gA9YSs,48
14
- clipsy-1.5.0.dist-info/top_level.txt,sha256=trxprVJk4ZMudCshc7PD0N9iFgQO4Tq4sW5L5wLduns,7
15
- clipsy-1.5.0.dist-info/RECORD,,
10
+ clipsy-1.7.0.dist-info/licenses/LICENSE,sha256=bZ7uVihgPnLGryi5ugUgkVrEoho0_hFAd3bVdhYXGqs,1071
11
+ clipsy-1.7.0.dist-info/METADATA,sha256=xO1ksDaZw867EM92OS3AsH8yakCtH1doeytarvNCAtQ,5811
12
+ clipsy-1.7.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
13
+ clipsy-1.7.0.dist-info/entry_points.txt,sha256=ISIoWU3Zj-4NEuj2pJW96LxpsvjRJJH73otv9gA9YSs,48
14
+ clipsy-1.7.0.dist-info/top_level.txt,sha256=trxprVJk4ZMudCshc7PD0N9iFgQO4Tq4sW5L5wLduns,7
15
+ clipsy-1.7.0.dist-info/RECORD,,
File without changes