procler 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.
- procler-0.2.0/.claude/settings.json +16 -0
- procler-0.2.0/.env.example +23 -0
- procler-0.2.0/.gitignore +57 -0
- procler-0.2.0/.pre-commit-config.yaml +7 -0
- procler-0.2.0/AGENTS.md +434 -0
- procler-0.2.0/CHANGELOG.md +84 -0
- procler-0.2.0/Dockerfile +70 -0
- procler-0.2.0/LICENSE +21 -0
- procler-0.2.0/PKG-INFO +545 -0
- procler-0.2.0/README.ja.md +498 -0
- procler-0.2.0/README.md +498 -0
- procler-0.2.0/docker-compose.yml +27 -0
- procler-0.2.0/procler/__init__.py +3 -0
- procler-0.2.0/procler/__main__.py +6 -0
- procler-0.2.0/procler/api/__init__.py +5 -0
- procler-0.2.0/procler/api/app.py +261 -0
- procler-0.2.0/procler/api/deps.py +21 -0
- procler-0.2.0/procler/api/routes/__init__.py +5 -0
- procler-0.2.0/procler/api/routes/config.py +290 -0
- procler-0.2.0/procler/api/routes/groups.py +62 -0
- procler-0.2.0/procler/api/routes/logs.py +43 -0
- procler-0.2.0/procler/api/routes/processes.py +185 -0
- procler-0.2.0/procler/api/routes/recipes.py +69 -0
- procler-0.2.0/procler/api/routes/snippets.py +134 -0
- procler-0.2.0/procler/api/routes/ws.py +459 -0
- procler-0.2.0/procler/cli.py +1478 -0
- procler-0.2.0/procler/config/__init__.py +65 -0
- procler-0.2.0/procler/config/changelog.py +148 -0
- procler-0.2.0/procler/config/loader.py +256 -0
- procler-0.2.0/procler/config/schema.py +315 -0
- procler-0.2.0/procler/core/__init__.py +54 -0
- procler-0.2.0/procler/core/context_base.py +117 -0
- procler-0.2.0/procler/core/context_docker.py +384 -0
- procler-0.2.0/procler/core/context_local.py +287 -0
- procler-0.2.0/procler/core/daemon_detector.py +325 -0
- procler-0.2.0/procler/core/events.py +74 -0
- procler-0.2.0/procler/core/groups.py +419 -0
- procler-0.2.0/procler/core/health.py +280 -0
- procler-0.2.0/procler/core/log_tailer.py +262 -0
- procler-0.2.0/procler/core/process_manager.py +1277 -0
- procler-0.2.0/procler/core/recipes.py +330 -0
- procler-0.2.0/procler/core/snippets.py +231 -0
- procler-0.2.0/procler/core/variable_substitution.py +65 -0
- procler-0.2.0/procler/db.py +96 -0
- procler-0.2.0/procler/logging.py +41 -0
- procler-0.2.0/procler/models.py +130 -0
- procler-0.2.0/procler/py.typed +0 -0
- procler-0.2.0/procler/settings.py +29 -0
- procler-0.2.0/procler/static/assets/AboutView-BwZnsfpW.js +4 -0
- procler-0.2.0/procler/static/assets/AboutView-UHbxWXcS.css +1 -0
- procler-0.2.0/procler/static/assets/Code-HTS-H1S6.js +74 -0
- procler-0.2.0/procler/static/assets/ConfigView-CGJcmp9G.css +1 -0
- procler-0.2.0/procler/static/assets/ConfigView-aVtbRDf8.js +1 -0
- procler-0.2.0/procler/static/assets/DashboardView-C5jw9Nsd.css +1 -0
- procler-0.2.0/procler/static/assets/DashboardView-Dab7Cu9v.js +1 -0
- procler-0.2.0/procler/static/assets/DataTable-z39TOAa4.js +746 -0
- procler-0.2.0/procler/static/assets/DescriptionsItem-B2E8YbqJ.js +74 -0
- procler-0.2.0/procler/static/assets/Divider-Dk-6aD2Y.js +42 -0
- procler-0.2.0/procler/static/assets/Empty-MuygEHZM.js +24 -0
- procler-0.2.0/procler/static/assets/Grid-CZ9QVKAT.js +1 -0
- procler-0.2.0/procler/static/assets/GroupsView-BALG7i1X.js +1 -0
- procler-0.2.0/procler/static/assets/GroupsView-gXAI1CVC.css +1 -0
- procler-0.2.0/procler/static/assets/Input-e0xaxoWE.js +259 -0
- procler-0.2.0/procler/static/assets/PhArrowsClockwise.vue-DqDg31az.js +1 -0
- procler-0.2.0/procler/static/assets/PhCheckCircle.vue-Fwj9sh9m.js +1 -0
- procler-0.2.0/procler/static/assets/PhEye.vue-JcPHciC2.js +1 -0
- procler-0.2.0/procler/static/assets/PhPlay.vue-CZm7Gy3u.js +1 -0
- procler-0.2.0/procler/static/assets/PhPlus.vue-yTWqKlSh.js +1 -0
- procler-0.2.0/procler/static/assets/PhStop.vue-DxsqwIki.js +1 -0
- procler-0.2.0/procler/static/assets/PhTrash.vue-DcqQbN1_.js +125 -0
- procler-0.2.0/procler/static/assets/PhXCircle.vue-BXWmrabV.js +1 -0
- procler-0.2.0/procler/static/assets/ProcessDetailView-DDbtIWq9.css +1 -0
- procler-0.2.0/procler/static/assets/ProcessDetailView-DPtdNV-q.js +1 -0
- procler-0.2.0/procler/static/assets/ProcessesView-B3a6Umur.js +1 -0
- procler-0.2.0/procler/static/assets/ProcessesView-goLmghbJ.css +1 -0
- procler-0.2.0/procler/static/assets/RecipesView-D2VxdneD.js +166 -0
- procler-0.2.0/procler/static/assets/RecipesView-DXnFDCK4.css +1 -0
- procler-0.2.0/procler/static/assets/Select-BBR17AHq.js +317 -0
- procler-0.2.0/procler/static/assets/SnippetsView-B3a9q3AI.css +1 -0
- procler-0.2.0/procler/static/assets/SnippetsView-DBCB2yGq.js +1 -0
- procler-0.2.0/procler/static/assets/Spin-BXTjvFUk.js +90 -0
- procler-0.2.0/procler/static/assets/Tag-Bh_qV63A.js +71 -0
- procler-0.2.0/procler/static/assets/changelog-KkTT4H9-.js +1 -0
- procler-0.2.0/procler/static/assets/groups-Zu-_v8ey.js +1 -0
- procler-0.2.0/procler/static/assets/index-BsN-YMXq.css +1 -0
- procler-0.2.0/procler/static/assets/index-BzW1XhyH.js +1282 -0
- procler-0.2.0/procler/static/assets/procler-DOrSB1Vj.js +1 -0
- procler-0.2.0/procler/static/assets/recipes-1w5SseGb.js +1 -0
- procler-0.2.0/procler/static/index.html +17 -0
- procler-0.2.0/procler/static/procler.png +0 -0
- procler-0.2.0/procler.png +0 -0
- procler-0.2.0/pyproject.toml +100 -0
- procler-0.2.0/uv.lock +1196 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PostToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit|Write",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '/frontend/'; then echo '[hook] Frontend file changed, rebuilding...' && cd \"$CLAUDE_PROJECT_DIR\" && ./scripts/build_frontend.sh > /dev/null 2>&1 && echo '[hook] Frontend build complete'; fi; }",
|
|
10
|
+
"timeout": 120
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Procler Environment Variables
|
|
2
|
+
# Copy to .env and customize as needed
|
|
3
|
+
|
|
4
|
+
# Logging
|
|
5
|
+
PROCLER_LOG_LEVEL=INFO # DEBUG, INFO, WARNING, ERROR
|
|
6
|
+
PROCLER_LOG_FILE= # Optional file path for logs (auto-rotates)
|
|
7
|
+
|
|
8
|
+
# Log rotation (for process output logs in DB)
|
|
9
|
+
PROCLER_LOG_ROTATION_INTERVAL=3600 # Seconds between rotation checks (default: 1 hour)
|
|
10
|
+
PROCLER_MAX_LOGS_PER_PROCESS=10000 # Max log entries per process (default: 10000)
|
|
11
|
+
|
|
12
|
+
# Config directory (defaults to .procler/ in current dir)
|
|
13
|
+
PROCLER_CONFIG_DIR= # Override config directory path
|
|
14
|
+
|
|
15
|
+
# Database
|
|
16
|
+
PROCLER_DB_PATH= # Override database path (default: .procler/state.db)
|
|
17
|
+
|
|
18
|
+
# Server
|
|
19
|
+
PROCLER_CORS_ORIGINS= # Comma-separated allowed origins (default: localhost)
|
|
20
|
+
PROCLER_DEBUG= # Set to 1 for detailed error messages
|
|
21
|
+
|
|
22
|
+
# Data directory (for CLI)
|
|
23
|
+
PROCLER_DATA_DIR= # Override data directory
|
procler-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.idea/
|
|
30
|
+
.vscode/
|
|
31
|
+
*.swp
|
|
32
|
+
*.swo
|
|
33
|
+
*~
|
|
34
|
+
|
|
35
|
+
# Testing
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
.coverage
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
|
|
42
|
+
# Type checking
|
|
43
|
+
.mypy_cache/
|
|
44
|
+
|
|
45
|
+
# Ruff
|
|
46
|
+
.ruff_cache/
|
|
47
|
+
|
|
48
|
+
# Local data
|
|
49
|
+
.procler/
|
|
50
|
+
|
|
51
|
+
# Local development preferences
|
|
52
|
+
CLAUDE.local.md
|
|
53
|
+
|
|
54
|
+
# Frontend build (keep built static/ in git for ease of use)
|
|
55
|
+
frontend/node_modules/
|
|
56
|
+
frontend/dist/
|
|
57
|
+
*.tsbuildinfo
|
procler-0.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# Procler - Agent Usage Guide
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive instructions for LLM agents to use Procler, an LLM-first process manager.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Reference
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Discovery
|
|
11
|
+
procler capabilities # JSON schema of all commands
|
|
12
|
+
procler help-llm # Comprehensive usage guide (JSON with markdown)
|
|
13
|
+
procler config explain # Plain-language config explanation
|
|
14
|
+
|
|
15
|
+
# Process Management
|
|
16
|
+
procler start <name> # Idempotent
|
|
17
|
+
procler stop <name> # Idempotent
|
|
18
|
+
procler restart <name> # With optional --clear-logs
|
|
19
|
+
procler status [name] # Status with Linux kernel state
|
|
20
|
+
procler logs <name> # --tail N, --since 5m
|
|
21
|
+
|
|
22
|
+
# Groups & Recipes
|
|
23
|
+
procler group start <name> # Ordered startup with dependencies
|
|
24
|
+
procler recipe run <name> # Multi-step operation (--dry-run to preview)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Response Format
|
|
30
|
+
|
|
31
|
+
All CLI commands return JSON to stdout. Parse the response as follows:
|
|
32
|
+
|
|
33
|
+
### Success
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"success": true,
|
|
37
|
+
"data": {
|
|
38
|
+
"process": { "name": "api", "status": "running", "pid": 12345 }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Error
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"success": false,
|
|
47
|
+
"error": "Process 'api' not found",
|
|
48
|
+
"error_code": "process_not_found",
|
|
49
|
+
"suggestion": "Run 'procler list' to see available processes"
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Always check `success` field first.** Use `error_code` for programmatic error handling and `suggestion` for recovery actions.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## CLI Help
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Usage: procler [OPTIONS] COMMAND [ARGS]...
|
|
61
|
+
|
|
62
|
+
Procler - LLM-first process manager for developers.
|
|
63
|
+
All commands output JSON for easy parsing by scripts and LLMs.
|
|
64
|
+
|
|
65
|
+
Options:
|
|
66
|
+
--version Show the version and exit.
|
|
67
|
+
--help Show this message and exit.
|
|
68
|
+
|
|
69
|
+
Commands:
|
|
70
|
+
capabilities Returns JSON schema of all commands.
|
|
71
|
+
config Manage configuration (config.yaml).
|
|
72
|
+
define Define a new process.
|
|
73
|
+
exec Execute an arbitrary command.
|
|
74
|
+
group Manage process groups (defined in config.yaml).
|
|
75
|
+
help-llm Output comprehensive LLM-focused usage instructions.
|
|
76
|
+
list List all process definitions.
|
|
77
|
+
logs Get logs for a process.
|
|
78
|
+
recipe Manage and run recipes (multi-step operations).
|
|
79
|
+
remove Remove a process definition.
|
|
80
|
+
restart Restart a process (stop then start).
|
|
81
|
+
serve Start the web server.
|
|
82
|
+
snippet Manage command snippets.
|
|
83
|
+
start Start a process (idempotent - no-op if running).
|
|
84
|
+
status Show status of all processes or a specific one.
|
|
85
|
+
stop Stop a process (idempotent - no-op if stopped).
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Command Discovery
|
|
91
|
+
|
|
92
|
+
Run `procler capabilities` to get a complete JSON schema of all available commands, their arguments, options, and examples. This is the recommended way for agents to discover functionality.
|
|
93
|
+
|
|
94
|
+
Run `procler help-llm` for a markdown-formatted comprehensive guide embedded in JSON.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Process Management
|
|
99
|
+
|
|
100
|
+
### Define a Process
|
|
101
|
+
```bash
|
|
102
|
+
procler define --name api --command 'uvicorn main:app' --cwd /app
|
|
103
|
+
procler define --name worker --command 'celery worker' --context docker --container myapp
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Start/Stop/Restart
|
|
107
|
+
```bash
|
|
108
|
+
procler start api # Returns immediately, process runs in background
|
|
109
|
+
procler stop api # Sends SIGTERM, waits for graceful shutdown
|
|
110
|
+
procler restart api # Stop then start
|
|
111
|
+
procler restart api --clear-logs # Clear accumulated logs
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Idempotency**: `start` on a running process and `stop` on a stopped process are no-ops that return success.
|
|
115
|
+
|
|
116
|
+
### Status
|
|
117
|
+
```bash
|
|
118
|
+
procler status # All processes
|
|
119
|
+
procler status api # Specific process
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Response includes:
|
|
123
|
+
- `status`: "running" | "stopped" | "failed"
|
|
124
|
+
- `pid`: Process ID (null if not running)
|
|
125
|
+
- `uptime_seconds`: Time since start
|
|
126
|
+
- `linux_state`: Kernel state information
|
|
127
|
+
- `warning`: Alert for problematic states (D, Z)
|
|
128
|
+
|
|
129
|
+
### Linux Process States
|
|
130
|
+
| Code | Name | Description | Killable |
|
|
131
|
+
|------|------|-------------|----------|
|
|
132
|
+
| R | running | On run queue | Yes |
|
|
133
|
+
| S | sleeping | Interruptible sleep | Yes |
|
|
134
|
+
| D | disk_sleep | Uninterruptible (I/O wait) | **No** |
|
|
135
|
+
| Z | zombie | Terminated, not reaped | **No** |
|
|
136
|
+
| T | stopped | Job control signal | Yes |
|
|
137
|
+
|
|
138
|
+
**Important**: Processes in D state cannot be killed. Wait for I/O to complete.
|
|
139
|
+
|
|
140
|
+
### Logs
|
|
141
|
+
```bash
|
|
142
|
+
procler logs api # Last 100 lines
|
|
143
|
+
procler logs api --tail 50 # Last 50 lines
|
|
144
|
+
procler logs api --since 5m # Last 5 minutes
|
|
145
|
+
procler logs api --since 1h # Last hour
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Groups
|
|
151
|
+
|
|
152
|
+
Groups define ordered startup sequences with optional dependencies.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
procler group list # List all groups
|
|
156
|
+
procler group start backend # Start processes in order
|
|
157
|
+
procler group stop backend # Stop in reverse order
|
|
158
|
+
procler group status backend # Status of all group processes
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Config Example
|
|
162
|
+
```yaml
|
|
163
|
+
groups:
|
|
164
|
+
backend:
|
|
165
|
+
processes: [redis, database, api, worker]
|
|
166
|
+
stop_order: [worker, api, database, redis] # Optional custom order
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Dependencies
|
|
170
|
+
```yaml
|
|
171
|
+
processes:
|
|
172
|
+
api:
|
|
173
|
+
command: uvicorn main:app
|
|
174
|
+
depends_on:
|
|
175
|
+
- redis # Wait for 'started'
|
|
176
|
+
- name: database
|
|
177
|
+
condition: healthy # Wait for health check pass
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Recipes
|
|
183
|
+
|
|
184
|
+
Recipes are multi-step automation workflows.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
procler recipe list
|
|
188
|
+
procler recipe show deploy # View steps
|
|
189
|
+
procler recipe run deploy --dry-run # Preview without executing
|
|
190
|
+
procler recipe run deploy # Execute
|
|
191
|
+
procler recipe run deploy --continue-on-error
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Config Example
|
|
195
|
+
```yaml
|
|
196
|
+
recipes:
|
|
197
|
+
deploy:
|
|
198
|
+
description: "Graceful deployment with migration"
|
|
199
|
+
on_error: stop # or continue
|
|
200
|
+
steps:
|
|
201
|
+
- stop: worker
|
|
202
|
+
- stop: api
|
|
203
|
+
- wait: 2s
|
|
204
|
+
- exec: "alembic upgrade head"
|
|
205
|
+
context: docker
|
|
206
|
+
container: myapp
|
|
207
|
+
- start: api
|
|
208
|
+
- start: worker
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Step Types
|
|
212
|
+
- `start: <process>` - Start a process
|
|
213
|
+
- `stop: <process>` - Stop a process
|
|
214
|
+
- `restart: <process>` - Restart a process
|
|
215
|
+
- `exec: "<command>"` - Run a one-off command
|
|
216
|
+
- `wait: <duration>` - Pause (e.g., "5s", "1m")
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Snippets
|
|
221
|
+
|
|
222
|
+
Snippets are saved commands for quick execution.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
procler snippet list
|
|
226
|
+
procler snippet list --tag docker # Filter by tag
|
|
227
|
+
procler snippet save --name rebuild --command 'docker compose build' --tags docker
|
|
228
|
+
procler snippet run rebuild
|
|
229
|
+
procler snippet remove rebuild
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Configuration
|
|
235
|
+
|
|
236
|
+
### Initialize
|
|
237
|
+
```bash
|
|
238
|
+
procler config init # Creates .procler/ directory
|
|
239
|
+
procler config validate # Validates config.yaml
|
|
240
|
+
procler config path # Shows resolved paths
|
|
241
|
+
procler config explain # Plain-language explanation
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Config Structure
|
|
245
|
+
```
|
|
246
|
+
.procler/
|
|
247
|
+
├── config.yaml # Version-controllable definitions
|
|
248
|
+
├── changelog.log # Audit trail of operations
|
|
249
|
+
└── state.db # Runtime state (auto-gitignored)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Full Config Example
|
|
253
|
+
```yaml
|
|
254
|
+
version: 1
|
|
255
|
+
|
|
256
|
+
processes:
|
|
257
|
+
redis:
|
|
258
|
+
command: redis-server
|
|
259
|
+
context: local
|
|
260
|
+
tags: [database, cache]
|
|
261
|
+
|
|
262
|
+
api:
|
|
263
|
+
command: uvicorn main:app --reload
|
|
264
|
+
context: local
|
|
265
|
+
cwd: /home/user/myapp
|
|
266
|
+
tags: [backend]
|
|
267
|
+
healthcheck:
|
|
268
|
+
test: "curl -f http://localhost:8000/health"
|
|
269
|
+
interval: 10s
|
|
270
|
+
timeout: 5s
|
|
271
|
+
retries: 3
|
|
272
|
+
start_period: 30s
|
|
273
|
+
depends_on:
|
|
274
|
+
- redis
|
|
275
|
+
|
|
276
|
+
worker:
|
|
277
|
+
command: celery -A tasks worker
|
|
278
|
+
context: docker
|
|
279
|
+
container: myapp-worker
|
|
280
|
+
depends_on:
|
|
281
|
+
- name: api
|
|
282
|
+
condition: healthy
|
|
283
|
+
|
|
284
|
+
groups:
|
|
285
|
+
backend:
|
|
286
|
+
description: "Full backend stack"
|
|
287
|
+
processes: [redis, api, worker]
|
|
288
|
+
|
|
289
|
+
recipes:
|
|
290
|
+
deploy:
|
|
291
|
+
description: "Zero-downtime deployment"
|
|
292
|
+
on_error: stop
|
|
293
|
+
steps:
|
|
294
|
+
- stop: worker
|
|
295
|
+
- stop: api
|
|
296
|
+
- exec: "alembic upgrade head"
|
|
297
|
+
- start: api
|
|
298
|
+
- start: worker
|
|
299
|
+
|
|
300
|
+
snippets:
|
|
301
|
+
rebuild:
|
|
302
|
+
command: docker compose build --no-cache
|
|
303
|
+
description: "Rebuild all containers"
|
|
304
|
+
tags: [docker, build]
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Web Server & API
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
procler serve # localhost:8000
|
|
313
|
+
procler serve --host 0.0.0.0 --port 8080
|
|
314
|
+
procler serve --reload # Development mode
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### REST API Endpoints
|
|
318
|
+
| Method | Endpoint | Description |
|
|
319
|
+
|--------|----------|-------------|
|
|
320
|
+
| GET | /api/processes | List all processes |
|
|
321
|
+
| GET | /api/processes/{name} | Get process details |
|
|
322
|
+
| POST | /api/processes | Create process |
|
|
323
|
+
| DELETE | /api/processes/{name} | Remove process |
|
|
324
|
+
| POST | /api/processes/{name}/start | Start process |
|
|
325
|
+
| POST | /api/processes/{name}/stop | Stop process |
|
|
326
|
+
| POST | /api/processes/{name}/restart | Restart process |
|
|
327
|
+
| GET | /api/logs/{name} | Get process logs |
|
|
328
|
+
| GET | /api/groups | List groups |
|
|
329
|
+
| POST | /api/groups/{name}/start | Start group |
|
|
330
|
+
| POST | /api/groups/{name}/stop | Stop group |
|
|
331
|
+
| GET | /api/recipes | List recipes |
|
|
332
|
+
| POST | /api/recipes/{name}/run | Run recipe |
|
|
333
|
+
| GET | /api/health | Health check |
|
|
334
|
+
|
|
335
|
+
### WebSocket
|
|
336
|
+
Connect to `ws://localhost:8000/api/ws` for real-time updates:
|
|
337
|
+
```json
|
|
338
|
+
{"action": "subscribe_logs", "process_id": 1}
|
|
339
|
+
{"action": "subscribe_status", "process_id": 1}
|
|
340
|
+
{"action": "subscribe_status"} // All processes
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Common Workflows
|
|
346
|
+
|
|
347
|
+
### Start Development Environment
|
|
348
|
+
```bash
|
|
349
|
+
procler group start backend
|
|
350
|
+
procler status
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Debug Failing Process
|
|
354
|
+
```bash
|
|
355
|
+
procler status api # Check status and Linux state
|
|
356
|
+
procler logs api --tail 100 # View recent logs
|
|
357
|
+
procler restart api --clear-logs
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Graceful Deployment
|
|
361
|
+
```bash
|
|
362
|
+
procler recipe run deploy --dry-run # Preview
|
|
363
|
+
procler recipe run deploy # Execute
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Quick Command Execution
|
|
367
|
+
```bash
|
|
368
|
+
procler exec "npm run build" --cwd /app
|
|
369
|
+
procler exec "python manage.py migrate" --context docker --container myapp
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Environment Variables
|
|
375
|
+
|
|
376
|
+
| Variable | Default | Description |
|
|
377
|
+
|----------|---------|-------------|
|
|
378
|
+
| `PROCLER_LOG_LEVEL` | `INFO` | DEBUG, INFO, WARNING, ERROR |
|
|
379
|
+
| `PROCLER_LOG_FILE` | - | Log file path (auto-rotates) |
|
|
380
|
+
| `PROCLER_LOG_ROTATION_INTERVAL` | `3600` | Seconds between log rotation |
|
|
381
|
+
| `PROCLER_MAX_LOGS_PER_PROCESS` | `10000` | Max log entries per process |
|
|
382
|
+
| `PROCLER_CONFIG_DIR` | `.procler/` | Config directory path |
|
|
383
|
+
| `PROCLER_DB_PATH` | `.procler/state.db` | Database path |
|
|
384
|
+
| `PROCLER_CORS_ORIGINS` | localhost | Allowed CORS origins |
|
|
385
|
+
| `PROCLER_DEBUG` | - | Enable detailed error messages |
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Error Codes
|
|
390
|
+
|
|
391
|
+
| Code | Description | Recovery |
|
|
392
|
+
|------|-------------|----------|
|
|
393
|
+
| `process_not_found` | Process doesn't exist | Run `procler list` |
|
|
394
|
+
| `process_exists` | Process name already taken | Choose different name or remove first |
|
|
395
|
+
| `process_running` | Operation invalid while running | Stop first |
|
|
396
|
+
| `process_stopped` | Operation invalid while stopped | Start first |
|
|
397
|
+
| `missing_container` | Docker context requires container | Add `--container` |
|
|
398
|
+
| `config_not_found` | No config.yaml | Run `procler config init` |
|
|
399
|
+
| `config_exists` | Config already exists | Use `--force` |
|
|
400
|
+
| `validation_failed` | Invalid config | Check error details |
|
|
401
|
+
| `group_not_found` | Group not in config | Check config.yaml |
|
|
402
|
+
| `recipe_not_found` | Recipe not in config | Check config.yaml |
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Docker Deployment
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
# Using Docker Compose
|
|
410
|
+
docker compose up -d
|
|
411
|
+
|
|
412
|
+
# Manual
|
|
413
|
+
docker build -t procler .
|
|
414
|
+
docker run -d -p 8000:8000 -v procler-data:/home/procler/.procler procler
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Production Features
|
|
418
|
+
- **Process Recovery**: Detects orphaned processes on startup
|
|
419
|
+
- **Graceful Shutdown**: SIGTERM/SIGINT triggers orderly process shutdown
|
|
420
|
+
- **Log Rotation**: Background task rotates logs hourly
|
|
421
|
+
- **Health Check**: `/api/health` endpoint for container health
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Tips for Agents
|
|
426
|
+
|
|
427
|
+
1. **Always parse JSON output** - Never assume command success from exit code alone
|
|
428
|
+
2. **Use `capabilities` for discovery** - Dynamically learn available commands
|
|
429
|
+
3. **Check `suggestion` on errors** - Contains actionable recovery steps
|
|
430
|
+
4. **Leverage idempotency** - Safe to retry start/stop operations
|
|
431
|
+
5. **Use `--dry-run` for recipes** - Preview destructive operations
|
|
432
|
+
6. **Monitor Linux state** - D and Z states require special handling
|
|
433
|
+
7. **Use groups for complex startups** - Dependencies are resolved automatically
|
|
434
|
+
8. **Clear logs on restart** - Use `--clear-logs` when debugging fresh starts
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Procler will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed graceful shutdown loop when pressing Ctrl+C multiple times
|
|
13
|
+
- Fixed log rotation to use correct `cleanup_all_logs()` method
|
|
14
|
+
- Fixed process recovery query to use proper sqler API
|
|
15
|
+
- Fixed graceful shutdown to use `status()` instead of non-existent `list_processes()`
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Frontend static files now bundled in repository for easier deployment
|
|
20
|
+
- Updated `.gitignore` to track `procler/static/` directory
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Test coverage for application lifespan startup/shutdown
|
|
25
|
+
|
|
26
|
+
## [0.1.0] - 2026-01-08
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **Process Management**
|
|
31
|
+
- Define, start, stop, restart, remove processes via CLI
|
|
32
|
+
- Local subprocess execution with process groups
|
|
33
|
+
- Docker container execution via docker-py SDK
|
|
34
|
+
- PID-based process verification across sessions
|
|
35
|
+
- Idempotent operations (start running process = no-op)
|
|
36
|
+
|
|
37
|
+
- **Logging**
|
|
38
|
+
- Automatic stdout/stderr capture to SQLite
|
|
39
|
+
- Log retrieval with `--tail` and `--since` filters
|
|
40
|
+
- Log rotation and cleanup per process
|
|
41
|
+
|
|
42
|
+
- **Snippets**
|
|
43
|
+
- Save reusable commands with descriptions and tags
|
|
44
|
+
- Tag filtering for snippet organization
|
|
45
|
+
- Execute snippets in local or Docker context
|
|
46
|
+
|
|
47
|
+
- **REST API**
|
|
48
|
+
- Full CRUD operations for processes and snippets
|
|
49
|
+
- Log retrieval endpoint
|
|
50
|
+
- Health check endpoint
|
|
51
|
+
- OpenAPI documentation at `/api/docs`
|
|
52
|
+
|
|
53
|
+
- **WebSocket Real-time**
|
|
54
|
+
- Live log streaming subscription
|
|
55
|
+
- Status change broadcasts
|
|
56
|
+
- Connection management with automatic cleanup
|
|
57
|
+
|
|
58
|
+
- **Vue 3 Frontend**
|
|
59
|
+
- Process list with start/stop/restart controls
|
|
60
|
+
- Process detail view with live log streaming
|
|
61
|
+
- Snippets management UI
|
|
62
|
+
- Cyberpunk design system (Naive UI + custom theme)
|
|
63
|
+
|
|
64
|
+
- **CLI**
|
|
65
|
+
- JSON-native output for all commands
|
|
66
|
+
- `capabilities` command for LLM discovery
|
|
67
|
+
- Rich error context with suggestions
|
|
68
|
+
- Exit codes for scripting
|
|
69
|
+
|
|
70
|
+
- **Production Features**
|
|
71
|
+
- Build script for Vue to static files
|
|
72
|
+
- FastAPI serves frontend in production
|
|
73
|
+
- CORS configuration via environment variable
|
|
74
|
+
- Global exception handler
|
|
75
|
+
|
|
76
|
+
### Technical Details
|
|
77
|
+
|
|
78
|
+
- Python 3.12+ required
|
|
79
|
+
- SQLite via sqler for persistence
|
|
80
|
+
- FastAPI for REST API and WebSocket
|
|
81
|
+
- Click for CLI
|
|
82
|
+
- Vue 3 + Vite + Pinia + Naive UI for frontend
|
|
83
|
+
|
|
84
|
+
[0.1.0]: https://github.com/gabu-quest/procler/releases/tag/v0.1.0
|
procler-0.2.0/Dockerfile
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Procler - LLM-first process manager
|
|
2
|
+
# Multi-stage build for smaller image
|
|
3
|
+
|
|
4
|
+
# Build frontend
|
|
5
|
+
FROM node:20-alpine AS frontend-builder
|
|
6
|
+
|
|
7
|
+
WORKDIR /app/frontend
|
|
8
|
+
COPY frontend/package*.json ./
|
|
9
|
+
RUN npm ci
|
|
10
|
+
|
|
11
|
+
COPY frontend/ ./
|
|
12
|
+
RUN npm run build
|
|
13
|
+
|
|
14
|
+
# Build Python app
|
|
15
|
+
FROM python:3.12-slim AS builder
|
|
16
|
+
|
|
17
|
+
# Install uv for fast dependency resolution
|
|
18
|
+
RUN pip install uv
|
|
19
|
+
|
|
20
|
+
WORKDIR /app
|
|
21
|
+
COPY pyproject.toml ./
|
|
22
|
+
COPY procler/ ./procler/
|
|
23
|
+
|
|
24
|
+
# Install dependencies
|
|
25
|
+
RUN uv pip install --system --no-cache .
|
|
26
|
+
|
|
27
|
+
# Final image
|
|
28
|
+
FROM python:3.12-slim
|
|
29
|
+
|
|
30
|
+
# Install runtime dependencies
|
|
31
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
32
|
+
curl \
|
|
33
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
34
|
+
|
|
35
|
+
# Create non-root user
|
|
36
|
+
RUN useradd --create-home --shell /bin/bash procler
|
|
37
|
+
USER procler
|
|
38
|
+
WORKDIR /home/procler
|
|
39
|
+
|
|
40
|
+
# Copy installed packages from builder
|
|
41
|
+
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
|
|
42
|
+
COPY --from=builder /usr/local/bin/procler /usr/local/bin/procler
|
|
43
|
+
|
|
44
|
+
# Copy frontend build
|
|
45
|
+
COPY --from=frontend-builder /app/frontend/dist /home/procler/static
|
|
46
|
+
|
|
47
|
+
# Copy application
|
|
48
|
+
COPY --chown=procler:procler procler/ /home/procler/procler/
|
|
49
|
+
|
|
50
|
+
# Copy static files to the right location
|
|
51
|
+
RUN mkdir -p /home/procler/procler/static && \
|
|
52
|
+
cp -r /home/procler/static/* /home/procler/procler/static/ 2>/dev/null || true
|
|
53
|
+
|
|
54
|
+
# Environment variables
|
|
55
|
+
ENV PROCLER_LOG_LEVEL=INFO
|
|
56
|
+
ENV PROCLER_LOG_ROTATION_INTERVAL=3600
|
|
57
|
+
ENV PROCLER_MAX_LOGS_PER_PROCESS=10000
|
|
58
|
+
|
|
59
|
+
# Data directory (mount as volume for persistence)
|
|
60
|
+
VOLUME /home/procler/.procler
|
|
61
|
+
|
|
62
|
+
# Expose port
|
|
63
|
+
EXPOSE 8000
|
|
64
|
+
|
|
65
|
+
# Health check
|
|
66
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
|
67
|
+
CMD curl -f http://localhost:8000/api/health || exit 1
|
|
68
|
+
|
|
69
|
+
# Run the server
|
|
70
|
+
CMD ["python", "-m", "procler", "serve", "--host", "0.0.0.0", "--port", "8000"]
|