agent-control-plane 0.6.0 → 0.7.1
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 +38 -5
- package/package.json +5 -3
- 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-config-lib.sh +13 -3508
- package/tools/bin/flow-execution-lib.sh +243 -0
- package/tools/bin/flow-forge-lib.sh +1770 -0
- package/tools/bin/flow-profile-lib.sh +335 -0
- package/tools/bin/flow-provider-lib.sh +981 -0
- package/tools/bin/flow-session-lib.sh +317 -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/run-with-adapter.sh +34 -0
- package/tools/dashboard/app.js +40 -3
- package/tools/dashboard/requirements.txt +3 -0
- package/tools/dashboard/server.py +250 -152
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# agent-control-plane
|
|
1
|
+
# agent-control-plane (ACP) v0.7.0
|
|
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,11 +7,21 @@
|
|
|
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.0-success?style=flat-square"></a>
|
|
11
|
+
<a href="./CHANGELOG.md"><img alt="Changelog" src="https://img.shields.io/badge/CHANGELOG-v0.7.0-blue?style=flat-square"></a>
|
|
10
12
|
</p>
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
you having to stare at them all day.
|
|
14
|
+
**agent-control-plane (ACP)** keeps your coding agents running reliably without you having to stare at them all day.
|
|
14
15
|
|
|
16
|
+
## ✅ ROADMAP UPDATE (v0.7.0) - New Features!
|
|
17
|
+
|
|
18
|
+
- **Real-time Dashboard**: WebSocket updates (no more 5s polling!)
|
|
19
|
+
- **Hardened Adapters**: All 6 backends now production-ready
|
|
20
|
+
- **Native Windows Support**: Run as Windows Service (NSSM/sc.exe/PowerShell)
|
|
21
|
+
- **Standardized Capabilities**: Worker capability detection across all backends
|
|
22
|
+
- **Provider Failover**: Auto-switch when backend is rate-limited/degraded
|
|
23
|
+
|
|
24
|
+
## ✅ ROADMAP COMPLETE (v0.6.0) - All 5 Sections Delivered!
|
|
15
25
|
**✅ ROADMAP COMPLETE (v0.6.0)** - All planned features delivered!
|
|
16
26
|
|
|
17
27
|
It is the operator layer for coding agents that need to keep running after the
|
|
@@ -140,12 +150,35 @@ familiar:
|
|
|
140
150
|
- Your local machine should behave like a reliable operator box, not a pile of
|
|
141
151
|
shell history that breaks after a reboot.
|
|
142
152
|
|
|
153
|
+
## Screenshots
|
|
154
|
+
|
|
155
|
+
### Light Mode
|
|
156
|
+

|
|
157
|
+
|
|
158
|
+
### Dark Mode
|
|
159
|
+

|
|
160
|
+
|
|
143
161
|
## Roadmap
|
|
144
162
|
|
|
145
163
|
ACP is moving toward a true multi-backend control plane. The goal is one runtime
|
|
146
|
-
and one dashboard for many coding-agent backends, across macOS, Linux,
|
|
147
|
-
Windows.
|
|
164
|
+
and one dashboard for many coding-agent backends, across macOS, Linux, Windows (WSL2),
|
|
165
|
+
and **native Windows** (service model).
|
|
166
|
+
|
|
167
|
+
### Windows Support
|
|
168
|
+
|
|
169
|
+
ACP now supports running as a native Windows Service!
|
|
170
|
+
|
|
171
|
+
- **Docs**: See [Windows Setup Guide](docs/WINDOWS_SETUP.md)
|
|
172
|
+
- **Service managers**: NSSM (recommended), sc.exe, or PowerShell cmdlets
|
|
173
|
+
- **Quick start**:
|
|
174
|
+
```powershell
|
|
175
|
+
# Using NSSM (download from https://nssm.cc/download)
|
|
176
|
+
nssm install "ACP_Dashboard" "C:\Path\To\python.exe" "C:\Path\To\agent-control-plane\tools\dashboard\server.py"
|
|
177
|
+
nssm start "ACP_Dashboard"
|
|
178
|
+
```
|
|
179
|
+
- **PowerShell installer**: `tools/bin/install-windows-service.ps1`
|
|
148
180
|
|
|
181
|
+
### Windows
|
|
149
182
|
### Backend Status
|
|
150
183
|
|
|
151
184
|
| Backend | Status | Notes |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-control-plane",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
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": {
|
|
@@ -57,6 +57,9 @@
|
|
|
57
57
|
"tools/bin/github-*.sh",
|
|
58
58
|
"tools/bin/profile-*.sh",
|
|
59
59
|
"tools/bin/test-smoke.sh",
|
|
60
|
+
"tools/bin/*-adapter.sh",
|
|
61
|
+
"tools/bin/adapter-*.sh",
|
|
62
|
+
"tools/bin/run-with-adapter.sh",
|
|
60
63
|
"tools/dashboard/",
|
|
61
64
|
"tools/templates/issue-prompt-template.md",
|
|
62
65
|
"tools/templates/pr-fix-template.md",
|
|
@@ -69,8 +72,7 @@
|
|
|
69
72
|
"tools/vendor/codex-quota-manager/scripts"
|
|
70
73
|
],
|
|
71
74
|
"publishConfig": {
|
|
72
|
-
"access": "public"
|
|
73
|
-
"provenance": true
|
|
75
|
+
"access": "public"
|
|
74
76
|
},
|
|
75
77
|
"engines": {
|
|
76
78
|
"node": ">=18"
|
|
@@ -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
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# codex-adapter.sh
|
|
3
|
+
# Adapter implementation for Codex (Claude CLI)
|
|
4
|
+
# Implements: adapter-interface.sh
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
source "${SCRIPT_DIR}/adapter-interface.sh"
|
|
10
|
+
source "${SCRIPT_DIR}/adapter-capabilities.sh"
|
|
11
|
+
|
|
12
|
+
# Codex adapter metadata
|
|
13
|
+
ADAPTER_ID="codex"
|
|
14
|
+
ADAPTER_NAME="Codex (Claude CLI)"
|
|
15
|
+
ADAPTER_TYPE="cloud-api"
|
|
16
|
+
ADAPTER_VERSION="1.0.0"
|
|
17
|
+
ADAPTER_MODEL="${CODEX_MODEL:-sonnet}"
|
|
18
|
+
ADAPTER_BASE_URL=""
|
|
19
|
+
|
|
20
|
+
# Codex capabilities
|
|
21
|
+
ADAPTER_CAP_CLOUD_API=true
|
|
22
|
+
ADAPTER_CAP_STREAMING=true
|
|
23
|
+
ADAPTER_CAP_JSON_OUTPUT=true
|
|
24
|
+
ADAPTER_CAP_MAX_TIMEOUT=900
|
|
25
|
+
|
|
26
|
+
# Print adapter info
|
|
27
|
+
adapter_info() {
|
|
28
|
+
cat <<EOF
|
|
29
|
+
id=${ADAPTER_ID}
|
|
30
|
+
name=${ADAPTER_NAME}
|
|
31
|
+
type=${ADAPTER_TYPE}
|
|
32
|
+
version=${ADAPTER_VERSION}
|
|
33
|
+
model=${ADAPTER_MODEL}
|
|
34
|
+
base_url=${ADAPTER_BASE_URL}
|
|
35
|
+
EOF
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Health check: verify claude CLI is available
|
|
39
|
+
adapter_health_check() {
|
|
40
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
41
|
+
echo "ERROR: claude CLI not found in PATH"
|
|
42
|
+
return 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Check if API key is set
|
|
46
|
+
if [[ -z "${ANTHROPIC_API_KEY:-}" && -z "${OPENROUTER_API_KEY:-}" ]]; then
|
|
47
|
+
echo "WARN: No ANTHROPIC_API_KEY or OPENROUTER_API_KEY found"
|
|
48
|
+
# Don't fail - user might use OAuth
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
echo "OK: Codex adapter healthy (claude CLI available)"
|
|
52
|
+
return 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Run a task using codex (claude CLI)
|
|
56
|
+
adapter_run() {
|
|
57
|
+
local mode="${1:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
58
|
+
local session="${2:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
59
|
+
local worktree="${3:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
60
|
+
local prompt_file="${4:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
|
|
61
|
+
|
|
62
|
+
local permission_mode="${CLAUDE_PERMISSION_MODE:-acceptEdits}"
|
|
63
|
+
local timeout_seconds="${CLAUDE_TIMEOUT_SECONDS:-900}"
|
|
64
|
+
local max_attempts="${CLAUDE_MAX_ATTEMPTS:-3}"
|
|
65
|
+
|
|
66
|
+
echo "Codex adapter: Running session ${session} with model ${ADAPTER_MODEL}"
|
|
67
|
+
|
|
68
|
+
# Read the prompt
|
|
69
|
+
local prompt
|
|
70
|
+
prompt="$(cat "${prompt_file}")"
|
|
71
|
+
|
|
72
|
+
# Change to worktree
|
|
73
|
+
cd "${worktree}" || return 1
|
|
74
|
+
|
|
75
|
+
# Run claude with the prompt
|
|
76
|
+
if ! timeout "${timeout_seconds}" claude \
|
|
77
|
+
--permission-mode "${permission_mode}" \
|
|
78
|
+
--model "${ADAPTER_MODEL}" \
|
|
79
|
+
--print \
|
|
80
|
+
"${prompt}" 2>&1; then
|
|
81
|
+
echo "ERROR: Codex run failed or timed out after ${timeout_seconds}s"
|
|
82
|
+
return 1
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
echo "Codex adapter: Session ${session} completed"
|
|
86
|
+
return 0
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Status check
|
|
90
|
+
adapter_status() {
|
|
91
|
+
local runs_root="${1:?usage: adapter_status RUNS_ROOT SESSION}"
|
|
92
|
+
local session="${2:?usage: adapter_status RUNS_ROOT SESSION}"
|
|
93
|
+
local run_dir="${runs_root}/${session}"
|
|
94
|
+
|
|
95
|
+
if [[ ! -d "$run_dir" ]]; then
|
|
96
|
+
echo "NOT_FOUND"
|
|
97
|
+
return 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Check for result file
|
|
101
|
+
if [[ -f "$run_dir/result.env" ]]; then
|
|
102
|
+
source "$run_dir/result.env"
|
|
103
|
+
echo "${OUTCOME:-UNKNOWN}"
|
|
104
|
+
return 0
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# Check if claude process is running
|
|
108
|
+
if pgrep -f "claude.*${session}" >/dev/null 2>&1; then
|
|
109
|
+
echo "RUNNING"
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
echo "UNKNOWN"
|
|
114
|
+
return 0
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# Self-register: validate this adapter implements required functions
|
|
118
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
119
|
+
# Running directly - print info
|
|
120
|
+
adapter_info
|
|
121
|
+
echo "---"
|
|
122
|
+
adapter_health_check
|
|
123
|
+
fi
|