agent-control-plane 0.3.0 → 0.6.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.
Files changed (106) hide show
  1. package/README.md +141 -28
  2. package/assets/workflow-catalog.json +1 -1
  3. package/bin/pr-risk.sh +22 -7
  4. package/bin/sync-pr-labels.sh +1 -1
  5. package/hooks/heartbeat-hooks.sh +125 -12
  6. package/hooks/issue-reconcile-hooks.sh +1 -1
  7. package/hooks/pr-reconcile-hooks.sh +1 -1
  8. package/npm/bin/agent-control-plane.js +257 -59
  9. package/package.json +39 -32
  10. package/tools/bin/debug-session.sh +106 -0
  11. package/tools/bin/flow-config-lib.sh +1203 -60
  12. package/tools/bin/flow-runtime-doctor-linux.sh +136 -0
  13. package/tools/bin/flow-runtime-doctor.sh +5 -1
  14. package/tools/bin/flow-shell-lib.sh +32 -0
  15. package/tools/bin/github-core-rate-limit-state.sh +77 -0
  16. package/tools/bin/github-write-outbox.sh +470 -0
  17. package/tools/bin/heartbeat-loop-scheduling-lib.sh +7 -7
  18. package/tools/bin/heartbeat-safe-auto.sh +42 -0
  19. package/tools/bin/install-project-launchd.sh +17 -2
  20. package/tools/bin/install-project-systemd.sh +255 -0
  21. package/tools/bin/project-init.sh +21 -1
  22. package/tools/bin/project-launchd-bootstrap.sh +5 -1
  23. package/tools/bin/project-runtimectl.sh +91 -2
  24. package/tools/bin/project-systemd-bootstrap.sh +74 -0
  25. package/tools/bin/scaffold-profile.sh +61 -3
  26. package/tools/bin/uninstall-project-systemd.sh +87 -0
  27. package/tools/dashboard/app.js +228 -6
  28. package/tools/dashboard/dashboard_snapshot.py +55 -0
  29. package/tools/dashboard/issue_queue_state.py +101 -0
  30. package/tools/dashboard/server.py +123 -1
  31. package/tools/dashboard/styles.css +526 -455
  32. package/tools/templates/pr-fix-template.md +3 -1
  33. package/tools/templates/pr-merge-repair-template.md +2 -1
  34. package/references/architecture.md +0 -217
  35. package/references/commands.md +0 -128
  36. package/references/control-plane-map.md +0 -124
  37. package/references/docs-map.md +0 -73
  38. package/references/release-checklist.md +0 -65
  39. package/references/repo-map.md +0 -36
  40. package/tools/bin/agent-cleanup-worktree +0 -247
  41. package/tools/bin/agent-github-update-labels +0 -71
  42. package/tools/bin/agent-init-worktree +0 -216
  43. package/tools/bin/agent-project-archive-run +0 -52
  44. package/tools/bin/agent-project-capture-worker +0 -46
  45. package/tools/bin/agent-project-catch-up-issue-pr-links +0 -118
  46. package/tools/bin/agent-project-catch-up-merged-prs +0 -194
  47. package/tools/bin/agent-project-catch-up-scheduled-issue-retries +0 -123
  48. package/tools/bin/agent-project-cleanup-session +0 -513
  49. package/tools/bin/agent-project-detached-launch +0 -127
  50. package/tools/bin/agent-project-heartbeat-loop +0 -1029
  51. package/tools/bin/agent-project-open-issue-worktree +0 -89
  52. package/tools/bin/agent-project-open-pr-worktree +0 -80
  53. package/tools/bin/agent-project-publish-issue-pr +0 -465
  54. package/tools/bin/agent-project-reconcile-issue-session +0 -1398
  55. package/tools/bin/agent-project-reconcile-pr-session +0 -1230
  56. package/tools/bin/agent-project-retry-state +0 -147
  57. package/tools/bin/agent-project-run-claude-session +0 -805
  58. package/tools/bin/agent-project-run-codex-resilient +0 -955
  59. package/tools/bin/agent-project-run-codex-session +0 -435
  60. package/tools/bin/agent-project-run-kilo-session +0 -369
  61. package/tools/bin/agent-project-run-ollama-session +0 -658
  62. package/tools/bin/agent-project-run-openclaw-session +0 -1309
  63. package/tools/bin/agent-project-run-opencode-session +0 -377
  64. package/tools/bin/agent-project-run-pi-session +0 -479
  65. package/tools/bin/agent-project-sync-anchor-repo +0 -139
  66. package/tools/bin/agent-project-worker-status +0 -188
  67. package/tools/bin/branch-verification-guard.sh +0 -364
  68. package/tools/bin/capture-worker.sh +0 -18
  69. package/tools/bin/cleanup-worktree.sh +0 -52
  70. package/tools/bin/codex-quota +0 -31
  71. package/tools/bin/create-follow-up-issue.sh +0 -114
  72. package/tools/bin/dashboard-launchd-bootstrap.sh +0 -50
  73. package/tools/bin/issue-publish-localization-guard.sh +0 -142
  74. package/tools/bin/issue-publish-scope-guard.sh +0 -242
  75. package/tools/bin/issue-requires-local-workspace-install.sh +0 -31
  76. package/tools/bin/issue-resource-class.sh +0 -12
  77. package/tools/bin/kick-scheduler.sh +0 -75
  78. package/tools/bin/label-follow-up-issues.sh +0 -14
  79. package/tools/bin/new-pr-worktree.sh +0 -50
  80. package/tools/bin/new-worktree.sh +0 -49
  81. package/tools/bin/pr-risk.sh +0 -12
  82. package/tools/bin/prepare-worktree.sh +0 -142
  83. package/tools/bin/provider-cooldown-state.sh +0 -204
  84. package/tools/bin/publish-issue-worker.sh +0 -31
  85. package/tools/bin/reconcile-bootstrap-lib.sh +0 -113
  86. package/tools/bin/reconcile-issue-worker.sh +0 -34
  87. package/tools/bin/reconcile-pr-worker.sh +0 -34
  88. package/tools/bin/record-verification.sh +0 -71
  89. package/tools/bin/render-flow-config.sh +0 -98
  90. package/tools/bin/resident-issue-controller-lib.sh +0 -448
  91. package/tools/bin/resident-issue-queue-status.py +0 -35
  92. package/tools/bin/retry-state.sh +0 -31
  93. package/tools/bin/reuse-issue-worktree.sh +0 -121
  94. package/tools/bin/run-codex-bypass.sh +0 -3
  95. package/tools/bin/run-codex-safe.sh +0 -3
  96. package/tools/bin/run-codex-task.sh +0 -280
  97. package/tools/bin/serve-dashboard.sh +0 -5
  98. package/tools/bin/split-retained-slice.sh +0 -124
  99. package/tools/bin/start-issue-worker.sh +0 -943
  100. package/tools/bin/start-pr-fix-worker.sh +0 -491
  101. package/tools/bin/start-pr-merge-repair-worker.sh +0 -8
  102. package/tools/bin/start-pr-review-worker.sh +0 -261
  103. package/tools/bin/start-resident-issue-loop.sh +0 -499
  104. package/tools/bin/update-github-labels.sh +0 -14
  105. package/tools/bin/worker-status.sh +0 -19
  106. package/tools/bin/workflow-catalog.sh +0 -77
@@ -1,435 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- usage() {
5
- cat <<'EOF'
6
- Usage:
7
- agent-project-run-codex-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 Codex worker session inside tmux for a project adapter and persist the
10
- standard run artifacts.
11
-
12
- Options:
13
- --safe-profile <name> Codex profile for safe mode
14
- --bypass-profile <name> Codex profile for bypass mode
15
- --env-prefix <prefix> Export prefixed runtime/context env vars inside the worker
16
- --context <KEY=VALUE> Extra metadata written to run.env and exported to the worker
17
- --collect-file <name> Copy sandbox artifact file into the host run dir after execution
18
- --reconcile-command <cmd> Host-side command queued after the worker exits
19
- --sandbox-subdir <name> Subdir under the worktree for worker artifacts (default: .openclaw-artifacts)
20
- --help Show this help
21
- EOF
22
- }
23
-
24
- mode=""
25
- session=""
26
- worktree=""
27
- worktree_realpath=""
28
- prompt_file=""
29
- runs_root=""
30
- adapter_id=""
31
- task_kind=""
32
- task_id=""
33
- safe_profile="default"
34
- bypass_profile="default"
35
- env_prefix=""
36
- sandbox_subdir=".openclaw-artifacts"
37
- reconcile_command=""
38
- declare -a context_items=()
39
- declare -a collect_files=()
40
-
41
- resolve_codex_bin() {
42
- local configured_bin="${CODEX_BIN:-${ACP_CODEX_BIN:-${F_LOSNING_CODEX_BIN:-}}}"
43
- local best_version=""
44
- local best_bin=""
45
- local candidate version_line version
46
- local -a fallback_paths=(
47
- "${HOME}/.local/bin/codex"
48
- "${HOME}/.codex/local/bin/codex"
49
- "/usr/local/bin/codex"
50
- "/opt/homebrew/bin/codex"
51
- )
52
-
53
- if [[ -n "$configured_bin" && -x "$configured_bin" ]]; then
54
- printf '%s\n' "$configured_bin"
55
- return 0
56
- fi
57
-
58
- if command -v codex >/dev/null 2>&1; then
59
- command -v codex
60
- return 0
61
- fi
62
-
63
- for candidate in "${fallback_paths[@]}"; do
64
- if [[ -x "$candidate" ]]; then
65
- printf '%s\n' "$candidate"
66
- return 0
67
- fi
68
- done
69
-
70
- if [[ -d "${HOME:-}/.nvm/versions/node" ]]; then
71
- while IFS= read -r candidate; do
72
- [[ -x "$candidate" ]] || continue
73
- version_line="$("$candidate" --version 2>/dev/null | head -n 1 || true)"
74
- version="$(sed -E 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/' <<<"$version_line")"
75
- if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
76
- continue
77
- fi
78
- if [[ -z "$best_version" || "$(printf '%s\n%s\n' "$best_version" "$version" | sort -V | tail -n 1)" == "$version" ]]; then
79
- best_version="$version"
80
- best_bin="$candidate"
81
- fi
82
- done < <(find "${HOME}/.nvm/versions/node" -path '*/bin/codex' -type f 2>/dev/null | sort -u)
83
- fi
84
-
85
- if [[ -n "$best_bin" ]]; then
86
- printf '%s\n' "$best_bin"
87
- return 0
88
- fi
89
-
90
- return 1
91
- }
92
-
93
- while [[ $# -gt 0 ]]; do
94
- case "$1" in
95
- --mode) mode="${2:-}"; shift 2 ;;
96
- --session) session="${2:-}"; shift 2 ;;
97
- --worktree) worktree="${2:-}"; shift 2 ;;
98
- --prompt-file) prompt_file="${2:-}"; shift 2 ;;
99
- --runs-root) runs_root="${2:-}"; shift 2 ;;
100
- --adapter-id) adapter_id="${2:-}"; shift 2 ;;
101
- --task-kind) task_kind="${2:-}"; shift 2 ;;
102
- --task-id) task_id="${2:-}"; shift 2 ;;
103
- --safe-profile) safe_profile="${2:-}"; shift 2 ;;
104
- --bypass-profile) bypass_profile="${2:-}"; shift 2 ;;
105
- --env-prefix) env_prefix="${2:-}"; shift 2 ;;
106
- --context) context_items+=("${2:-}"); shift 2 ;;
107
- --collect-file) collect_files+=("${2:-}"); shift 2 ;;
108
- --reconcile-command) reconcile_command="${2:-}"; shift 2 ;;
109
- --sandbox-subdir) sandbox_subdir="${2:-}"; shift 2 ;;
110
- --help|-h) usage; exit 0 ;;
111
- *) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
112
- esac
113
- done
114
-
115
- if [[ -z "$mode" || -z "$session" || -z "$worktree" || -z "$prompt_file" || -z "$runs_root" || -z "$adapter_id" || -z "$task_kind" || -z "$task_id" ]]; then
116
- usage >&2
117
- exit 1
118
- fi
119
-
120
- worktree_realpath="$(cd "$worktree" 2>/dev/null && pwd -P || true)"
121
- if [[ -z "$worktree_realpath" || ! -d "$worktree_realpath" ]]; then
122
- echo "unable to resolve worktree realpath: $worktree" >&2
123
- exit 1
124
- fi
125
-
126
- case "$mode" in
127
- safe|bypass) ;;
128
- *)
129
- echo "--mode must be safe or bypass" >&2
130
- exit 1
131
- ;;
132
- esac
133
-
134
- artifact_dir="${runs_root}/${session}"
135
- output_file="${artifact_dir}/${session}.log"
136
- inner_script="${artifact_dir}/${session}.sh"
137
- meta_file="${artifact_dir}/run.env"
138
- result_file="${artifact_dir}/result.env"
139
- runner_state_file="${artifact_dir}/runner.env"
140
- sandbox_run_dir="${worktree_realpath%/}/${sandbox_subdir}/${session}"
141
- started_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
142
- codex_bin="$(resolve_codex_bin || true)"
143
- runner_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/agent-project-run-codex-resilient"
144
-
145
- mkdir -p "$artifact_dir"
146
- mkdir -p "$sandbox_run_dir"
147
-
148
- if tmux has-session -t "$session" 2>/dev/null; then
149
- echo "tmux session already exists: $session" >&2
150
- exit 1
151
- fi
152
-
153
- if [[ -z "$codex_bin" || ! -x "$codex_bin" ]]; then
154
- echo "unable to resolve a runnable codex binary" >&2
155
- exit 1
156
- fi
157
-
158
- branch_name="$(git -C "$worktree_realpath" branch --show-current 2>/dev/null || true)"
159
-
160
- printf -v session_q '%q' "$session"
161
- printf -v task_kind_q '%q' "$task_kind"
162
- printf -v task_id_q '%q' "$task_id"
163
- printf -v mode_q '%q' "$mode"
164
- printf -v worktree_q '%q' "$worktree"
165
- printf -v worktree_realpath_q '%q' "$worktree_realpath"
166
- printf -v prompt_q '%q' "$prompt_file"
167
- printf -v output_q '%q' "$output_file"
168
- printf -v artifact_dir_q '%q' "$artifact_dir"
169
- printf -v script_q '%q' "$inner_script"
170
- printf -v result_q '%q' "$result_file"
171
- printf -v meta_file_q '%q' "$meta_file"
172
- printf -v runner_state_q '%q' "$runner_state_file"
173
- printf -v branch_q '%q' "$branch_name"
174
- printf -v sandbox_run_dir_q '%q' "$sandbox_run_dir"
175
- printf -v adapter_id_q '%q' "$adapter_id"
176
- printf -v started_at_q '%q' "$started_at"
177
- printf -v codex_bin_q '%q' "$codex_bin"
178
- printf -v runner_bin_q '%q' "$runner_bin"
179
- printf -v safe_profile_q '%q' "$safe_profile"
180
- printf -v bypass_profile_q '%q' "$bypass_profile"
181
- helper_bin_dir="${artifact_dir}/worker-bin"
182
- printf -v helper_bin_dir_q '%q' "$helper_bin_dir"
183
-
184
- {
185
- printf 'TASK_KIND=%s\n' "$task_kind_q"
186
- printf 'TASK_ID=%s\n' "$task_id_q"
187
- printf 'SESSION=%s\n' "$session_q"
188
- printf 'MODE=%s\n' "$mode_q"
189
- printf 'WORKTREE=%s\n' "$worktree_q"
190
- printf 'WORKTREE_REALPATH=%s\n' "$worktree_realpath_q"
191
- printf 'PROMPT_FILE=%s\n' "$prompt_q"
192
- printf 'OUTPUT_FILE=%s\n' "$output_q"
193
- printf 'SCRIPT=%s\n' "$script_q"
194
- printf 'BRANCH=%s\n' "$branch_q"
195
- printf 'RESULT_FILE=%s\n' "$result_q"
196
- printf 'RUNNER_STATE_FILE=%s\n' "$runner_state_q"
197
- printf 'SANDBOX_RUN_DIR=%s\n' "$sandbox_run_dir_q"
198
- printf 'ADAPTER_ID=%s\n' "$adapter_id_q"
199
- printf 'STARTED_AT=%s\n' "$started_at_q"
200
- printf 'CODEX_BIN=%s\n' "$codex_bin_q"
201
- printf 'RUNNER_BIN=%s\n' "$runner_bin_q"
202
- } >"$meta_file"
203
-
204
- context_exports=""
205
- if ((${#context_items[@]} > 0)); then
206
- for item in "${context_items[@]}"; do
207
- if [[ "$item" != *=* ]]; then
208
- echo "--context must use KEY=VALUE syntax: $item" >&2
209
- exit 1
210
- fi
211
- key="${item%%=*}"
212
- value="${item#*=}"
213
- if [[ ! "$key" =~ ^[A-Z0-9_]+$ ]]; then
214
- echo "Invalid context key: $key" >&2
215
- exit 1
216
- fi
217
- printf -v value_q '%q' "$value"
218
- printf '%s=%s\n' "$key" "$value_q" >>"$meta_file"
219
- if [[ -n "$env_prefix" ]]; then
220
- context_exports+="export ${env_prefix}${key}=${value_q}"$'\n'
221
- fi
222
- context_exports+="export ACP_${key}=${value_q}"$'\n'
223
- if [[ "$env_prefix" != "F_LOSNING_" ]]; then
224
- context_exports+="export F_LOSNING_${key}=${value_q}"$'\n'
225
- fi
226
- done
227
- fi
228
-
229
- runtime_exports=$(
230
- cat <<EOF
231
- export AGENT_PROJECT_SESSION=${session_q}
232
- export AGENT_PROJECT_RUN_DIR=${sandbox_run_dir_q}
233
- export AGENT_PROJECT_HOST_RUN_DIR=${artifact_dir_q}
234
- export AGENT_PROJECT_RESULT_FILE=${sandbox_run_dir_q}/result.env
235
- export AGENT_PROJECT_CODEX_BIN=${codex_bin_q}
236
- export ACP_SESSION=${session_q}
237
- export ACP_RUN_DIR=${sandbox_run_dir_q}
238
- export ACP_HOST_RUN_DIR=${artifact_dir_q}
239
- export ACP_RESULT_FILE=${sandbox_run_dir_q}/result.env
240
- export ACP_CODEX_BIN=${codex_bin_q}
241
- export F_LOSNING_SESSION=${session_q}
242
- export F_LOSNING_RUN_DIR=${sandbox_run_dir_q}
243
- export F_LOSNING_HOST_RUN_DIR=${artifact_dir_q}
244
- export F_LOSNING_RESULT_FILE=${sandbox_run_dir_q}/result.env
245
- export F_LOSNING_CODEX_BIN=${codex_bin_q}
246
- EOF
247
- )
248
-
249
- if [[ -n "$env_prefix" ]]; then
250
- runtime_exports+=$'\n'
251
- runtime_exports+=$(cat <<EOF
252
- export ${env_prefix}SESSION=${session_q}
253
- export ${env_prefix}RUN_DIR=${sandbox_run_dir_q}
254
- export ${env_prefix}HOST_RUN_DIR=${artifact_dir_q}
255
- export ${env_prefix}RESULT_FILE=${sandbox_run_dir_q}/result.env
256
- export ${env_prefix}CODEX_BIN=${codex_bin_q}
257
- EOF
258
- )
259
- fi
260
-
261
- collect_copy_snippet=""
262
- if ((${#collect_files[@]} > 0)); then
263
- for artifact_name in "${collect_files[@]}"; do
264
- if [[ -z "$artifact_name" ]]; then
265
- continue
266
- fi
267
- printf -v artifact_q '%q' "$artifact_name"
268
- collect_copy_snippet+=$(
269
- cat <<EOF
270
- if [[ -f ${sandbox_run_dir_q}/${artifact_q} ]]; then
271
- cp ${sandbox_run_dir_q}/${artifact_q} ${artifact_dir_q}/${artifact_q}
272
- fi
273
- EOF
274
- )
275
- collect_copy_snippet+=$'\n'
276
- done
277
- fi
278
-
279
- reconcile_snippet=""
280
- if [[ -n "$reconcile_command" ]]; then
281
- 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"
282
- reconcile_snippet="nohup bash -lc ${delayed_reconcile_q} >> ${output_q} 2>&1 </dev/null &"
283
- fi
284
-
285
- cat >"$inner_script" <<EOF
286
- #!/usr/bin/env bash
287
- set -euo pipefail
288
- ${runtime_exports}
289
- ${context_exports}cd ${worktree_realpath_q}
290
- bootstrap_codex_helper_env() {
291
- local helper_bin_dir=${helper_bin_dir_q}
292
- local openspec_shim=""
293
-
294
- mkdir -p "\${helper_bin_dir}"
295
-
296
- if [[ -d ${worktree_realpath_q}/node_modules/.bin ]]; then
297
- export PATH="${worktree_realpath_q}/node_modules/.bin:\${PATH}"
298
- fi
299
- export PATH="\${helper_bin_dir}:\${PATH}"
300
-
301
- if command -v openspec >/dev/null 2>&1; then
302
- return 0
303
- fi
304
-
305
- if [[ ! -d ${worktree_realpath_q}/openspec ]]; then
306
- return 0
307
- fi
308
-
309
- openspec_shim="\${helper_bin_dir}/openspec"
310
- cat >"\${openspec_shim}" <<'SHIM'
311
- #!/usr/bin/env bash
312
- set -euo pipefail
313
-
314
- repo_root="\${ACP_REPO_ROOT:-\${F_LOSNING_REPO_ROOT:-\$(pwd)}}"
315
- openspec_root="\${repo_root}/openspec"
316
-
317
- if [[ ! -d "\${openspec_root}" ]]; then
318
- echo "openspec directory not found: \${openspec_root}" >&2
319
- exit 1
320
- fi
321
-
322
- command_name="\${1:-}"
323
- case "\${command_name}" in
324
- list)
325
- shift || true
326
- if [[ "\${1:-}" == "--specs" ]]; then
327
- find "\${openspec_root}/specs" -mindepth 1 -maxdepth 1 -type d 2>/dev/null \
328
- | xargs -n1 basename 2>/dev/null \
329
- | sort
330
- exit 0
331
- fi
332
- find "\${openspec_root}/changes" -mindepth 1 -maxdepth 1 -type d ! -name archive 2>/dev/null \
333
- | xargs -n1 basename 2>/dev/null \
334
- | sort
335
- exit 0
336
- ;;
337
- *)
338
- echo "openspec shim only supports 'list' and 'list --specs'; use direct file reads for other operations" >&2
339
- exit 64
340
- ;;
341
- esac
342
- SHIM
343
- chmod +x "\${openspec_shim}"
344
- }
345
- reset_sandbox_run_dir() {
346
- mkdir -p ${sandbox_run_dir_q}
347
- find ${sandbox_run_dir_q} -mindepth 1 -maxdepth 1 -exec rm -rf {} + 2>/dev/null || true
348
- }
349
- find_logged_artifact_path() {
350
- local artifact_name="\${1:?artifact name required}"
351
- local candidate=""
352
-
353
- while IFS= read -r candidate; do
354
- [[ -n "\${candidate}" ]] || continue
355
- while [[ "\${candidate}" == *')' || "\${candidate}" == *']' || "\${candidate}" == *',' || "\${candidate}" == *'"' || "\${candidate}" == *"'" ]]; do
356
- candidate="\${candidate%?}"
357
- done
358
- if [[ "\$(basename "\${candidate}")" == "\${artifact_name}" && -f "\${candidate}" ]]; then
359
- printf '%s\n' "\${candidate}"
360
- fi
361
- done < <(grep -oE '/[^[:space:])"]+' ${output_q} 2>/dev/null || true)
362
- }
363
- recover_logged_artifact() {
364
- local artifact_name="\${1:?artifact name required}"
365
- local destination="\${2:?destination required}"
366
- local source_path=""
367
-
368
- source_path="\$(find_logged_artifact_path "\${artifact_name}" | tail -n 1)"
369
- [[ -n "\${source_path}" ]] || return 0
370
- mkdir -p "\$(dirname "\${destination}")"
371
- if [[ "\${source_path}" != "\${destination}" ]]; then
372
- cp "\${source_path}" "\${destination}"
373
- fi
374
- }
375
- recover_collected_artifact() {
376
- local artifact_name="\${1:?artifact name required}"
377
- local destination="\${2:?destination required}"
378
-
379
- if [[ -f ${sandbox_run_dir_q}/"\${artifact_name}" ]]; then
380
- if [[ ${sandbox_run_dir_q}/"\${artifact_name}" != "\${destination}" ]]; then
381
- cp ${sandbox_run_dir_q}/"\${artifact_name}" "\${destination}"
382
- fi
383
- return 0
384
- fi
385
-
386
- recover_logged_artifact "\${artifact_name}" "\${destination}"
387
- }
388
- record_final_git_state() {
389
- local final_head final_branch tmp_file
390
-
391
- final_head="\$(git -C ${worktree_realpath_q} rev-parse HEAD 2>/dev/null || true)"
392
- final_branch="\$(git -C ${worktree_realpath_q} branch --show-current 2>/dev/null || true)"
393
- tmp_file=${meta_file_q}.tmp.final.$$
394
- grep -vE '^(FINAL_HEAD|FINAL_BRANCH|WORKTREE_REALPATH)=' ${meta_file_q} >"\${tmp_file}" 2>/dev/null || true
395
- {
396
- printf 'WORKTREE_REALPATH=%s\n' ${worktree_realpath_q}
397
- printf 'FINAL_HEAD=%q\n' "\${final_head}"
398
- printf 'FINAL_BRANCH=%q\n' "\${final_branch}"
399
- } >>"\${tmp_file}"
400
- mv "\${tmp_file}" ${meta_file_q}
401
- }
402
- bootstrap_codex_helper_env
403
- reset_sandbox_run_dir
404
- set +e
405
- bash ${runner_bin_q} \\
406
- --mode ${mode_q} \\
407
- --worktree ${worktree_realpath_q} \\
408
- --prompt-file ${prompt_q} \\
409
- --output-file ${output_q} \\
410
- --host-run-dir ${artifact_dir_q} \\
411
- --sandbox-run-dir ${sandbox_run_dir_q} \\
412
- --safe-profile ${safe_profile_q} \\
413
- --bypass-profile ${bypass_profile_q} \\
414
- --codex-bin ${codex_bin_q}
415
- status=\$?
416
- record_final_git_state
417
- recover_collected_artifact result.env ${result_q}
418
- recover_collected_artifact issue-comment.md ${artifact_dir_q}/issue-comment.md
419
- recover_collected_artifact pr-comment.md ${artifact_dir_q}/pr-comment.md
420
- recover_collected_artifact verification.jsonl ${artifact_dir_q}/verification.jsonl
421
- ${collect_copy_snippet}${reconcile_snippet}
422
- printf '\n__CODEX_EXIT__:%s\n' "\$status" | tee -a ${output_q}
423
- exit "\$status"
424
- EOF
425
-
426
- chmod +x "$inner_script"
427
- tmux new-session -d -s "$session" "$inner_script"
428
-
429
- printf 'SESSION=%s\n' "$session"
430
- printf 'TASK_KIND=%s\n' "$task_kind"
431
- printf 'TASK_ID=%s\n' "$task_id"
432
- printf 'WORKTREE=%s\n' "$worktree"
433
- printf 'OUTPUT=%s\n' "$output_file"
434
- printf 'SCRIPT=%s\n' "$inner_script"
435
- printf 'META=%s\n' "$meta_file"