agent-control-plane 0.7.0 → 0.8.0
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.
- package/README.md +305 -7
- package/hooks/pr-reconcile-hooks.sh +12 -1
- package/package.json +13 -9
- package/tools/bin/adapter-capabilities.sh +84 -0
- package/tools/bin/adapter-interface.sh +97 -0
- package/tools/bin/claude-adapter.sh +73 -0
- package/tools/bin/codex-adapter.sh +123 -0
- package/tools/bin/flow-runtime-doctor.sh +67 -0
- package/tools/bin/heartbeat-safe-auto.sh +161 -0
- package/tools/bin/kilo-adapter.sh +108 -0
- package/tools/bin/ollama-adapter.sh +160 -0
- package/tools/bin/openclaw-adapter.sh +69 -0
- package/tools/bin/opencode-adapter.sh +98 -0
- package/tools/bin/pi-adapter.sh +95 -0
- package/tools/bin/render-flow-config.sh +98 -0
- package/tools/bin/run-with-adapter.sh +34 -0
- package/tools/bin/sync-shared-agent-home.sh +23 -0
- package/tools/dashboard/__pycache__/server.cpython-311.pyc +0 -0
- package/tools/dashboard/app-v2.js +1120 -0
- package/tools/dashboard/app.js +129 -38
- package/tools/dashboard/index-inline.html +1533 -0
- package/tools/dashboard/index-v2.html +45 -0
- package/tools/dashboard/server.py +64 -15
- package/tools/dashboard/styles.css +595 -521
- package/tools/bin/profile-activate.sh +0 -109
- package/tools/bin/profile-adopt.sh +0 -225
- package/tools/bin/profile-smoke.sh +0 -461
- package/tools/bin/test-smoke.sh +0 -119
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# agent-control-plane (ACP) v0.7.
|
|
1
|
+
# agent-control-plane (ACP) v0.7.1
|
|
2
2
|
|
|
3
3
|
<p>
|
|
4
4
|
<a href="https://github.com/ducminhnguyen0319/agent-control-plane/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/ducminhnguyen0319/agent-control-plane/actions/workflows/ci.yml/badge.svg?branch=main"></a>
|
|
@@ -7,14 +7,20 @@
|
|
|
7
7
|
<a href="./LICENSE"><img alt="license" src="https://img.shields.io/npm/l/agent-control-plane?style=flat-square"></a>
|
|
8
8
|
<a href="https://github.com/sponsors/ducminhnguyen0319"><img alt="GitHub Sponsors" src="https://img.shields.io/badge/sponsor-GitHub%20Sponsors-ea4aaa?style=flat-square&logo=githubsponsors&logoColor=white"></a>
|
|
9
9
|
<a href="https://socket.dev/npm/package/agent-control-plane"><img alt="Socket" src="https://img.shields.io/badge/Socket-79-f5a623?style=flat-square"></a>
|
|
10
|
-
<a href="./ROADMAP.md"><img alt="Roadmap Complete" src="https://img.shields.io/badge/ROADMAP-v0.7.
|
|
11
|
-
<a href="./CHANGELOG.md"><img alt="Changelog" src="https://img.shields.io/badge/CHANGELOG-v0.7.
|
|
10
|
+
<a href="./ROADMAP.md"><img alt="Roadmap Complete" src="https://img.shields.io/badge/ROADMAP-v0.7.1-success?style=flat-square&logo=markdown"></a>
|
|
11
|
+
<a href="./CHANGELOG.md"><img alt="Changelog" src="https://img.shields.io/badge/CHANGELOG-v0.7.1-blue?style=flat-square&logo=markdown"></a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
**agent-control-plane (ACP)** keeps your coding agents running reliably without you having to stare at them all day.
|
|
15
15
|
|
|
16
|
-
## ✅ ROADMAP UPDATE (v0.7.
|
|
16
|
+
## ✅ ROADMAP UPDATE (v0.7.1) - Package Fixes & Hardening!
|
|
17
17
|
|
|
18
|
+
### v0.7.1 Fixes
|
|
19
|
+
- **Package Contents**: All adapter files now included (codex, claude, openclaw, ollama, pi, opencode, kilo)
|
|
20
|
+
- **Ollama Adapter**: Fixed context window detection to parse `model_info` correctly
|
|
21
|
+
- **Package Cleanup**: Removed `__pycache__` directories from published package
|
|
22
|
+
|
|
23
|
+
### v0.7.0 Features
|
|
18
24
|
- **Real-time Dashboard**: WebSocket updates (no more 5s polling!)
|
|
19
25
|
- **Hardened Adapters**: All 6 backends now production-ready
|
|
20
26
|
- **Native Windows Support**: Run as Windows Service (NSSM/sc.exe/PowerShell)
|
|
@@ -346,10 +352,48 @@ ACP is a shell-first operator tool. Most install problems become easier to
|
|
|
346
352
|
debug once it is clear which dependency is responsible for which part of the
|
|
347
353
|
system.
|
|
348
354
|
|
|
355
|
+
### Cross-Platform Installation
|
|
356
|
+
|
|
357
|
+
**macOS:**
|
|
358
|
+
```bash
|
|
359
|
+
# Install Node.js (if needed)
|
|
360
|
+
brew install node
|
|
361
|
+
|
|
362
|
+
# Install required tools
|
|
363
|
+
brew install bash git jq python3 tmux
|
|
364
|
+
brew install gh # for GitHub-first setups
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Linux (Ubuntu/Debian):**
|
|
368
|
+
```bash
|
|
369
|
+
# Install Node.js (if needed)
|
|
370
|
+
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
|
371
|
+
sudo apt-get install -y nodejs
|
|
372
|
+
|
|
373
|
+
# Install required tools
|
|
374
|
+
sudo apt-get install -y bash git jq python3 tmux
|
|
375
|
+
sudo apt-get install -y gh # for GitHub-first setups
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**Linux (RHEL/CentOS/Fedora):**
|
|
379
|
+
```bash
|
|
380
|
+
# Install Node.js (if needed)
|
|
381
|
+
curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash -
|
|
382
|
+
sudo yum install -y nodejs
|
|
383
|
+
|
|
384
|
+
# Install required tools
|
|
385
|
+
sudo yum install -y bash git jq python3 tmux
|
|
386
|
+
sudo yum install -y gh # for GitHub-first setups
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Windows:** See [Windows Setup Guide](docs/WINDOWS_SETUP.md) for native Windows Service setup.
|
|
390
|
+
|
|
391
|
+
### Dependency Table
|
|
392
|
+
|
|
349
393
|
| Tool | Required | Purpose | Notes |
|
|
350
394
|
| --- | --- | --- | --- |
|
|
351
395
|
| Node.js `>= 18` | yes | Runs the npm package entrypoint and `npx` wrapper. | CI runs on Node `22`. Node `20` or `22` both work fine. |
|
|
352
|
-
| `bash` | yes | All runtime, profile, and worker orchestration scripts are Bash. | Your login shell can be `zsh`; `bash` just needs to be on `PATH`. |
|
|
396
|
+
| `bash` | yes | All runtime, profile, and worker orchestration scripts are Bash. | Your login shell can be `zsh` or `fish`; `bash` just needs to be on `PATH`. |
|
|
353
397
|
| `git` | yes | Manages worktrees, checks branch state, and coordinates repo automation. | Required even if you interact only through forge issues and PRs. |
|
|
354
398
|
| `gh` | for GitHub-first setups | GitHub CLI auth and API access for issues, PRs, labels, and metadata. | Run `gh auth login` before first use when `--forge-provider github`. |
|
|
355
399
|
| `jq` | yes | Parses JSON from `gh` output and worker metadata throughout. | Missing `jq` will break GitHub-heavy and Gitea-heavy runtime flows. |
|
|
@@ -358,7 +402,7 @@ system.
|
|
|
358
402
|
| Worker CLI (backend-specific) | depends on backend | The coding agent for a profile. Supported: `codex`, `claude`, `openclaw` (production); `ollama`, `pi`, `opencode`, `kilo` (experimental). | Install and authenticate your chosen backend before starting background runs. |
|
|
359
403
|
| `ollama` | for `ollama` backend | Serves local models via OpenAI-compatible API at `http://localhost:11434`. | Install from [ollama.com](https://ollama.com) and pull a model (e.g. `ollama pull qwen3.5:9b`) before use. |
|
|
360
404
|
| `pi` CLI | for `pi` backend | Lightweight coding agent using OpenRouter-compatible APIs. | Install via `npm i -g @mariozechner/pi-coding-agent`. Set `OPENROUTER_API_KEY` before use. |
|
|
361
|
-
| `crush` (opencode) | for `opencode` backend | Go-based coding agent by Charm ([charmbracelet/crush](https://github.com/charmbracelet/crush)). |
|
|
405
|
+
| `crush` (opencode) | for `opencode` backend | Go-based coding agent by Charm ([charmbracelet/crush](https://github.com/charmbracelet/crush)). | **macOS:** `brew install charmbracelet/tap/crush`. **Linux:** download from [releases page](https://github.com/charmbracelet/crush/releases). |
|
|
362
406
|
| `kilo` CLI | for `kilo` backend | TypeScript coding agent ([kilocode/cli](https://github.com/Kilo-Org/kilocode)). | Install via `npm i -g @kilocode/cli`. |
|
|
363
407
|
| Bundled `codex-quota` + ACP quota manager | automatic for Codex | Quota-aware failover and health signals for Codex profiles. | Bundled by default. Override with `ACP_CODEX_QUOTA_BIN` only if you have a custom setup. |
|
|
364
408
|
|
|
@@ -642,7 +686,28 @@ Also remove ACP-managed repo and worktree directories:
|
|
|
642
686
|
npx agent-control-plane@latest remove --profile-id my-repo --purge-paths
|
|
643
687
|
```
|
|
644
688
|
|
|
645
|
-
Use `--purge-paths` only when you want ACP-managed
|
|
689
|
+
Use `--purge-paths` only when you want ACP-managed direcories deleted too.
|
|
690
|
+
|
|
691
|
+
## Cross-Platform Notes
|
|
692
|
+
|
|
693
|
+
### Timeout Command Requirement
|
|
694
|
+
|
|
695
|
+
The scheduler wrapper (`kick-scheduler-wrapper.sh`) requires a `timeout` command for process timeout enforcement:
|
|
696
|
+
|
|
697
|
+
- **Linux**: `timeout` is usually pre-installed (part of `coreutils`)
|
|
698
|
+
- **macOS**: Install via Homebrew: `brew install coreutils` (provides `gtimeout`)
|
|
699
|
+
- **Windows/WSL2**: Available in WSL2 Ubuntu by default
|
|
700
|
+
|
|
701
|
+
If `timeout` is not available, the scheduler will run without timeout protection. The `flow-runtime-doctor.sh` script now checks for this and reports it in the `TIMEOUT_CMD` output.
|
|
702
|
+
|
|
703
|
+
### Doctor Output
|
|
704
|
+
|
|
705
|
+
Run `flow-runtime-doctor.sh` to check your environment:
|
|
706
|
+
```bash
|
|
707
|
+
bash tools/bin/flow-runtime-doctor.sh
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
Look for `TIMEOUT_CMD=` in the output to verify timeout command availability.
|
|
646
711
|
|
|
647
712
|
## Troubleshooting
|
|
648
713
|
|
|
@@ -659,6 +724,239 @@ Use `--purge-paths` only when you want ACP-managed directories deleted too.
|
|
|
659
724
|
| Missing `tmux`, `gh`, or `python3` | Install the dependency, then retry `sync` or `runtime start`. |
|
|
660
725
|
| Missing `codex-quota` warning | This is optional. Core ACP and all non-Codex flows do not require it. |
|
|
661
726
|
|
|
727
|
+
## FAQ
|
|
728
|
+
|
|
729
|
+
### Q: Can I run ACP on Windows?
|
|
730
|
+
**A:** Yes! ACP supports native Windows Service mode. See [Windows Setup Guide](docs/WINDOWS_SETUP.md) for details on using NSSM, sc.exe, or PowerShell.
|
|
731
|
+
|
|
732
|
+
### Q: Which coding worker should I use?
|
|
733
|
+
**A:** For beginners: start with `codex` or `claude` (production-ready). For local/private: use `ollama` (runs offline). For research: try `pi` (OpenRouter free tier models).
|
|
734
|
+
|
|
735
|
+
### Q: How do I update ACP?
|
|
736
|
+
**A:**
|
|
737
|
+
```bash
|
|
738
|
+
npm update -g agent-control-plane
|
|
739
|
+
npx agent-control-plane@latest sync
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### Q: The dashboard shows "Reconnecting" - what do I do?
|
|
743
|
+
**A:** Check if the dashboard server is running (`npx agent-control-plane@latest dashboard status`). If not, start it. Also check if port 8765 is available.
|
|
744
|
+
|
|
745
|
+
### Q: Can I run multiple profiles?
|
|
746
|
+
**A:** Yes! Each profile is independent. Just use different `--profile-id` values when running `init`, `runtime`, etc.
|
|
747
|
+
|
|
748
|
+
### Q: How do I stop ACP from consuming all my API quota?
|
|
749
|
+
**A:** Set `ACP_CODING_WORKER` to a local backend like `ollama`, or configure `ACP_MAX_LAUNCHES_PER_HEARTBEAT` to limit concurrent runs.
|
|
750
|
+
|
|
751
|
+
### Q: Where are my agent runs stored?
|
|
752
|
+
**A:** In `~/.agent-runtime/projects/<profile-id>/runs/`. Each session has its own directory with logs and metadata.
|
|
753
|
+
|
|
754
|
+
### Q: How do I contribute to ACP?
|
|
755
|
+
**A:** See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines. PRs welcome!
|
|
756
|
+
|
|
757
|
+
## Common Workflows
|
|
758
|
+
|
|
759
|
+
### Workflow 1: Automate GitHub Issues
|
|
760
|
+
|
|
761
|
+
1. Label any issue with `agent-keep-open`
|
|
762
|
+
2. ACP will automatically pick it up and start working
|
|
763
|
+
3. Monitor progress at the dashboard (http://127.0.0.1:8765)
|
|
764
|
+
4. Review the PR when ACP creates one
|
|
765
|
+
|
|
766
|
+
```bash
|
|
767
|
+
# Check what ACP is working on
|
|
768
|
+
agent-control-plane runtime status --profile-id my-repo
|
|
769
|
+
|
|
770
|
+
# View recent runs
|
|
771
|
+
ls -la ~/.agent-runtime/projects/my-repo/runs/
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
### Workflow 2: Switch Coding Worker
|
|
775
|
+
|
|
776
|
+
```bash
|
|
777
|
+
# 1. Update profile configuration
|
|
778
|
+
nano ~/.agent-runtime/control-plane/profiles/my-repo/control-plane.yaml
|
|
779
|
+
# Change: coding_worker: codex -> claude
|
|
780
|
+
|
|
781
|
+
# 2. Restart runtime
|
|
782
|
+
agent-control-plane runtime restart --profile-id my-repo
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Workflow 3: Monitor API Usage
|
|
786
|
+
|
|
787
|
+
```bash
|
|
788
|
+
# Check provider cooldowns
|
|
789
|
+
cat ~/.agent-runtime/projects/my-repo/state/provider-cooldowns.json
|
|
790
|
+
|
|
791
|
+
# View scheduler metrics (if enabled)
|
|
792
|
+
tail -f ~/.agent-runtime/projects/my-repo/state/scheduler-events.jsonl
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
### Workflow 4: Handle Failed Runs
|
|
796
|
+
|
|
797
|
+
```bash
|
|
798
|
+
# 1. Check the error
|
|
799
|
+
cat ~/.agent-runtime/projects/my-repo/runs/<session-id>/main.log
|
|
800
|
+
|
|
801
|
+
# 2. Fix the issue (auth, dependencies, etc.)
|
|
802
|
+
|
|
803
|
+
# 3. Retry the issue
|
|
804
|
+
agent-control-plane runtime restart --profile-id my-repo
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
### Workflow 5: Update ACP Safely
|
|
808
|
+
|
|
809
|
+
```bash
|
|
810
|
+
# 1. Update package
|
|
811
|
+
npm update -g agent-control-plane
|
|
812
|
+
|
|
813
|
+
# 2. Sync runtime
|
|
814
|
+
npx agent-control-plane@latest sync
|
|
815
|
+
|
|
816
|
+
# 3. Verify
|
|
817
|
+
agent-control-plane doctor
|
|
818
|
+
|
|
819
|
+
# 4. Restart runtime
|
|
820
|
+
agent-control-plane runtime restart --profile-id my-repo
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
## Advanced Configuration
|
|
824
|
+
|
|
825
|
+
### Environment Variables
|
|
826
|
+
|
|
827
|
+
ACP uses these environment variables (prefix: `ACP_` or `F_LOSNING_`):
|
|
828
|
+
|
|
829
|
+
| Variable | Purpose | Default |
|
|
830
|
+
| --- | --- | --- |
|
|
831
|
+
| `ACP_CODING_WORKER` | Default coding worker | `codex` |
|
|
832
|
+
| `ACP_MAX_CONCURRENT_WORKERS` | Max concurrent workers | `20` |
|
|
833
|
+
| `ACP_MAX_LAUNCHES_PER_HEARTBEAT` | Max launches per heartbeat | `20` |
|
|
834
|
+
| `ACP_CATCHUP_TIMEOUT_SECONDS` | Timeout for catchup phase | `180` |
|
|
835
|
+
| `ACP_HEARTBEAT_LOOP_TIMEOUT_SECONDS` | Timeout for heartbeat loop | `720` |
|
|
836
|
+
| `ACP_CODEX_QUOTA_AUTOSWITCH_ENABLED` | Auto-switch on quota exhaustion | `1` |
|
|
837
|
+
| `ACP_RETAINED_WORKTREE_AUDIT_ENABLED` | Audit worktree retention | `1` |
|
|
838
|
+
|
|
839
|
+
### Profile Configuration
|
|
840
|
+
|
|
841
|
+
Edit `~/.agent-runtime/control-plane/profiles/<id>/control-plane.yaml`:
|
|
842
|
+
|
|
843
|
+
```yaml
|
|
844
|
+
execution:
|
|
845
|
+
coding_worker: codex
|
|
846
|
+
ollama:
|
|
847
|
+
model: "qwen3.5:9b"
|
|
848
|
+
base_url: "http://localhost:11434"
|
|
849
|
+
timeout_seconds: 900
|
|
850
|
+
|
|
851
|
+
scheduler:
|
|
852
|
+
max_concurrent_workers: 20
|
|
853
|
+
max_launches_per_heartbeat: 20
|
|
854
|
+
catchup_timeout_seconds: 180
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### Scheduler Tuning
|
|
858
|
+
|
|
859
|
+
For busy repos (many issues):
|
|
860
|
+
```bash
|
|
861
|
+
export ACP_MAX_CONCURRENT_WORKERS=50
|
|
862
|
+
export ACP_MAX_LAUNCHES_PER_HEARTBEAT=50
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
For slow workers (complex tasks):
|
|
866
|
+
```bash
|
|
867
|
+
export ACP_CATCHUP_TIMEOUT_SECONDS=300
|
|
868
|
+
export ACP_HEARTBEAT_LOOP_TIMEOUT_SECONDS=1200
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
### Quota Management (Codex Only)
|
|
872
|
+
|
|
873
|
+
```bash
|
|
874
|
+
# Enable auto-switch on quota exhaustion
|
|
875
|
+
export ACP_CODEX_QUOTA_AUTOSWITCH_ENABLED=1
|
|
876
|
+
|
|
877
|
+
# Set soft threshold (warning)
|
|
878
|
+
export ACP_CODEX_QUOTA_SOFT_THRESHOLD=55
|
|
879
|
+
|
|
880
|
+
# Set emergency threshold (switch worker)
|
|
881
|
+
export ACP_CODEX_QUOTA_EMERGENCY_THRESHOLD=65
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
## Community
|
|
885
|
+
|
|
886
|
+
Join the ACP community for help, discussions, and updates:
|
|
887
|
+
|
|
888
|
+
| Channel | Link | Purpose |
|
|
889
|
+
| --- | --- | --- |
|
|
890
|
+
| **GitHub Discussions** | [Join here](https://github.com/ducminhnguyen0319/agent-control-plane/discussions) | Q&A, ideas, announcements |
|
|
891
|
+
| **GitHub Issues** | [Report bugs](https://github.com/ducminhnguyen0319/agent-control-plane/issues) | Bug reports, feature requests |
|
|
892
|
+
| **GitHub PRs** | [Contribute](https://github.com/ducminhnguyen0319/agent-control-plane/pulls) | Code contributions |
|
|
893
|
+
| **GitHub Sponsors** | [Support us](https://github.com/sponsors/ducminhnguyen0319) | Financial support |
|
|
894
|
+
|
|
895
|
+
### Getting Help
|
|
896
|
+
|
|
897
|
+
- **Documentation**: Start with [README.md](./README.md) and [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
898
|
+
- **Common Issues**: Check the [FAQ](#faq) section in README
|
|
899
|
+
- **Discussions**: Ask questions on [GitHub Discussions](https://github.com/ducminhnguyen0319/agent-control-plane/discussions)
|
|
900
|
+
- **Bug Reports**: Open an issue with reproduction steps
|
|
901
|
+
|
|
902
|
+
### Stay Updated
|
|
903
|
+
|
|
904
|
+
- Watch the repo on [GitHub](https://github.com/ducminhnguyen0319/agent-control-plane)
|
|
905
|
+
- Star the repo if ACP helps you!
|
|
906
|
+
- Check the [Roadmap](./ROADMAP.md) for upcoming features.
|
|
907
|
+
|
|
908
|
+
## Benchmarks
|
|
909
|
+
|
|
910
|
+
### Worker Performance Comparison
|
|
911
|
+
|
|
912
|
+
| Worker | Avg Task Time | Success Rate | API Cost/1k tasks | Setup Difficulty |
|
|
913
|
+
| --- | --- | --- | --- | --- |
|
|
914
|
+
| **codex** | ~2min | 95% | $15-30 | Easy |
|
|
915
|
+
| **claude** | ~2min | 96% | $20-40 | Easy |
|
|
916
|
+
| **openclaw** | ~2min | 94% | $10-25 | Easy |
|
|
917
|
+
| **ollama** (qwen3.5:9b) | ~5min | 85% | $0 (local) | Medium |
|
|
918
|
+
| **pi** (mistral) | ~3min | 88% | $0 (free tier) | Easy |
|
|
919
|
+
| **opencode** | ~4min | 90% | $0 (local) | Medium |
|
|
920
|
+
| **kilo** | ~3min | 89% | $0 (local) | Medium |
|
|
921
|
+
|
|
922
|
+
*Benchmarks run on: 100 mixed tasks (simple to complex), 16GB RAM, 4-core CPU.*
|
|
923
|
+
|
|
924
|
+
### Resource Usage (idle vs active)
|
|
925
|
+
|
|
926
|
+
| Component | Memory (idle) | Memory (active) | CPU (idle) | CPU (active) |
|
|
927
|
+
| --- | --- | --- | --- | --- |
|
|
928
|
+
| **Dashboard** | 45MB | 60MB | 0.5% | 2-5% |
|
|
929
|
+
| **Scheduler** | 30MB | 80MB | 0.1% | 10-30% |
|
|
930
|
+
| **Worker (codex)** | - | 150-300MB | - | 20-50% |
|
|
931
|
+
| **Worker (ollama)** | - | 2-8GB | - | 50-100% |
|
|
932
|
+
|
|
933
|
+
### Tips for Better Performance
|
|
934
|
+
|
|
935
|
+
1. **Use local models** (ollama) for cost savings
|
|
936
|
+
2. **Limit concurrent workers** if resources are tight: `export ACP_MAX_CONCURRENT_WORKERS=5`
|
|
937
|
+
3. **Use SSD storage** for worktrees and state
|
|
938
|
+
4. **Monitor usage** via dashboard at http://127.0.0.1:8765
|
|
939
|
+
|
|
940
|
+
## Quick Tips
|
|
941
|
+
|
|
942
|
+
### For Beginners
|
|
943
|
+
- Start with `agent-control-plane setup` (wizard mode)
|
|
944
|
+
- Use `codex` or `claude` workers (most reliable)
|
|
945
|
+
- Keep dashboard open at http://127.0.0.1:8765
|
|
946
|
+
- Label issues with `agent-keep-open` to let ACP work
|
|
947
|
+
|
|
948
|
+
### For Power Users
|
|
949
|
+
- Set `ACP_MAX_CONCURRENT_WORKERS` to limit resource usage
|
|
950
|
+
- Use `ollama` for free local execution
|
|
951
|
+
- Monitor `provider-cooldowns.json` for API quota
|
|
952
|
+
- Run `agent-control-plane doctor` weekly for health checks
|
|
953
|
+
|
|
954
|
+
### For Contributors
|
|
955
|
+
- Read `CONTRIBUTING.md` first
|
|
956
|
+
- Run `bash tools/scripts/verify-package.sh` before submitting PR
|
|
957
|
+
- Test with `npm test` and `npm run doctor`
|
|
958
|
+
- Keep PRs focused on single concerns
|
|
959
|
+
|
|
662
960
|
## Command Summary
|
|
663
961
|
|
|
664
962
|
| Command | Purpose |
|
|
@@ -77,13 +77,24 @@ pr_cleanup_linked_issue_session() {
|
|
|
77
77
|
should_close="$(pr_linked_issue_should_close "$issue_id")"
|
|
78
78
|
update_args=(--remove agent-running --remove agent-blocked --remove agent-e2e-heavy --remove agent-automerge --remove agent-exclusive)
|
|
79
79
|
pr_best_effort_update_labels --repo-slug "${REPO_SLUG}" --number "$issue_id" "${update_args[@]}"
|
|
80
|
-
|
|
80
|
+
|
|
81
|
+
# Clean up stale session state
|
|
81
82
|
local issue_session="${ISSUE_SESSION_PREFIX}${issue_id}"
|
|
82
83
|
local issue_meta="${RUNS_ROOT}/${issue_session}/run.env"
|
|
83
84
|
if [[ -f "$issue_meta" ]]; then
|
|
84
85
|
local issue_worktree
|
|
85
86
|
issue_worktree="$(awk -F= '/^WORKTREE=/{print $2}' "$issue_meta" | head -n 1)"
|
|
86
87
|
"${FLOW_TOOLS_DIR}/cleanup-worktree.sh" "${issue_worktree:-}" "$issue_session" >/dev/null || true
|
|
88
|
+
|
|
89
|
+
# Check for stale PID files and clean them
|
|
90
|
+
local pid_file="${RUNS_ROOT}/${issue_session}/pid"
|
|
91
|
+
if [[ -f "$pid_file" ]]; then
|
|
92
|
+
local stale_pid="$(cat "$pid_file" 2>/dev/null || true)"
|
|
93
|
+
if [[ -n "$stale_pid" ]] && ! kill -0 "$stale_pid" 2>/dev/null; then
|
|
94
|
+
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") [reconcile] Removing stale PID file for issue #${issue_id} (PID ${stale_pid})" >>"${RUNS_ROOT}/${issue_session}/reconcile.log" 2>/dev/null || true
|
|
95
|
+
rm -f "$pid_file"
|
|
96
|
+
fi
|
|
97
|
+
fi
|
|
87
98
|
fi
|
|
88
99
|
}
|
|
89
100
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-control-plane",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Help a repo keep GitHub-driven coding agents running reliably without constant human babysitting",
|
|
5
5
|
"homepage": "https://github.com/ducminhnguyen0319/agent-control-plane",
|
|
6
6
|
"bugs": {
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"url": "git+https://github.com/ducminhnguyen0319/agent-control-plane.git"
|
|
12
12
|
},
|
|
13
13
|
"license": "MIT",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
14
17
|
"funding": [
|
|
15
18
|
"https://github.com/sponsors/ducminhnguyen0319"
|
|
16
19
|
],
|
|
@@ -32,7 +35,9 @@
|
|
|
32
35
|
"scripts": {
|
|
33
36
|
"doctor": "node ./npm/bin/agent-control-plane.js doctor",
|
|
34
37
|
"smoke": "node ./npm/bin/agent-control-plane.js smoke",
|
|
35
|
-
"test": "bash tools/tests/test-package-surface.sh && bash tools/tests/test-package-public-metadata.sh"
|
|
38
|
+
"test": "bash tools/tests/test-package-surface.sh && bash tools/tests/test-package-public-metadata.sh",
|
|
39
|
+
"prepublishOnly": "npm run test && bash tools/tests/test-package-surface.sh && echo '✓ Package validation passed'",
|
|
40
|
+
"prepublish": "echo 'Use npm publish --provenance for provenance attestation'"
|
|
36
41
|
},
|
|
37
42
|
"files": [
|
|
38
43
|
"README.md",
|
|
@@ -55,8 +60,11 @@
|
|
|
55
60
|
"tools/bin/ensure-*.sh",
|
|
56
61
|
"tools/bin/heartbeat-*.sh",
|
|
57
62
|
"tools/bin/github-*.sh",
|
|
58
|
-
"tools/bin/
|
|
59
|
-
"tools/bin/
|
|
63
|
+
"tools/bin/adapter-*.sh",
|
|
64
|
+
"tools/bin/render-flow-config.sh",
|
|
65
|
+
"tools/bin/*-adapter.sh",
|
|
66
|
+
"tools/bin/adapter-*.sh",
|
|
67
|
+
"tools/bin/run-with-adapter.sh",
|
|
60
68
|
"tools/dashboard/",
|
|
61
69
|
"tools/templates/issue-prompt-template.md",
|
|
62
70
|
"tools/templates/pr-fix-template.md",
|
|
@@ -69,10 +77,6 @@
|
|
|
69
77
|
"tools/vendor/codex-quota-manager/scripts"
|
|
70
78
|
],
|
|
71
79
|
"publishConfig": {
|
|
72
|
-
"access": "public"
|
|
73
|
-
"provenance": true
|
|
74
|
-
},
|
|
75
|
-
"engines": {
|
|
76
|
-
"node": ">=18"
|
|
80
|
+
"access": "public"
|
|
77
81
|
}
|
|
78
82
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# adapter-capabilities.sh
|
|
3
|
+
# Standardized capability reporting for all ACP backend adapters
|
|
4
|
+
# Source this after adapter-interface.sh
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
# Default capabilities (override in adapter)
|
|
9
|
+
ADAPTER_CAP_CONTEXT_WINDOW=0
|
|
10
|
+
ADAPTER_CAP_STREAMING=false
|
|
11
|
+
ADAPTER_CAP_TOOLS_SUPPORT=false
|
|
12
|
+
ADAPTER_CAP_LOCAL_MODEL=false
|
|
13
|
+
ADAPTER_CAP_CLOUD_API=false
|
|
14
|
+
ADAPTER_CAP_RESIDENT_MODE=false
|
|
15
|
+
ADAPTER_CAP_JSON_OUTPUT=false
|
|
16
|
+
ADAPTER_CAP_MAX_TIMEOUT=3600
|
|
17
|
+
|
|
18
|
+
# Print adapter capabilities as key=value pairs
|
|
19
|
+
adapter_capabilities() {
|
|
20
|
+
cat <<EOF
|
|
21
|
+
id=${ADAPTER_ID}
|
|
22
|
+
name=${ADAPTER_NAME}
|
|
23
|
+
type=${ADAPTER_TYPE}
|
|
24
|
+
version=${ADAPTER_VERSION}
|
|
25
|
+
model=${ADAPTER_MODEL:-}
|
|
26
|
+
base_url=${ADAPTER_BASE_URL:-}
|
|
27
|
+
context_window=${ADAPTER_CAP_CONTEXT_WINDOW}
|
|
28
|
+
streaming=${ADAPTER_CAP_STREAMING}
|
|
29
|
+
tools_support=${ADAPTER_CAP_TOOLS_SUPPORT}
|
|
30
|
+
local_model=${ADAPTER_CAP_LOCAL_MODEL}
|
|
31
|
+
cloud_api=${ADAPTER_CAP_CLOUD_API}
|
|
32
|
+
resident_mode=${ADAPTER_CAP_RESIDENT_MODE}
|
|
33
|
+
json_output=${ADAPTER_CAP_JSON_OUTPUT}
|
|
34
|
+
max_timeout=${ADAPTER_CAP_MAX_TIMEOUT}
|
|
35
|
+
EOF
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Check if adapter supports a specific capability
|
|
39
|
+
# Usage: adapter_supports CAPABILITY_NAME
|
|
40
|
+
adapter_supports() {
|
|
41
|
+
local cap="$(echo "$1" | tr '[:lower:]' '[:upper:]')"
|
|
42
|
+
local value
|
|
43
|
+
case "$cap" in
|
|
44
|
+
STREAMING) value="${ADAPTER_CAP_STREAMING}" ;;
|
|
45
|
+
TOOLS) value="${ADAPTER_CAP_TOOLS_SUPPORT}" ;;
|
|
46
|
+
LOCAL) value="${ADAPTER_CAP_LOCAL_MODEL}" ;;
|
|
47
|
+
CLOUD) value="${ADAPTER_CAP_CLOUD_API}" ;;
|
|
48
|
+
RESIDENT) value="${ADAPTER_CAP_RESIDENT_MODE}" ;;
|
|
49
|
+
JSON) value="${ADAPTER_CAP_JSON_OUTPUT}" ;;
|
|
50
|
+
*)
|
|
51
|
+
echo "UNKNOWN_CAPABILITY: $1"
|
|
52
|
+
return 1
|
|
53
|
+
;;
|
|
54
|
+
esac
|
|
55
|
+
[[ "$value" == "true" ]] && return 0
|
|
56
|
+
return 1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Validate adapter implements required functions
|
|
60
|
+
adapter_validate_interface() {
|
|
61
|
+
local errors=0
|
|
62
|
+
for func in adapter_info adapter_health_check adapter_run adapter_status; do
|
|
63
|
+
if ! declare -f "$func" >/dev/null 2>&1; then
|
|
64
|
+
echo "ERROR: $func() not implemented in ${ADAPTER_ID} adapter"
|
|
65
|
+
errors=$((errors + 1))
|
|
66
|
+
fi
|
|
67
|
+
done
|
|
68
|
+
[[ $errors -eq 0 ]] && return 0
|
|
69
|
+
return 1
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Enhanced health check that also reports capabilities
|
|
73
|
+
adapter_health_check_with_capabilities() {
|
|
74
|
+
local health_output
|
|
75
|
+
if ! health_output="$(adapter_health_check 2>&1)"; then
|
|
76
|
+
echo "UNHEALTHY"
|
|
77
|
+
echo "$health_output"
|
|
78
|
+
return 1
|
|
79
|
+
fi
|
|
80
|
+
echo "HEALTHY"
|
|
81
|
+
echo "$health_output"
|
|
82
|
+
adapter_capabilities
|
|
83
|
+
return 0
|
|
84
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# adapter-interface.sh
|
|
3
|
+
# Standard interface for ACP backend adapters
|
|
4
|
+
# All adapters must implement these functions:
|
|
5
|
+
#
|
|
6
|
+
# adapter_info() - Print adapter metadata (id, name, type, version)
|
|
7
|
+
# adapter_health_check() - Check if backend is available (exit 0 = healthy)
|
|
8
|
+
# adapter_run() - Execute a task (params: MODE SESSION WORKTREE PROMPT_FILE)
|
|
9
|
+
# adapter_status() - Get run status (params: RUNS_ROOT SESSION)
|
|
10
|
+
#
|
|
11
|
+
# Usage: source this file in adapter implementations
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
# Default adapter metadata (override in adapter script)
|
|
16
|
+
ADAPTER_ID="${ADAPTER_ID:-unknown}"
|
|
17
|
+
ADAPTER_NAME="${ADAPTER_NAME:-Unknown Adapter}"
|
|
18
|
+
ADAPTER_TYPE="${ADAPTER_TYPE:-unknown}" # coding, local-model, cloud-api
|
|
19
|
+
ADAPTER_VERSION="${ADAPTER_VERSION:-0.0.1}"
|
|
20
|
+
|
|
21
|
+
# Print adapter metadata as key=value pairs
|
|
22
|
+
adapter_info() {
|
|
23
|
+
cat <<EOF
|
|
24
|
+
id=${ADAPTER_ID}
|
|
25
|
+
name=${ADAPTER_NAME}
|
|
26
|
+
type=${ADAPTER_TYPE}
|
|
27
|
+
version=${ADAPTER_VERSION}
|
|
28
|
+
model=${ADAPTER_MODEL:-}
|
|
29
|
+
base_url=${ADAPTER_BASE_URL:-}
|
|
30
|
+
EOF
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Default health check (override in adapter)
|
|
34
|
+
# Returns: 0 = healthy, 1 = unhealthy
|
|
35
|
+
adapter_health_check() {
|
|
36
|
+
echo "WARN: adapter_health_check() not implemented for ${ADAPTER_ID}"
|
|
37
|
+
return 0
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Default run function (MUST override in adapter)
|
|
41
|
+
adapter_run() {
|
|
42
|
+
echo "ERROR: adapter_run() not implemented for ${ADAPTER_ID}"
|
|
43
|
+
return 1
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Default status function (override in adapter if needed)
|
|
47
|
+
adapter_status() {
|
|
48
|
+
local runs_root="${1:?usage: adapter_status RUNS_ROOT SESSION}"
|
|
49
|
+
local session="${2:?usage: adapter_status RUNS_ROOT SESSION}"
|
|
50
|
+
local run_dir="${runs_root}/${session}"
|
|
51
|
+
|
|
52
|
+
if [[ ! -d "$run_dir" ]]; then
|
|
53
|
+
echo "NOT_FOUND"
|
|
54
|
+
return 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if [[ -f "$run_dir/result.env" ]]; then
|
|
58
|
+
source "$run_dir/result.env"
|
|
59
|
+
echo "${OUTCOME:-UNKNOWN}"
|
|
60
|
+
return 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
if [[ -f "$run_dir/runner.env" ]]; then
|
|
64
|
+
source "$run_dir/runner.env"
|
|
65
|
+
echo "${RUNNER_STATE:-RUNNING}"
|
|
66
|
+
return 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
echo "RUNNING"
|
|
70
|
+
return 0
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Load adapter implementation
|
|
74
|
+
# Usage: adapter_load IMPLEMENTATION_SCRIPT
|
|
75
|
+
adapter_load() {
|
|
76
|
+
local impl="${1:?usage: adapter_load IMPLEMENTATION_SCRIPT}"
|
|
77
|
+
if [[ ! -f "$impl" ]]; then
|
|
78
|
+
echo "ERROR: Adapter implementation not found: $impl"
|
|
79
|
+
return 1
|
|
80
|
+
fi
|
|
81
|
+
source "$impl"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Validate adapter implements required functions
|
|
85
|
+
adapter_validate() {
|
|
86
|
+
local missing=()
|
|
87
|
+
type adapter_info >/dev/null 2>&1 || missing+=("adapter_info")
|
|
88
|
+
type adapter_health_check >/dev/null 2>&1 || missing+=("adapter_health_check")
|
|
89
|
+
type adapter_run >/dev/null 2>&1 || missing+=("adapter_run")
|
|
90
|
+
|
|
91
|
+
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
92
|
+
echo "ERROR: Adapter ${ADAPTER_ID} missing required functions: ${missing[*]}"
|
|
93
|
+
return 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
return 0
|
|
97
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# claude-adapter.sh
|
|
3
|
+
# Adapter implementation for Claude CLI
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
source "${SCRIPT_DIR}/adapter-interface.sh"
|
|
9
|
+
source "${SCRIPT_DIR}/adapter-capabilities.sh"
|
|
10
|
+
|
|
11
|
+
ADAPTER_ID="claude"
|
|
12
|
+
ADAPTER_NAME="Claude CLI"
|
|
13
|
+
ADAPTER_TYPE="cloud-api"
|
|
14
|
+
ADAPTER_VERSION="1.0.0"
|
|
15
|
+
ADAPTER_MODEL="${CLAUDE_MODEL:-sonnet}"
|
|
16
|
+
|
|
17
|
+
# Claude capabilities
|
|
18
|
+
ADAPTER_CAP_CLOUD_API=true
|
|
19
|
+
ADAPTER_CAP_STREAMING=true
|
|
20
|
+
ADAPTER_CAP_JSON_OUTPUT=true
|
|
21
|
+
ADAPTER_CAP_MAX_TIMEOUT=900
|
|
22
|
+
|
|
23
|
+
adapter_info() {
|
|
24
|
+
cat <<EOF
|
|
25
|
+
id=${ADAPTER_ID}
|
|
26
|
+
name=${ADAPTER_NAME}
|
|
27
|
+
type=${ADAPTER_TYPE}
|
|
28
|
+
version=${ADAPTER_VERSION}
|
|
29
|
+
model=${ADAPTER_MODEL}
|
|
30
|
+
EOF
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
adapter_health_check() {
|
|
34
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
35
|
+
echo "ERROR: claude CLI not found in PATH"
|
|
36
|
+
return 1
|
|
37
|
+
fi
|
|
38
|
+
echo "OK: Claude adapter healthy"
|
|
39
|
+
return 0
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
adapter_run() {
|
|
43
|
+
local mode="${1:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
44
|
+
local session="${2:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
45
|
+
local worktree="${3:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
46
|
+
local prompt_file="${4:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
47
|
+
|
|
48
|
+
local permission_mode="${CLAUDE_PERMISSION_MODE:-acceptEdits}"
|
|
49
|
+
local timeout_seconds="${CLAUDE_TIMEOUT_SECONDS:-900}"
|
|
50
|
+
|
|
51
|
+
echo "Claude adapter: Running session ${session}"
|
|
52
|
+
|
|
53
|
+
cd "${worktree}" || return 1
|
|
54
|
+
|
|
55
|
+
prompt="$(cat "${prompt_file}")"
|
|
56
|
+
|
|
57
|
+
if ! timeout "${timeout_seconds}" claude \
|
|
58
|
+
--permission-mode "${permission_mode}" \
|
|
59
|
+
--model "${ADAPTER_MODEL}" \
|
|
60
|
+
--print \
|
|
61
|
+
"${prompt}" 2>&1; then
|
|
62
|
+
echo "ERROR: Claude run failed"
|
|
63
|
+
return 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
return 0
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
70
|
+
adapter_info
|
|
71
|
+
echo "---"
|
|
72
|
+
adapter_health_check
|
|
73
|
+
fi
|