abstractassistant 0.3.2__py3-none-any.whl → 0.3.4__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.
setup_macos_app.py DELETED
@@ -1,323 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- macOS App Bundle Generator for AbstractAssistant.
4
-
5
- Creates a native macOS .app bundle with Dock integration and system tray support.
6
- Usage: create-app-bundle (after pip install abstractassistant)
7
- """
8
-
9
- import os
10
- import sys
11
- import shutil
12
- import subprocess
13
- from pathlib import Path
14
-
15
- try:
16
- from PIL import Image
17
- PIL_AVAILABLE = True
18
- except ImportError:
19
- PIL_AVAILABLE = False
20
-
21
-
22
- class MacOSAppBundleGenerator:
23
- """Generates macOS app bundles for AbstractAssistant."""
24
-
25
- def __init__(self, package_dir: Path):
26
- """Initialize the app bundle generator.
27
-
28
- Args:
29
- package_dir: Path to the abstractassistant package directory
30
- """
31
- self.package_dir = package_dir
32
- self.app_name = "AbstractAssistant"
33
- self.app_bundle_path = Path("/Applications") / f"{self.app_name}.app"
34
-
35
- def is_macos(self) -> bool:
36
- """Check if running on macOS."""
37
- return sys.platform == "darwin"
38
-
39
- def has_permissions(self) -> bool:
40
- """Check if we have permissions to write to /Applications."""
41
- try:
42
- test_file = Path("/Applications") / ".test_write_permission"
43
- test_file.touch()
44
- test_file.unlink()
45
- return True
46
- except (PermissionError, OSError):
47
- return False
48
-
49
- def create_app_bundle_structure(self) -> bool:
50
- """Create the basic app bundle directory structure."""
51
- try:
52
- # Create main directories
53
- contents_dir = self.app_bundle_path / "Contents"
54
- macos_dir = contents_dir / "MacOS"
55
- resources_dir = contents_dir / "Resources"
56
-
57
- for directory in [contents_dir, macos_dir, resources_dir]:
58
- directory.mkdir(parents=True, exist_ok=True)
59
-
60
- return True
61
- except Exception as e:
62
- print(f"Error creating app bundle structure: {e}")
63
- return False
64
-
65
- def generate_app_icon(self) -> bool:
66
- """Generate the app icon using the existing icon generator."""
67
- try:
68
- # Import the icon generator
69
- sys.path.insert(0, str(self.package_dir))
70
- from abstractassistant.utils.icon_generator import IconGenerator
71
-
72
- # Generate high-resolution icon
73
- generator = IconGenerator(size=512)
74
- icon = generator.create_app_icon('blue', animated=False)
75
-
76
- # Save as PNG
77
- icon_path = self.app_bundle_path / "Contents" / "Resources" / "icon.png"
78
- icon.save(str(icon_path))
79
-
80
- # Create ICNS file
81
- return self._create_icns_file(icon_path)
82
-
83
- except Exception as e:
84
- print(f"Error generating app icon: {e}")
85
- return False
86
-
87
- def _create_icns_file(self, png_path: Path) -> bool:
88
- """Create ICNS file from PNG using macOS iconutil."""
89
- try:
90
- # Create iconset directory
91
- iconset_dir = png_path.parent / "temp_icons.iconset"
92
- iconset_dir.mkdir(exist_ok=True)
93
-
94
- # Load the PNG and create different sizes
95
- icon = Image.open(png_path)
96
- sizes = [
97
- (16, 'icon_16x16.png'),
98
- (32, 'icon_16x16@2x.png'),
99
- (32, 'icon_32x32.png'),
100
- (64, 'icon_32x32@2x.png'),
101
- (128, 'icon_128x128.png'),
102
- (256, 'icon_128x128@2x.png'),
103
- (256, 'icon_256x256.png'),
104
- (512, 'icon_256x256@2x.png'),
105
- (512, 'icon_512x512.png'),
106
- (1024, 'icon_512x512@2x.png')
107
- ]
108
-
109
- for size, filename in sizes:
110
- resized = icon.resize((size, size), Image.Resampling.LANCZOS)
111
- resized.save(iconset_dir / filename)
112
-
113
- # Convert to ICNS
114
- icns_path = png_path.parent / "icon.icns"
115
- result = subprocess.run([
116
- 'iconutil', '-c', 'icns', str(iconset_dir),
117
- '-o', str(icns_path)
118
- ], capture_output=True, text=True)
119
-
120
- # Clean up
121
- shutil.rmtree(iconset_dir)
122
-
123
- return result.returncode == 0
124
-
125
- except Exception as e:
126
- print(f"Error creating ICNS file: {e}")
127
- return False
128
-
129
- def create_info_plist(self) -> bool:
130
- """Create the Info.plist file."""
131
- try:
132
- plist_content = '''<?xml version="1.0" encoding="UTF-8"?>
133
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
134
- <plist version="1.0">
135
- <dict>
136
- <key>CFBundleExecutable</key>
137
- <string>AbstractAssistant</string>
138
- <key>CFBundleIdentifier</key>
139
- <string>ai.abstractcore.abstractassistant</string>
140
- <key>CFBundleName</key>
141
- <string>AbstractAssistant</string>
142
- <key>CFBundleDisplayName</key>
143
- <string>AbstractAssistant</string>
144
- <key>CFBundleVersion</key>
145
- <string>0.2.8</string>
146
- <key>CFBundleShortVersionString</key>
147
- <string>0.2.8</string>
148
- <key>CFBundlePackageType</key>
149
- <string>APPL</string>
150
- <key>CFBundleSignature</key>
151
- <string>????</string>
152
- <key>CFBundleIconFile</key>
153
- <string>icon.icns</string>
154
- <key>LSMinimumSystemVersion</key>
155
- <string>10.15</string>
156
- <key>NSHighResolutionCapable</key>
157
- <true/>
158
- <key>NSRequiresAquaSystemAppearance</key>
159
- <false/>
160
- <key>LSUIElement</key>
161
- <true/>
162
- <key>NSAppleScriptEnabled</key>
163
- <false/>
164
- <key>CFBundleDocumentTypes</key>
165
- <array/>
166
- <key>NSPrincipalClass</key>
167
- <string>NSApplication</string>
168
- </dict>
169
- </plist>'''
170
-
171
- plist_path = self.app_bundle_path / "Contents" / "Info.plist"
172
- plist_path.write_text(plist_content)
173
- return True
174
-
175
- except Exception as e:
176
- print(f"Error creating Info.plist: {e}")
177
- return False
178
-
179
- def create_launch_script(self) -> bool:
180
- """Create the executable launch script."""
181
- try:
182
- script_content = '''#!/bin/bash
183
-
184
- # AbstractAssistant macOS App Launcher
185
- # This script launches the AbstractAssistant application
186
-
187
- # Set up environment paths for GUI launch (common locations)
188
- export PATH="/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:$PATH"
189
-
190
- # Add user-specific Python paths if they exist
191
- if [ -d "$HOME/.pyenv/shims" ]; then
192
- export PATH="$HOME/.pyenv/shims:$PATH"
193
- fi
194
-
195
- if [ -d "$HOME/.local/bin" ]; then
196
- export PATH="$HOME/.local/bin:$PATH"
197
- fi
198
-
199
- if [ -d "/opt/anaconda3/bin" ]; then
200
- export PATH="/opt/anaconda3/bin:$PATH"
201
- fi
202
-
203
- if [ -d "$HOME/anaconda3/bin" ]; then
204
- export PATH="$HOME/anaconda3/bin:$PATH"
205
- fi
206
-
207
- # Function to find Python with abstractassistant installed
208
- find_python_with_abstractassistant() {
209
- # Try specific paths first (more reliable than PATH-based search)
210
- for python_path in \\
211
- "$HOME/.pyenv/versions/*/bin/python3" \\
212
- "$HOME/.pyenv/shims/python3" \\
213
- "/usr/local/bin/python3" \\
214
- "/opt/homebrew/bin/python3" \\
215
- "/usr/bin/python3" \\
216
- "/opt/anaconda3/bin/python" \\
217
- "$HOME/anaconda3/bin/python" \\
218
- "/usr/local/anaconda3/bin/python"; do
219
-
220
- # Expand glob patterns
221
- for py in $python_path; do
222
- if [ -x "$py" ] && "$py" -c "import abstractassistant" 2>/dev/null; then
223
- echo "$py"
224
- return 0
225
- fi
226
- done
227
- done
228
-
229
- # Fallback to PATH-based search
230
- for python_cmd in python3 python python3.12 python3.11 python3.10 python3.9; do
231
- if command -v "$python_cmd" >/dev/null 2>&1; then
232
- if "$python_cmd" -c "import abstractassistant" 2>/dev/null; then
233
- echo "$python_cmd"
234
- return 0
235
- fi
236
- fi
237
- done
238
-
239
- return 1
240
- }
241
-
242
- # Find Python with AbstractAssistant
243
- PYTHON_EXEC=$(find_python_with_abstractassistant)
244
-
245
- if [ -z "$PYTHON_EXEC" ]; then
246
- osascript -e 'display dialog "AbstractAssistant not found in any Python installation.\\n\\nPlease install it with:\\npip install abstractassistant\\n\\nOr run the create-app-bundle command after installation." with title "AbstractAssistant" buttons {"OK"} default button "OK" with icon caution'
247
- exit 1
248
- fi
249
-
250
- # Change to a neutral directory to avoid importing development versions
251
- cd /tmp
252
-
253
- # Launch the assistant
254
- exec "$PYTHON_EXEC" -m abstractassistant.cli "$@"'''
255
-
256
- script_path = self.app_bundle_path / "Contents" / "MacOS" / "AbstractAssistant"
257
- script_path.write_text(script_content)
258
-
259
- # Make executable
260
- os.chmod(script_path, 0o755)
261
- return True
262
-
263
- except Exception as e:
264
- print(f"Error creating launch script: {e}")
265
- return False
266
-
267
- def generate_app_bundle(self) -> bool:
268
- """Generate the complete macOS app bundle."""
269
- if not self.is_macos():
270
- print("macOS app bundle generation is only available on macOS")
271
- return False
272
-
273
- if not self.has_permissions():
274
- print("Insufficient permissions to create app bundle in /Applications")
275
- print("Please run with sudo or manually copy the app bundle")
276
- return False
277
-
278
- print("Creating macOS app bundle...")
279
-
280
- # Remove existing bundle if it exists
281
- if self.app_bundle_path.exists():
282
- shutil.rmtree(self.app_bundle_path)
283
-
284
- # Create bundle structure
285
- if not self.create_app_bundle_structure():
286
- return False
287
-
288
- # Generate icon
289
- if not self.generate_app_icon():
290
- return False
291
-
292
- # Create Info.plist
293
- if not self.create_info_plist():
294
- return False
295
-
296
- # Create launch script
297
- if not self.create_launch_script():
298
- return False
299
-
300
- print(f"✅ macOS app bundle created successfully!")
301
- print(f" Location: {self.app_bundle_path}")
302
- print(f" You can now launch AbstractAssistant from the Dock!")
303
-
304
- return True
305
-
306
-
307
- def create_macos_app_bundle():
308
- """Main function to create macOS app bundle during installation."""
309
- try:
310
- # Find the package directory
311
- package_dir = Path(__file__).parent
312
-
313
- generator = MacOSAppBundleGenerator(package_dir)
314
- return generator.generate_app_bundle()
315
-
316
- except Exception as e:
317
- print(f"Error creating macOS app bundle: {e}")
318
- return False
319
-
320
-
321
- if __name__ == "__main__":
322
- success = create_macos_app_bundle()
323
- sys.exit(0 if success else 1)