agent-control-plane 0.8.0 → 0.9.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 +7 -0
- package/package.json +3 -2
- package/tools/bin/adapter-interface.sh +58 -0
- package/tools/bin/claude-adapter.sh +14 -4
- package/tools/bin/codex-adapter.sh +1 -1
- package/tools/bin/flow-forge-lib.sh +4 -2
- package/tools/bin/flow-runtime-doctor.sh +5 -4
- package/tools/bin/kilo-adapter.sh +1 -1
- package/tools/bin/ollama-adapter.sh +3 -18
- package/tools/bin/openclaw-adapter.sh +1 -1
- package/tools/bin/opencode-adapter.sh +1 -1
- package/tools/bin/pi-adapter.sh +1 -1
- package/tools/dashboard/__pycache__/server.cpython-311.pyc +0 -0
package/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
<picture>
|
|
2
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/logo-dark.svg">
|
|
3
|
+
<source media="(prefers-color-scheme: light)" srcset="assets/logo-light.svg">
|
|
4
|
+
<img alt="ACP — agent-control-plane" src="assets/logo-light.svg" height="80">
|
|
5
|
+
</picture>
|
|
6
|
+
|
|
1
7
|
# agent-control-plane (ACP) v0.7.1
|
|
2
8
|
|
|
3
9
|
<p>
|
|
@@ -39,6 +45,7 @@ going completely off the rails.
|
|
|
39
45
|
- Roadmap: [ROADMAP.md](./ROADMAP.md)
|
|
40
46
|
- Architecture: [references/architecture.md](./references/architecture.md)
|
|
41
47
|
- Commands: [references/commands.md](./references/commands.md)
|
|
48
|
+
- Examples: [docs/examples.md](./docs/examples.md)
|
|
42
49
|
|
|
43
50
|
## The Big Idea
|
|
44
51
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-control-plane",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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": {
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"tools/vendor/codex-quota-manager/scripts"
|
|
78
78
|
],
|
|
79
79
|
"publishConfig": {
|
|
80
|
-
"access": "public"
|
|
80
|
+
"access": "public",
|
|
81
|
+
"provenance": true
|
|
81
82
|
}
|
|
82
83
|
}
|
|
@@ -81,6 +81,64 @@ adapter_load() {
|
|
|
81
81
|
source "$impl"
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
# Run a command with a wall-clock timeout. Uses GNU `timeout` / `gtimeout`
|
|
85
|
+
# when available, else falls back to a python3 wrapper, else perl. Streams
|
|
86
|
+
# the child's stdout/stderr to the caller. Exits 124 on timeout.
|
|
87
|
+
# Usage: adapter_run_with_timeout SECS CMD [ARGS...]
|
|
88
|
+
adapter_run_with_timeout() {
|
|
89
|
+
local secs="${1:?usage: adapter_run_with_timeout SECS CMD [ARGS...]}"
|
|
90
|
+
shift
|
|
91
|
+
if command -v gtimeout >/dev/null 2>&1; then
|
|
92
|
+
gtimeout "${secs}" "$@"
|
|
93
|
+
return $?
|
|
94
|
+
fi
|
|
95
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
96
|
+
timeout "${secs}" "$@"
|
|
97
|
+
return $?
|
|
98
|
+
fi
|
|
99
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
100
|
+
python3 - "${secs}" "$@" <<'PY'
|
|
101
|
+
import subprocess, sys
|
|
102
|
+
secs = float(sys.argv[1])
|
|
103
|
+
cmd = sys.argv[2:]
|
|
104
|
+
try:
|
|
105
|
+
proc = subprocess.Popen(cmd)
|
|
106
|
+
except FileNotFoundError as exc:
|
|
107
|
+
sys.stderr.write("adapter_run_with_timeout: %s\n" % exc)
|
|
108
|
+
sys.exit(127)
|
|
109
|
+
try:
|
|
110
|
+
proc.wait(timeout=secs)
|
|
111
|
+
except subprocess.TimeoutExpired:
|
|
112
|
+
proc.terminate()
|
|
113
|
+
try:
|
|
114
|
+
proc.wait(timeout=10)
|
|
115
|
+
except subprocess.TimeoutExpired:
|
|
116
|
+
proc.kill()
|
|
117
|
+
proc.wait()
|
|
118
|
+
sys.exit(124)
|
|
119
|
+
sys.exit(proc.returncode)
|
|
120
|
+
PY
|
|
121
|
+
return $?
|
|
122
|
+
fi
|
|
123
|
+
if command -v perl >/dev/null 2>&1; then
|
|
124
|
+
perl -e '
|
|
125
|
+
my $secs = shift @ARGV;
|
|
126
|
+
my $pid = fork();
|
|
127
|
+
die "fork: $!" unless defined $pid;
|
|
128
|
+
if ($pid == 0) { exec { $ARGV[0] } @ARGV or exit 127; }
|
|
129
|
+
local $SIG{ALRM} = sub { kill "TERM", $pid; sleep 10; kill "KILL", $pid; waitpid($pid, 0); exit 124; };
|
|
130
|
+
alarm $secs;
|
|
131
|
+
waitpid($pid, 0);
|
|
132
|
+
alarm 0;
|
|
133
|
+
my $rc = $? >> 8;
|
|
134
|
+
exit $rc;
|
|
135
|
+
' "${secs}" "$@"
|
|
136
|
+
return $?
|
|
137
|
+
fi
|
|
138
|
+
echo "adapter_run_with_timeout: no gtimeout/timeout/python3/perl available; running without timeout" >&2
|
|
139
|
+
"$@"
|
|
140
|
+
}
|
|
141
|
+
|
|
84
142
|
# Validate adapter implements required functions
|
|
85
143
|
adapter_validate() {
|
|
86
144
|
local missing=()
|
|
@@ -49,12 +49,22 @@ adapter_run() {
|
|
|
49
49
|
local timeout_seconds="${CLAUDE_TIMEOUT_SECONDS:-900}"
|
|
50
50
|
|
|
51
51
|
echo "Claude adapter: Running session ${session}"
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
cd "${worktree}" || return 1
|
|
54
|
-
|
|
54
|
+
|
|
55
|
+
local sandbox_subdir="${ACP_SANDBOX_SUBDIR:-.openclaw-artifacts}"
|
|
56
|
+
local sandbox_run_dir="${worktree%/}/${sandbox_subdir}/${session}"
|
|
57
|
+
mkdir -p "${sandbox_run_dir}" 2>/dev/null || true
|
|
58
|
+
export ACP_SESSION="${session}"
|
|
59
|
+
export ACP_RUN_DIR="${sandbox_run_dir}"
|
|
60
|
+
export ACP_RESULT_FILE="${sandbox_run_dir}/result.env"
|
|
61
|
+
export F_LOSNING_SESSION="${session}"
|
|
62
|
+
export F_LOSNING_RUN_DIR="${sandbox_run_dir}"
|
|
63
|
+
export F_LOSNING_RESULT_FILE="${sandbox_run_dir}/result.env"
|
|
64
|
+
|
|
55
65
|
prompt="$(cat "${prompt_file}")"
|
|
56
|
-
|
|
57
|
-
if !
|
|
66
|
+
|
|
67
|
+
if ! adapter_run_with_timeout "${timeout_seconds}" claude \
|
|
58
68
|
--permission-mode "${permission_mode}" \
|
|
59
69
|
--model "${ADAPTER_MODEL}" \
|
|
60
70
|
--print \
|
|
@@ -73,7 +73,7 @@ adapter_run() {
|
|
|
73
73
|
cd "${worktree}" || return 1
|
|
74
74
|
|
|
75
75
|
# Run claude with the prompt
|
|
76
|
-
if !
|
|
76
|
+
if ! adapter_run_with_timeout "${timeout_seconds}" claude \
|
|
77
77
|
--permission-mode "${permission_mode}" \
|
|
78
78
|
--model "${ADAPTER_MODEL}" \
|
|
79
79
|
--print \
|
|
@@ -1151,8 +1151,10 @@ flow_github_pr_view_json() {
|
|
|
1151
1151
|
fi
|
|
1152
1152
|
|
|
1153
1153
|
if flow_github_graphql_available "${repo_slug}" \
|
|
1154
|
-
&& pr_json="$(gh pr view "${pr_number}" -R "${repo_slug}" --json number,title,body,url,headRefName,baseRefName,mergeStateStatus,statusCheckRollup,labels,comments,state,isDraft 2>/dev/null)"; then
|
|
1155
|
-
printf '%s\n' "${pr_json}"
|
|
1154
|
+
&& pr_json="$(gh pr view "${pr_number}" -R "${repo_slug}" --json number,title,body,url,headRefName,baseRefName,mergeStateStatus,statusCheckRollup,labels,comments,state,isDraft,author 2>/dev/null)"; then
|
|
1155
|
+
printf '%s\n' "${pr_json}" \
|
|
1156
|
+
| jq '. + {authorLogin: ((.author.login) // "")}' 2>/dev/null \
|
|
1157
|
+
|| printf '%s\n' "${pr_json}"
|
|
1156
1158
|
return 0
|
|
1157
1159
|
fi
|
|
1158
1160
|
|
|
@@ -88,12 +88,13 @@ printf 'WORKFLOW_CATALOG=%s\n' "${CATALOG_FILE}"
|
|
|
88
88
|
printf 'WORKFLOW_CATALOG_EXISTS=%s\n' "${catalog_exists}"
|
|
89
89
|
# Check timeout command (needed for scheduler cross-platform)
|
|
90
90
|
if command -v timeout &>/dev/null; then
|
|
91
|
-
|
|
91
|
+
TIMEOUT_CMD="timeout"
|
|
92
92
|
elif command -v gtimeout &>/dev/null; then
|
|
93
|
-
|
|
93
|
+
TIMEOUT_CMD="gtimeout (from coreutils)"
|
|
94
94
|
else
|
|
95
|
-
|
|
95
|
+
TIMEOUT_CMD="missing (install coreutils for timeout command)"
|
|
96
96
|
fi
|
|
97
|
+
printf 'TIMEOUT_CMD=%s\n' "${TIMEOUT_CMD}"
|
|
97
98
|
printf 'DOCTOR_STATUS=%s\n' "${status}"
|
|
98
99
|
|
|
99
100
|
# Provide clear next steps based on state
|
|
@@ -116,7 +117,7 @@ else
|
|
|
116
117
|
fi
|
|
117
118
|
|
|
118
119
|
# Cross-platform tips
|
|
119
|
-
if [[ "${TIMEOUT_CMD}" == *"missing"* ]]; then
|
|
120
|
+
if [[ "${TIMEOUT_CMD:-}" == *"missing"* ]]; then
|
|
120
121
|
printf '\n⚠ Cross-Platform Tip: Install coreutils for timeout command:\n'
|
|
121
122
|
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
122
123
|
printf ' macOS: brew install coreutils\n'
|
|
@@ -85,7 +85,7 @@ adapter_run() {
|
|
|
85
85
|
|
|
86
86
|
# Run kilo and capture output
|
|
87
87
|
local output
|
|
88
|
-
if ! output="$(
|
|
88
|
+
if ! output="$(adapter_run_with_timeout "${timeout_seconds}" kilo --model "${ADAPTER_MODEL}" "${prompt}" 2>&1)"; then
|
|
89
89
|
echo "ERROR: Kilo run failed or timed out after ${timeout_seconds}s"
|
|
90
90
|
return 1
|
|
91
91
|
fi
|
|
@@ -99,24 +99,9 @@ adapter_run() {
|
|
|
99
99
|
local prompt
|
|
100
100
|
prompt="$(cat "${prompt_file}")"
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if ! timeout "${timeout_seconds}" ollama run "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
|
|
106
|
-
echo "ERROR: Ollama run failed or timed out after ${timeout_seconds}s"
|
|
107
|
-
return 1
|
|
108
|
-
fi
|
|
109
|
-
elif command -v perl >/dev/null 2>&1; then
|
|
110
|
-
if ! perl -e "alarm ${timeout_seconds}; exec @ARGV" ollama run "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
|
|
111
|
-
echo "ERROR: Ollama run failed or timed out after ${timeout_seconds}s"
|
|
112
|
-
return 1
|
|
113
|
-
fi
|
|
114
|
-
else
|
|
115
|
-
# No timeout available, run without timeout
|
|
116
|
-
if ! ollama run "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
|
|
117
|
-
echo "ERROR: Ollama run failed"
|
|
118
|
-
return 1
|
|
119
|
-
fi
|
|
102
|
+
if ! adapter_run_with_timeout "${timeout_seconds}" ollama run "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
|
|
103
|
+
echo "ERROR: Ollama run failed or timed out after ${timeout_seconds}s"
|
|
104
|
+
return 1
|
|
120
105
|
fi
|
|
121
106
|
|
|
122
107
|
echo "Ollama adapter: Session ${session} completed"
|
|
@@ -54,7 +54,7 @@ adapter_run() {
|
|
|
54
54
|
|
|
55
55
|
prompt="$(cat "${prompt_file}")"
|
|
56
56
|
|
|
57
|
-
if !
|
|
57
|
+
if ! adapter_run_with_timeout "${timeout_seconds}" openclaw --model "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
|
|
58
58
|
echo "ERROR: OpenClaw run failed"
|
|
59
59
|
return 1
|
|
60
60
|
fi
|
|
@@ -83,7 +83,7 @@ adapter_run() {
|
|
|
83
83
|
|
|
84
84
|
prompt="$(cat "${prompt_file}")"
|
|
85
85
|
|
|
86
|
-
if !
|
|
86
|
+
if ! adapter_run_with_timeout "${timeout_seconds}" crush --model "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
|
|
87
87
|
echo "ERROR: OpenCode run failed"
|
|
88
88
|
return 1
|
|
89
89
|
fi
|
package/tools/bin/pi-adapter.sh
CHANGED
|
@@ -80,7 +80,7 @@ adapter_run() {
|
|
|
80
80
|
|
|
81
81
|
prompt="$(cat "${prompt_file}")"
|
|
82
82
|
|
|
83
|
-
if !
|
|
83
|
+
if ! adapter_run_with_timeout "${timeout_seconds}" pi --model "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
|
|
84
84
|
echo "ERROR: Pi run failed"
|
|
85
85
|
return 1
|
|
86
86
|
fi
|
|
Binary file
|