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,261 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- # shellcheck source=/dev/null
6
- source "${SCRIPT_DIR}/flow-config-lib.sh"
7
-
8
- PR_NUMBER="${1:?usage: start-pr-review-worker.sh PR_NUMBER [safe|bypass]}"
9
- MODE="${2:-safe}"
10
- WORKSPACE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
11
- FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
12
- if ! flow_require_explicit_profile_selection "${FLOW_SKILL_DIR}" "start-pr-review-worker.sh"; then
13
- exit 64
14
- fi
15
- CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
16
- flow_export_execution_env "${CONFIG_YAML}"
17
- flow_export_project_env_aliases
18
- AGENT_ROOT="$(flow_resolve_agent_root "${CONFIG_YAML}")"
19
- PR_SESSION_PREFIX="$(flow_resolve_pr_session_prefix "${CONFIG_YAML}")"
20
- MANAGED_PR_BRANCH_GLOBS="$(flow_resolve_managed_pr_branch_globs "${CONFIG_YAML}")"
21
- RUNS_ROOT="$(flow_resolve_runs_root "${CONFIG_YAML}")"
22
- HISTORY_ROOT="$(flow_resolve_history_root "${CONFIG_YAML}")"
23
- REPO_SLUG="$(flow_resolve_repo_slug "${CONFIG_YAML}")"
24
- TEMPLATE_FILE="$(flow_resolve_template_file "pr-review-template.md" "${WORKSPACE_DIR}" "${CONFIG_YAML}")"
25
- SESSION="${PR_SESSION_PREFIX}${PR_NUMBER}"
26
- RUN_DIR="${RUNS_ROOT}/${SESSION}"
27
- UPDATE_LABELS_BIN="${WORKSPACE_DIR}/bin/agent-github-update-labels"
28
- launch_success="no"
29
- label_rollback_armed="no"
30
-
31
- rollback_labels_on_failure() {
32
- if [[ "${label_rollback_armed}" != "yes" || "${launch_success}" == "yes" ]]; then
33
- return 0
34
- fi
35
- if [[ -d "${RUN_DIR}" && ! -f "${RUN_DIR}/run.env" && ! -f "${RUN_DIR}/runner.env" && ! -f "${RUN_DIR}/result.env" ]]; then
36
- rm -rf "${RUN_DIR}" >/dev/null 2>&1 || true
37
- fi
38
- if [[ -x "${UPDATE_LABELS_BIN}" ]]; then
39
- bash "${UPDATE_LABELS_BIN}" --repo-slug "${REPO_SLUG}" --number "${PR_NUMBER}" --remove agent-running >/dev/null 2>&1 || true
40
- fi
41
- }
42
-
43
- reap_stale_run_dir() {
44
- if [[ ! -d "$RUN_DIR" ]]; then
45
- return 0
46
- fi
47
- if [[ -f "$RUN_DIR/run.env" ]]; then
48
- if "${WORKSPACE_DIR}/bin/cleanup-worktree.sh" "" "$SESSION" >/dev/null 2>&1; then
49
- return 0
50
- fi
51
- fi
52
- mkdir -p "$HISTORY_ROOT"
53
- mv "$RUN_DIR" "${HISTORY_ROOT}/${SESSION}-stale-$(date +%Y%m%d-%H%M%S)"
54
- }
55
-
56
- is_managed_agent_pr_branch() {
57
- local head_ref="${1:-}"
58
- local branch_glob=""
59
- for branch_glob in ${MANAGED_PR_BRANCH_GLOBS}; do
60
- case "$head_ref" in
61
- ${branch_glob}) return 0 ;;
62
- esac
63
- done
64
- return 1
65
- }
66
-
67
- if tmux has-session -t "$SESSION" 2>/dev/null; then
68
- echo "worker session already exists: $SESSION" >&2
69
- exit 1
70
- fi
71
-
72
- label_rollback_armed="yes"
73
- trap rollback_labels_on_failure EXIT INT TERM
74
-
75
- if [[ -d "$RUN_DIR" ]]; then
76
- reap_stale_run_dir
77
- fi
78
-
79
- PR_JSON="$(flow_github_pr_view_json "$REPO_SLUG" "$PR_NUMBER")"
80
- PR_TITLE="$(jq -r '.title' <<<"$PR_JSON")"
81
- PR_BODY="$(jq -r '.body // ""' <<<"$PR_JSON")"
82
- PR_URL="$(jq -r '.url' <<<"$PR_JSON")"
83
- PR_HEAD_REF="$(jq -r '.headRefName' <<<"$PR_JSON")"
84
- PR_BASE_REF="$(jq -r '.baseRefName' <<<"$PR_JSON")"
85
- PR_MERGE_STATE_STATUS="$(jq -r '.mergeStateStatus // "UNKNOWN"' <<<"$PR_JSON")"
86
- PR_HAS_HANDOFF_LABEL="$(jq -r 'any(.labels[]?; .name == "agent-handoff")' <<<"$PR_JSON")"
87
- PR_HAS_AGENT_STATUS_COMMENT="$(jq -r 'any(.comments[]?; ((.body // "") | test("^## PR (final review blocker|repair worker summary|repair summary|repair update)"; "i")))' <<<"$PR_JSON")"
88
- PR_CHECKS_TEXT="$(jq -r '
89
- if ((.statusCheckRollup // []) | length) == 0 then
90
- "- none"
91
- else
92
- (.statusCheckRollup // [])
93
- | map(
94
- "- "
95
- + (.name // .context // "unknown-check")
96
- + ": "
97
- + (.status // "UNKNOWN")
98
- + (
99
- if (.conclusion // "") != "" then
100
- " / " + .conclusion
101
- else
102
- ""
103
- end
104
- )
105
- )
106
- | join("\n")
107
- end
108
- ' <<<"$PR_JSON")"
109
-
110
- if ! is_managed_agent_pr_branch "$PR_HEAD_REF" && [[ "$PR_HAS_HANDOFF_LABEL" != "true" ]] && [[ "$PR_HAS_AGENT_STATUS_COMMENT" != "true" ]]; then
111
- echo "PR branch is not an agent branch: $PR_HEAD_REF" >&2
112
- exit 1
113
- fi
114
-
115
- RISK_JSON="$("${WORKSPACE_DIR}/bin/pr-risk.sh" "$PR_NUMBER")"
116
- PR_RISK="$(jq -r '.risk' <<<"$RISK_JSON")"
117
- PR_RISK_REASON="$(jq -r '.riskReason' <<<"$RISK_JSON")"
118
- PR_AGENT_LANE="$(jq -r '.agentLane' <<<"$RISK_JSON")"
119
- PR_DOUBLE_CHECK_STAGE="$(jq -r '.currentDoubleCheckStage // 0' <<<"$RISK_JSON")"
120
- PR_LINKED_ISSUE_ID="$(jq -r '.linkedIssueId // ""' <<<"$RISK_JSON")"
121
- PR_CHECKS_BYPASSED="$(jq -r '.checksBypassed // false' <<<"$RISK_JSON")"
122
- PR_FILES_TEXT="$(jq -r '.files[] | "- " + .' <<<"$RISK_JSON")"
123
- PR_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
124
- PR_DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-${F_LOSNING_DEPENDENCY_SOURCE_ROOT:-$PR_REPO_ROOT}}"
125
-
126
- render_pr_context_reads_text() {
127
- local repo_root="${1:?repo root required}"
128
- local -a candidate_paths=(
129
- "${repo_root}/AGENTS.md"
130
- "${repo_root}/openspec/AGENT_RULES.md"
131
- "${repo_root}/openspec/AGENTS.md"
132
- "${repo_root}/openspec/project.md"
133
- "${repo_root}/openspec/CONVENTIONS.md"
134
- "${repo_root}/docs/TESTING_AND_SEED_POLICY.md"
135
- )
136
- local -a existing_paths=()
137
- local candidate_path=""
138
-
139
- for candidate_path in "${candidate_paths[@]}"; do
140
- if [[ -f "${candidate_path}" ]]; then
141
- existing_paths+=("${candidate_path}")
142
- fi
143
- done
144
-
145
- if [[ "${#existing_paths[@]}" -eq 0 ]]; then
146
- printf '%s\n' '- No repo-specific context files were found under the expected AGENTS/OpenSpec/testing-doc locations; rely on the current diff and nearby source.'
147
- return 0
148
- fi
149
-
150
- printf '%s\n' "${existing_paths[@]}" | sed 's/^/- `/' | sed 's/$/`/'
151
- }
152
-
153
- PR_CONTEXT_READS_TEXT="$(render_pr_context_reads_text "${PR_REPO_ROOT}")"
154
-
155
- case "$PR_AGENT_LANE" in
156
- double-check-1)
157
- PR_REVIEW_STAGE_TEXT="Independent agent double-check 1 of 2. A clean pass should advance this PR to the second review pass, not merge it yet."
158
- ;;
159
- double-check-2)
160
- PR_REVIEW_STAGE_TEXT="Independent agent double-check 2 of 2. Review this PR from scratch again; a clean pass may let host reconcile merge it."
161
- ;;
162
- *)
163
- PR_REVIEW_STAGE_TEXT="Single final agent review before merge."
164
- ;;
165
- esac
166
-
167
- WORKTREE_OUT="$("${WORKSPACE_DIR}/bin/new-pr-worktree.sh" "$PR_NUMBER" "$PR_HEAD_REF")"
168
- WORKTREE="$(awk -F= '/^WORKTREE=/{print $2}' <<<"$WORKTREE_OUT")"
169
-
170
- mkdir -p "$RUN_DIR"
171
- PROMPT_FILE="${RUN_DIR}/prompt.md"
172
-
173
- PR_NUMBER="$PR_NUMBER" \
174
- PR_TITLE="$PR_TITLE" \
175
- PR_URL="$PR_URL" \
176
- PR_HEAD_REF="$PR_HEAD_REF" \
177
- PR_BASE_REF="$PR_BASE_REF" \
178
- PR_BODY="$PR_BODY" \
179
- PR_RISK="$PR_RISK" \
180
- PR_RISK_REASON="$PR_RISK_REASON" \
181
- PR_AGENT_LANE="$PR_AGENT_LANE" \
182
- PR_DOUBLE_CHECK_STAGE="$PR_DOUBLE_CHECK_STAGE" \
183
- PR_REVIEW_STAGE_TEXT="$PR_REVIEW_STAGE_TEXT" \
184
- PR_LINKED_ISSUE_ID="$PR_LINKED_ISSUE_ID" \
185
- PR_CHECKS_BYPASSED="$PR_CHECKS_BYPASSED" \
186
- PR_MERGE_STATE_STATUS="$PR_MERGE_STATE_STATUS" \
187
- PR_CHECKS_TEXT="$PR_CHECKS_TEXT" \
188
- PR_FILES_TEXT="$PR_FILES_TEXT" \
189
- PR_CONTEXT_READS_TEXT="$PR_CONTEXT_READS_TEXT" \
190
- PR_REPO_ROOT="$PR_REPO_ROOT" \
191
- PR_DEPENDENCY_SOURCE_ROOT="$PR_DEPENDENCY_SOURCE_ROOT" \
192
- REPO_SLUG="$REPO_SLUG" \
193
- TEMPLATE_FILE="$TEMPLATE_FILE" \
194
- node <<'EOF' >"$PROMPT_FILE"
195
- const fs = require('fs');
196
-
197
- const template = fs.readFileSync(process.env.TEMPLATE_FILE, 'utf8');
198
- const replacements = {
199
- '{PR_NUMBER}': process.env.PR_NUMBER || '',
200
- '{PR_TITLE}': process.env.PR_TITLE || '',
201
- '{PR_URL}': process.env.PR_URL || '',
202
- '{PR_HEAD_REF}': process.env.PR_HEAD_REF || '',
203
- '{PR_BASE_REF}': process.env.PR_BASE_REF || '',
204
- '{PR_BODY}': process.env.PR_BODY || '',
205
- '{REPO_SLUG}': process.env.REPO_SLUG || '',
206
- '{PR_RISK}': process.env.PR_RISK || '',
207
- '{PR_RISK_REASON}': process.env.PR_RISK_REASON || '',
208
- '{PR_AGENT_LANE}': process.env.PR_AGENT_LANE || '',
209
- '{PR_DOUBLE_CHECK_STAGE}': process.env.PR_DOUBLE_CHECK_STAGE || '0',
210
- '{PR_REVIEW_STAGE_TEXT}': process.env.PR_REVIEW_STAGE_TEXT || '',
211
- '{PR_LINKED_ISSUE_ID}': process.env.PR_LINKED_ISSUE_ID || '',
212
- '{PR_CHECKS_BYPASSED}': process.env.PR_CHECKS_BYPASSED || 'false',
213
- '{PR_MERGE_STATE_STATUS}': process.env.PR_MERGE_STATE_STATUS || '',
214
- '{PR_CHECKS_TEXT}': process.env.PR_CHECKS_TEXT || '',
215
- '{PR_FILES_TEXT}': process.env.PR_FILES_TEXT || '',
216
- '{PR_CONTEXT_READS_TEXT}': process.env.PR_CONTEXT_READS_TEXT || '',
217
- '{REPO_ROOT}': process.env.PR_REPO_ROOT || '',
218
- '{DEPENDENCY_SOURCE_ROOT}': process.env.PR_DEPENDENCY_SOURCE_ROOT || '',
219
- };
220
-
221
- let rendered = template;
222
- for (const [key, value] of Object.entries(replacements)) {
223
- rendered = rendered.split(key).join(value);
224
- }
225
- process.stdout.write(rendered);
226
- EOF
227
-
228
- case "$MODE" in
229
- safe)
230
- F_LOSNING_PR_NUMBER="$PR_NUMBER" \
231
- F_LOSNING_PR_URL="$PR_URL" \
232
- F_LOSNING_PR_HEAD_REF="$PR_HEAD_REF" \
233
- F_LOSNING_ISSUE_ID="$PR_LINKED_ISSUE_ID" \
234
- "${WORKSPACE_DIR}/bin/run-codex-safe.sh" "$SESSION" "$WORKTREE" "$PROMPT_FILE"
235
- ;;
236
- bypass)
237
- F_LOSNING_PR_NUMBER="$PR_NUMBER" \
238
- F_LOSNING_PR_URL="$PR_URL" \
239
- F_LOSNING_PR_HEAD_REF="$PR_HEAD_REF" \
240
- F_LOSNING_ISSUE_ID="$PR_LINKED_ISSUE_ID" \
241
- "${WORKSPACE_DIR}/bin/run-codex-bypass.sh" "$SESSION" "$WORKTREE" "$PROMPT_FILE"
242
- ;;
243
- *)
244
- echo "unknown mode: $MODE" >&2
245
- exit 1
246
- ;;
247
- esac
248
-
249
- launch_success="yes"
250
-
251
- printf 'PR_NUMBER=%s\n' "$PR_NUMBER"
252
- printf 'TITLE=%s\n' "$PR_TITLE"
253
- printf 'URL=%s\n' "$PR_URL"
254
- printf 'HEAD_REF=%s\n' "$PR_HEAD_REF"
255
- printf 'BASE_REF=%s\n' "$PR_BASE_REF"
256
- printf 'LINKED_ISSUE_ID=%s\n' "$PR_LINKED_ISSUE_ID"
257
- printf 'RISK=%s\n' "$PR_RISK"
258
- printf 'RISK_REASON=%s\n' "$PR_RISK_REASON"
259
- printf 'SESSION=%s\n' "$SESSION"
260
- printf 'WORKTREE=%s\n' "$WORKTREE"
261
- printf 'PROMPT=%s\n' "$PROMPT_FILE"