agent-control-plane 0.4.9 → 0.7.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 +109 -13
- package/npm/bin/agent-control-plane.js +1 -1
- package/package.json +39 -33
- package/tools/bin/debug-session.sh +106 -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-runtime-doctor-linux.sh +136 -0
- package/tools/bin/flow-runtime-doctor.sh +5 -1
- package/tools/bin/flow-session-lib.sh +317 -0
- package/tools/bin/install-project-systemd.sh +255 -0
- package/tools/bin/project-runtimectl.sh +45 -0
- package/tools/bin/project-systemd-bootstrap.sh +74 -0
- package/tools/bin/uninstall-project-systemd.sh +87 -0
- package/tools/dashboard/app.js +238 -8
- package/tools/dashboard/issue_queue_state.py +101 -0
- package/tools/dashboard/requirements.txt +3 -0
- package/tools/dashboard/server.py +250 -30
- package/tools/dashboard/styles.css +526 -455
- package/tools/bin/agent-cleanup-worktree +0 -247
- package/tools/bin/agent-github-update-labels +0 -105
- package/tools/bin/agent-init-worktree +0 -216
- package/tools/bin/agent-project-archive-run +0 -52
- package/tools/bin/agent-project-capture-worker +0 -46
- package/tools/bin/agent-project-catch-up-issue-pr-links +0 -118
- package/tools/bin/agent-project-catch-up-merged-prs +0 -195
- package/tools/bin/agent-project-catch-up-scheduled-issue-retries +0 -123
- package/tools/bin/agent-project-cleanup-session +0 -513
- package/tools/bin/agent-project-detached-launch +0 -127
- package/tools/bin/agent-project-heartbeat-loop +0 -1029
- package/tools/bin/agent-project-open-issue-worktree +0 -89
- package/tools/bin/agent-project-open-pr-worktree +0 -80
- package/tools/bin/agent-project-publish-issue-pr +0 -468
- package/tools/bin/agent-project-reconcile-issue-session +0 -1409
- package/tools/bin/agent-project-reconcile-pr-session +0 -1288
- package/tools/bin/agent-project-retry-state +0 -158
- package/tools/bin/agent-project-run-claude-session +0 -805
- package/tools/bin/agent-project-run-codex-resilient +0 -963
- package/tools/bin/agent-project-run-codex-session +0 -435
- package/tools/bin/agent-project-run-kilo-session +0 -369
- package/tools/bin/agent-project-run-ollama-session +0 -658
- package/tools/bin/agent-project-run-openclaw-session +0 -1309
- package/tools/bin/agent-project-run-opencode-session +0 -377
- package/tools/bin/agent-project-run-pi-session +0 -479
- package/tools/bin/agent-project-sync-anchor-repo +0 -139
- package/tools/bin/agent-project-sync-source-repo-main +0 -163
- package/tools/bin/agent-project-worker-status +0 -188
- package/tools/bin/branch-verification-guard.sh +0 -364
- package/tools/bin/capture-worker.sh +0 -18
- package/tools/bin/cleanup-worktree.sh +0 -52
- package/tools/bin/codex-quota +0 -31
- package/tools/bin/create-follow-up-issue.sh +0 -114
- package/tools/bin/dashboard-launchd-bootstrap.sh +0 -50
- package/tools/bin/issue-publish-localization-guard.sh +0 -142
- package/tools/bin/issue-publish-scope-guard.sh +0 -242
- package/tools/bin/issue-requires-local-workspace-install.sh +0 -31
- package/tools/bin/issue-resource-class.sh +0 -12
- package/tools/bin/kick-scheduler.sh +0 -75
- package/tools/bin/label-follow-up-issues.sh +0 -14
- package/tools/bin/new-pr-worktree.sh +0 -50
- package/tools/bin/new-worktree.sh +0 -49
- package/tools/bin/pr-risk.sh +0 -12
- package/tools/bin/prepare-worktree.sh +0 -142
- package/tools/bin/provider-cooldown-state.sh +0 -204
- package/tools/bin/publish-issue-worker.sh +0 -31
- package/tools/bin/reconcile-bootstrap-lib.sh +0 -113
- package/tools/bin/reconcile-issue-worker.sh +0 -34
- package/tools/bin/reconcile-pr-worker.sh +0 -34
- package/tools/bin/record-verification.sh +0 -71
- package/tools/bin/render-flow-config.sh +0 -98
- package/tools/bin/resident-issue-controller-lib.sh +0 -448
- package/tools/bin/retry-state.sh +0 -31
- package/tools/bin/reuse-issue-worktree.sh +0 -121
- package/tools/bin/run-codex-bypass.sh +0 -3
- package/tools/bin/run-codex-safe.sh +0 -3
- package/tools/bin/run-codex-task.sh +0 -280
- package/tools/bin/serve-dashboard.sh +0 -5
- package/tools/bin/start-issue-worker.sh +0 -943
- package/tools/bin/start-pr-fix-worker.sh +0 -528
- package/tools/bin/start-pr-merge-repair-worker.sh +0 -8
- package/tools/bin/start-pr-review-worker.sh +0 -261
- package/tools/bin/start-resident-issue-loop.sh +0 -499
- package/tools/bin/update-github-labels.sh +0 -14
- package/tools/bin/worker-status.sh +0 -19
- package/tools/bin/workflow-catalog.sh +0 -77
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
usage() {
|
|
5
|
-
cat <<'EOF'
|
|
6
|
-
Usage:
|
|
7
|
-
agent-project-run-opencode-session --mode safe|bypass --session <id> --worktree <path> --prompt-file <path> --runs-root <path> --adapter-id <id> --task-kind <kind> --task-id <id> [options]
|
|
8
|
-
|
|
9
|
-
Launch a Crush (formerly OpenCode) worker session inside tmux for a project
|
|
10
|
-
adapter and persist the standard run artifacts.
|
|
11
|
-
|
|
12
|
-
Crush is the Go-based coding agent by Charm (charmbracelet/crush).
|
|
13
|
-
It executes via `crush run` in non-interactive mode.
|
|
14
|
-
|
|
15
|
-
Options:
|
|
16
|
-
--env-prefix <prefix> Export prefixed runtime/context env vars inside the worker
|
|
17
|
-
--context <KEY=VALUE> Extra metadata written to run.env and exported to the worker
|
|
18
|
-
--collect-file <name> Copy sandbox artifact file into the host run dir after execution
|
|
19
|
-
--reconcile-command <cmd> Host-side command queued after the worker exits
|
|
20
|
-
--sandbox-subdir <name> Subdir under the worktree for worker artifacts (default: .opencode-artifacts)
|
|
21
|
-
--opencode-model <id> Model in provider/name format (default: anthropic/claude-sonnet-4-20250514)
|
|
22
|
-
--opencode-timeout-seconds <secs> Hard timeout in seconds (default: 900)
|
|
23
|
-
--help Show this help
|
|
24
|
-
EOF
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
mode=""
|
|
28
|
-
session=""
|
|
29
|
-
worktree=""
|
|
30
|
-
prompt_file=""
|
|
31
|
-
runs_root=""
|
|
32
|
-
adapter_id=""
|
|
33
|
-
task_kind=""
|
|
34
|
-
task_id=""
|
|
35
|
-
env_prefix=""
|
|
36
|
-
sandbox_subdir=".opencode-artifacts"
|
|
37
|
-
reconcile_command=""
|
|
38
|
-
opencode_model="${ACP_OPENCODE_MODEL:-${F_LOSNING_OPENCODE_MODEL:-anthropic/claude-sonnet-4-20250514}}"
|
|
39
|
-
opencode_timeout_seconds="${ACP_OPENCODE_TIMEOUT_SECONDS:-${F_LOSNING_OPENCODE_TIMEOUT_SECONDS:-900}}"
|
|
40
|
-
declare -a context_items=()
|
|
41
|
-
declare -a collect_files=()
|
|
42
|
-
|
|
43
|
-
while [[ $# -gt 0 ]]; do
|
|
44
|
-
case "$1" in
|
|
45
|
-
--mode) mode="${2:-}"; shift 2 ;;
|
|
46
|
-
--session) session="${2:-}"; shift 2 ;;
|
|
47
|
-
--worktree) worktree="${2:-}"; shift 2 ;;
|
|
48
|
-
--prompt-file) prompt_file="${2:-}"; shift 2 ;;
|
|
49
|
-
--runs-root) runs_root="${2:-}"; shift 2 ;;
|
|
50
|
-
--adapter-id) adapter_id="${2:-}"; shift 2 ;;
|
|
51
|
-
--task-kind) task_kind="${2:-}"; shift 2 ;;
|
|
52
|
-
--task-id) task_id="${2:-}"; shift 2 ;;
|
|
53
|
-
--env-prefix) env_prefix="${2:-}"; shift 2 ;;
|
|
54
|
-
--context) context_items+=("${2:-}"); shift 2 ;;
|
|
55
|
-
--collect-file) collect_files+=("${2:-}"); shift 2 ;;
|
|
56
|
-
--reconcile-command) reconcile_command="${2:-}"; shift 2 ;;
|
|
57
|
-
--sandbox-subdir) sandbox_subdir="${2:-}"; shift 2 ;;
|
|
58
|
-
--opencode-model) opencode_model="${2:-}"; shift 2 ;;
|
|
59
|
-
--opencode-timeout-seconds) opencode_timeout_seconds="${2:-}"; shift 2 ;;
|
|
60
|
-
--help|-h) usage; exit 0 ;;
|
|
61
|
-
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
|
62
|
-
esac
|
|
63
|
-
done
|
|
64
|
-
|
|
65
|
-
if [[ -z "$mode" || -z "$session" || -z "$worktree" || -z "$prompt_file" || -z "$runs_root" || -z "$adapter_id" || -z "$task_kind" || -z "$task_id" ]]; then
|
|
66
|
-
usage >&2
|
|
67
|
-
exit 1
|
|
68
|
-
fi
|
|
69
|
-
|
|
70
|
-
case "$mode" in
|
|
71
|
-
safe|bypass) ;;
|
|
72
|
-
*) echo "--mode must be safe or bypass" >&2; exit 1 ;;
|
|
73
|
-
esac
|
|
74
|
-
|
|
75
|
-
case "$opencode_timeout_seconds" in
|
|
76
|
-
''|*[!0-9]*|0) echo "--opencode-timeout-seconds must be a positive integer" >&2; exit 1 ;;
|
|
77
|
-
esac
|
|
78
|
-
|
|
79
|
-
resolve_crush_bin() {
|
|
80
|
-
local configured_bin="${CRUSH_BIN:-${ACP_CRUSH_BIN:-${ACP_OPENCODE_BIN:-}}}"
|
|
81
|
-
if [[ -n "${configured_bin}" && -x "${configured_bin}" ]]; then
|
|
82
|
-
printf '%s\n' "${configured_bin}"
|
|
83
|
-
return 0
|
|
84
|
-
fi
|
|
85
|
-
# Try crush first (current name), then opencode (legacy name)
|
|
86
|
-
if command -v crush >/dev/null 2>&1; then
|
|
87
|
-
command -v crush
|
|
88
|
-
return 0
|
|
89
|
-
fi
|
|
90
|
-
if command -v opencode >/dev/null 2>&1; then
|
|
91
|
-
command -v opencode
|
|
92
|
-
return 0
|
|
93
|
-
fi
|
|
94
|
-
local -a fallback_paths=(
|
|
95
|
-
"/opt/homebrew/bin/crush"
|
|
96
|
-
"/usr/local/bin/crush"
|
|
97
|
-
"${HOME}/.local/bin/crush"
|
|
98
|
-
"${HOME}/go/bin/crush"
|
|
99
|
-
"/opt/homebrew/bin/opencode"
|
|
100
|
-
"/usr/local/bin/opencode"
|
|
101
|
-
)
|
|
102
|
-
local p
|
|
103
|
-
for p in "${fallback_paths[@]}"; do
|
|
104
|
-
if [[ -x "${p}" ]]; then
|
|
105
|
-
printf '%s\n' "${p}"
|
|
106
|
-
return 0
|
|
107
|
-
fi
|
|
108
|
-
done
|
|
109
|
-
return 1
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
crush_bin="$(resolve_crush_bin || true)"
|
|
113
|
-
if [[ -z "${crush_bin}" || ! -x "${crush_bin}" ]]; then
|
|
114
|
-
echo "unable to resolve a runnable crush/opencode binary — install with: brew install charmbracelet/tap/crush" >&2
|
|
115
|
-
exit 1
|
|
116
|
-
fi
|
|
117
|
-
|
|
118
|
-
artifact_dir="${runs_root}/${session}"
|
|
119
|
-
output_file="${artifact_dir}/${session}.log"
|
|
120
|
-
inner_script="${artifact_dir}/${session}.sh"
|
|
121
|
-
meta_file="${artifact_dir}/run.env"
|
|
122
|
-
result_file="${artifact_dir}/result.env"
|
|
123
|
-
runner_state_file="${artifact_dir}/runner.env"
|
|
124
|
-
sandbox_run_dir="${worktree%/}/${sandbox_subdir}/${session}"
|
|
125
|
-
started_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
126
|
-
|
|
127
|
-
mkdir -p "$artifact_dir" "$sandbox_run_dir"
|
|
128
|
-
|
|
129
|
-
if tmux has-session -t "$session" 2>/dev/null; then
|
|
130
|
-
echo "tmux session already exists: $session" >&2
|
|
131
|
-
exit 1
|
|
132
|
-
fi
|
|
133
|
-
|
|
134
|
-
branch_name="$(git -C "$worktree" branch --show-current 2>/dev/null || true)"
|
|
135
|
-
|
|
136
|
-
printf -v session_q '%q' "$session"
|
|
137
|
-
printf -v task_kind_q '%q' "$task_kind"
|
|
138
|
-
printf -v task_id_q '%q' "$task_id"
|
|
139
|
-
printf -v mode_q '%q' "$mode"
|
|
140
|
-
printf -v worktree_q '%q' "$worktree"
|
|
141
|
-
printf -v prompt_q '%q' "$prompt_file"
|
|
142
|
-
printf -v output_q '%q' "$output_file"
|
|
143
|
-
printf -v artifact_dir_q '%q' "$artifact_dir"
|
|
144
|
-
printf -v script_q '%q' "$inner_script"
|
|
145
|
-
printf -v result_q '%q' "$result_file"
|
|
146
|
-
printf -v meta_file_q '%q' "$meta_file"
|
|
147
|
-
printf -v runner_state_q '%q' "$runner_state_file"
|
|
148
|
-
printf -v branch_q '%q' "$branch_name"
|
|
149
|
-
printf -v sandbox_run_dir_q '%q' "$sandbox_run_dir"
|
|
150
|
-
printf -v adapter_id_q '%q' "$adapter_id"
|
|
151
|
-
printf -v started_at_q '%q' "$started_at"
|
|
152
|
-
printf -v crush_bin_q '%q' "$crush_bin"
|
|
153
|
-
printf -v opencode_model_q '%q' "$opencode_model"
|
|
154
|
-
printf -v opencode_timeout_q '%q' "$opencode_timeout_seconds"
|
|
155
|
-
|
|
156
|
-
{
|
|
157
|
-
printf 'TASK_KIND=%s\n' "$task_kind_q"
|
|
158
|
-
printf 'TASK_ID=%s\n' "$task_id_q"
|
|
159
|
-
printf 'SESSION=%s\n' "$session_q"
|
|
160
|
-
printf 'MODE=%s\n' "$mode_q"
|
|
161
|
-
printf 'WORKTREE=%s\n' "$worktree_q"
|
|
162
|
-
printf 'PROMPT_FILE=%s\n' "$prompt_q"
|
|
163
|
-
printf 'OUTPUT_FILE=%s\n' "$output_q"
|
|
164
|
-
printf 'BRANCH=%s\n' "$branch_q"
|
|
165
|
-
printf 'RESULT_FILE=%s\n' "$result_q"
|
|
166
|
-
printf 'RUNNER_STATE_FILE=%s\n' "$runner_state_q"
|
|
167
|
-
printf 'SANDBOX_RUN_DIR=%s\n' "$sandbox_run_dir_q"
|
|
168
|
-
printf 'ADAPTER_ID=%s\n' "$adapter_id_q"
|
|
169
|
-
printf 'STARTED_AT=%s\n' "$started_at_q"
|
|
170
|
-
printf 'CRUSH_BIN=%s\n' "$crush_bin_q"
|
|
171
|
-
printf 'OPENCODE_MODEL=%s\n' "$opencode_model_q"
|
|
172
|
-
printf 'OPENCODE_TIMEOUT_SECONDS=%s\n' "$opencode_timeout_q"
|
|
173
|
-
} >"$meta_file"
|
|
174
|
-
|
|
175
|
-
context_exports=""
|
|
176
|
-
if ((${#context_items[@]} > 0)); then
|
|
177
|
-
for item in "${context_items[@]}"; do
|
|
178
|
-
if [[ "$item" != *=* ]]; then
|
|
179
|
-
echo "--context must use KEY=VALUE syntax: $item" >&2
|
|
180
|
-
exit 1
|
|
181
|
-
fi
|
|
182
|
-
key="${item%%=*}"
|
|
183
|
-
value="${item#*=}"
|
|
184
|
-
if [[ ! "$key" =~ ^[A-Z0-9_]+$ ]]; then
|
|
185
|
-
echo "Invalid context key: $key" >&2
|
|
186
|
-
exit 1
|
|
187
|
-
fi
|
|
188
|
-
printf -v value_q '%q' "$value"
|
|
189
|
-
printf '%s=%s\n' "$key" "$value_q" >>"$meta_file"
|
|
190
|
-
if [[ -n "$env_prefix" ]]; then
|
|
191
|
-
context_exports+="export ${env_prefix}${key}=${value_q}"$'\n'
|
|
192
|
-
fi
|
|
193
|
-
context_exports+="export ACP_${key}=${value_q}"$'\n'
|
|
194
|
-
if [[ "$env_prefix" != "F_LOSNING_" ]]; then
|
|
195
|
-
context_exports+="export F_LOSNING_${key}=${value_q}"$'\n'
|
|
196
|
-
fi
|
|
197
|
-
done
|
|
198
|
-
fi
|
|
199
|
-
|
|
200
|
-
runtime_exports=$(
|
|
201
|
-
cat <<EOF
|
|
202
|
-
export AGENT_PROJECT_SESSION=${session_q}
|
|
203
|
-
export AGENT_PROJECT_RUN_DIR=${sandbox_run_dir_q}
|
|
204
|
-
export AGENT_PROJECT_HOST_RUN_DIR=${artifact_dir_q}
|
|
205
|
-
export AGENT_PROJECT_RESULT_FILE=${sandbox_run_dir_q}/result.env
|
|
206
|
-
export ACP_SESSION=${session_q}
|
|
207
|
-
export ACP_RUN_DIR=${sandbox_run_dir_q}
|
|
208
|
-
export ACP_HOST_RUN_DIR=${artifact_dir_q}
|
|
209
|
-
export ACP_RESULT_FILE=${sandbox_run_dir_q}/result.env
|
|
210
|
-
export F_LOSNING_SESSION=${session_q}
|
|
211
|
-
export F_LOSNING_RUN_DIR=${sandbox_run_dir_q}
|
|
212
|
-
export F_LOSNING_HOST_RUN_DIR=${artifact_dir_q}
|
|
213
|
-
export F_LOSNING_RESULT_FILE=${sandbox_run_dir_q}/result.env
|
|
214
|
-
EOF
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
if [[ -n "$env_prefix" ]]; then
|
|
218
|
-
runtime_exports+=$'\n'
|
|
219
|
-
runtime_exports+=$(cat <<EOF
|
|
220
|
-
export ${env_prefix}SESSION=${session_q}
|
|
221
|
-
export ${env_prefix}RUN_DIR=${sandbox_run_dir_q}
|
|
222
|
-
export ${env_prefix}HOST_RUN_DIR=${artifact_dir_q}
|
|
223
|
-
export ${env_prefix}RESULT_FILE=${sandbox_run_dir_q}/result.env
|
|
224
|
-
EOF
|
|
225
|
-
)
|
|
226
|
-
fi
|
|
227
|
-
|
|
228
|
-
collect_copy_snippet=""
|
|
229
|
-
if ((${#collect_files[@]} > 0)); then
|
|
230
|
-
for artifact_name in "${collect_files[@]}"; do
|
|
231
|
-
[[ -z "$artifact_name" ]] && continue
|
|
232
|
-
printf -v artifact_q '%q' "$artifact_name"
|
|
233
|
-
collect_copy_snippet+=$(cat <<EOF
|
|
234
|
-
if [[ -f ${sandbox_run_dir_q}/${artifact_q} ]]; then
|
|
235
|
-
cp ${sandbox_run_dir_q}/${artifact_q} ${artifact_dir_q}/${artifact_q}
|
|
236
|
-
fi
|
|
237
|
-
EOF
|
|
238
|
-
)
|
|
239
|
-
collect_copy_snippet+=$'\n'
|
|
240
|
-
done
|
|
241
|
-
fi
|
|
242
|
-
|
|
243
|
-
# Always collect result.env from sandbox to artifact_dir
|
|
244
|
-
collect_copy_snippet+=$(
|
|
245
|
-
cat <<EOF
|
|
246
|
-
if [[ -f ${sandbox_run_dir_q}/result.env ]]; then
|
|
247
|
-
cp ${sandbox_run_dir_q}/result.env ${artifact_dir_q}/result.env
|
|
248
|
-
fi
|
|
249
|
-
EOF
|
|
250
|
-
)
|
|
251
|
-
collect_copy_snippet+=$'\n'
|
|
252
|
-
|
|
253
|
-
reconcile_snippet=""
|
|
254
|
-
if [[ -n "$reconcile_command" ]]; then
|
|
255
|
-
printf -v delayed_reconcile_q '%q' "export ACP_EXPECTED_RUN_STARTED_AT=${started_at_q}; export F_LOSNING_EXPECTED_RUN_STARTED_AT=${started_at_q}; while tmux has-session -t ${session_q} 2>/dev/null; do sleep 1; done; sleep 2; $reconcile_command"
|
|
256
|
-
reconcile_snippet="nohup bash -lc ${delayed_reconcile_q} >> ${output_q} 2>&1 </dev/null &"
|
|
257
|
-
fi
|
|
258
|
-
|
|
259
|
-
cat >"$inner_script" <<EOF
|
|
260
|
-
#!/usr/bin/env bash
|
|
261
|
-
set -euo pipefail
|
|
262
|
-
${runtime_exports}
|
|
263
|
-
${context_exports}cd ${worktree_q}
|
|
264
|
-
|
|
265
|
-
runner_state_file=${runner_state_q}
|
|
266
|
-
output_file=${output_q}
|
|
267
|
-
sandbox_run_dir=${sandbox_run_dir_q}
|
|
268
|
-
artifact_dir=${artifact_dir_q}
|
|
269
|
-
result_file_path=${sandbox_run_dir_q}/result.env
|
|
270
|
-
host_result_file=${result_q}
|
|
271
|
-
crush_bin=${crush_bin_q}
|
|
272
|
-
opencode_model=${opencode_model_q}
|
|
273
|
-
opencode_timeout=${opencode_timeout_q}
|
|
274
|
-
prompt_file=${prompt_q}
|
|
275
|
-
worktree=${worktree_q}
|
|
276
|
-
|
|
277
|
-
write_state() {
|
|
278
|
-
local runner_state="\${1:?runner state required}"
|
|
279
|
-
local last_exit_code="\${2:-}"
|
|
280
|
-
local failure_reason="\${3:-}"
|
|
281
|
-
local updated_at tmp_file
|
|
282
|
-
|
|
283
|
-
updated_at="\$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
284
|
-
tmp_file="\${runner_state_file}.tmp.\$\$"
|
|
285
|
-
{
|
|
286
|
-
printf 'RUNNER_STATE=%q\n' "\${runner_state}"
|
|
287
|
-
printf 'ATTEMPT=1\n'
|
|
288
|
-
printf 'RESUME_COUNT=0\n'
|
|
289
|
-
printf 'LAST_EXIT_CODE=%q\n' "\${last_exit_code}"
|
|
290
|
-
printf 'LAST_FAILURE_REASON=%q\n' "\${failure_reason}"
|
|
291
|
-
printf 'UPDATED_AT=%q\n' "\${updated_at}"
|
|
292
|
-
} >"\${tmp_file}"
|
|
293
|
-
mv "\${tmp_file}" "\${runner_state_file}"
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
record_final_git_state() {
|
|
297
|
-
local final_head final_branch tmp_file
|
|
298
|
-
final_head="\$(git -C ${worktree_q} rev-parse HEAD 2>/dev/null || true)"
|
|
299
|
-
final_branch="\$(git -C ${worktree_q} branch --show-current 2>/dev/null || true)"
|
|
300
|
-
tmp_file=${meta_file_q}.tmp.final.\$\$
|
|
301
|
-
grep -vE '^(FINAL_HEAD|FINAL_BRANCH)=' ${meta_file_q} >"\${tmp_file}" 2>/dev/null || true
|
|
302
|
-
{
|
|
303
|
-
printf 'FINAL_HEAD=%q\n' "\${final_head}"
|
|
304
|
-
printf 'FINAL_BRANCH=%q\n' "\${final_branch}"
|
|
305
|
-
} >>"\${tmp_file}"
|
|
306
|
-
mv "\${tmp_file}" ${meta_file_q}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
write_state running
|
|
310
|
-
|
|
311
|
-
mkdir -p "\${sandbox_run_dir}"
|
|
312
|
-
|
|
313
|
-
# Crush (opencode) runs via 'crush run' in non-interactive mode.
|
|
314
|
-
# --quiet suppresses spinner, --yolo auto-approves all tool permissions,
|
|
315
|
-
# --model selects the provider/model, --cwd sets the working directory.
|
|
316
|
-
# Prompt is provided via stdin.
|
|
317
|
-
crush_exit_code=0
|
|
318
|
-
crush_args=(run --quiet --model "\${opencode_model}" --cwd ${worktree_q})
|
|
319
|
-
if [[ "${mode_q}" == "bypass" ]]; then
|
|
320
|
-
crush_args+=(--yolo)
|
|
321
|
-
fi
|
|
322
|
-
|
|
323
|
-
if command -v timeout >/dev/null 2>&1; then
|
|
324
|
-
timeout "\${opencode_timeout}" "\${crush_bin}" "\${crush_args[@]}" <"\${prompt_file}" 2>&1 | tee -a "\${output_file}" || crush_exit_code=\$?
|
|
325
|
-
elif command -v gtimeout >/dev/null 2>&1; then
|
|
326
|
-
gtimeout "\${opencode_timeout}" "\${crush_bin}" "\${crush_args[@]}" <"\${prompt_file}" 2>&1 | tee -a "\${output_file}" || crush_exit_code=\$?
|
|
327
|
-
else
|
|
328
|
-
"\${crush_bin}" "\${crush_args[@]}" <"\${prompt_file}" 2>&1 | tee -a "\${output_file}" &
|
|
329
|
-
_crush_pid=\$!
|
|
330
|
-
( sleep "\${opencode_timeout}" && kill "\${_crush_pid}" 2>/dev/null ) &
|
|
331
|
-
_wd=\$!
|
|
332
|
-
wait "\${_crush_pid}" || crush_exit_code=\$?
|
|
333
|
-
kill "\${_wd}" 2>/dev/null || true; wait "\${_wd}" 2>/dev/null || true
|
|
334
|
-
[[ "\${crush_exit_code}" -eq 143 ]] && crush_exit_code=124
|
|
335
|
-
fi
|
|
336
|
-
|
|
337
|
-
if [[ "\${crush_exit_code}" -eq 0 ]]; then
|
|
338
|
-
write_state succeeded 0
|
|
339
|
-
# Crush has full tool access — it can write files and make commits.
|
|
340
|
-
# Infer result from git state if result.env was not written by the agent.
|
|
341
|
-
if [[ ! -f "\${result_file_path}" ]]; then
|
|
342
|
-
if git -C ${worktree_q} diff --name-only HEAD 2>/dev/null | grep -qvE '\.md$' 2>/dev/null \\
|
|
343
|
-
|| git -C ${worktree_q} diff --cached --name-only 2>/dev/null | grep -qvE '\.md$' 2>/dev/null \\
|
|
344
|
-
|| git -C ${worktree_q} diff --name-only origin/main..HEAD 2>/dev/null | grep -qvE '\.md$' 2>/dev/null; then
|
|
345
|
-
printf 'OUTCOME=implemented\nACTION=host-publish-issue-pr\n' >"\${result_file_path}"
|
|
346
|
-
else
|
|
347
|
-
printf 'OUTCOME=blocked\nACTION=host-comment-blocker\nDETAIL=missing-result-contract\n' >"\${result_file_path}"
|
|
348
|
-
fi
|
|
349
|
-
fi
|
|
350
|
-
else
|
|
351
|
-
failure_reason="opencode-exit-\${crush_exit_code}"
|
|
352
|
-
[[ "\${crush_exit_code}" -eq 124 ]] && failure_reason="timeout"
|
|
353
|
-
write_state failed "\${crush_exit_code}" "\${failure_reason}"
|
|
354
|
-
if [[ ! -f "\${result_file_path}" ]]; then
|
|
355
|
-
printf 'OUTCOME=blocked\nACTION=host-comment-blocker\nDETAIL=%s\n' "\${failure_reason}" >"\${result_file_path}"
|
|
356
|
-
fi
|
|
357
|
-
fi
|
|
358
|
-
|
|
359
|
-
record_final_git_state
|
|
360
|
-
|
|
361
|
-
if [[ -f "\${result_file_path}" ]]; then
|
|
362
|
-
cp "\${result_file_path}" "\${host_result_file}"
|
|
363
|
-
fi
|
|
364
|
-
${collect_copy_snippet}
|
|
365
|
-
${reconcile_snippet}
|
|
366
|
-
printf '\n__CODEX_EXIT__:%s\n' "\${crush_exit_code}" | tee -a "\${output_file}"
|
|
367
|
-
exit "\${crush_exit_code}"
|
|
368
|
-
EOF
|
|
369
|
-
|
|
370
|
-
chmod +x "$inner_script"
|
|
371
|
-
tmux new-session -d -s "$session" "$inner_script"
|
|
372
|
-
|
|
373
|
-
printf 'SESSION=%s\n' "$session"
|
|
374
|
-
printf 'TASK_KIND=%s\n' "$task_kind"
|
|
375
|
-
printf 'TASK_ID=%s\n' "$task_id"
|
|
376
|
-
printf 'WORKTREE=%s\n' "$worktree"
|
|
377
|
-
printf 'OUTPUT=%s\n' "$output_file"
|