agent-control-plane 0.4.9 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +109 -13
  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-config-lib.sh +13 -3508
  6. package/tools/bin/flow-execution-lib.sh +243 -0
  7. package/tools/bin/flow-forge-lib.sh +1770 -0
  8. package/tools/bin/flow-profile-lib.sh +335 -0
  9. package/tools/bin/flow-provider-lib.sh +981 -0
  10. package/tools/bin/flow-runtime-doctor-linux.sh +136 -0
  11. package/tools/bin/flow-runtime-doctor.sh +5 -1
  12. package/tools/bin/flow-session-lib.sh +317 -0
  13. package/tools/bin/install-project-systemd.sh +255 -0
  14. package/tools/bin/project-runtimectl.sh +45 -0
  15. package/tools/bin/project-systemd-bootstrap.sh +74 -0
  16. package/tools/bin/uninstall-project-systemd.sh +87 -0
  17. package/tools/dashboard/app.js +238 -8
  18. package/tools/dashboard/issue_queue_state.py +101 -0
  19. package/tools/dashboard/requirements.txt +3 -0
  20. package/tools/dashboard/server.py +250 -30
  21. package/tools/dashboard/styles.css +526 -455
  22. package/tools/bin/agent-cleanup-worktree +0 -247
  23. package/tools/bin/agent-github-update-labels +0 -105
  24. package/tools/bin/agent-init-worktree +0 -216
  25. package/tools/bin/agent-project-archive-run +0 -52
  26. package/tools/bin/agent-project-capture-worker +0 -46
  27. package/tools/bin/agent-project-catch-up-issue-pr-links +0 -118
  28. package/tools/bin/agent-project-catch-up-merged-prs +0 -195
  29. package/tools/bin/agent-project-catch-up-scheduled-issue-retries +0 -123
  30. package/tools/bin/agent-project-cleanup-session +0 -513
  31. package/tools/bin/agent-project-detached-launch +0 -127
  32. package/tools/bin/agent-project-heartbeat-loop +0 -1029
  33. package/tools/bin/agent-project-open-issue-worktree +0 -89
  34. package/tools/bin/agent-project-open-pr-worktree +0 -80
  35. package/tools/bin/agent-project-publish-issue-pr +0 -468
  36. package/tools/bin/agent-project-reconcile-issue-session +0 -1409
  37. package/tools/bin/agent-project-reconcile-pr-session +0 -1288
  38. package/tools/bin/agent-project-retry-state +0 -158
  39. package/tools/bin/agent-project-run-claude-session +0 -805
  40. package/tools/bin/agent-project-run-codex-resilient +0 -963
  41. package/tools/bin/agent-project-run-codex-session +0 -435
  42. package/tools/bin/agent-project-run-kilo-session +0 -369
  43. package/tools/bin/agent-project-run-ollama-session +0 -658
  44. package/tools/bin/agent-project-run-openclaw-session +0 -1309
  45. package/tools/bin/agent-project-run-opencode-session +0 -377
  46. package/tools/bin/agent-project-run-pi-session +0 -479
  47. package/tools/bin/agent-project-sync-anchor-repo +0 -139
  48. package/tools/bin/agent-project-sync-source-repo-main +0 -163
  49. package/tools/bin/agent-project-worker-status +0 -188
  50. package/tools/bin/branch-verification-guard.sh +0 -364
  51. package/tools/bin/capture-worker.sh +0 -18
  52. package/tools/bin/cleanup-worktree.sh +0 -52
  53. package/tools/bin/codex-quota +0 -31
  54. package/tools/bin/create-follow-up-issue.sh +0 -114
  55. package/tools/bin/dashboard-launchd-bootstrap.sh +0 -50
  56. package/tools/bin/issue-publish-localization-guard.sh +0 -142
  57. package/tools/bin/issue-publish-scope-guard.sh +0 -242
  58. package/tools/bin/issue-requires-local-workspace-install.sh +0 -31
  59. package/tools/bin/issue-resource-class.sh +0 -12
  60. package/tools/bin/kick-scheduler.sh +0 -75
  61. package/tools/bin/label-follow-up-issues.sh +0 -14
  62. package/tools/bin/new-pr-worktree.sh +0 -50
  63. package/tools/bin/new-worktree.sh +0 -49
  64. package/tools/bin/pr-risk.sh +0 -12
  65. package/tools/bin/prepare-worktree.sh +0 -142
  66. package/tools/bin/provider-cooldown-state.sh +0 -204
  67. package/tools/bin/publish-issue-worker.sh +0 -31
  68. package/tools/bin/reconcile-bootstrap-lib.sh +0 -113
  69. package/tools/bin/reconcile-issue-worker.sh +0 -34
  70. package/tools/bin/reconcile-pr-worker.sh +0 -34
  71. package/tools/bin/record-verification.sh +0 -71
  72. package/tools/bin/render-flow-config.sh +0 -98
  73. package/tools/bin/resident-issue-controller-lib.sh +0 -448
  74. package/tools/bin/retry-state.sh +0 -31
  75. package/tools/bin/reuse-issue-worktree.sh +0 -121
  76. package/tools/bin/run-codex-bypass.sh +0 -3
  77. package/tools/bin/run-codex-safe.sh +0 -3
  78. package/tools/bin/run-codex-task.sh +0 -280
  79. package/tools/bin/serve-dashboard.sh +0 -5
  80. package/tools/bin/start-issue-worker.sh +0 -943
  81. package/tools/bin/start-pr-fix-worker.sh +0 -528
  82. package/tools/bin/start-pr-merge-repair-worker.sh +0 -8
  83. package/tools/bin/start-pr-review-worker.sh +0 -261
  84. package/tools/bin/start-resident-issue-loop.sh +0 -499
  85. package/tools/bin/update-github-labels.sh +0 -14
  86. package/tools/bin/worker-status.sh +0 -19
  87. 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