agent-control-plane 0.1.2 → 0.1.3

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 (179) hide show
  1. package/README.md +6 -0
  2. package/npm/bin/agent-control-plane.js +149 -5
  3. package/package.json +1 -2
  4. package/tools/tests/test-agent-control-plane-npm-cli.sh +0 -280
  5. package/tools/tests/test-agent-github-update-labels-falls-back-to-repository-id.sh +0 -56
  6. package/tools/tests/test-agent-project-claude-session-wrapper-clears-stale-sandbox-artifacts.sh +0 -89
  7. package/tools/tests/test-agent-project-claude-session-wrapper-does-not-retry-provider-quota.sh +0 -82
  8. package/tools/tests/test-agent-project-claude-session-wrapper-retries-transient-failures.sh +0 -90
  9. package/tools/tests/test-agent-project-claude-session-wrapper-times-out.sh +0 -73
  10. package/tools/tests/test-agent-project-claude-session-wrapper.sh +0 -103
  11. package/tools/tests/test-agent-project-cleanup-session-orphan-fallback.sh +0 -90
  12. package/tools/tests/test-agent-project-cleanup-session-skip-worktree-cleanup.sh +0 -90
  13. package/tools/tests/test-agent-project-codex-live-thread-persist.sh +0 -76
  14. package/tools/tests/test-agent-project-codex-recovery.sh +0 -731
  15. package/tools/tests/test-agent-project-codex-session-wrapper-clears-stale-sandbox-artifacts.sh +0 -105
  16. package/tools/tests/test-agent-project-codex-session-wrapper.sh +0 -97
  17. package/tools/tests/test-agent-project-open-pr-worktree-config-prefix.sh +0 -81
  18. package/tools/tests/test-agent-project-openclaw-session-wrapper-clears-stale-sandbox-artifacts.sh +0 -109
  19. package/tools/tests/test-agent-project-openclaw-session-wrapper-infers-blocked-result-contract.sh +0 -89
  20. package/tools/tests/test-agent-project-openclaw-session-wrapper-recovers-literal-env-artifacts.sh +0 -113
  21. package/tools/tests/test-agent-project-openclaw-session-wrapper-recovers-version-mismatch.sh +0 -135
  22. package/tools/tests/test-agent-project-openclaw-session-wrapper-resident.sh +0 -179
  23. package/tools/tests/test-agent-project-openclaw-session-wrapper-reuses-existing-agent-after-add-race.sh +0 -119
  24. package/tools/tests/test-agent-project-openclaw-session-wrapper-terminates-rate-limit-hang.sh +0 -91
  25. package/tools/tests/test-agent-project-openclaw-session-wrapper.sh +0 -117
  26. package/tools/tests/test-agent-project-publish-issue-pr-prunes-stale-worktree-entry.sh +0 -148
  27. package/tools/tests/test-agent-project-publish-issue-pr-reads-archived-session.sh +0 -146
  28. package/tools/tests/test-agent-project-publish-issue-pr-recovers-final-head.sh +0 -145
  29. package/tools/tests/test-agent-project-publish-issue-pr-reuses-existing-worktree.sh +0 -147
  30. package/tools/tests/test-agent-project-reconcile-failure-reason.sh +0 -456
  31. package/tools/tests/test-agent-project-reconcile-issue-archived-session-fallback.sh +0 -96
  32. package/tools/tests/test-agent-project-reconcile-issue-before-blocked.sh +0 -90
  33. package/tools/tests/test-agent-project-reconcile-issue-host-verification-recovery-uses-recovered-worktree.sh +0 -212
  34. package/tools/tests/test-agent-project-reconcile-issue-host-verification-recovery.sh +0 -207
  35. package/tools/tests/test-agent-project-reconcile-issue-provider-quota-schedules-provider-cooldown.sh +0 -101
  36. package/tools/tests/test-agent-project-reconcile-issue-session-backfills-lane-metadata-from-worker-key.sh +0 -113
  37. package/tools/tests/test-agent-project-reconcile-issue-session-clears-stale-failed-summary.sh +0 -117
  38. package/tools/tests/test-agent-project-reconcile-issue-session-initializes-shared-agent-home.sh +0 -55
  39. package/tools/tests/test-agent-project-reconcile-issue-session-normalizes-runner-state.sh +0 -125
  40. package/tools/tests/test-agent-project-reconcile-issue-session-records-invalid-contract-summary.sh +0 -118
  41. package/tools/tests/test-agent-project-reconcile-issue-session-skips-duplicate-blocked-comment.sh +0 -144
  42. package/tools/tests/test-agent-project-reconcile-issue-session-standardizes-no-commits-blocker.sh +0 -145
  43. package/tools/tests/test-agent-project-reconcile-issue-session-synthesizes-blocked-comment.sh +0 -139
  44. package/tools/tests/test-agent-project-reconcile-pr-blocked-host-recovery.sh +0 -242
  45. package/tools/tests/test-agent-project-reconcile-pr-guard-blocked-no-commit.sh +0 -142
  46. package/tools/tests/test-agent-project-reconcile-pr-provider-quota-schedules-provider-cooldown.sh +0 -106
  47. package/tools/tests/test-agent-project-reconcile-pr-session-initializes-shared-agent-home.sh +0 -66
  48. package/tools/tests/test-agent-project-reconcile-pr-updated-branch-noop.sh +0 -129
  49. package/tools/tests/test-audit-agent-worktrees-active-launch-skips-git-inspection.sh +0 -69
  50. package/tools/tests/test-audit-agent-worktrees-broken-worktree.sh +0 -43
  51. package/tools/tests/test-audit-agent-worktrees-pending-launch-owner.sh +0 -46
  52. package/tools/tests/test-audit-agent-worktrees-unreconciled-owner.sh +0 -79
  53. package/tools/tests/test-audit-issue-routing-managed-branch-globs.sh +0 -56
  54. package/tools/tests/test-branch-verification-guard-generated-artifacts.sh +0 -72
  55. package/tools/tests/test-branch-verification-guard-targeted-coverage.sh +0 -125
  56. package/tools/tests/test-codex-quota-manager-failure-driven-rotation.sh +0 -178
  57. package/tools/tests/test-codex-quota-wrapper.sh +0 -37
  58. package/tools/tests/test-contribution-docs.sh +0 -18
  59. package/tools/tests/test-control-plane-dashboard-runtime-smoke.sh +0 -343
  60. package/tools/tests/test-create-follow-up-issue.sh +0 -73
  61. package/tools/tests/test-dashboard-launchd-bootstrap.sh +0 -55
  62. package/tools/tests/test-flow-export-execution-env-exports-repo-id.sh +0 -30
  63. package/tools/tests/test-flow-export-github-cli-auth-env-prefers-git-credential.sh +0 -48
  64. package/tools/tests/test-flow-github-api-repo-fallback-preserves-input.sh +0 -85
  65. package/tools/tests/test-flow-github-api-repo-prefers-explicit-repository-id.sh +0 -60
  66. package/tools/tests/test-flow-github-issue-list-falls-back-to-repository-id.sh +0 -64
  67. package/tools/tests/test-flow-github-pr-list-falls-back-to-repository-id.sh +0 -77
  68. package/tools/tests/test-flow-resident-can-reuse-does-not-leak-metadata.sh +0 -52
  69. package/tools/tests/test-flow-resident-reap-stale-controllers.sh +0 -63
  70. package/tools/tests/test-flow-resolve-codex-quota-tools.sh +0 -104
  71. package/tools/tests/test-flow-runtime-doctor-profile-selection.sh +0 -27
  72. package/tools/tests/test-heartbeat-codex-pr-linked-issue-exclusion.sh +0 -79
  73. package/tools/tests/test-heartbeat-hooks-enqueue-resident-issue-for-idle-controller.sh +0 -115
  74. package/tools/tests/test-heartbeat-hooks-enqueue-resident-issue-for-live-lane-controller.sh +0 -117
  75. package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop-claude.sh +0 -96
  76. package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop-codex.sh +0 -96
  77. package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop.sh +0 -96
  78. package/tools/tests/test-heartbeat-loop-auth-wait-does-not-consume-capacity.sh +0 -170
  79. package/tools/tests/test-heartbeat-loop-blocked-recovery-lane.sh +0 -201
  80. package/tools/tests/test-heartbeat-loop-blocked-recovery-vs-pr-reservation.sh +0 -201
  81. package/tools/tests/test-heartbeat-loop-idle-resident-controller-does-not-block-launches.sh +0 -160
  82. package/tools/tests/test-heartbeat-loop-pr-launch-dedup.sh +0 -133
  83. package/tools/tests/test-heartbeat-loop-provider-cooldown-suppresses-launches.sh +0 -157
  84. package/tools/tests/test-heartbeat-loop-reaps-stale-resident-controller.sh +0 -181
  85. package/tools/tests/test-heartbeat-loop-waiting-provider-resident-controller-does-not-block-launches.sh +0 -160
  86. package/tools/tests/test-heartbeat-ready-issues-blocked-recovery.sh +0 -134
  87. package/tools/tests/test-heartbeat-safe-auto-dynamic-concurrency.sh +0 -162
  88. package/tools/tests/test-heartbeat-safe-auto-no-tmux-sessions.sh +0 -136
  89. package/tools/tests/test-heartbeat-safe-auto-openclaw-skips-codex-quota.sh +0 -139
  90. package/tools/tests/test-heartbeat-safe-auto-quota-health-signal.sh +0 -119
  91. package/tools/tests/test-heartbeat-safe-auto-stale-shared-loop-pid-does-not-skip.sh +0 -140
  92. package/tools/tests/test-heartbeat-safe-auto-static-capacity-without-quota-cache.sh +0 -142
  93. package/tools/tests/test-heartbeat-safe-auto-zero-healthy-pools.sh +0 -141
  94. package/tools/tests/test-heartbeat-sync-issue-labels-empty-schedule.sh +0 -65
  95. package/tools/tests/test-heartbeat-sync-open-agent-prs-terminal-clears-running.sh +0 -179
  96. package/tools/tests/test-install-dashboard-launchd.sh +0 -78
  97. package/tools/tests/test-install-project-launchd-adds-tool-paths.sh +0 -87
  98. package/tools/tests/test-install-project-launchd.sh +0 -110
  99. package/tools/tests/test-issue-local-workspace-install-policy.sh +0 -81
  100. package/tools/tests/test-issue-publish-scope-guard-docs-signal.sh +0 -70
  101. package/tools/tests/test-issue-reconcile-hooks-success-clears-blocked.sh +0 -36
  102. package/tools/tests/test-kick-scheduler-requires-explicit-profile.sh +0 -47
  103. package/tools/tests/test-label-follow-up-issues-falls-back-to-repository-id.sh +0 -132
  104. package/tools/tests/test-manual-operator-entrypoints-require-explicit-profile.sh +0 -64
  105. package/tools/tests/test-package-funding-metadata.sh +0 -21
  106. package/tools/tests/test-package-public-metadata.sh +0 -62
  107. package/tools/tests/test-placeholder-worker-adapters.sh +0 -38
  108. package/tools/tests/test-pr-reconcile-hooks-refreshes-recurring-issue-checklist.sh +0 -110
  109. package/tools/tests/test-pr-risk-cohesive-mobile-locale-scope.sh +0 -70
  110. package/tools/tests/test-pr-risk-fix-label-semantics.sh +0 -114
  111. package/tools/tests/test-pr-risk-local-first-no-checks.sh +0 -70
  112. package/tools/tests/test-prepare-worktree-simple-repo-baseline.sh +0 -67
  113. package/tools/tests/test-profile-activate.sh +0 -33
  114. package/tools/tests/test-profile-adopt-allow-missing-repo.sh +0 -68
  115. package/tools/tests/test-profile-adopt-skip-workspace-sync-missing-file.sh +0 -61
  116. package/tools/tests/test-profile-adopt-syncs-anchor-and-workspace.sh +0 -90
  117. package/tools/tests/test-profile-smoke-collision.sh +0 -44
  118. package/tools/tests/test-profile-smoke-invalid-claude-config.sh +0 -31
  119. package/tools/tests/test-profile-smoke-invalid-provider-pool.sh +0 -68
  120. package/tools/tests/test-profile-smoke-repo-slug-mismatch.sh +0 -36
  121. package/tools/tests/test-profile-smoke.sh +0 -45
  122. package/tools/tests/test-project-init-force-and-skip-sync.sh +0 -61
  123. package/tools/tests/test-project-init-repo-slug-mismatch.sh +0 -29
  124. package/tools/tests/test-project-init.sh +0 -66
  125. package/tools/tests/test-project-launchd-bootstrap.sh +0 -66
  126. package/tools/tests/test-project-remove.sh +0 -150
  127. package/tools/tests/test-project-runtime-supervisor.sh +0 -47
  128. package/tools/tests/test-project-runtimectl-launchd.sh +0 -115
  129. package/tools/tests/test-project-runtimectl-missing-profile.sh +0 -54
  130. package/tools/tests/test-project-runtimectl-start-falls-back-to-bootstrap.sh +0 -108
  131. package/tools/tests/test-project-runtimectl-status-reports-supervisor-as-heartbeat-parent.sh +0 -95
  132. package/tools/tests/test-project-runtimectl-status-supervisor-running.sh +0 -59
  133. package/tools/tests/test-project-runtimectl-stop-cancels-pending-kick.sh +0 -85
  134. package/tools/tests/test-project-runtimectl-stop-clears-running-labels.sh +0 -78
  135. package/tools/tests/test-project-runtimectl.sh +0 -212
  136. package/tools/tests/test-provider-cooldown-state-prefers-runtime-worker-context.sh +0 -39
  137. package/tools/tests/test-provider-cooldown-state.sh +0 -59
  138. package/tools/tests/test-public-repo-docs.sh +0 -161
  139. package/tools/tests/test-reconcile-pr-worker-acp-config-routing.sh +0 -75
  140. package/tools/tests/test-render-dashboard-snapshot.sh +0 -149
  141. package/tools/tests/test-render-flow-config-demo-profile.sh +0 -36
  142. package/tools/tests/test-render-flow-config-provider-pool-fallback.sh +0 -81
  143. package/tools/tests/test-render-flow-config.sh +0 -52
  144. package/tools/tests/test-run-codex-task-claude-routing.sh +0 -125
  145. package/tools/tests/test-run-codex-task-codex-resident-routing.sh +0 -108
  146. package/tools/tests/test-run-codex-task-kilo-routing.sh +0 -98
  147. package/tools/tests/test-run-codex-task-openclaw-resident-routing.sh +0 -117
  148. package/tools/tests/test-run-codex-task-openclaw-routing.sh +0 -113
  149. package/tools/tests/test-run-codex-task-opencode-routing.sh +0 -98
  150. package/tools/tests/test-run-codex-task-provider-pool-fallback-routing.sh +0 -146
  151. package/tools/tests/test-scaffold-profile.sh +0 -108
  152. package/tools/tests/test-serve-dashboard.sh +0 -93
  153. package/tools/tests/test-start-issue-worker-blocked-context.sh +0 -129
  154. package/tools/tests/test-start-issue-worker-blocks-complete-recurring-checklist.sh +0 -189
  155. package/tools/tests/test-start-issue-worker-local-install-routing.sh +0 -157
  156. package/tools/tests/test-start-issue-worker-profile-template-routing.sh +0 -149
  157. package/tools/tests/test-start-issue-worker-recurring-resident-reuse-codex.sh +0 -212
  158. package/tools/tests/test-start-issue-worker-recurring-resident-reuse.sh +0 -219
  159. package/tools/tests/test-start-issue-worker-renders-verification-snippet.sh +0 -155
  160. package/tools/tests/test-start-issue-worker-resident-reuse-falls-back-to-new-worktree.sh +0 -199
  161. package/tools/tests/test-start-pr-fix-worker-host-blocker-context.sh +0 -275
  162. package/tools/tests/test-start-resident-issue-loop-adopts-next-recurring-issue.sh +0 -185
  163. package/tools/tests/test-start-resident-issue-loop-clears-pending-while-waiting-due.sh +0 -152
  164. package/tools/tests/test-start-resident-issue-loop-consumes-queued-lease.sh +0 -186
  165. package/tools/tests/test-start-resident-issue-loop-fails-over-provider-pool.sh +0 -212
  166. package/tools/tests/test-start-resident-issue-loop-immediate-cycles.sh +0 -148
  167. package/tools/tests/test-start-resident-issue-loop-waits-for-provider.sh +0 -194
  168. package/tools/tests/test-start-resident-issue-loop-waits-for-terminal-reconcile-status.sh +0 -198
  169. package/tools/tests/test-start-resident-issue-loop-yields-to-live-lane-controller.sh +0 -145
  170. package/tools/tests/test-sync-pr-labels-fix-lane-uses-repair-queued.sh +0 -67
  171. package/tools/tests/test-sync-recurring-issue-checklist-backfills-workflow-complete-blocker.sh +0 -70
  172. package/tools/tests/test-sync-recurring-issue-checklist.sh +0 -95
  173. package/tools/tests/test-sync-shared-agent-home-local-source-root.sh +0 -66
  174. package/tools/tests/test-sync-shared-agent-home-preserves-unrelated-workflow-catalog-skill.sh +0 -47
  175. package/tools/tests/test-test-smoke.sh +0 -86
  176. package/tools/tests/test-uninstall-project-launchd.sh +0 -37
  177. package/tools/tests/test-update-github-labels-prefers-sibling-helper.sh +0 -49
  178. package/tools/tests/test-vendored-codex-quota-claude-oauth-only.sh +0 -38
  179. package/tools/tests/test-workflow-catalog.sh +0 -43
@@ -1,343 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- FLOW_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5
- SNAPSHOT_BIN="${FLOW_ROOT}/tools/bin/render-dashboard-snapshot.py"
6
- SERVER_BIN="${FLOW_ROOT}/tools/bin/serve-dashboard.sh"
7
- RUNTIMECTL_BIN="${FLOW_ROOT}/tools/bin/project-runtimectl.sh"
8
-
9
- tmpdir="$(mktemp -d)"
10
- server_pid=""
11
- supervisor_pid=""
12
- heartbeat_pid=""
13
- shared_loop_pid=""
14
- controller_pid=""
15
- cleanup() {
16
- local pid=""
17
- for pid in "${server_pid}" "${shared_loop_pid}" "${controller_pid}" "${heartbeat_pid}" "${supervisor_pid}"; do
18
- [[ -n "${pid}" ]] || continue
19
- kill "${pid}" >/dev/null 2>&1 || true
20
- wait "${pid}" >/dev/null 2>&1 || true
21
- done
22
- rm -rf "${tmpdir}"
23
- }
24
- trap cleanup EXIT
25
-
26
- profile_registry_root="${tmpdir}/profiles"
27
- profile_dir="${profile_registry_root}/demo"
28
- runs_root="${tmpdir}/runtime/demo/runs"
29
- state_root="${tmpdir}/runtime/demo/state"
30
- recurring_run_dir="${runs_root}/demo-issue-2"
31
- scheduled_run_dir="${runs_root}/demo-issue-3"
32
- recurring_worker_key="issue-lane-recurring-general-openclaw-safe"
33
- scheduled_worker_key="issue-lane-scheduled-1800-openclaw-safe"
34
- repo_slug="example/demo-control-plane"
35
- port="18766"
36
- heartbeat_child_pid_file="${tmpdir}/heartbeat-child.pid"
37
- heartbeat_script="${tmpdir}/heartbeat-safe-auto.sh"
38
- supervisor_script="${tmpdir}/project-runtime-supervisor.sh"
39
- shared_loop_script="${tmpdir}/agent-project-heartbeat-loop"
40
-
41
- mkdir -p \
42
- "${profile_dir}" \
43
- "${recurring_run_dir}" \
44
- "${scheduled_run_dir}" \
45
- "${state_root}/heartbeat-loop.lock" \
46
- "${state_root}/resident-workers/issues/2" \
47
- "${state_root}/resident-workers/issues/${recurring_worker_key}" \
48
- "${state_root}/resident-workers/issues/${scheduled_worker_key}" \
49
- "${state_root}/resident-workers/issue-queue/pending" \
50
- "${state_root}/retries/providers" \
51
- "${state_root}/scheduled-issues"
52
-
53
- cat >"${profile_dir}/control-plane.yaml" <<EOF
54
- schema_version: "1"
55
- id: "demo"
56
- repo:
57
- slug: "${repo_slug}"
58
- root: "${tmpdir}/repo"
59
- default_branch: "main"
60
- runtime:
61
- orchestrator_agent_root: "${tmpdir}/runtime/demo"
62
- worktree_root: "${tmpdir}/worktrees"
63
- agent_repo_root: "${tmpdir}/repo"
64
- runs_root: "${runs_root}"
65
- state_root: "${state_root}"
66
- history_root: "${tmpdir}/runtime/demo/history"
67
- retained_repo_root: "${tmpdir}/repo"
68
- vscode_workspace_file: "${tmpdir}/demo.code-workspace"
69
- session_naming:
70
- issue_prefix: "demo-issue-"
71
- pr_prefix: "demo-pr-"
72
- execution:
73
- coding_worker: "openclaw"
74
- openclaw:
75
- model: "primary/model"
76
- thinking: "adaptive"
77
- timeout_seconds: 900
78
- EOF
79
-
80
- cat >"${recurring_run_dir}/run.env" <<EOF
81
- TASK_KIND=issue
82
- TASK_ID=2
83
- SESSION=demo-issue-2
84
- MODE=safe
85
- STARTED_AT=2026-03-27T11:00:00Z
86
- CODING_WORKER=openclaw
87
- WORKTREE=${tmpdir}/worktrees/issue-2
88
- BRANCH=agent/demo/issue-2
89
- RESIDENT_WORKER_KEY=${recurring_worker_key}
90
- OPENCLAW_MODEL=primary/model
91
- EOF
92
-
93
- cat >"${recurring_run_dir}/runner.env" <<'EOF'
94
- RUNNER_STATE=succeeded
95
- THREAD_ID=thread-demo-2
96
- LAST_EXIT_CODE=0
97
- LAST_FAILURE_REASON=''
98
- UPDATED_AT=2026-03-27T11:03:00Z
99
- EOF
100
-
101
- cat >"${recurring_run_dir}/result.env" <<'EOF'
102
- OUTCOME=implemented
103
- ACTION=host-publish-issue-pr
104
- EOF
105
-
106
- cat >"${scheduled_run_dir}/run.env" <<EOF
107
- TASK_KIND=issue
108
- TASK_ID=3
109
- SESSION=demo-issue-3
110
- MODE=safe
111
- STARTED_AT=2026-03-27T11:10:00Z
112
- CODING_WORKER=openclaw
113
- WORKTREE=${tmpdir}/worktrees/issue-3
114
- BRANCH=agent/demo/issue-3
115
- RESIDENT_WORKER_KEY=${scheduled_worker_key}
116
- OPENCLAW_MODEL=primary/model
117
- EOF
118
-
119
- cat >"${scheduled_run_dir}/runner.env" <<'EOF'
120
- RUNNER_STATE=succeeded
121
- THREAD_ID=thread-demo-3
122
- LAST_EXIT_CODE=0
123
- LAST_FAILURE_REASON=''
124
- UPDATED_AT=2026-03-27T11:12:00Z
125
- EOF
126
-
127
- cat >"${scheduled_run_dir}/result.env" <<'EOF'
128
- OUTCOME=reported
129
- ACTION=host-comment-scheduled-report
130
- EOF
131
-
132
- cat >"${heartbeat_script}" <<'EOF'
133
- #!/usr/bin/env bash
134
- set -euo pipefail
135
- sleep 60
136
- EOF
137
- chmod +x "${heartbeat_script}"
138
-
139
- cat >"${supervisor_script}" <<EOF
140
- #!/usr/bin/env bash
141
- set -euo pipefail
142
- bash "${heartbeat_script}" >/dev/null 2>&1 &
143
- child_pid=\$!
144
- printf '%s\n' "\${child_pid}" >"${heartbeat_child_pid_file}"
145
- wait "\${child_pid}"
146
- EOF
147
- chmod +x "${supervisor_script}"
148
-
149
- cat >"${shared_loop_script}" <<'EOF'
150
- #!/usr/bin/env bash
151
- set -euo pipefail
152
- sleep 60
153
- EOF
154
- chmod +x "${shared_loop_script}"
155
-
156
- bash "${supervisor_script}" >/dev/null 2>&1 &
157
- supervisor_pid="$!"
158
-
159
- for _ in $(seq 1 50); do
160
- if [[ -s "${heartbeat_child_pid_file}" ]]; then
161
- break
162
- fi
163
- sleep 0.1
164
- done
165
-
166
- heartbeat_pid="$(tr -d '[:space:]' <"${heartbeat_child_pid_file}")"
167
- if [[ -z "${heartbeat_pid}" ]]; then
168
- echo "failed to capture heartbeat pid" >&2
169
- exit 1
170
- fi
171
-
172
- printf '%s\n' "${heartbeat_pid}" >"${state_root}/heartbeat-loop.lock/pid"
173
- printf '%s\n' "${supervisor_pid}" >"${state_root}/runtime-supervisor.pid"
174
-
175
- bash "${shared_loop_script}" --repo-slug "${repo_slug}" >/dev/null 2>&1 &
176
- shared_loop_pid="$!"
177
- printf '%s\n' "${shared_loop_pid}" >"${state_root}/shared-heartbeat-loop.pid"
178
-
179
- sleep 60 >/dev/null 2>&1 &
180
- controller_pid="$!"
181
-
182
- cat >"${state_root}/resident-workers/issues/2/controller.env" <<EOF
183
- ISSUE_ID=2
184
- SESSION=demo-issue-2
185
- CONTROLLER_PID=${controller_pid}
186
- CONTROLLER_MODE=safe
187
- CONTROLLER_LOOP_COUNT=4
188
- CONTROLLER_STATE=waiting-provider
189
- CONTROLLER_REASON=provider-cooldown
190
- ACTIVE_RESIDENT_WORKER_KEY=${recurring_worker_key}
191
- ACTIVE_RESIDENT_LANE_KIND=recurring
192
- ACTIVE_RESIDENT_LANE_VALUE=general
193
- ACTIVE_PROVIDER_BACKEND=openclaw
194
- ACTIVE_PROVIDER_MODEL=primary/model
195
- ACTIVE_PROVIDER_KEY=openclaw-primary-model
196
- PROVIDER_SWITCH_COUNT=2
197
- PROVIDER_FAILOVER_COUNT=1
198
- PROVIDER_WAIT_COUNT=3
199
- PROVIDER_WAIT_TOTAL_SECONDS=90
200
- PROVIDER_LAST_WAIT_SECONDS=30
201
- UPDATED_AT=2026-03-27T11:13:00Z
202
- EOF
203
-
204
- cat >"${state_root}/resident-workers/issues/${recurring_worker_key}/metadata.env" <<EOF
205
- RESIDENT_WORKER_KIND=issue
206
- RESIDENT_WORKER_SCOPE=lane
207
- RESIDENT_WORKER_KEY=${recurring_worker_key}
208
- RESIDENT_LANE_KIND=recurring
209
- RESIDENT_LANE_VALUE=general
210
- ISSUE_ID=2
211
- CODING_WORKER=openclaw
212
- TASK_COUNT=5
213
- LAST_STATUS=SUCCEEDED
214
- LAST_STARTED_AT=2026-03-27T11:00:00Z
215
- LAST_FINISHED_AT=2026-03-27T11:03:00Z
216
- LAST_RUN_SESSION=demo-issue-2
217
- LAST_OUTCOME=implemented
218
- LAST_ACTION=host-publish-issue-pr
219
- LAST_FAILURE_REASON=
220
- EOF
221
-
222
- cat >"${state_root}/resident-workers/issues/${scheduled_worker_key}/metadata.env" <<EOF
223
- RESIDENT_WORKER_KIND=issue
224
- RESIDENT_WORKER_SCOPE=lane
225
- RESIDENT_WORKER_KEY=${scheduled_worker_key}
226
- RESIDENT_LANE_KIND=scheduled
227
- RESIDENT_LANE_VALUE=1800
228
- ISSUE_ID=3
229
- CODING_WORKER=openclaw
230
- TASK_COUNT=2
231
- LAST_STATUS=SUCCEEDED
232
- LAST_STARTED_AT=2026-03-27T11:10:00Z
233
- LAST_FINISHED_AT=2026-03-27T11:12:00Z
234
- LAST_RUN_SESSION=demo-issue-3
235
- LAST_OUTCOME=reported
236
- LAST_ACTION=host-comment-scheduled-report
237
- LAST_FAILURE_REASON=
238
- EOF
239
-
240
- cat >"${state_root}/scheduled-issues/3.env" <<'EOF'
241
- INTERVAL_SECONDS=1800
242
- LAST_STARTED_AT=2026-03-27T11:10:00Z
243
- NEXT_DUE_AT=2026-03-27T11:40:00Z
244
- UPDATED_AT=2026-03-27T11:12:00Z
245
- EOF
246
-
247
- cat >"${state_root}/retries/providers/openclaw-primary-model.env" <<'EOF'
248
- ATTEMPTS=2
249
- NEXT_ATTEMPT_EPOCH=4102444800
250
- NEXT_ATTEMPT_AT=2100-01-01T00:00:00Z
251
- LAST_REASON=provider-quota-limit
252
- UPDATED_AT=2026-03-27T11:13:00Z
253
- EOF
254
-
255
- cat >"${state_root}/resident-workers/issue-queue/pending/issue-6.env" <<'EOF'
256
- ISSUE_ID=6
257
- SESSION=demo-issue-6
258
- UPDATED_AT=2026-03-27T11:13:30Z
259
- EOF
260
-
261
- snapshot_file="${tmpdir}/snapshot.json"
262
- api_snapshot_file="${tmpdir}/api-snapshot.json"
263
-
264
- ACP_PROFILE_REGISTRY_ROOT="${profile_registry_root}" python3 "${SNAPSHOT_BIN}" --pretty >"${snapshot_file}"
265
-
266
- bash "${SERVER_BIN}" --host 127.0.0.1 --port "${port}" --registry-root "${profile_registry_root}" >"${tmpdir}/server.log" 2>&1 &
267
- server_pid="$!"
268
-
269
- for _ in $(seq 1 10); do
270
- if curl -fsS "http://127.0.0.1:${port}/api/snapshot.json" >/dev/null 2>&1; then
271
- break
272
- fi
273
- sleep 1
274
- done
275
-
276
- curl -fsS "http://127.0.0.1:${port}/api/snapshot.json" >"${api_snapshot_file}"
277
- html="$(curl -fsS "http://127.0.0.1:${port}/")"
278
-
279
- status_output="$(
280
- ACP_PROFILE_REGISTRY_ROOT="${profile_registry_root}" \
281
- ACP_PROJECT_RUNTIME_LAUNCHCTL_BIN="/nonexistent" \
282
- bash "${RUNTIMECTL_BIN}" status --profile-id demo
283
- )"
284
-
285
- grep -q '^RUNTIME_STATUS=running$' <<<"${status_output}"
286
- grep -q "^HEARTBEAT_PID=${heartbeat_pid}$" <<<"${status_output}"
287
- grep -q "^HEARTBEAT_PARENT_PID=${supervisor_pid}$" <<<"${status_output}"
288
- grep -q "^SHARED_LOOP_PID=${shared_loop_pid}$" <<<"${status_output}"
289
- grep -q "^SUPERVISOR_PID=${supervisor_pid}$" <<<"${status_output}"
290
- grep -q '^CONTROLLER_COUNT=1$' <<<"${status_output}"
291
-
292
- grep -q 'ACP Worker Dashboard' <<<"${html}"
293
- grep -q 'Track active runs, resident controllers, queue pressure, and provider failover in one place.' <<<"${html}"
294
-
295
- python3 - "${snapshot_file}" "${api_snapshot_file}" <<'PY'
296
- import json
297
- import sys
298
-
299
- snapshot_path, api_path = sys.argv[1], sys.argv[2]
300
- snapshot = json.load(open(snapshot_path, encoding="utf-8"))
301
- api_snapshot = json.load(open(api_path, encoding="utf-8"))
302
-
303
- assert snapshot["profile_count"] == 1
304
- assert api_snapshot["profile_count"] == 1
305
-
306
- profile = snapshot["profiles"][0]
307
- api_profile = api_snapshot["profiles"][0]
308
-
309
- assert profile["id"] == "demo"
310
- assert profile["repo_slug"] == "example/demo-control-plane"
311
- assert profile["counts"]["implemented_runs"] == 1
312
- assert profile["counts"]["reported_runs"] == 1
313
- assert profile["counts"]["blocked_runs"] == 0
314
- assert profile["counts"]["live_resident_controllers"] == 1
315
- assert profile["counts"]["resident_workers"] == 2
316
- assert profile["counts"]["queued_issues"] == 1
317
- assert profile["counts"]["provider_cooldowns"] == 1
318
- assert profile["counts"]["scheduled_issues"] == 1
319
-
320
- runs = {item["session"]: item for item in profile["runs"]}
321
- assert runs["demo-issue-2"]["result_kind"] == "implemented"
322
- assert runs["demo-issue-2"]["action"] == "host-publish-issue-pr"
323
- assert runs["demo-issue-3"]["result_kind"] == "reported"
324
- assert runs["demo-issue-3"]["action"] == "host-comment-scheduled-report"
325
-
326
- controllers = {item["issue_id"]: item for item in profile["resident_controllers"]}
327
- controller = controllers["2"]
328
- assert controller["state"] == "waiting-provider"
329
- assert controller["controller_live"] is True
330
- assert controller["provider_failover_count"] == 1
331
- assert controller["provider_wait_total_seconds"] == 90
332
-
333
- workers = {item["key"]: item for item in profile["resident_workers"]}
334
- assert workers["issue-lane-recurring-general-openclaw-safe"]["last_action"] == "host-publish-issue-pr"
335
- assert workers["issue-lane-scheduled-1800-openclaw-safe"]["last_action"] == "host-comment-scheduled-report"
336
-
337
- assert api_profile["counts"]["implemented_runs"] == 1
338
- assert api_profile["counts"]["reported_runs"] == 1
339
- assert api_profile["counts"]["live_resident_controllers"] == 1
340
- assert api_profile["counts"]["scheduled_issues"] == 1
341
- PY
342
-
343
- echo "control plane dashboard runtime smoke test passed"
@@ -1,73 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- FLOW_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5
- SCRIPT="${FLOW_ROOT}/tools/bin/create-follow-up-issue.sh"
6
-
7
- tmpdir="$(mktemp -d)"
8
- trap 'rm -rf "$tmpdir"' EXIT
9
-
10
- bin_dir="$tmpdir/bin"
11
- labels_log="$tmpdir/labels.log"
12
- body_capture="$tmpdir/body.txt"
13
- mkdir -p "$bin_dir"
14
-
15
- cat >"$bin_dir/gh" <<'EOF'
16
- #!/usr/bin/env bash
17
- set -euo pipefail
18
-
19
- if [[ "${1:-}" == "issue" && "${2:-}" == "create" ]]; then
20
- body_file=""
21
- while [[ $# -gt 0 ]]; do
22
- case "$1" in
23
- --body-file)
24
- body_file="${2:-}"
25
- shift 2
26
- ;;
27
- *)
28
- shift
29
- ;;
30
- esac
31
- done
32
- cat "$body_file" >"${TEST_BODY_CAPTURE:?}"
33
- printf 'https://github.com/example/repo/issues/912\n'
34
- exit 0
35
- fi
36
-
37
- echo "unexpected gh args: $*" >&2
38
- exit 1
39
- EOF
40
- chmod +x "$bin_dir/gh"
41
-
42
- cat >"$bin_dir/agent-github-update-labels" <<'EOF'
43
- #!/usr/bin/env bash
44
- set -euo pipefail
45
- printf '%s\n' "$*" >"${TEST_LABELS_LOG:?}"
46
- EOF
47
- chmod +x "$bin_dir/agent-github-update-labels"
48
-
49
- body_file="$tmpdir/follow-up.md"
50
- cat >"$body_file" <<'EOF'
51
- Target slice: mobile settings language cluster
52
-
53
- - Keep PR to one route family
54
- - Reuse account cluster shell
55
- EOF
56
-
57
- TEST_BODY_CAPTURE="$body_capture" \
58
- TEST_LABELS_LOG="$labels_log" \
59
- UPDATE_LABELS_BIN="$bin_dir/agent-github-update-labels" \
60
- PATH="$bin_dir:$PATH" \
61
- bash "$SCRIPT" \
62
- --parent 421 \
63
- --title "Mobile settings: split language cluster from umbrella" \
64
- --body-file "$body_file" \
65
- --label agent-e2e-heavy >"$tmpdir/out.txt"
66
-
67
- grep -q '^ISSUE_NUMBER=912$' "$tmpdir/out.txt"
68
- grep -q '^ISSUE_URL=https://github.com/example/repo/issues/912$' "$tmpdir/out.txt"
69
- grep -q '^Parent issue: #421$' "$body_capture"
70
- grep -q 'Target slice: mobile settings language cluster' "$body_capture"
71
- grep -q -- '--number 912 --add agent-e2e-heavy' "$labels_log"
72
-
73
- echo "create follow-up issue test passed"
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- FLOW_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5
- BOOTSTRAP_BIN="${FLOW_ROOT}/tools/bin/dashboard-launchd-bootstrap.sh"
6
-
7
- tmpdir="$(mktemp -d)"
8
- trap 'rm -rf "$tmpdir"' EXIT
9
-
10
- home_dir="$tmpdir/home"
11
- runtime_home="$tmpdir/runtime-home"
12
- profile_registry_root="$tmpdir/profiles"
13
- capture_dir="$tmpdir/capture"
14
- sync_script="$tmpdir/sync.sh"
15
- runtime_serve_script="$runtime_home/skills/openclaw/agent-control-plane/tools/bin/serve-dashboard.sh"
16
-
17
- mkdir -p "$home_dir" "$profile_registry_root" "$(dirname "$runtime_serve_script")" "$capture_dir"
18
-
19
- cat >"$sync_script" <<'EOF'
20
- #!/usr/bin/env bash
21
- set -euo pipefail
22
- printf 'SYNC_SOURCE=%s\n' "$1" >"${ACP_DASHBOARD_CAPTURE_DIR}/sync.log"
23
- printf 'SYNC_TARGET=%s\n' "$2" >>"${ACP_DASHBOARD_CAPTURE_DIR}/sync.log"
24
- EOF
25
- chmod +x "$sync_script"
26
-
27
- cat >"$runtime_serve_script" <<'EOF'
28
- #!/usr/bin/env bash
29
- set -euo pipefail
30
- printf 'ARGS=%s %s %s %s\n' "$1" "$2" "$3" "$4" >"${ACP_DASHBOARD_CAPTURE_DIR}/serve.log"
31
- printf 'PROFILE_REGISTRY_ROOT=%s\n' "${ACP_PROFILE_REGISTRY_ROOT:-}" >>"${ACP_DASHBOARD_CAPTURE_DIR}/serve.log"
32
- printf 'HOME=%s\n' "${HOME:-}" >>"${ACP_DASHBOARD_CAPTURE_DIR}/serve.log"
33
- printf 'PYTHONDONTWRITEBYTECODE=%s\n' "${PYTHONDONTWRITEBYTECODE:-}" >>"${ACP_DASHBOARD_CAPTURE_DIR}/serve.log"
34
- EOF
35
- chmod +x "$runtime_serve_script"
36
-
37
- ACP_DASHBOARD_HOME_DIR="$home_dir" \
38
- ACP_DASHBOARD_SOURCE_HOME="$tmpdir/source-home" \
39
- ACP_DASHBOARD_RUNTIME_HOME="$runtime_home" \
40
- ACP_DASHBOARD_PROFILE_REGISTRY_ROOT="$profile_registry_root" \
41
- ACP_DASHBOARD_HOST="127.0.0.1" \
42
- ACP_DASHBOARD_PORT="9911" \
43
- ACP_DASHBOARD_SYNC_SCRIPT="$sync_script" \
44
- ACP_DASHBOARD_RUNTIME_SERVE_SCRIPT="$runtime_serve_script" \
45
- ACP_DASHBOARD_CAPTURE_DIR="$capture_dir" \
46
- bash "$BOOTSTRAP_BIN"
47
-
48
- grep -q "^SYNC_SOURCE=$tmpdir/source-home$" "$capture_dir/sync.log"
49
- grep -q "^SYNC_TARGET=$runtime_home$" "$capture_dir/sync.log"
50
- grep -q '^ARGS=--host 127.0.0.1 --port 9911$' "$capture_dir/serve.log"
51
- grep -q "^PROFILE_REGISTRY_ROOT=$profile_registry_root$" "$capture_dir/serve.log"
52
- grep -q "^HOME=$home_dir$" "$capture_dir/serve.log"
53
- grep -q '^PYTHONDONTWRITEBYTECODE=1$' "$capture_dir/serve.log"
54
-
55
- echo "dashboard launchd bootstrap test passed"
@@ -1,30 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- FLOW_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5
- CONFIG_LIB="${FLOW_ROOT}/tools/bin/flow-config-lib.sh"
6
-
7
- tmpdir="$(mktemp -d)"
8
- trap 'rm -rf "$tmpdir"' EXIT
9
-
10
- config_file="$tmpdir/control-plane.yaml"
11
-
12
- cat >"$config_file" <<'EOF'
13
- schema_version: "1"
14
- id: "demo"
15
- repo:
16
- slug: "example/repo"
17
- id: "123"
18
- default_branch: "main"
19
- EOF
20
-
21
- output="$(
22
- bash -lc 'source "'"$CONFIG_LIB"'"; flow_export_execution_env "'"$config_file"'"; printf "ACP_REPO_ID=%s\nF_LOSNING_REPO_ID=%s\nACP_GITHUB_REPOSITORY_ID=%s\nF_LOSNING_GITHUB_REPOSITORY_ID=%s\n" "${ACP_REPO_ID:-}" "${F_LOSNING_REPO_ID:-}" "${ACP_GITHUB_REPOSITORY_ID:-}" "${F_LOSNING_GITHUB_REPOSITORY_ID:-}"'
23
- )"
24
-
25
- grep -q '^ACP_REPO_ID=123$' <<<"$output"
26
- grep -q '^F_LOSNING_REPO_ID=123$' <<<"$output"
27
- grep -q '^ACP_GITHUB_REPOSITORY_ID=123$' <<<"$output"
28
- grep -q '^F_LOSNING_GITHUB_REPOSITORY_ID=123$' <<<"$output"
29
-
30
- echo "flow export execution env exports repo id test passed"
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- FLOW_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5
- REAL_CONFIG_LIB="${FLOW_ROOT}/tools/bin/flow-config-lib.sh"
6
- REAL_SHELL_LIB="${FLOW_ROOT}/tools/bin/flow-shell-lib.sh"
7
-
8
- tmpdir="$(mktemp -d)"
9
- trap 'rm -rf "$tmpdir"' EXIT
10
-
11
- bin_dir="$tmpdir/bin"
12
- mkdir -p "$bin_dir"
13
-
14
- cp "$REAL_CONFIG_LIB" "$bin_dir/flow-config-lib.sh"
15
- cp "$REAL_SHELL_LIB" "$bin_dir/flow-shell-lib.sh"
16
-
17
- cat >"$bin_dir/git" <<'EOF'
18
- #!/usr/bin/env bash
19
- set -euo pipefail
20
- if [[ "${1:-}" == "credential" && "${2:-}" == "fill" ]]; then
21
- cat >/dev/null
22
- printf 'protocol=https\n'
23
- printf 'host=github.com\n'
24
- printf 'username=test-user\n'
25
- printf 'password=repo-specific-token\n'
26
- exit 0
27
- fi
28
- exit 1
29
- EOF
30
- chmod +x "$bin_dir/git"
31
-
32
- output="$(
33
- LIB_PATH="$bin_dir/flow-config-lib.sh" \
34
- PATH="$bin_dir:/usr/bin:/bin:/usr/sbin:/sbin" \
35
- GITHUB_PERSONAL_ACCESS_TOKEN="env-fallback-token" \
36
- bash <<'EOF'
37
- set -euo pipefail
38
- source "$LIB_PATH"
39
- unset GH_TOKEN
40
- unset GITHUB_TOKEN
41
- flow_export_github_cli_auth_env "owner/repo"
42
- printf 'GH_TOKEN=%s\n' "${GH_TOKEN:-}"
43
- EOF
44
- )"
45
-
46
- grep -q '^GH_TOKEN=repo-specific-token$' <<<"$output"
47
-
48
- echo "flow export github cli auth env prefers git credential test passed"
@@ -1,85 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- FLOW_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5
- REAL_CONFIG_LIB="${FLOW_ROOT}/tools/bin/flow-config-lib.sh"
6
- REAL_SHELL_LIB="${FLOW_ROOT}/tools/bin/flow-shell-lib.sh"
7
-
8
- tmpdir="$(mktemp -d)"
9
- trap 'rm -rf "$tmpdir"' EXIT
10
-
11
- bin_dir="$tmpdir/bin"
12
- mkdir -p "$bin_dir"
13
-
14
- cp "$REAL_CONFIG_LIB" "$bin_dir/flow-config-lib.sh"
15
- cp "$REAL_SHELL_LIB" "$bin_dir/flow-shell-lib.sh"
16
-
17
- captured_payload_file="$tmpdir/captured-payload.json"
18
- cat >"$bin_dir/gh" <<'EOF'
19
- #!/usr/bin/env bash
20
- set -euo pipefail
21
-
22
- if [[ "${1:-}" != "api" ]]; then
23
- echo "unexpected gh invocation: $*" >&2
24
- exit 1
25
- fi
26
-
27
- route="${2:-}"
28
- shift 2 || true
29
-
30
- input_file=""
31
- while [[ $# -gt 0 ]]; do
32
- case "$1" in
33
- --input)
34
- input_file="${2:-}"
35
- shift 2
36
- ;;
37
- *)
38
- shift
39
- ;;
40
- esac
41
- done
42
-
43
- case "$route" in
44
- repos/example/repo/issues/42)
45
- if [[ -n "$input_file" && -f "$input_file" ]]; then
46
- cat "$input_file" >/dev/null
47
- fi
48
- exit 1
49
- ;;
50
- repositories/123/issues/42)
51
- if [[ -z "$input_file" || ! -f "$input_file" ]]; then
52
- echo "missing preserved input file" >&2
53
- exit 97
54
- fi
55
- cp "$input_file" "${TEST_CAPTURED_PAYLOAD_FILE:?}"
56
- printf '{"number":42,"state":"open"}\n'
57
- exit 0
58
- ;;
59
- *)
60
- echo "unexpected gh api route: $route" >&2
61
- exit 1
62
- ;;
63
- esac
64
- EOF
65
-
66
- chmod +x "$bin_dir/flow-config-lib.sh" "$bin_dir/flow-shell-lib.sh" "$bin_dir/gh"
67
-
68
- output="$(
69
- LIB_PATH="$bin_dir/flow-config-lib.sh" \
70
- PATH="$bin_dir:/usr/bin:/bin:/usr/sbin:/sbin" \
71
- ACP_REPO_ID="123" \
72
- ACP_REPO_SLUG="example/repo" \
73
- TEST_CAPTURED_PAYLOAD_FILE="$captured_payload_file" \
74
- bash <<'EOF'
75
- set -euo pipefail
76
- source "$LIB_PATH"
77
- printf '{"body":"patched body"}' | flow_github_api_repo "example/repo" "issues/42" --method PATCH --input -
78
- EOF
79
- )"
80
-
81
- test "$(jq -r '.number' <<<"$output")" = "42"
82
- test "$(jq -r '.state' <<<"$output")" = "open"
83
- test "$(jq -r '.body' "$captured_payload_file")" = "patched body"
84
-
85
- echo "flow github api repo fallback preserves input test passed"