mirror of
https://github.com/HKUDS/CLI-Anything.git
synced 2026-09-17 17:38:11 +08:00
Three new agent-native CLI harnesses for the CLI-Anything ecosystem: **cli-anything-seaclip** — Kanban board + 6-agent AI pipeline management - Wraps SeaClip-Lite FastAPI (HTTP) + SQLite (direct reads) - Commands: issue (list/create/move/delete), agent (list), pipeline (start/stop/resume/status), scheduler (list/sync), activity (list), server (health) - 35 tests (25 unit + 10 E2E) **cli-anything-pm2** — Node.js process management - Wraps PM2 CLI via subprocess - Commands: process (list/describe/metrics), lifecycle (start/stop/restart/delete), logs (view/flush), system (save/version) - 37 tests (28 unit + 9 E2E) **cli-anything-chromadb** — Vector database operations - Wraps ChromaDB HTTP API v2 - Commands: collection (list/create/delete/info), document (add/get/delete/count), query (search), server (heartbeat/version) - 51 tests (38 unit + 14 E2E, 1 skip) All harnesses follow the standard CLI-Anything patterns: - Dual output mode (human-readable + --json) - Interactive REPL with unified repl_skin - Full SOP documentation (<SOFTWARE>.md) - SKILL.md with YAML frontmatter - Comprehensive test suites (test_core.py + test_full_e2e.py) - TEST.md with test plan and results Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
102 lines
3.8 KiB
Markdown
102 lines
3.8 KiB
Markdown
# Agent Harness SOP: PM2 Process Management
|
|
|
|
## Purpose
|
|
|
|
This harness provides a CLI-Anything interface for PM2 process management.
|
|
It wraps the PM2 CLI via subprocess calls and exposes process lifecycle, logs,
|
|
and system commands through a unified Click CLI with interactive REPL mode.
|
|
|
|
## Backend
|
|
|
|
- **Engine**: PM2 (Node.js process manager) via subprocess
|
|
- **Binary**: `pm2` resolved via `shutil.which()` with fallback paths
|
|
- **Protocol**: Subprocess execution with stdout/stderr capture
|
|
- **Data format**: PM2 outputs JSON via `pm2 jlist`; other commands return plain text
|
|
|
|
## Architecture
|
|
|
|
```
|
|
cli-anything-pm2 (Click CLI)
|
|
|
|
|
+-- pm2_cli.py # Click groups + REPL dispatcher
|
|
|
|
|
+-- core/
|
|
| +-- processes.py # list, describe, metrics
|
|
| +-- lifecycle.py # start, stop, restart, delete
|
|
| +-- logs.py # view, flush
|
|
| +-- system.py # save, startup, version
|
|
|
|
|
+-- utils/
|
|
| +-- pm2_backend.py # subprocess wrapper (_run_pm2, pm2_jlist, etc.)
|
|
| +-- repl_skin.py # cli-anything branded REPL UI
|
|
|
|
|
+-- tests/
|
|
| +-- test_core.py # Unit tests (mocked subprocess)
|
|
| +-- test_full_e2e.py # E2E tests (real pm2 binary)
|
|
| +-- TEST.md # Test plan and results
|
|
|
|
|
+-- skills/
|
|
+-- SKILL.md # Agent skill definitions
|
|
```
|
|
|
|
## Command Groups
|
|
|
|
| Group | Commands | Backend Calls |
|
|
|-------------|------------------------------|-----------------------------------|
|
|
| `process` | list, describe, metrics | `pm2 jlist` (JSON parse) |
|
|
| `lifecycle` | start, stop, restart, delete | `pm2 start/stop/restart/delete` |
|
|
| `logs` | view, flush | `pm2 logs --nostream`, `pm2 flush`|
|
|
| `system` | save, startup, version | `pm2 save/startup/--version` |
|
|
|
|
## State Model
|
|
|
|
**Stateless.** Every command queries PM2 fresh via subprocess. There is no
|
|
in-memory session state, no project files, and no undo/redo. The PM2 daemon
|
|
itself maintains process state; this harness is a read/write proxy.
|
|
|
|
## Output Modes
|
|
|
|
All commands support two output modes controlled by the `--json` flag:
|
|
|
|
- **Human mode** (default): Formatted tables, status messages with color
|
|
- **JSON mode** (`--json`): Machine-readable JSON for agent consumption
|
|
|
|
## Interaction Modes
|
|
|
|
1. **Subcommand CLI**: `cli-anything-pm2 [--json] <group> <command> [args]`
|
|
2. **Interactive REPL**: `cli-anything-pm2` (no subcommand) launches the REPL
|
|
|
|
## Key Design Decisions
|
|
|
|
- PM2 binary path is cached after first lookup (`_PM2_BIN` module-level)
|
|
- `pm2 jlist` is used instead of `pm2 describe` for JSON reliability
|
|
- Subprocess environment includes `/opt/homebrew/bin` for macOS compatibility
|
|
- Timeout defaults to 30 seconds per subprocess call
|
|
- JSON parsing has fallback extraction for non-JSON preamble in stdout
|
|
|
|
## Error Handling
|
|
|
|
| Scenario | Behavior |
|
|
|-----------------------|---------------------------------------------|
|
|
| pm2 not installed | `RuntimeError` with install instructions |
|
|
| pm2 binary vanishes | `FileNotFoundError` caught, error dict returned |
|
|
| Command timeout | `TimeoutExpired` caught, error dict returned |
|
|
| Invalid JSON output | Fallback regex extraction, then `data: None` |
|
|
| Process not found | Returns `None` or exit code 1 |
|
|
|
|
## Testing
|
|
|
|
- **Unit tests**: `test_core.py` -- all subprocess calls mocked, no pm2 required
|
|
- **E2E tests**: `test_full_e2e.py` -- calls real pm2 binary, requires pm2 installed
|
|
|
|
```bash
|
|
# Run all tests
|
|
python -m pytest cli_anything/pm2/tests/ -v
|
|
|
|
# Run only unit tests (no pm2 needed)
|
|
python -m pytest cli_anything/pm2/tests/test_core.py -v
|
|
|
|
# Run only E2E tests (pm2 must be installed and running)
|
|
python -m pytest cli_anything/pm2/tests/test_full_e2e.py -v
|
|
```
|