agent-control-plane 0.4.9 → 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 (80) hide show
  1. package/README.md +72 -9
  2. package/npm/bin/agent-control-plane.js +1 -1
  3. package/package.json +39 -33
  4. package/tools/bin/debug-session.sh +106 -0
  5. package/tools/bin/flow-runtime-doctor-linux.sh +136 -0
  6. package/tools/bin/flow-runtime-doctor.sh +5 -1
  7. package/tools/bin/install-project-systemd.sh +255 -0
  8. package/tools/bin/project-runtimectl.sh +45 -0
  9. package/tools/bin/project-systemd-bootstrap.sh +74 -0
  10. package/tools/bin/uninstall-project-systemd.sh +87 -0
  11. package/tools/dashboard/app.js +198 -5
  12. package/tools/dashboard/issue_queue_state.py +101 -0
  13. package/tools/dashboard/server.py +123 -1
  14. package/tools/dashboard/styles.css +526 -455
  15. package/tools/bin/agent-cleanup-worktree +0 -247
  16. package/tools/bin/agent-github-update-labels +0 -105
  17. package/tools/bin/agent-init-worktree +0 -216
  18. package/tools/bin/agent-project-archive-run +0 -52
  19. package/tools/bin/agent-project-capture-worker +0 -46
  20. package/tools/bin/agent-project-catch-up-issue-pr-links +0 -118
  21. package/tools/bin/agent-project-catch-up-merged-prs +0 -195
  22. package/tools/bin/agent-project-catch-up-scheduled-issue-retries +0 -123
  23. package/tools/bin/agent-project-cleanup-session +0 -513
  24. package/tools/bin/agent-project-detached-launch +0 -127
  25. package/tools/bin/agent-project-heartbeat-loop +0 -1029
  26. package/tools/bin/agent-project-open-issue-worktree +0 -89
  27. package/tools/bin/agent-project-open-pr-worktree +0 -80
  28. package/tools/bin/agent-project-publish-issue-pr +0 -468
  29. package/tools/bin/agent-project-reconcile-issue-session +0 -1409
  30. package/tools/bin/agent-project-reconcile-pr-session +0 -1288
  31. package/tools/bin/agent-project-retry-state +0 -158
  32. package/tools/bin/agent-project-run-claude-session +0 -805
  33. package/tools/bin/agent-project-run-codex-resilient +0 -963
  34. package/tools/bin/agent-project-run-codex-session +0 -435
  35. package/tools/bin/agent-project-run-kilo-session +0 -369
  36. package/tools/bin/agent-project-run-ollama-session +0 -658
  37. package/tools/bin/agent-project-run-openclaw-session +0 -1309
  38. package/tools/bin/agent-project-run-opencode-session +0 -377
  39. package/tools/bin/agent-project-run-pi-session +0 -479
  40. package/tools/bin/agent-project-sync-anchor-repo +0 -139
  41. package/tools/bin/agent-project-sync-source-repo-main +0 -163
  42. package/tools/bin/agent-project-worker-status +0 -188
  43. package/tools/bin/branch-verification-guard.sh +0 -364
  44. package/tools/bin/capture-worker.sh +0 -18
  45. package/tools/bin/cleanup-worktree.sh +0 -52
  46. package/tools/bin/codex-quota +0 -31
  47. package/tools/bin/create-follow-up-issue.sh +0 -114
  48. package/tools/bin/dashboard-launchd-bootstrap.sh +0 -50
  49. package/tools/bin/issue-publish-localization-guard.sh +0 -142
  50. package/tools/bin/issue-publish-scope-guard.sh +0 -242
  51. package/tools/bin/issue-requires-local-workspace-install.sh +0 -31
  52. package/tools/bin/issue-resource-class.sh +0 -12
  53. package/tools/bin/kick-scheduler.sh +0 -75
  54. package/tools/bin/label-follow-up-issues.sh +0 -14
  55. package/tools/bin/new-pr-worktree.sh +0 -50
  56. package/tools/bin/new-worktree.sh +0 -49
  57. package/tools/bin/pr-risk.sh +0 -12
  58. package/tools/bin/prepare-worktree.sh +0 -142
  59. package/tools/bin/provider-cooldown-state.sh +0 -204
  60. package/tools/bin/publish-issue-worker.sh +0 -31
  61. package/tools/bin/reconcile-bootstrap-lib.sh +0 -113
  62. package/tools/bin/reconcile-issue-worker.sh +0 -34
  63. package/tools/bin/reconcile-pr-worker.sh +0 -34
  64. package/tools/bin/record-verification.sh +0 -71
  65. package/tools/bin/render-flow-config.sh +0 -98
  66. package/tools/bin/resident-issue-controller-lib.sh +0 -448
  67. package/tools/bin/retry-state.sh +0 -31
  68. package/tools/bin/reuse-issue-worktree.sh +0 -121
  69. package/tools/bin/run-codex-bypass.sh +0 -3
  70. package/tools/bin/run-codex-safe.sh +0 -3
  71. package/tools/bin/run-codex-task.sh +0 -280
  72. package/tools/bin/serve-dashboard.sh +0 -5
  73. package/tools/bin/start-issue-worker.sh +0 -943
  74. package/tools/bin/start-pr-fix-worker.sh +0 -528
  75. package/tools/bin/start-pr-merge-repair-worker.sh +0 -8
  76. package/tools/bin/start-pr-review-worker.sh +0 -261
  77. package/tools/bin/start-resident-issue-loop.sh +0 -499
  78. package/tools/bin/update-github-labels.sh +0 -14
  79. package/tools/bin/worker-status.sh +0 -19
  80. package/tools/bin/workflow-catalog.sh +0 -77
@@ -1,118 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- usage() {
5
- cat <<'EOF'
6
- Usage:
7
- agent-project-catch-up-issue-pr-links --repo-slug <owner/repo> --state-root <path> --hook-file <path> [--limit <n>]
8
-
9
- Clear stale issue retry state when an issue already has a linked PR comment and
10
- that PR still exists (open, closed, or merged).
11
- EOF
12
- }
13
-
14
- repo_slug=""
15
- state_root=""
16
- hook_file=""
17
- limit="100"
18
-
19
- while [[ $# -gt 0 ]]; do
20
- case "$1" in
21
- --repo-slug) repo_slug="${2:-}"; shift 2 ;;
22
- --state-root) state_root="${2:-}"; shift 2 ;;
23
- --hook-file) hook_file="${2:-}"; shift 2 ;;
24
- --limit) limit="${2:-}"; shift 2 ;;
25
- --help|-h) usage; exit 0 ;;
26
- *) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
27
- esac
28
- done
29
-
30
- if [[ -z "$repo_slug" || -z "$state_root" || -z "$hook_file" ]]; then
31
- usage >&2
32
- exit 1
33
- fi
34
-
35
- if [[ ! -f "$hook_file" ]]; then
36
- echo "missing hook file: $hook_file" >&2
37
- exit 1
38
- fi
39
-
40
- # shellcheck source=/dev/null
41
- source "$hook_file"
42
-
43
- if ! declare -F issue_clear_retry >/dev/null 2>&1; then
44
- issue_clear_retry() { :; }
45
- fi
46
-
47
- ledger_dir="${state_root}/linked-pr-issue-catchup"
48
- retry_dir="${state_root}/retries/issues"
49
- mkdir -p "$ledger_dir" "$retry_dir"
50
-
51
- extract_latest_linked_pr() {
52
- local issue_json="${1:-}"
53
- ISSUE_JSON="$issue_json" python3 - <<'PY'
54
- import json
55
- import os
56
- import re
57
-
58
- issue = json.loads(os.environ.get("ISSUE_JSON", "{}") or "{}")
59
- latest = ""
60
- latest_at = ""
61
- for comment in issue.get("comments", []) or []:
62
- body = comment.get("body") or ""
63
- match = None
64
- for candidate in re.finditer(r"Opened PR #(\d+)", body):
65
- match = candidate
66
- if not match:
67
- continue
68
- created = comment.get("createdAt") or ""
69
- pr_number = match.group(1)
70
- if created >= latest_at:
71
- latest_at = created
72
- latest = pr_number
73
-
74
- print(latest)
75
- PY
76
- }
77
-
78
- pr_exists() {
79
- local pr_number="${1:?pr number required}"
80
- local pr_json=""
81
- pr_json="$(flow_github_pr_view_json "$repo_slug" "$pr_number" 2>/dev/null || true)"
82
- [[ -n "$pr_json" && "$pr_json" != "{}" ]]
83
- }
84
-
85
- for retry_file in "$retry_dir"/*.env; do
86
- [[ -f "$retry_file" ]] || continue
87
- issue_id="$(basename "${retry_file%.env}")"
88
- [[ -n "$issue_id" ]] || continue
89
-
90
- retry_reason="$(awk -F= '/^LAST_REASON=/{print $2; exit}' "$retry_file" 2>/dev/null | tr -d '\r' || true)"
91
- if [[ "$retry_reason" != "host-publish-failed" ]]; then
92
- continue
93
- fi
94
-
95
- ledger_file="${ledger_dir}/${issue_id}.env"
96
- if [[ -f "$ledger_file" ]]; then
97
- continue
98
- fi
99
-
100
- issue_json="$(flow_github_issue_view_json "$repo_slug" "$issue_id" 2>/dev/null || true)"
101
- [[ -n "$issue_json" && "$issue_json" != "{}" ]] || continue
102
-
103
- linked_pr="$(extract_latest_linked_pr "$issue_json")"
104
- [[ -n "$linked_pr" ]] || continue
105
- if ! pr_exists "$linked_pr"; then
106
- continue
107
- fi
108
-
109
- ISSUE_ID="$issue_id" issue_clear_retry || true
110
-
111
- {
112
- printf 'ISSUE_ID=%s\n' "$issue_id"
113
- printf 'LINKED_PR=%s\n' "$linked_pr"
114
- printf 'PROCESSED_AT=%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
115
- } >"$ledger_file"
116
-
117
- printf 'CATCHUP_LINKED_PR_ISSUE=%s\n' "$issue_id"
118
- done
@@ -1,195 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- usage() {
5
- cat <<'EOF'
6
- Usage:
7
- agent-project-catch-up-merged-prs --repo-slug <owner/repo> --state-root <path> --hook-file <path> [--limit <n>]
8
-
9
- Catch up merge-cleanup for managed PRs that were merged manually after their
10
- worker session had already been reconciled and cleaned up.
11
- EOF
12
- }
13
-
14
- repo_slug=""
15
- state_root=""
16
- hook_file=""
17
- limit="100"
18
-
19
- while [[ $# -gt 0 ]]; do
20
- case "$1" in
21
- --repo-slug) repo_slug="${2:-}"; shift 2 ;;
22
- --state-root) state_root="${2:-}"; shift 2 ;;
23
- --hook-file) hook_file="${2:-}"; shift 2 ;;
24
- --limit) limit="${2:-}"; shift 2 ;;
25
- --help|-h) usage; exit 0 ;;
26
- *) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
27
- esac
28
- done
29
-
30
- if [[ -z "$repo_slug" || -z "$state_root" || -z "$hook_file" ]]; then
31
- usage >&2
32
- exit 1
33
- fi
34
-
35
- if [[ ! -f "$hook_file" ]]; then
36
- echo "missing hook file: $hook_file" >&2
37
- exit 1
38
- fi
39
-
40
- # shellcheck source=/dev/null
41
- source "$hook_file"
42
-
43
- optional_hooks=(
44
- pr_clear_retry
45
- pr_cleanup_linked_issue_session
46
- pr_cleanup_merged_residue
47
- pr_linked_issue_should_close
48
- pr_after_merged
49
- pr_after_closed
50
- )
51
-
52
- for hook_name in "${optional_hooks[@]}"; do
53
- if ! declare -F "$hook_name" >/dev/null 2>&1; then
54
- eval "${hook_name}() { :; }"
55
- fi
56
- done
57
-
58
- forge_scope="$(printf '%s' "${ACP_FORGE_PROVIDER:-${F_LOSNING_FORGE_PROVIDER:-github}}" | tr -c '[:alnum:]._-' '-')"
59
- merged_ledger_dir="${state_root}/merged-pr-catchup-${forge_scope}"
60
- closed_ledger_dir="${state_root}/closed-pr-catchup-${forge_scope}"
61
- mkdir -p "$merged_ledger_dir" "$closed_ledger_dir"
62
-
63
- get_pr_risk_json() {
64
- local pr_number="${1:?pr number required}"
65
- if declare -F heartbeat_pr_risk_json >/dev/null 2>&1; then
66
- heartbeat_pr_risk_json "$pr_number"
67
- return 0
68
- fi
69
- if [[ -n "${ADAPTER_BIN_DIR:-}" && -x "${ADAPTER_BIN_DIR}/pr-risk.sh" ]]; then
70
- "${ADAPTER_BIN_DIR}/pr-risk.sh" "$pr_number"
71
- return 0
72
- fi
73
- echo "missing PR risk provider for catch-up" >&2
74
- return 1
75
- }
76
-
77
- close_issue_if_needed() {
78
- local pr_number="${1:?pr number required}"
79
- local issue_id="${2:-}"
80
- [[ -n "$issue_id" ]] || return 0
81
-
82
- local should_close="yes"
83
- should_close="$(pr_linked_issue_should_close "$issue_id" || printf 'yes\n')"
84
- if [[ "$should_close" != "yes" ]]; then
85
- return 0
86
- fi
87
-
88
- pr_cleanup_linked_issue_session "$issue_id" || true
89
-
90
- local issue_state=""
91
- issue_state="$(flow_github_issue_view_json "$repo_slug" "$issue_id" 2>/dev/null | jq -r '.state // empty' || true)"
92
- if [[ "$issue_state" == "OPEN" ]]; then
93
- flow_github_issue_close "$repo_slug" "$issue_id" "Closed automatically after PR #${pr_number} merged." >/dev/null 2>&1 || true
94
- printf 'CATCHUP_CLOSED_ISSUE=%s\n' "$issue_id"
95
- fi
96
- }
97
-
98
- process_terminal_pr() {
99
- local pr_number="${1:?pr number required}"
100
- local linked_issue_id="${2:-}"
101
- local merged_at="${3:-}"
102
- local processed_state="${4:?processed state required}"
103
- local ledger_dir=""
104
- local ledger_file=""
105
-
106
- case "$processed_state" in
107
- merged) ledger_dir="$merged_ledger_dir" ;;
108
- closed) ledger_dir="$closed_ledger_dir" ;;
109
- *)
110
- echo "unsupported terminal PR state: ${processed_state}" >&2
111
- return 1
112
- ;;
113
- esac
114
-
115
- ledger_file="${ledger_dir}/${pr_number}.env"
116
- if [[ -f "$ledger_file" ]]; then
117
- return 0
118
- fi
119
-
120
- PR_NUMBER="$pr_number" pr_clear_retry || true
121
- if [[ "$processed_state" == "merged" ]]; then
122
- close_issue_if_needed "$pr_number" "$linked_issue_id"
123
- if ! PR_NUMBER="$pr_number" pr_after_merged "$pr_number"; then
124
- printf 'CATCHUP_FAILED_PR=%s\n' "$pr_number" >&2
125
- return 1
126
- fi
127
- else
128
- if ! PR_NUMBER="$pr_number" pr_after_closed "$pr_number"; then
129
- printf 'CATCHUP_FAILED_CLOSED_PR=%s\n' "$pr_number" >&2
130
- return 1
131
- fi
132
- fi
133
-
134
- if ! PR_NUMBER="$pr_number" pr_cleanup_merged_residue "$pr_number"; then
135
- printf 'CATCHUP_FAILED_RESIDUE=%s\n' "$pr_number" >&2
136
- return 1
137
- fi
138
-
139
- {
140
- printf 'PR_NUMBER=%s\n' "$pr_number"
141
- printf 'ISSUE_ID=%s\n' "$linked_issue_id"
142
- printf 'PR_STATE=%s\n' "$processed_state"
143
- printf 'MERGED_AT=%s\n' "$merged_at"
144
- printf 'PROCESSED_AT=%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
145
- } >"$ledger_file"
146
-
147
- if [[ "$processed_state" == "merged" ]]; then
148
- printf 'CATCHUP_MERGED_PR=%s\n' "$pr_number"
149
- else
150
- printf 'CATCHUP_CLOSED_PR=%s\n' "$pr_number"
151
- fi
152
- }
153
-
154
- merged_prs_json="$(flow_github_pr_list_json "$repo_slug" merged "$limit")"
155
- closed_prs_json="$(flow_github_pr_list_json "$repo_slug" closed "$limit")"
156
-
157
- while IFS= read -r pr_number; do
158
- [[ -n "$pr_number" ]] || continue
159
-
160
- risk_json="$(get_pr_risk_json "$pr_number" 2>/dev/null || true)"
161
- if [[ -z "$risk_json" ]]; then
162
- continue
163
- fi
164
-
165
- is_managed="$(jq -r '.isManagedByAgent // .isAgentBranch // false' <<<"$risk_json" 2>/dev/null || printf 'false\n')"
166
- if [[ "$is_managed" != "true" ]]; then
167
- continue
168
- fi
169
-
170
- linked_issue_id="$(jq -r '.linkedIssueId // empty' <<<"$risk_json" 2>/dev/null || true)"
171
- merged_at="$(jq -r --arg pr "$pr_number" 'map(select((.number | tostring) == $pr)) | .[0].mergedAt // ""' <<<"$merged_prs_json")"
172
- process_terminal_pr "$pr_number" "$linked_issue_id" "$merged_at" merged || true
173
- done < <(jq -r 'sort_by(.mergedAt) | reverse | .[].number' <<<"$merged_prs_json")
174
-
175
- while IFS= read -r pr_number; do
176
- [[ -n "$pr_number" ]] || continue
177
-
178
- merged_at="$(jq -r --arg pr "$pr_number" 'map(select((.number | tostring) == $pr)) | .[0].mergedAt // ""' <<<"$closed_prs_json")"
179
- if [[ -n "$merged_at" ]]; then
180
- continue
181
- fi
182
-
183
- risk_json="$(get_pr_risk_json "$pr_number" 2>/dev/null || true)"
184
- if [[ -z "$risk_json" ]]; then
185
- continue
186
- fi
187
-
188
- is_managed="$(jq -r '.isManagedByAgent // .isAgentBranch // false' <<<"$risk_json" 2>/dev/null || printf 'false\n')"
189
- if [[ "$is_managed" != "true" ]]; then
190
- continue
191
- fi
192
-
193
- linked_issue_id="$(jq -r '.linkedIssueId // empty' <<<"$risk_json" 2>/dev/null || true)"
194
- process_terminal_pr "$pr_number" "$linked_issue_id" "" closed || true
195
- done < <(jq -r 'sort_by(.createdAt) | reverse | .[].number' <<<"$closed_prs_json")
@@ -1,123 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- usage() {
5
- cat <<'EOF'
6
- Usage:
7
- agent-project-catch-up-scheduled-issue-retries --repo-slug <owner/repo> --state-root <path> --hook-file <path> [--limit <n>]
8
-
9
- Clear stale retry state for recurring scheduled reporting issues once GitHub
10
- already reflects the latest terminal status via labels and the issue is not
11
- currently running.
12
- EOF
13
- }
14
-
15
- repo_slug=""
16
- state_root=""
17
- hook_file=""
18
- limit="100"
19
-
20
- while [[ $# -gt 0 ]]; do
21
- case "$1" in
22
- --repo-slug) repo_slug="${2:-}"; shift 2 ;;
23
- --state-root) state_root="${2:-}"; shift 2 ;;
24
- --hook-file) hook_file="${2:-}"; shift 2 ;;
25
- --limit) limit="${2:-}"; shift 2 ;;
26
- --help|-h) usage; exit 0 ;;
27
- *) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
28
- esac
29
- done
30
-
31
- if [[ -z "$repo_slug" || -z "$state_root" || -z "$hook_file" ]]; then
32
- usage >&2
33
- exit 1
34
- fi
35
-
36
- if [[ ! -f "$hook_file" ]]; then
37
- echo "missing hook file: $hook_file" >&2
38
- exit 1
39
- fi
40
-
41
- # shellcheck source=/dev/null
42
- source "$hook_file"
43
-
44
- if ! declare -F issue_clear_retry >/dev/null 2>&1; then
45
- issue_clear_retry() { :; }
46
- fi
47
-
48
- ledger_dir="${state_root}/scheduled-issue-retry-catchup"
49
- retry_dir="${state_root}/retries/issues"
50
- mkdir -p "$ledger_dir" "$retry_dir"
51
-
52
- issue_has_terminal_scheduled_status() {
53
- local issue_json="${1:-}"
54
- ISSUE_JSON="$issue_json" python3 - <<'PY'
55
- import json
56
- import os
57
- import re
58
- import sys
59
-
60
- issue = json.loads(os.environ.get("ISSUE_JSON", "{}") or "{}")
61
- state = (issue.get("state") or "").upper()
62
- labels = {str(item.get("name") or "") for item in (issue.get("labels") or [])}
63
- body = issue.get("body") or ""
64
-
65
- has_schedule = bool(re.search(r'^\s*(?:Agent schedule|Schedule|Cadence)\s*:\s*(?:every\s+)?\d+\s*[mhd]\s*$', body, re.I | re.M))
66
- if not has_schedule and "agent-scheduled" not in labels:
67
- sys.exit(1)
68
-
69
- if state != "OPEN":
70
- sys.exit(1)
71
-
72
- if "agent-running" in labels:
73
- sys.exit(1)
74
-
75
- terminal_status_labels = {
76
- "health-ok",
77
- "health-not-ok",
78
- "checks-ok",
79
- "checks-not-ok",
80
- "smoke-ok",
81
- "smoke-not-ok",
82
- }
83
- if not (labels & terminal_status_labels):
84
- sys.exit(1)
85
-
86
- sys.exit(0)
87
- PY
88
- }
89
-
90
- processed=0
91
- for retry_file in "$retry_dir"/*.env; do
92
- [[ -f "$retry_file" ]] || continue
93
- if [[ "$processed" -ge "$limit" ]]; then
94
- break
95
- fi
96
-
97
- issue_id="$(basename "${retry_file%.env}")"
98
- [[ -n "$issue_id" ]] || continue
99
-
100
- ledger_file="${ledger_dir}/${issue_id}.env"
101
- if [[ -f "$ledger_file" ]]; then
102
- continue
103
- fi
104
-
105
- issue_json="$(flow_github_issue_view_json "$repo_slug" "$issue_id" 2>/dev/null || true)"
106
- [[ -n "$issue_json" && "$issue_json" != "{}" ]] || continue
107
-
108
- if ! issue_has_terminal_scheduled_status "$issue_json"; then
109
- continue
110
- fi
111
-
112
- retry_reason="$(awk -F= '/^LAST_REASON=/{print $2; exit}' "$retry_file" 2>/dev/null | tr -d '\r' || true)"
113
- ISSUE_ID="$issue_id" issue_clear_retry || true
114
-
115
- {
116
- printf 'ISSUE_ID=%s\n' "$issue_id"
117
- printf 'LAST_REASON=%s\n' "$retry_reason"
118
- printf 'PROCESSED_AT=%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
119
- } >"$ledger_file"
120
-
121
- printf 'CATCHUP_SCHEDULED_ISSUE=%s\n' "$issue_id"
122
- processed=$((processed + 1))
123
- done