copa-cli 0.2.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.
copa_cli-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mark Stanford
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,465 @@
1
+ Metadata-Version: 2.4
2
+ Name: copa-cli
3
+ Version: 0.2.0
4
+ Summary: Command Palette — smart command tracking, ranking, and sharing for your shell
5
+ Author: Mark Stanford
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/MaStanford/copa
8
+ Project-URL: Repository, https://github.com/MaStanford/copa
9
+ Project-URL: Issues, https://github.com/MaStanford/copa/issues
10
+ Keywords: cli,command-palette,shell,fzf,productivity
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: System :: Shells
17
+ Classifier: Topic :: Utilities
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: click>=8.0
22
+ Provides-Extra: mcp
23
+ Requires-Dist: mcp; extra == "mcp"
24
+ Provides-Extra: ollama
25
+ Requires-Dist: requests; extra == "ollama"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest; extra == "dev"
28
+ Requires-Dist: ruff; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # Copa — Command Palette for your shell
32
+
33
+ [![CI](https://github.com/MaStanford/copa/actions/workflows/ci.yml/badge.svg)](https://github.com/MaStanford/copa/actions/workflows/ci.yml)
34
+ [![PyPI](https://img.shields.io/pypi/v/copa-cli)](https://pypi.org/project/copa-cli/)
35
+ [![Python](https://img.shields.io/pypi/pyversions/copa-cli)](https://pypi.org/project/copa-cli/)
36
+
37
+ Copa tracks the commands you run, ranks them by frequency and recency, and gives you instant fuzzy search via fzf. Think of it as a smart, searchable, shareable upgrade to shell history.
38
+
39
+ ## Features
40
+
41
+ - **Smart ranking** — commands scored by `2*log(1+freq) + 8*0.5^(age/3d)`, so frequent *and* recent commands float to the top
42
+ - **FTS search** — full-text search across commands and their descriptions
43
+ - **fzf integration** — Ctrl+R opens a fuzzy-searchable command palette with preview pane; searches across commands *and* their descriptions
44
+ - **Tab completion** — Copa supplements zsh's tab completion for *any* command using your command history database
45
+ - **Auto-evolution** — `copa evolve` finds your most-used commands from zsh history and promotes them
46
+ - **LLM descriptions** — `copa fix --auto` uses Claude or ollama to generate descriptions for undescribed commands
47
+ - **Script protocol** — `#@ Description:` / `#@ Usage:` / `#@ Purpose:` / `#@ Flag:` headers in your scripts are auto-detected by `copa scan` across all `$PATH` directories
48
+ - **Flag documentation** — document command flags with descriptions; flags are searchable, visible in the preview pane, and preserved in `.copa` exports
49
+ - **Groups & Ctrl+G** — organize commands by project, device, or workflow; assign groups inline from the fzf palette with Ctrl+G
50
+ - **Sharing & `copa create`** — export/import command sets as `.copa` JSON files; `copa create` scaffolds a `.copa` file from an existing group
51
+ - **Set filtering** — scope list, search, and fzf to a specific shared set with `--set`
52
+ - **MCP server** — expose your commands to Claude Code (or any MCP client)
53
+ - **Zero latency** — precmd hook records usage in the background
54
+
55
+ ## Install
56
+
57
+ ### Prerequisites
58
+
59
+ - **Python 3.12+**
60
+ - **fzf** — required for Ctrl+R command palette
61
+
62
+ ```bash
63
+ # macOS
64
+ brew install fzf
65
+
66
+ # Linux (apt)
67
+ sudo apt install fzf
68
+
69
+ # or see https://github.com/junegunn/fzf#installation
70
+ ```
71
+
72
+ ### Install Copa
73
+
74
+ ```bash
75
+ pip install copa-cli
76
+ # or from source:
77
+ git clone https://github.com/MaStanford/copa.git
78
+ cd copa
79
+ pip install -e .
80
+
81
+ # Optional: ollama backend for LLM descriptions
82
+ pip install copa-cli[ollama]
83
+ ```
84
+
85
+ ### Shell integration (required)
86
+
87
+ Add this line to your `~/.zshrc`:
88
+
89
+ ```bash
90
+ source /path/to/copa/copa.zsh
91
+ ```
92
+
93
+ Then restart your shell or run `source ~/.zshrc`. This does three things:
94
+
95
+ 1. **Records every command you run** — a `precmd` hook silently calls `copa _record` in the background after each command, building up frequency and recency data with zero latency impact.
96
+ 2. **Replaces Ctrl+R** — the default zsh reverse-history-search is replaced with Copa's fzf-powered command palette (see below).
97
+ 3. **Supplements tab completion** — Copa registers as a fallback completer so that any command gets completion candidates from your Copa database (see [Tab Completion](#tab-completion) below).
98
+
99
+ Initialize the database:
100
+
101
+ ```bash
102
+ copa _init
103
+ ```
104
+
105
+ ## Ctrl+R — fzf Command Palette
106
+
107
+ Once shell integration is sourced, pressing **Ctrl+R** opens an fzf-powered command palette instead of the default zsh reverse search. This is Copa's primary interface.
108
+
109
+ ### What you see
110
+
111
+ Copa pipes every tracked command into fzf with aligned columns:
112
+
113
+ ```
114
+ command text (padded) ┃ [group] freq×N
115
+ ```
116
+
117
+ The left panel shows the command text. The right panel shows metadata: a pin indicator, group badge (dim magenta), and frequency count (dim). Descriptions and flag documentation are not shown in the list — they appear in the preview pane but are still included as a hidden field that fzf searches. This means typing "bluetooth" in fzf will find a command whose description mentions "bluetooth" even if the command text doesn't contain it.
118
+
119
+ **fzf searches across all fields** — the command text, group names, descriptions, and flag documentation. A hidden search field contains the full description and flag text so fzf's fuzzy matching covers everything even though only the command and metadata columns are displayed.
120
+
121
+ This is the key difference from plain zsh Ctrl+R: you're not just searching raw history text, you're searching annotated, described, ranked commands.
122
+
123
+ ### Modes
124
+
125
+ The header shows available modes. Press **Ctrl+R** again while fzf is open to cycle:
126
+
127
+ | Mode | Sort order | Use case |
128
+ |------|-----------|----------|
129
+ | `all` | Score (frequency + recency) | Default — best commands float to top |
130
+ | `frequent` | Frequency only | Find your most-used commands |
131
+ | `recent` | Last used time | Find commands you ran recently |
132
+
133
+ ### Keybindings
134
+
135
+ While the fzf palette is open, these keys are available:
136
+
137
+ | Key | Action | Effect |
138
+ |-----|--------|--------|
139
+ | **Ctrl+R** | Cycle mode | all → frequent → recent → all |
140
+ | **Ctrl+V** | Append `&` | Run selected command in background |
141
+ | **Ctrl+O** | Append `2>&1` | Merge stderr into stdout |
142
+ | **Ctrl+X** | Append `\|` | Pipe into next command |
143
+ | **Ctrl+T** | Append `>` | Redirect output |
144
+ | **Ctrl+A** | Append `&&` | Chain with next command |
145
+ | **Ctrl+/** | Append `2>/dev/null` | Suppress stderr |
146
+ | **Ctrl+G** | Set group | Assign or change the group for the highlighted command |
147
+ | **Ctrl+D** | Describe | Generate/edit a description for the highlighted command |
148
+ | **Ctrl+F** | Edit flags | Add flag documentation to the highlighted command |
149
+
150
+ Keybindings are configurable via `~/.copa/config.toml`. See the `[keys]` section.
151
+
152
+ ### Preview pane
153
+
154
+ The right side shows a detail card for the highlighted command: full description, usage, purpose, flag documentation, score breakdown, frequency, last used, source, group, shared set, and tags.
155
+
156
+ ### Result
157
+
158
+ Selecting a command places it directly into your shell prompt (without executing it), so you can review or edit before pressing Enter.
159
+
160
+ ## Tab Completion
161
+
162
+ Copa supplements zsh's built-in tab completion for **any** command — not just Copa's own CLI. Once `copa.zsh` is sourced, Copa registers as a fallback completer in zsh's completion system.
163
+
164
+ ### How it works
165
+
166
+ When you press Tab, zsh runs its normal completers first. If Copa's fallback also fires, it queries the Copa database for commands matching what you've typed so far and suggests the next word(s):
167
+
168
+ ```
169
+ $ adb shell dump<TAB>
170
+ → dumpsys dumpstate
171
+ ```
172
+
173
+ Copa looks at your tracked commands starting with `adb shell dump` and extracts the next word from each match. Candidates are deduplicated and ordered by frequency.
174
+
175
+ ### Examples
176
+
177
+ ```bash
178
+ # Complete subcommands for adb
179
+ adb <TAB>
180
+ → shell devices logcat push pull ...
181
+
182
+ # Complete arguments deeper in the command
183
+ adb shell cmd bluetooth_manager <TAB>
184
+ → enable disable ...
185
+ ```
186
+
187
+ This works automatically once `copa.zsh` is sourced — no extra setup needed. The more commands you use (and track with Copa), the better the completions get.
188
+
189
+ Copa's own CLI completions (`copa li<TAB>` → `list`) continue to work as before via Click's built-in completion.
190
+
191
+ ## Quick Start
192
+
193
+ ```bash
194
+ # Import your shell history
195
+ copa sync
196
+
197
+ # Add a command manually
198
+ copa add "adb shell cmd bluetooth_manager enable" -d "Enable Bluetooth" -g bluetooth
199
+
200
+ # Add a command with flag documentation
201
+ copa add "flash_all" -d "Flash AOSP build" -f "--wipe: Wipe userdata" -f "-v: Verbose"
202
+
203
+ # Create a .copa file from a group (or scaffold an empty one)
204
+ copa create -g bluetooth
205
+
206
+ # List top commands by score
207
+ copa list
208
+
209
+ # Search by keyword
210
+ copa search bluetooth
211
+
212
+ # Auto-promote frequent commands from history
213
+ copa evolve -k 20
214
+
215
+ # Auto-promote and generate descriptions in one pass
216
+ copa evolve -k 20 --auto
217
+
218
+ # Generate descriptions with LLM
219
+ copa fix --auto
220
+
221
+ # Scan $PATH for scripts with metadata
222
+ copa scan
223
+
224
+ # Open fzf command palette (or press Ctrl+R)
225
+ copa fzf-list --mode all | fzf
226
+ ```
227
+
228
+ ## LLM-Powered Descriptions
229
+
230
+ Copa can use an LLM to auto-generate descriptions for your undescribed commands. Two backends are supported:
231
+
232
+ ### Configure
233
+
234
+ ```bash
235
+ copa configure
236
+ ```
237
+
238
+ This prompts you to choose a backend:
239
+
240
+ - **claude** (default) — shells out to the `claude` CLI. No API key needed if Claude Code is already authenticated.
241
+ - **ollama** — calls a local ollama server at `localhost:11434`. Copa checks that ollama is installed and running, prompts for a model name, and offers to pull it if missing.
242
+
243
+ Settings are stored in the Copa database (`meta` table).
244
+
245
+ ### Bulk descriptions with `copa fix --auto`
246
+
247
+ ```bash
248
+ # First, add undescribed commands
249
+ copa evolve -k 20
250
+
251
+ # Then generate descriptions with LLM suggestions
252
+ copa fix --auto
253
+
254
+ # Or do both in one step
255
+ copa evolve -k 20 --auto
256
+ ```
257
+
258
+ With `--auto`, each command gets an LLM-generated suggestion:
259
+
260
+ ```
261
+ [42] adb shell dumpsys bluetooth_manager
262
+ Suggestion: Dump Bluetooth manager state
263
+ Description [Dump Bluetooth manager state]:
264
+ ```
265
+
266
+ - Press **Enter** to accept the suggestion
267
+ - **Type** a replacement to override it
268
+ - Press **q** to quit
269
+
270
+ Without `--auto`, `copa fix` behaves as before (blank prompt, Enter to skip).
271
+
272
+ ### Single command description
273
+
274
+ ```bash
275
+ copa describe 42
276
+ ```
277
+
278
+ Generates a description for a specific command by ID. Same accept/edit flow as `fix --auto`.
279
+
280
+ ## Script Metadata Protocol
281
+
282
+ Copa recognizes `#@` headers in script files (checked in the first 50 lines):
283
+
284
+ ```bash
285
+ #!/bin/bash
286
+ #@ Description: Flash AOSP build to connected device
287
+ #@ Usage: flash_all.py <build-dir> -w [--skip firmware vendor_boot ...]
288
+ #@ Purpose: Streamline the device flashing workflow
289
+ #@ Flag: -w, --wipe: Wipe userdata before flashing
290
+ #@ Flag: --skip <parts>: Skip specific partitions
291
+ #@ Flag: -n, --dry-run: Show what would be done without flashing
292
+ ```
293
+
294
+ When scanned, Description, Usage, Purpose, and Flags are stored and displayed in the Ctrl+R preview pane:
295
+
296
+ ```
297
+ Description: Flash AOSP build to connected device
298
+ Usage: flash_all.py <build-dir> -w [--skip firmware vendor_boot ...]
299
+ Purpose: Streamline the device flashing workflow
300
+
301
+ Flags:
302
+ -w, --wipe Wipe userdata before flashing
303
+ --skip <parts> Skip specific partitions
304
+ -n, --dry-run Show what would be done without flashing
305
+ ```
306
+
307
+ ### Supported headers
308
+
309
+ | Header | Effect |
310
+ |--------|--------|
311
+ | `#@ Description: <text>` | Sets the command description (highest priority) |
312
+ | `#@ Usage: <text>` | Usage / invocation syntax |
313
+ | `#@ Purpose: <text>` | Why the script exists / when to use it |
314
+ | `#@ Flag: <flag>: <description>` | Document a flag/option (repeatable) |
315
+
316
+ Scripts without `#@` headers still work — Copa falls back to legacy patterns (`# Description:`, `# Purpose:`, Python docstrings, generic comments).
317
+
318
+ ### Scan scripts
319
+
320
+ ```bash
321
+ copa scan # scans all $PATH directories
322
+ copa scan --dir ~/bin # scan a specific directory
323
+ ```
324
+
325
+ ## Sharing
326
+
327
+ Export a group as a `.copa` file:
328
+
329
+ ```bash
330
+ # Using copa create (recommended — creates a .copa file you can edit)
331
+ copa create -g bluetooth
332
+
333
+ # Or using share export (direct export)
334
+ copa share export bluetooth -o bluetooth.copa
335
+ ```
336
+
337
+ Share it with your team (via git, fbsource, or any file share):
338
+
339
+ ```bash
340
+ copa share load bluetooth.copa
341
+ copa share load /path/to/team/commands.copa
342
+ copa share sync /path/to/team/copa-files/
343
+ ```
344
+
345
+ ### Filtering by shared set
346
+
347
+ Once you've loaded shared sets, you can scope commands to just that set:
348
+
349
+ ```bash
350
+ # List only commands from the bluetooth shared set
351
+ copa list --set bluetooth
352
+
353
+ # Search within a shared set
354
+ copa search "enable" --set bluetooth
355
+
356
+ # fzf filtered to a shared set
357
+ copa fzf-list --mode set --set bluetooth | fzf
358
+ ```
359
+
360
+ You can also filter by source type:
361
+
362
+ ```bash
363
+ copa search "adb" --source shared
364
+ copa list --source scan
365
+ ```
366
+
367
+ Create an alias for quick set-scoped search:
368
+
369
+ ```bash
370
+ alias copa-bt='copa fzf-list --set bluetooth | fzf'
371
+ ```
372
+
373
+ ### `.copa` file format
374
+
375
+ ```json
376
+ {
377
+ "copa_version": "1.0",
378
+ "name": "bluetooth",
379
+ "description": "Bluetooth commands for Android devices",
380
+ "author": "markstanford",
381
+ "commands": [
382
+ {
383
+ "command": "adb shell cmd bluetooth_manager enable",
384
+ "description": "Enable Bluetooth",
385
+ "tags": ["bt", "android"]
386
+ },
387
+ {
388
+ "command": "flash_all",
389
+ "description": "Flash AOSP build to device",
390
+ "tags": ["aosp"],
391
+ "flags": {
392
+ "-w, --wipe": "Wipe userdata before flashing",
393
+ "--skip <parts>": "Skip specific partitions"
394
+ }
395
+ }
396
+ ]
397
+ }
398
+ ```
399
+
400
+ ## MCP Server (Claude Code integration)
401
+
402
+ Copa includes an MCP server so Claude Code can search and add commands.
403
+
404
+ Install the MCP dependency:
405
+
406
+ ```bash
407
+ pip install copa-cli[mcp]
408
+ ```
409
+
410
+ Add to your Claude Code MCP config (`.mcp.json` in your project or home dir):
411
+
412
+ ```json
413
+ {
414
+ "mcpServers": {
415
+ "copa": {
416
+ "command": "python3",
417
+ "args": ["-m", "copa.mcp_server"]
418
+ }
419
+ }
420
+ }
421
+ ```
422
+
423
+ Available MCP tools:
424
+ - `copa_search` — search commands by keyword
425
+ - `copa_list_commands` — list commands ranked by score
426
+ - `copa_list_groups` — list all groups
427
+ - `copa_get_stats` — usage statistics
428
+ - `copa_add_command` — add a command
429
+ - `copa_update_description` — update a description
430
+ - `copa_create_group` — create a group with commands
431
+ - `copa_bulk_add` — bulk add commands
432
+
433
+ ## CLI Reference
434
+
435
+ | Command | Purpose |
436
+ |---------|---------|
437
+ | `copa add "cmd" -d "desc" -g group -f "flag: desc"` | Save a command (with optional flags) |
438
+ | `copa create -g group [-o file]` | Create a .copa file from a group |
439
+ | `copa list [-g group] [-s source] [--set name]` | List by score |
440
+ | `copa search "query" [-g group] [-s source] [--set name]` | FTS search |
441
+ | `copa remove ID` | Remove a command |
442
+ | `copa stats` | Usage statistics |
443
+ | `copa sync` | Import from zsh history |
444
+ | `copa scan [--dir path]` | Import script metadata from $PATH |
445
+ | `copa evolve [-k 20] [--auto]` | Auto-add frequent commands (with optional LLM descriptions) |
446
+ | `copa fix [--auto]` | Add missing descriptions (with optional LLM) |
447
+ | `copa describe ID` | Generate description for one command |
448
+ | `copa configure` | Set LLM backend (claude/ollama) |
449
+ | `copa share export GROUP -o file` | Export group |
450
+ | `copa share load SOURCE` | Load shared set |
451
+ | `copa share list` | List shared sets |
452
+ | `copa share sync DIR` | Sync .copa files from dir |
453
+ | `copa import FILE [-g group]` | Import commands from markdown |
454
+
455
+ ## How Scoring Works
456
+
457
+ ```
458
+ score = 2.0 * log(1 + frequency) + 8.0 * 0.5^(age_seconds / 3_days)
459
+ ```
460
+
461
+ Pinned commands get a +1000 bonus. The 3-day half-life means commands used in the last few days are strongly favored — a command used today scores ~8.0 recency, after 3 days ~4.0, after a week ~1.6.
462
+
463
+ ## License
464
+
465
+ MIT