chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
---
|
||||
description: List all available CLI-Anything tools (installed and generated)
|
||||
---
|
||||
# cli-anything-list Command
|
||||
|
||||
List all available CLI-Anything tools (installed and generated).
|
||||
|
||||
**Arguments**: $ARGUMENTS
|
||||
|
||||
## Options
|
||||
|
||||
- `--path <directory>` - Directory to search for generated CLIs (default: current directory)
|
||||
- `--depth <n>` - Maximum recursion depth for scanning (default: unlimited). Use `0` for current directory only, `1` for one level deep, etc.
|
||||
- `--json` - Output in JSON format for machine parsing
|
||||
|
||||
## What This Command Does
|
||||
|
||||
Displays all CLI-Anything tools available in the system:
|
||||
|
||||
### 1. Installed CLIs
|
||||
|
||||
Uses `importlib.metadata` to find installed `cli-anything-*` packages:
|
||||
- Pattern: package name starts with `cli-anything-`
|
||||
- Extracts: software name, version, entry point
|
||||
|
||||
```python
|
||||
from importlib.metadata import distributions
|
||||
|
||||
installed = {}
|
||||
for dist in distributions():
|
||||
name = dist.metadata.get("Name", "")
|
||||
if name.startswith("cli-anything-"):
|
||||
software = name.replace("cli-anything-", "")
|
||||
version = dist.version
|
||||
# Find executable via entry points or shutil.which
|
||||
executable = shutil.which(f"cli-anything-{software}")
|
||||
installed[software] = {
|
||||
"status": "installed",
|
||||
"version": version,
|
||||
"executable": executable
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Generated CLIs
|
||||
|
||||
Uses `glob` to find local CLI directories:
|
||||
- Pattern: `**/agent-harness/cli_anything/*/__init__.py` (or depth-limited variant)
|
||||
- Extracts: software name, version (from setup.py), source path
|
||||
- Status: `generated`
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
import glob
|
||||
import re
|
||||
|
||||
search_path = args.get("path", ".")
|
||||
max_depth = args.get("depth", None) # None means unlimited
|
||||
generated = {}
|
||||
|
||||
def extract_version_from_setup(setup_path):
|
||||
"""Extract version from setup.py using regex."""
|
||||
try:
|
||||
content = Path(setup_path).read_text()
|
||||
match = re.search(r'version\s*=\s*["\']([^"\']+)["\']', content)
|
||||
return match.group(1) if match else None
|
||||
except:
|
||||
return None
|
||||
|
||||
def build_glob_patterns(base_path, depth):
|
||||
"""Build list of glob patterns for depths 0 through max_depth."""
|
||||
base = Path(base_path)
|
||||
suffix = "agent-harness/cli_anything/*/__init__.py"
|
||||
|
||||
if depth is None:
|
||||
return [str(base / "**" / suffix)]
|
||||
|
||||
patterns = []
|
||||
for d in range(depth + 1):
|
||||
if d == 0:
|
||||
patterns.append(str(base / suffix))
|
||||
else:
|
||||
prefix = "/".join(["*"] * d)
|
||||
patterns.append(str(base / prefix / suffix))
|
||||
return patterns
|
||||
|
||||
patterns = build_glob_patterns(search_path, max_depth)
|
||||
for pattern in patterns:
|
||||
for init_file in glob.glob(pattern, recursive=True):
|
||||
parts = Path(init_file).parts
|
||||
for i, p in enumerate(parts):
|
||||
if p == "cli_anything" and i + 1 < len(parts):
|
||||
software = parts[i + 1]
|
||||
agent_harness_idx = parts.index("agent-harness") if "agent-harness" in parts else i - 1
|
||||
source = str(Path(*parts[:agent_harness_idx + 2]))
|
||||
setup_path = Path(*parts[:agent_harness_idx + 1]) / "setup.py"
|
||||
version = extract_version_from_setup(setup_path)
|
||||
generated[software] = {
|
||||
"status": "generated",
|
||||
"version": version,
|
||||
"executable": None,
|
||||
"source": source
|
||||
}
|
||||
break
|
||||
```
|
||||
|
||||
### 3. Merge Results
|
||||
|
||||
- Deduplicate by software name
|
||||
- If both installed and generated: show `installed` status with both paths
|
||||
- The `source` field shows where the generated code is (even for installed)
|
||||
|
||||
## Output Formats
|
||||
|
||||
### Table Format (default)
|
||||
|
||||
```
|
||||
CLI-Anything Tools (found 5)
|
||||
|
||||
Name Status Version Source
|
||||
──────────────────────────────────────────────────────────────
|
||||
gimp installed 1.0.0 ./gimp/agent-harness
|
||||
blender installed 1.0.0 ./blender/agent-harness
|
||||
inkscape generated 1.0.0 ./inkscape/agent-harness
|
||||
audacity generated 1.0.0 ./audacity/agent-harness
|
||||
libreoffice generated 1.0.0 ./libreoffice/agent-harness
|
||||
```
|
||||
|
||||
### JSON Format (--json)
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"name": "gimp",
|
||||
"status": "installed",
|
||||
"version": "1.0.0",
|
||||
"executable": "/usr/local/bin/cli-anything-gimp",
|
||||
"source": "./gimp/agent-harness"
|
||||
},
|
||||
{
|
||||
"name": "inkscape",
|
||||
"status": "generated",
|
||||
"version": "1.0.0",
|
||||
"executable": null,
|
||||
"source": "./inkscape/agent-harness"
|
||||
}
|
||||
],
|
||||
"total": 2,
|
||||
"installed": 1,
|
||||
"generated_only": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
When this command is invoked, the agent should:
|
||||
|
||||
1. **Parse arguments** from `$ARGUMENTS`
|
||||
- Extract `--path` value (default: `.`)
|
||||
- Extract `--depth` value (default: `None` for unlimited recursion)
|
||||
- Extract `--json` flag (default: false)
|
||||
|
||||
2. **Validate path exists**
|
||||
- If `--path` specified and doesn't exist, show error and exit
|
||||
|
||||
3. **Scan installed CLIs**
|
||||
- Use `importlib.metadata.distributions()` to find all packages
|
||||
- Filter for packages starting with `cli-anything-`
|
||||
- Extract name, version, find executable path
|
||||
|
||||
4. **Scan generated CLIs**
|
||||
- Build glob pattern based on depth parameter
|
||||
- Use `glob.glob(pattern, recursive=True)`
|
||||
- Parse directory structure to extract software name
|
||||
- Calculate relative path from current directory
|
||||
|
||||
5. **Merge results**
|
||||
- Create dict keyed by software name
|
||||
- Prefer installed data when both exist
|
||||
- Keep source path from generated if available
|
||||
|
||||
6. **Format output**
|
||||
- If `--json`: output JSON to stdout
|
||||
- Otherwise: format as table with proper alignment
|
||||
|
||||
7. **Print results**
|
||||
- Show summary line with count
|
||||
- Show table or JSON
|
||||
Reference in New Issue
Block a user