gc-shell 0.1.0__tar.gz
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.
- gc_shell-0.1.0/PKG-INFO +169 -0
- gc_shell-0.1.0/README.md +158 -0
- gc_shell-0.1.0/commands/__init__.py +0 -0
- gc_shell-0.1.0/commands/apps.py +202 -0
- gc_shell-0.1.0/commands/files.py +310 -0
- gc_shell-0.1.0/executor.py +273 -0
- gc_shell-0.1.0/gc_shell.egg-info/PKG-INFO +169 -0
- gc_shell-0.1.0/gc_shell.egg-info/SOURCES.txt +16 -0
- gc_shell-0.1.0/gc_shell.egg-info/dependency_links.txt +1 -0
- gc_shell-0.1.0/gc_shell.egg-info/entry_points.txt +2 -0
- gc_shell-0.1.0/gc_shell.egg-info/requires.txt +2 -0
- gc_shell-0.1.0/gc_shell.egg-info/top_level.txt +5 -0
- gc_shell-0.1.0/main.py +12 -0
- gc_shell-0.1.0/pyproject.toml +35 -0
- gc_shell-0.1.0/registry/__init__.py +0 -0
- gc_shell-0.1.0/registry/scanner.py +96 -0
- gc_shell-0.1.0/setup.cfg +4 -0
- gc_shell-0.1.0/shell.py +110 -0
gc_shell-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gc-shell
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An intelligent macOS shell
|
|
5
|
+
Author: Goutham Reddy
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: rich>=13.0
|
|
10
|
+
Requires-Dist: prompt_toolkit>=3.0
|
|
11
|
+
|
|
12
|
+
# 🚀 Goutham Shell
|
|
13
|
+
|
|
14
|
+
A custom interactive shell for macOS that combines the power of a standard terminal with personalized built-in commands.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Clone the repository
|
|
20
|
+
git clone <repo-url>
|
|
21
|
+
cd goutham-shell
|
|
22
|
+
|
|
23
|
+
# Install in development mode
|
|
24
|
+
pip install -e .
|
|
25
|
+
|
|
26
|
+
# Launch the shell
|
|
27
|
+
goutham
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
$ goutham
|
|
34
|
+
🚀 Welcome to Goutham Shell v0.1.0
|
|
35
|
+
Type help for commands, exit to quit.
|
|
36
|
+
|
|
37
|
+
💡 No app registry found. Run scan to discover installed applications.
|
|
38
|
+
|
|
39
|
+
goutham ~ ❯ scan
|
|
40
|
+
🔍 Scanning for applications...
|
|
41
|
+
✓ Found 142 applications
|
|
42
|
+
✓ Registry saved to ~/.goutham/apps.json
|
|
43
|
+
|
|
44
|
+
goutham ~ ❯ open chrome
|
|
45
|
+
▶ Opening Google Chrome...
|
|
46
|
+
|
|
47
|
+
goutham ~ ❯ running
|
|
48
|
+
┌──────────────────────────────┐
|
|
49
|
+
│ Running Applications │
|
|
50
|
+
├────┬─────────────────────────┤
|
|
51
|
+
│ # │ Application │
|
|
52
|
+
├────┼─────────────────────────┤
|
|
53
|
+
│ 1 │ Finder │
|
|
54
|
+
│ 2 │ Google Chrome │
|
|
55
|
+
│ 3 │ Terminal │
|
|
56
|
+
└────┴─────────────────────────┘
|
|
57
|
+
|
|
58
|
+
goutham ~ ❯ ls -la
|
|
59
|
+
total 32
|
|
60
|
+
drwxr-xr-x 8 user staff 256 Jun 26 12:00 .
|
|
61
|
+
...
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Features
|
|
65
|
+
|
|
66
|
+
### System Commands
|
|
67
|
+
|
|
68
|
+
All standard terminal commands work transparently — they're forwarded to your system's `zsh` shell:
|
|
69
|
+
|
|
70
|
+
- `ls`, `pwd`, `cat`, `grep`, `echo`
|
|
71
|
+
- `git status`, `git commit`, `git push`
|
|
72
|
+
- `python app.py`, `node server.js`
|
|
73
|
+
- `docker ps`, `npm run dev`
|
|
74
|
+
- Pipes (`|`), redirection (`>`), chaining (`&&`)
|
|
75
|
+
|
|
76
|
+
### Custom Commands
|
|
77
|
+
|
|
78
|
+
| Command | Description |
|
|
79
|
+
|---------|-------------|
|
|
80
|
+
| `scan` | Scan /Applications and build the app registry |
|
|
81
|
+
| `open <app>` | Open an application by name (fuzzy matching) |
|
|
82
|
+
| `close <app>` | Close a running application |
|
|
83
|
+
| `apps` | List all registered applications |
|
|
84
|
+
| `running` | List currently running GUI applications |
|
|
85
|
+
| `tree [path]` | Display a directory tree (`--depth N`) |
|
|
86
|
+
| `preview <file>` | Preview a file with syntax highlighting (`--lines N`) |
|
|
87
|
+
| `mkp <dir>` | Create nested directories (like `mkdir -p`) |
|
|
88
|
+
| `search <pattern>` | Find files by glob pattern (`--path <dir>`) |
|
|
89
|
+
| `help` | Show all available commands |
|
|
90
|
+
| `exit` / `quit` | Exit the shell |
|
|
91
|
+
|
|
92
|
+
### App Management
|
|
93
|
+
|
|
94
|
+
On first run, use `scan` to discover installed applications. Then use `open` and `close` with **fuzzy name matching** — no need to type the full name:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
goutham ~ ❯ open chrome # Opens "Google Chrome"
|
|
98
|
+
goutham ~ ❯ open code # Opens "Visual Studio Code"
|
|
99
|
+
goutham ~ ❯ close spotify # Closes "Spotify"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The `open` command is smart — paths, URLs, and flags are forwarded to the system `open`:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
goutham ~ ❯ open . # Opens current dir in Finder
|
|
106
|
+
goutham ~ ❯ open https://x.com # Opens URL in default browser
|
|
107
|
+
goutham ~ ❯ open -a Safari # System open with flags
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Architecture
|
|
111
|
+
|
|
112
|
+
Goutham Shell is a **wrapper shell** — it intercepts custom commands while forwarding everything else transparently to `zsh`.
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
User Input → Command Parser → Custom Command? → Execute Handler
|
|
116
|
+
↓ No
|
|
117
|
+
Forward to zsh via subprocess
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Key design decisions:
|
|
121
|
+
|
|
122
|
+
- **Shell state is maintained in-process**: `cd` updates `current_directory` so subsequent commands run in the right place.
|
|
123
|
+
- **No hardcoded paths**: All app paths come from the scanned registry at `~/.goutham/apps.json`.
|
|
124
|
+
- **`shell=True` forwarding**: Preserves pipes, redirection, globbing, and chaining — users get the full power of `zsh`.
|
|
125
|
+
|
|
126
|
+
## Requirements
|
|
127
|
+
|
|
128
|
+
- macOS 10.15+
|
|
129
|
+
- Python 3.9+
|
|
130
|
+
- [Rich](https://github.com/Textualize/rich) (installed automatically)
|
|
131
|
+
|
|
132
|
+
## Configuration
|
|
133
|
+
|
|
134
|
+
All configuration is stored in `~/.goutham/`:
|
|
135
|
+
|
|
136
|
+
| File | Purpose |
|
|
137
|
+
|------|---------|
|
|
138
|
+
| `apps.json` | Application registry (generated by `scan`) |
|
|
139
|
+
|
|
140
|
+
## Project Structure
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
goutham-shell/
|
|
144
|
+
├── main.py # Entry point
|
|
145
|
+
├── shell.py # Interactive REPL loop
|
|
146
|
+
├── executor.py # Command routing & shell state
|
|
147
|
+
├── commands/
|
|
148
|
+
│ ├── apps.py # open, close, apps, running
|
|
149
|
+
│ └── files.py # tree, preview, mkp, search
|
|
150
|
+
├── registry/
|
|
151
|
+
│ └── scanner.py # macOS app scanner
|
|
152
|
+
├── ai/ # Phase 5+ (AI commands)
|
|
153
|
+
├── utils/
|
|
154
|
+
├── pyproject.toml
|
|
155
|
+
└── README.md
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Roadmap
|
|
159
|
+
|
|
160
|
+
- [x] Phase 1 — Interactive shell skeleton
|
|
161
|
+
- [x] Phase 2 — System command forwarding with persistent state
|
|
162
|
+
- [x] Phase 3 — Custom built-in commands (app management)
|
|
163
|
+
- [x] Phase 4 — File utility commands
|
|
164
|
+
- [ ] Phase 5 — AI commands (`ai explain`, `ai generate`, `ai summarize`)
|
|
165
|
+
- [ ] Phase 6 — LangGraph agent workflows
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
gc_shell-0.1.0/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# 🚀 Goutham Shell
|
|
2
|
+
|
|
3
|
+
A custom interactive shell for macOS that combines the power of a standard terminal with personalized built-in commands.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Clone the repository
|
|
9
|
+
git clone <repo-url>
|
|
10
|
+
cd goutham-shell
|
|
11
|
+
|
|
12
|
+
# Install in development mode
|
|
13
|
+
pip install -e .
|
|
14
|
+
|
|
15
|
+
# Launch the shell
|
|
16
|
+
goutham
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
$ goutham
|
|
23
|
+
🚀 Welcome to Goutham Shell v0.1.0
|
|
24
|
+
Type help for commands, exit to quit.
|
|
25
|
+
|
|
26
|
+
💡 No app registry found. Run scan to discover installed applications.
|
|
27
|
+
|
|
28
|
+
goutham ~ ❯ scan
|
|
29
|
+
🔍 Scanning for applications...
|
|
30
|
+
✓ Found 142 applications
|
|
31
|
+
✓ Registry saved to ~/.goutham/apps.json
|
|
32
|
+
|
|
33
|
+
goutham ~ ❯ open chrome
|
|
34
|
+
▶ Opening Google Chrome...
|
|
35
|
+
|
|
36
|
+
goutham ~ ❯ running
|
|
37
|
+
┌──────────────────────────────┐
|
|
38
|
+
│ Running Applications │
|
|
39
|
+
├────┬─────────────────────────┤
|
|
40
|
+
│ # │ Application │
|
|
41
|
+
├────┼─────────────────────────┤
|
|
42
|
+
│ 1 │ Finder │
|
|
43
|
+
│ 2 │ Google Chrome │
|
|
44
|
+
│ 3 │ Terminal │
|
|
45
|
+
└────┴─────────────────────────┘
|
|
46
|
+
|
|
47
|
+
goutham ~ ❯ ls -la
|
|
48
|
+
total 32
|
|
49
|
+
drwxr-xr-x 8 user staff 256 Jun 26 12:00 .
|
|
50
|
+
...
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
### System Commands
|
|
56
|
+
|
|
57
|
+
All standard terminal commands work transparently — they're forwarded to your system's `zsh` shell:
|
|
58
|
+
|
|
59
|
+
- `ls`, `pwd`, `cat`, `grep`, `echo`
|
|
60
|
+
- `git status`, `git commit`, `git push`
|
|
61
|
+
- `python app.py`, `node server.js`
|
|
62
|
+
- `docker ps`, `npm run dev`
|
|
63
|
+
- Pipes (`|`), redirection (`>`), chaining (`&&`)
|
|
64
|
+
|
|
65
|
+
### Custom Commands
|
|
66
|
+
|
|
67
|
+
| Command | Description |
|
|
68
|
+
|---------|-------------|
|
|
69
|
+
| `scan` | Scan /Applications and build the app registry |
|
|
70
|
+
| `open <app>` | Open an application by name (fuzzy matching) |
|
|
71
|
+
| `close <app>` | Close a running application |
|
|
72
|
+
| `apps` | List all registered applications |
|
|
73
|
+
| `running` | List currently running GUI applications |
|
|
74
|
+
| `tree [path]` | Display a directory tree (`--depth N`) |
|
|
75
|
+
| `preview <file>` | Preview a file with syntax highlighting (`--lines N`) |
|
|
76
|
+
| `mkp <dir>` | Create nested directories (like `mkdir -p`) |
|
|
77
|
+
| `search <pattern>` | Find files by glob pattern (`--path <dir>`) |
|
|
78
|
+
| `help` | Show all available commands |
|
|
79
|
+
| `exit` / `quit` | Exit the shell |
|
|
80
|
+
|
|
81
|
+
### App Management
|
|
82
|
+
|
|
83
|
+
On first run, use `scan` to discover installed applications. Then use `open` and `close` with **fuzzy name matching** — no need to type the full name:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
goutham ~ ❯ open chrome # Opens "Google Chrome"
|
|
87
|
+
goutham ~ ❯ open code # Opens "Visual Studio Code"
|
|
88
|
+
goutham ~ ❯ close spotify # Closes "Spotify"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The `open` command is smart — paths, URLs, and flags are forwarded to the system `open`:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
goutham ~ ❯ open . # Opens current dir in Finder
|
|
95
|
+
goutham ~ ❯ open https://x.com # Opens URL in default browser
|
|
96
|
+
goutham ~ ❯ open -a Safari # System open with flags
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Architecture
|
|
100
|
+
|
|
101
|
+
Goutham Shell is a **wrapper shell** — it intercepts custom commands while forwarding everything else transparently to `zsh`.
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
User Input → Command Parser → Custom Command? → Execute Handler
|
|
105
|
+
↓ No
|
|
106
|
+
Forward to zsh via subprocess
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Key design decisions:
|
|
110
|
+
|
|
111
|
+
- **Shell state is maintained in-process**: `cd` updates `current_directory` so subsequent commands run in the right place.
|
|
112
|
+
- **No hardcoded paths**: All app paths come from the scanned registry at `~/.goutham/apps.json`.
|
|
113
|
+
- **`shell=True` forwarding**: Preserves pipes, redirection, globbing, and chaining — users get the full power of `zsh`.
|
|
114
|
+
|
|
115
|
+
## Requirements
|
|
116
|
+
|
|
117
|
+
- macOS 10.15+
|
|
118
|
+
- Python 3.9+
|
|
119
|
+
- [Rich](https://github.com/Textualize/rich) (installed automatically)
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
All configuration is stored in `~/.goutham/`:
|
|
124
|
+
|
|
125
|
+
| File | Purpose |
|
|
126
|
+
|------|---------|
|
|
127
|
+
| `apps.json` | Application registry (generated by `scan`) |
|
|
128
|
+
|
|
129
|
+
## Project Structure
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
goutham-shell/
|
|
133
|
+
├── main.py # Entry point
|
|
134
|
+
├── shell.py # Interactive REPL loop
|
|
135
|
+
├── executor.py # Command routing & shell state
|
|
136
|
+
├── commands/
|
|
137
|
+
│ ├── apps.py # open, close, apps, running
|
|
138
|
+
│ └── files.py # tree, preview, mkp, search
|
|
139
|
+
├── registry/
|
|
140
|
+
│ └── scanner.py # macOS app scanner
|
|
141
|
+
├── ai/ # Phase 5+ (AI commands)
|
|
142
|
+
├── utils/
|
|
143
|
+
├── pyproject.toml
|
|
144
|
+
└── README.md
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Roadmap
|
|
148
|
+
|
|
149
|
+
- [x] Phase 1 — Interactive shell skeleton
|
|
150
|
+
- [x] Phase 2 — System command forwarding with persistent state
|
|
151
|
+
- [x] Phase 3 — Custom built-in commands (app management)
|
|
152
|
+
- [x] Phase 4 — File utility commands
|
|
153
|
+
- [ ] Phase 5 — AI commands (`ai explain`, `ai generate`, `ai summarize`)
|
|
154
|
+
- [ ] Phase 6 — LangGraph agent workflows
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT
|
|
File without changes
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""App management commands — open, close, list apps, list running."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
|
|
8
|
+
from registry.scanner import get_registry_path, load_registry
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
# Fuzzy matching
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
def _fuzzy_match(query: str, registry: dict) -> tuple | None:
|
|
16
|
+
"""Find the best match for *query* in the registry.
|
|
17
|
+
|
|
18
|
+
Match precedence:
|
|
19
|
+
1. Exact key match (e.g. "google chrome" → "google chrome")
|
|
20
|
+
2. Query is a substring of a key (e.g. "chrome" → "google chrome")
|
|
21
|
+
3. Key is a substring of the query
|
|
22
|
+
When multiple candidates tie, the shortest key wins (most specific).
|
|
23
|
+
"""
|
|
24
|
+
query = query.lower().strip()
|
|
25
|
+
|
|
26
|
+
# 1. Exact match
|
|
27
|
+
if query in registry:
|
|
28
|
+
return query, registry[query]
|
|
29
|
+
|
|
30
|
+
# 2/3. Substring matches
|
|
31
|
+
matches = [
|
|
32
|
+
(key, info)
|
|
33
|
+
for key, info in registry.items()
|
|
34
|
+
if query in key or key in query
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
if len(matches) == 1:
|
|
38
|
+
return matches[0]
|
|
39
|
+
if len(matches) > 1:
|
|
40
|
+
matches.sort(key=lambda x: len(x[0]))
|
|
41
|
+
return matches[0]
|
|
42
|
+
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# Commands
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
def open_app(name: str, console: Console) -> bool:
|
|
51
|
+
"""Open an application by name.
|
|
52
|
+
|
|
53
|
+
Returns True if the app was found (whether or not it launched successfully),
|
|
54
|
+
False if no match was found so the caller can fall through.
|
|
55
|
+
"""
|
|
56
|
+
registry = load_registry()
|
|
57
|
+
|
|
58
|
+
if not registry:
|
|
59
|
+
console.print(
|
|
60
|
+
"[yellow]⚠ No app registry found. "
|
|
61
|
+
"Run [bold]scan[/bold] first.[/yellow]"
|
|
62
|
+
)
|
|
63
|
+
return True # handled (with a warning), don't fall through
|
|
64
|
+
|
|
65
|
+
match = _fuzzy_match(name, registry)
|
|
66
|
+
|
|
67
|
+
if match:
|
|
68
|
+
_key, info = match
|
|
69
|
+
app_name = info["name"]
|
|
70
|
+
console.print(f"[green]▶[/green] Opening [bold]{app_name}[/bold]...")
|
|
71
|
+
try:
|
|
72
|
+
subprocess.run(
|
|
73
|
+
["open", "-a", info["path"]],
|
|
74
|
+
check=True,
|
|
75
|
+
capture_output=True,
|
|
76
|
+
text=True,
|
|
77
|
+
)
|
|
78
|
+
except subprocess.CalledProcessError as e:
|
|
79
|
+
console.print(
|
|
80
|
+
f"[red]✗ Failed to open {app_name}:[/red] {e.stderr.strip()}"
|
|
81
|
+
)
|
|
82
|
+
return True
|
|
83
|
+
|
|
84
|
+
return False # not in registry — let the executor fall through
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def close_app(name: str, console: Console) -> None:
|
|
88
|
+
"""Close an application by name via AppleScript quit."""
|
|
89
|
+
registry = load_registry()
|
|
90
|
+
|
|
91
|
+
if not registry:
|
|
92
|
+
console.print(
|
|
93
|
+
"[yellow]⚠ No app registry found. "
|
|
94
|
+
"Run [bold]scan[/bold] first.[/yellow]"
|
|
95
|
+
)
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
match = _fuzzy_match(name, registry)
|
|
99
|
+
|
|
100
|
+
if match:
|
|
101
|
+
_key, info = match
|
|
102
|
+
app_name = info["name"]
|
|
103
|
+
console.print(f"[red]■[/red] Closing [bold]{app_name}[/bold]...")
|
|
104
|
+
try:
|
|
105
|
+
subprocess.run(
|
|
106
|
+
[
|
|
107
|
+
"osascript",
|
|
108
|
+
"-e",
|
|
109
|
+
f'tell application "{app_name}" to quit',
|
|
110
|
+
],
|
|
111
|
+
check=True,
|
|
112
|
+
capture_output=True,
|
|
113
|
+
text=True,
|
|
114
|
+
)
|
|
115
|
+
except subprocess.CalledProcessError:
|
|
116
|
+
# Fallback: SIGTERM via pkill
|
|
117
|
+
try:
|
|
118
|
+
subprocess.run(
|
|
119
|
+
["pkill", "-f", app_name], capture_output=True
|
|
120
|
+
)
|
|
121
|
+
except Exception:
|
|
122
|
+
console.print(f"[red]✗ Could not close {app_name}[/red]")
|
|
123
|
+
else:
|
|
124
|
+
console.print(f"[red]✗ App '{name}' not found in registry.[/red]")
|
|
125
|
+
console.print(
|
|
126
|
+
"[dim]Run [bold]scan[/bold] to update the app registry.[/dim]"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def list_apps(console: Console) -> None:
|
|
131
|
+
"""Print a table of all registered applications."""
|
|
132
|
+
registry = load_registry()
|
|
133
|
+
|
|
134
|
+
if not registry:
|
|
135
|
+
console.print(
|
|
136
|
+
"[yellow]⚠ No app registry found. "
|
|
137
|
+
"Run [bold]scan[/bold] first.[/yellow]"
|
|
138
|
+
)
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
table = Table(
|
|
142
|
+
title="Registered Applications",
|
|
143
|
+
show_lines=False,
|
|
144
|
+
border_style="dim",
|
|
145
|
+
title_style="bold cyan",
|
|
146
|
+
)
|
|
147
|
+
table.add_column("#", style="dim", justify="right", width=4)
|
|
148
|
+
table.add_column("Application", style="cyan bold", no_wrap=True)
|
|
149
|
+
table.add_column("Path", style="dim")
|
|
150
|
+
|
|
151
|
+
for i, key in enumerate(sorted(registry.keys()), 1):
|
|
152
|
+
info = registry[key]
|
|
153
|
+
table.add_row(str(i), info["name"], info["path"])
|
|
154
|
+
|
|
155
|
+
console.print()
|
|
156
|
+
console.print(table)
|
|
157
|
+
console.print(
|
|
158
|
+
f"\n[dim]{len(registry)} applications registered • "
|
|
159
|
+
f"Registry: {get_registry_path()}[/dim]\n"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def list_running(console: Console) -> None:
|
|
164
|
+
"""List currently running GUI applications via System Events."""
|
|
165
|
+
try:
|
|
166
|
+
result = subprocess.run(
|
|
167
|
+
[
|
|
168
|
+
"osascript",
|
|
169
|
+
"-e",
|
|
170
|
+
'tell application "System Events" to get name of '
|
|
171
|
+
"every process whose background only is false",
|
|
172
|
+
],
|
|
173
|
+
capture_output=True,
|
|
174
|
+
text=True,
|
|
175
|
+
check=True,
|
|
176
|
+
)
|
|
177
|
+
app_names = sorted(
|
|
178
|
+
name.strip() for name in result.stdout.strip().split(", ")
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
table = Table(
|
|
182
|
+
title="Running Applications",
|
|
183
|
+
show_lines=False,
|
|
184
|
+
border_style="dim",
|
|
185
|
+
title_style="bold green",
|
|
186
|
+
)
|
|
187
|
+
table.add_column("#", style="dim", justify="right", width=4)
|
|
188
|
+
table.add_column("Application", style="green bold", no_wrap=True)
|
|
189
|
+
|
|
190
|
+
for i, name in enumerate(app_names, 1):
|
|
191
|
+
table.add_row(str(i), name)
|
|
192
|
+
|
|
193
|
+
console.print()
|
|
194
|
+
console.print(table)
|
|
195
|
+
console.print(f"\n[dim]{len(app_names)} applications running[/dim]\n")
|
|
196
|
+
|
|
197
|
+
except subprocess.CalledProcessError as e:
|
|
198
|
+
console.print(
|
|
199
|
+
f"[red]✗ Failed to list running apps:[/red] {e.stderr.strip()}"
|
|
200
|
+
)
|
|
201
|
+
except Exception as e:
|
|
202
|
+
console.print(f"[red]✗ Error:[/red] {e}")
|