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.
- package/README.md +141 -28
- package/assets/workflow-catalog.json +1 -1
- package/bin/pr-risk.sh +22 -7
- package/bin/sync-pr-labels.sh +1 -1
- package/hooks/heartbeat-hooks.sh +125 -12
- package/hooks/issue-reconcile-hooks.sh +1 -1
- package/hooks/pr-reconcile-hooks.sh +1 -1
- package/npm/bin/agent-control-plane.js +257 -59
- package/package.json +39 -32
- package/tools/bin/debug-session.sh +106 -0
- package/tools/bin/flow-config-lib.sh +1203 -60
- package/tools/bin/flow-runtime-doctor-linux.sh +136 -0
- package/tools/bin/flow-runtime-doctor.sh +5 -1
- package/tools/bin/flow-shell-lib.sh +32 -0
- package/tools/bin/github-core-rate-limit-state.sh +77 -0
- package/tools/bin/github-write-outbox.sh +470 -0
- package/tools/bin/heartbeat-loop-scheduling-lib.sh +7 -7
- package/tools/bin/heartbeat-safe-auto.sh +42 -0
- package/tools/bin/install-project-launchd.sh +17 -2
- package/tools/bin/install-project-systemd.sh +255 -0
- package/tools/bin/project-init.sh +21 -1
- package/tools/bin/project-launchd-bootstrap.sh +5 -1
- package/tools/bin/project-runtimectl.sh +91 -2
- package/tools/bin/project-systemd-bootstrap.sh +74 -0
- package/tools/bin/scaffold-profile.sh +61 -3
- package/tools/bin/uninstall-project-systemd.sh +87 -0
- package/tools/dashboard/app.js +228 -6
- package/tools/dashboard/dashboard_snapshot.py +55 -0
- package/tools/dashboard/issue_queue_state.py +101 -0
- package/tools/dashboard/server.py +123 -1
- package/tools/dashboard/styles.css +526 -455
- package/tools/templates/pr-fix-template.md +3 -1
- package/tools/templates/pr-merge-repair-template.md +2 -1
- package/references/architecture.md +0 -217
- package/references/commands.md +0 -128
- package/references/control-plane-map.md +0 -124
- package/references/docs-map.md +0 -73
- package/references/release-checklist.md +0 -65
- package/references/repo-map.md +0 -36
- package/tools/bin/agent-cleanup-worktree +0 -247
- package/tools/bin/agent-github-update-labels +0 -71
- package/tools/bin/agent-init-worktree +0 -216
- package/tools/bin/agent-project-archive-run +0 -52
- package/tools/bin/agent-project-capture-worker +0 -46
- package/tools/bin/agent-project-catch-up-issue-pr-links +0 -118
- package/tools/bin/agent-project-catch-up-merged-prs +0 -194
- package/tools/bin/agent-project-catch-up-scheduled-issue-retries +0 -123
- package/tools/bin/agent-project-cleanup-session +0 -513
- package/tools/bin/agent-project-detached-launch +0 -127
- package/tools/bin/agent-project-heartbeat-loop +0 -1029
- package/tools/bin/agent-project-open-issue-worktree +0 -89
- package/tools/bin/agent-project-open-pr-worktree +0 -80
- package/tools/bin/agent-project-publish-issue-pr +0 -465
- package/tools/bin/agent-project-reconcile-issue-session +0 -1398
- package/tools/bin/agent-project-reconcile-pr-session +0 -1230
- package/tools/bin/agent-project-retry-state +0 -147
- package/tools/bin/agent-project-run-claude-session +0 -805
- package/tools/bin/agent-project-run-codex-resilient +0 -955
- package/tools/bin/agent-project-run-codex-session +0 -435
- package/tools/bin/agent-project-run-kilo-session +0 -369
- package/tools/bin/agent-project-run-ollama-session +0 -658
- package/tools/bin/agent-project-run-openclaw-session +0 -1309
- package/tools/bin/agent-project-run-opencode-session +0 -377
- package/tools/bin/agent-project-run-pi-session +0 -479
- package/tools/bin/agent-project-sync-anchor-repo +0 -139
- package/tools/bin/agent-project-worker-status +0 -188
- package/tools/bin/branch-verification-guard.sh +0 -364
- package/tools/bin/capture-worker.sh +0 -18
- package/tools/bin/cleanup-worktree.sh +0 -52
- package/tools/bin/codex-quota +0 -31
- package/tools/bin/create-follow-up-issue.sh +0 -114
- package/tools/bin/dashboard-launchd-bootstrap.sh +0 -50
- package/tools/bin/issue-publish-localization-guard.sh +0 -142
- package/tools/bin/issue-publish-scope-guard.sh +0 -242
- package/tools/bin/issue-requires-local-workspace-install.sh +0 -31
- package/tools/bin/issue-resource-class.sh +0 -12
- package/tools/bin/kick-scheduler.sh +0 -75
- package/tools/bin/label-follow-up-issues.sh +0 -14
- package/tools/bin/new-pr-worktree.sh +0 -50
- package/tools/bin/new-worktree.sh +0 -49
- package/tools/bin/pr-risk.sh +0 -12
- package/tools/bin/prepare-worktree.sh +0 -142
- package/tools/bin/provider-cooldown-state.sh +0 -204
- package/tools/bin/publish-issue-worker.sh +0 -31
- package/tools/bin/reconcile-bootstrap-lib.sh +0 -113
- package/tools/bin/reconcile-issue-worker.sh +0 -34
- package/tools/bin/reconcile-pr-worker.sh +0 -34
- package/tools/bin/record-verification.sh +0 -71
- package/tools/bin/render-flow-config.sh +0 -98
- package/tools/bin/resident-issue-controller-lib.sh +0 -448
- package/tools/bin/resident-issue-queue-status.py +0 -35
- package/tools/bin/retry-state.sh +0 -31
- package/tools/bin/reuse-issue-worktree.sh +0 -121
- package/tools/bin/run-codex-bypass.sh +0 -3
- package/tools/bin/run-codex-safe.sh +0 -3
- package/tools/bin/run-codex-task.sh +0 -280
- package/tools/bin/serve-dashboard.sh +0 -5
- package/tools/bin/split-retained-slice.sh +0 -124
- package/tools/bin/start-issue-worker.sh +0 -943
- package/tools/bin/start-pr-fix-worker.sh +0 -491
- package/tools/bin/start-pr-merge-repair-worker.sh +0 -8
- package/tools/bin/start-pr-review-worker.sh +0 -261
- package/tools/bin/start-resident-issue-loop.sh +0 -499
- package/tools/bin/update-github-labels.sh +0 -14
- package/tools/bin/worker-status.sh +0 -19
- package/tools/bin/workflow-catalog.sh +0 -77
package/references/repo-map.md
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Repository Map
|
|
2
|
-
|
|
3
|
-
This file maps the `agent-control-plane` repository itself.
|
|
4
|
-
|
|
5
|
-
## Core Layout
|
|
6
|
-
|
|
7
|
-
- `SKILL.md`
|
|
8
|
-
Shared operating manual for the control plane.
|
|
9
|
-
- `assets/`
|
|
10
|
-
Workflow catalog and static non-profile assets.
|
|
11
|
-
- `bin/`
|
|
12
|
-
Queue, label, and risk scripts shared by installed profiles.
|
|
13
|
-
- `hooks/`
|
|
14
|
-
Heartbeat and reconcile hooks shared by installed profiles.
|
|
15
|
-
- `tools/bin/`
|
|
16
|
-
Runtime wrappers, onboarding helpers, publication utilities, and doctor tools.
|
|
17
|
-
- `tools/templates/`
|
|
18
|
-
Generic fallback prompts used when a profile does not override a template.
|
|
19
|
-
- `tools/tests/`
|
|
20
|
-
Shell regression coverage for control-plane behavior.
|
|
21
|
-
- `references/`
|
|
22
|
-
Control-plane docs, operator commands, and repository maps.
|
|
23
|
-
|
|
24
|
-
## Operator Surfaces
|
|
25
|
-
|
|
26
|
-
- `tools/bin/render-flow-config.sh`
|
|
27
|
-
Effective config viewer for the selected profile.
|
|
28
|
-
- `tools/bin/profile-smoke.sh`
|
|
29
|
-
Installed-profile validation and collision detection.
|
|
30
|
-
- `tools/bin/profile-adopt.sh`
|
|
31
|
-
Local runtime/bootstrap helper for onboarding a profile onto a workstation.
|
|
32
|
-
- `tools/bin/sync-shared-agent-home.sh`
|
|
33
|
-
Publication repair for shared/runtime copies.
|
|
34
|
-
|
|
35
|
-
Installed profiles live outside this repo under
|
|
36
|
-
`~/.agent-runtime/control-plane/profiles/<id>/`.
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
usage() {
|
|
5
|
-
cat <<'EOF'
|
|
6
|
-
Usage:
|
|
7
|
-
agent-cleanup-worktree --branch <branch-name> [--merged-base <ref>] [--path <worktree-path>] [--remote <name>] [--keep-remote] [--allow-unmerged] [--dry-run]
|
|
8
|
-
|
|
9
|
-
Safely cleans up a dedicated task branch/worktree:
|
|
10
|
-
- optionally prunes remote refs
|
|
11
|
-
- by default verifies the branch is merged into the base ref
|
|
12
|
-
- removes the dedicated worktree
|
|
13
|
-
- deletes the local branch
|
|
14
|
-
- deletes the remote branch if it still exists unless --keep-remote is set
|
|
15
|
-
|
|
16
|
-
Run this from a retained checkout, not from the task worktree being removed.
|
|
17
|
-
EOF
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
branch_name=""
|
|
21
|
-
merged_base=""
|
|
22
|
-
worktree_path=""
|
|
23
|
-
remote_name="origin"
|
|
24
|
-
keep_remote="false"
|
|
25
|
-
allow_unmerged="false"
|
|
26
|
-
dry_run="false"
|
|
27
|
-
branch_delete_flag="-d"
|
|
28
|
-
|
|
29
|
-
while [[ $# -gt 0 ]]; do
|
|
30
|
-
case "$1" in
|
|
31
|
-
--branch) branch_name="${2:-}"; shift 2 ;;
|
|
32
|
-
--merged-base) merged_base="${2:-}"; shift 2 ;;
|
|
33
|
-
--path) worktree_path="${2:-}"; shift 2 ;;
|
|
34
|
-
--remote) remote_name="${2:-}"; shift 2 ;;
|
|
35
|
-
--keep-remote) keep_remote="true"; shift ;;
|
|
36
|
-
--allow-unmerged) allow_unmerged="true"; shift ;;
|
|
37
|
-
--dry-run) dry_run="true"; shift ;;
|
|
38
|
-
--help|-h) usage; exit 0 ;;
|
|
39
|
-
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
|
40
|
-
esac
|
|
41
|
-
done
|
|
42
|
-
|
|
43
|
-
if [[ -z "$branch_name" ]]; then
|
|
44
|
-
echo "--branch is required" >&2
|
|
45
|
-
usage >&2
|
|
46
|
-
exit 1
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
if [[ "$branch_name" == "main" || "$branch_name" == "master" ]]; then
|
|
50
|
-
echo "[agent-cleanup] Refusing to clean up protected branch: $branch_name" >&2
|
|
51
|
-
exit 1
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
repo_root="$(git rev-parse --show-toplevel)"
|
|
55
|
-
git_common_dir="$(cd "$(git rev-parse --git-common-dir)" && pwd)"
|
|
56
|
-
source_root="$(dirname "$git_common_dir")"
|
|
57
|
-
current_branch="$(git rev-parse --abbrev-ref HEAD)"
|
|
58
|
-
current_worktree_root="$repo_root"
|
|
59
|
-
local_branch_exists="false"
|
|
60
|
-
remote_branch_exists="false"
|
|
61
|
-
|
|
62
|
-
if [[ -z "$merged_base" ]]; then
|
|
63
|
-
remote_head="$(git symbolic-ref --quiet --short refs/remotes/${remote_name}/HEAD 2>/dev/null || true)"
|
|
64
|
-
if [[ -n "$remote_head" ]]; then
|
|
65
|
-
merged_base="${remote_head#${remote_name}/}"
|
|
66
|
-
merged_base="${remote_name}/${merged_base}"
|
|
67
|
-
elif git show-ref --verify --quiet "refs/remotes/${remote_name}/main"; then
|
|
68
|
-
merged_base="${remote_name}/main"
|
|
69
|
-
elif git show-ref --verify --quiet "refs/heads/main"; then
|
|
70
|
-
merged_base="main"
|
|
71
|
-
else
|
|
72
|
-
merged_base="HEAD"
|
|
73
|
-
fi
|
|
74
|
-
fi
|
|
75
|
-
|
|
76
|
-
canonicalize_existing_dir() {
|
|
77
|
-
local target="$1"
|
|
78
|
-
if [[ ! -d "$target" ]]; then
|
|
79
|
-
return 1
|
|
80
|
-
fi
|
|
81
|
-
(
|
|
82
|
-
cd "$target"
|
|
83
|
-
pwd -P
|
|
84
|
-
)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
prune_worktree_runtime_artifacts() {
|
|
88
|
-
local target="${1:?target worktree required}"
|
|
89
|
-
local candidate=""
|
|
90
|
-
local -a paths=(
|
|
91
|
-
"$target/.openclaw-artifacts"
|
|
92
|
-
"$target/node_modules"
|
|
93
|
-
"$target/apps/api/node_modules"
|
|
94
|
-
"$target/apps/mobile/node_modules"
|
|
95
|
-
"$target/apps/web/node_modules"
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
if [[ -d "$target/packages" ]]; then
|
|
99
|
-
while IFS= read -r candidate; do
|
|
100
|
-
paths+=("$candidate")
|
|
101
|
-
done < <(find "$target/packages" -mindepth 2 -maxdepth 2 -type d -name node_modules | sort)
|
|
102
|
-
fi
|
|
103
|
-
|
|
104
|
-
for candidate in "${paths[@]}"; do
|
|
105
|
-
[[ -e "$candidate" ]] || continue
|
|
106
|
-
rm -rf "$candidate"
|
|
107
|
-
done
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
resolve_branch_worktree_path() {
|
|
111
|
-
local line=""
|
|
112
|
-
local worktree=""
|
|
113
|
-
local branch=""
|
|
114
|
-
local ref="refs/heads/${branch_name}"
|
|
115
|
-
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
116
|
-
if [[ -z "$line" ]]; then
|
|
117
|
-
if [[ "$branch" == "$ref" ]]; then
|
|
118
|
-
printf '%s\n' "$worktree"
|
|
119
|
-
return 0
|
|
120
|
-
fi
|
|
121
|
-
worktree=""
|
|
122
|
-
branch=""
|
|
123
|
-
continue
|
|
124
|
-
fi
|
|
125
|
-
case "$line" in
|
|
126
|
-
worktree\ *) worktree="${line#worktree }" ;;
|
|
127
|
-
branch\ *) branch="${line#branch }" ;;
|
|
128
|
-
esac
|
|
129
|
-
done < <(git worktree list --porcelain)
|
|
130
|
-
if [[ "$branch" == "$ref" ]]; then
|
|
131
|
-
printf '%s\n' "$worktree"
|
|
132
|
-
fi
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if [[ "$current_branch" == "$branch_name" ]]; then
|
|
136
|
-
echo "[agent-cleanup] Refusing to clean up the branch currently checked out: $branch_name" >&2
|
|
137
|
-
exit 1
|
|
138
|
-
fi
|
|
139
|
-
|
|
140
|
-
if git show-ref --verify --quiet "refs/heads/${branch_name}"; then
|
|
141
|
-
local_branch_exists="true"
|
|
142
|
-
fi
|
|
143
|
-
|
|
144
|
-
resolved_branch_worktree_path=""
|
|
145
|
-
if [[ -z "$worktree_path" ]]; then
|
|
146
|
-
worktree_path="$(resolve_branch_worktree_path || true)"
|
|
147
|
-
resolved_branch_worktree_path="$worktree_path"
|
|
148
|
-
else
|
|
149
|
-
resolved_branch_worktree_path="$(resolve_branch_worktree_path || true)"
|
|
150
|
-
if [[ -z "$resolved_branch_worktree_path" ]]; then
|
|
151
|
-
echo "[agent-cleanup] Branch $branch_name is not associated with a dedicated worktree." >&2
|
|
152
|
-
echo "[agent-cleanup] Refusing to trust explicit --path '$worktree_path' without a Git-resolved branch worktree." >&2
|
|
153
|
-
exit 1
|
|
154
|
-
fi
|
|
155
|
-
|
|
156
|
-
explicit_canonical_path="$(canonicalize_existing_dir "$worktree_path" || true)"
|
|
157
|
-
branch_canonical_path="$(canonicalize_existing_dir "$resolved_branch_worktree_path" || true)"
|
|
158
|
-
if [[ -z "$explicit_canonical_path" ]]; then
|
|
159
|
-
echo "[agent-cleanup] Explicit --path '$worktree_path' does not exist as a directory." >&2
|
|
160
|
-
exit 1
|
|
161
|
-
fi
|
|
162
|
-
if [[ -z "$branch_canonical_path" ]]; then
|
|
163
|
-
echo "[agent-cleanup] Git resolved branch worktree '$resolved_branch_worktree_path' does not exist as a directory." >&2
|
|
164
|
-
exit 1
|
|
165
|
-
fi
|
|
166
|
-
if [[ "$explicit_canonical_path" != "$branch_canonical_path" ]]; then
|
|
167
|
-
echo "[agent-cleanup] Explicit --path '$worktree_path' does not match the worktree Git associates with branch '$branch_name' ('$resolved_branch_worktree_path')." >&2
|
|
168
|
-
exit 1
|
|
169
|
-
fi
|
|
170
|
-
worktree_path="$branch_canonical_path"
|
|
171
|
-
fi
|
|
172
|
-
|
|
173
|
-
if [[ "$dry_run" != "true" && "$remote_name" != "" ]]; then
|
|
174
|
-
git fetch --prune "$remote_name"
|
|
175
|
-
fi
|
|
176
|
-
|
|
177
|
-
if git show-ref --verify --quiet "refs/remotes/${remote_name}/${branch_name}"; then
|
|
178
|
-
remote_branch_exists="true"
|
|
179
|
-
fi
|
|
180
|
-
|
|
181
|
-
if [[ "$allow_unmerged" != "true" && "$local_branch_exists" == "true" ]]; then
|
|
182
|
-
if ! git merge-base --is-ancestor "$branch_name" "$merged_base"; then
|
|
183
|
-
echo "[agent-cleanup] Branch $branch_name is not merged into $merged_base" >&2
|
|
184
|
-
exit 1
|
|
185
|
-
fi
|
|
186
|
-
fi
|
|
187
|
-
|
|
188
|
-
if [[ "$allow_unmerged" == "true" ]]; then
|
|
189
|
-
branch_delete_flag="-D"
|
|
190
|
-
fi
|
|
191
|
-
|
|
192
|
-
if [[ -n "$worktree_path" && "$worktree_path" == "$current_worktree_root" ]]; then
|
|
193
|
-
echo "[agent-cleanup] Refusing to remove the current worktree: $worktree_path" >&2
|
|
194
|
-
exit 1
|
|
195
|
-
fi
|
|
196
|
-
|
|
197
|
-
if [[ -n "$worktree_path" ]]; then
|
|
198
|
-
canonical_worktree_path="$(canonicalize_existing_dir "$worktree_path" || true)"
|
|
199
|
-
if [[ -n "$canonical_worktree_path" && "$canonical_worktree_path" == "$source_root" ]]; then
|
|
200
|
-
echo "[agent-cleanup] Refusing to remove the canonical source checkout: $canonical_worktree_path" >&2
|
|
201
|
-
exit 1
|
|
202
|
-
fi
|
|
203
|
-
fi
|
|
204
|
-
|
|
205
|
-
if [[ "$dry_run" == "true" ]]; then
|
|
206
|
-
if [[ -n "$worktree_path" ]]; then
|
|
207
|
-
echo "git worktree remove --force '$worktree_path'"
|
|
208
|
-
fi
|
|
209
|
-
if [[ "$local_branch_exists" == "true" ]]; then
|
|
210
|
-
echo "git branch $branch_delete_flag '$branch_name'"
|
|
211
|
-
fi
|
|
212
|
-
if [[ "$remote_branch_exists" == "true" && "$keep_remote" != "true" ]]; then
|
|
213
|
-
echo "git push '$remote_name' --delete '$branch_name'"
|
|
214
|
-
fi
|
|
215
|
-
if [[ "$remote_name" != "" ]]; then
|
|
216
|
-
echo "git fetch --prune '$remote_name'"
|
|
217
|
-
fi
|
|
218
|
-
exit 0
|
|
219
|
-
fi
|
|
220
|
-
|
|
221
|
-
if [[ -n "$worktree_path" ]]; then
|
|
222
|
-
prune_worktree_runtime_artifacts "$worktree_path"
|
|
223
|
-
(
|
|
224
|
-
cd "$source_root"
|
|
225
|
-
git worktree remove --force "$worktree_path"
|
|
226
|
-
)
|
|
227
|
-
fi
|
|
228
|
-
if [[ "$local_branch_exists" == "true" ]]; then
|
|
229
|
-
git branch "$branch_delete_flag" "$branch_name"
|
|
230
|
-
fi
|
|
231
|
-
if [[ "$remote_branch_exists" == "true" && "$keep_remote" != "true" ]]; then
|
|
232
|
-
remote_delete_output="$(git push "$remote_name" --delete "$branch_name" 2>&1)" || remote_delete_status=$?
|
|
233
|
-
remote_delete_status="${remote_delete_status:-0}"
|
|
234
|
-
if [[ "$remote_delete_status" -ne 0 ]]; then
|
|
235
|
-
if rg -q "remote ref does not exist|unable to delete" <<<"$remote_delete_output"; then
|
|
236
|
-
:
|
|
237
|
-
else
|
|
238
|
-
printf '%s\n' "$remote_delete_output" >&2
|
|
239
|
-
exit "$remote_delete_status"
|
|
240
|
-
fi
|
|
241
|
-
fi
|
|
242
|
-
fi
|
|
243
|
-
if [[ "$remote_name" != "" ]]; then
|
|
244
|
-
git fetch --prune "$remote_name"
|
|
245
|
-
fi
|
|
246
|
-
|
|
247
|
-
echo "[agent-cleanup] cleanup complete for $branch_name"
|
|
@@ -1,71 +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
|
-
usage() {
|
|
9
|
-
cat <<'EOF'
|
|
10
|
-
Usage:
|
|
11
|
-
agent-github-update-labels --repo-slug <owner/repo> --number <issue-or-pr-number> [--add LABEL]... [--remove LABEL]...
|
|
12
|
-
|
|
13
|
-
Merge requested label adds/removals into the current issue/PR labels and patch
|
|
14
|
-
the final sorted label set back to GitHub.
|
|
15
|
-
EOF
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
repo_slug=""
|
|
19
|
-
number=""
|
|
20
|
-
add_file="$(mktemp)"
|
|
21
|
-
remove_file="$(mktemp)"
|
|
22
|
-
trap 'rm -f "$add_file" "$remove_file"' EXIT
|
|
23
|
-
|
|
24
|
-
while [[ $# -gt 0 ]]; do
|
|
25
|
-
case "$1" in
|
|
26
|
-
--repo-slug) repo_slug="${2:-}"; shift 2 ;;
|
|
27
|
-
--number) number="${2:-}"; shift 2 ;;
|
|
28
|
-
--add)
|
|
29
|
-
printf '%s\n' "${2:?missing label after --add}" >>"$add_file"
|
|
30
|
-
shift 2
|
|
31
|
-
;;
|
|
32
|
-
--remove)
|
|
33
|
-
printf '%s\n' "${2:?missing label after --remove}" >>"$remove_file"
|
|
34
|
-
shift 2
|
|
35
|
-
;;
|
|
36
|
-
--help|-h) usage; exit 0 ;;
|
|
37
|
-
*)
|
|
38
|
-
echo "unknown argument: $1" >&2
|
|
39
|
-
usage >&2
|
|
40
|
-
exit 1
|
|
41
|
-
;;
|
|
42
|
-
esac
|
|
43
|
-
done
|
|
44
|
-
|
|
45
|
-
if [[ -z "$repo_slug" || -z "$number" ]]; then
|
|
46
|
-
usage >&2
|
|
47
|
-
exit 1
|
|
48
|
-
fi
|
|
49
|
-
|
|
50
|
-
resource="issues/${number}"
|
|
51
|
-
# Use caller-provided cached JSON if available to skip the GET call
|
|
52
|
-
if [[ -n "${ACP_CACHED_ISSUE_JSON:-}" ]]; then
|
|
53
|
-
current_json="${ACP_CACHED_ISSUE_JSON}"
|
|
54
|
-
else
|
|
55
|
-
current_json="$(flow_github_api_repo "${repo_slug}" "${resource}")"
|
|
56
|
-
fi
|
|
57
|
-
add_json="$(jq -R . <"$add_file" | jq -s .)"
|
|
58
|
-
remove_json="$(jq -R . <"$remove_file" | jq -s .)"
|
|
59
|
-
payload="$(
|
|
60
|
-
CURRENT_JSON="$current_json" ADD_JSON="$add_json" REMOVE_JSON="$remove_json" node <<'EOF'
|
|
61
|
-
const current = JSON.parse(process.env.CURRENT_JSON || '{}');
|
|
62
|
-
const add = JSON.parse(process.env.ADD_JSON || '[]');
|
|
63
|
-
const remove = new Set(JSON.parse(process.env.REMOVE_JSON || '[]'));
|
|
64
|
-
const labels = new Set((current.labels || []).map((label) => label.name));
|
|
65
|
-
for (const label of remove) labels.delete(label);
|
|
66
|
-
for (const label of add) labels.add(label);
|
|
67
|
-
process.stdout.write(JSON.stringify({ labels: Array.from(labels).sort() }));
|
|
68
|
-
EOF
|
|
69
|
-
)"
|
|
70
|
-
|
|
71
|
-
printf '%s' "$payload" | flow_github_api_repo "${repo_slug}" "${resource}" --method PATCH --input - >/dev/null
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
usage() {
|
|
5
|
-
cat <<'EOF'
|
|
6
|
-
Usage:
|
|
7
|
-
agent-init-worktree --branch <branch-name> --claim <task-id> [--base <ref>] [--path <worktree-path>] [--allow-unclaimed] [--no-bootstrap-deps] [--dry-run]
|
|
8
|
-
|
|
9
|
-
Creates a dedicated agent branch + worktree and writes a namespaced env file:
|
|
10
|
-
.agent-session.env
|
|
11
|
-
|
|
12
|
-
Options:
|
|
13
|
-
--branch <name> Required branch name for the task
|
|
14
|
-
--base <ref> Base ref for a new branch (default: remote HEAD, else origin/main, else main, else HEAD)
|
|
15
|
-
--path <path> Explicit worktree path
|
|
16
|
-
--claim <task-id> Required shared task claim, e.g. change-id:2.1
|
|
17
|
-
--allow-unclaimed Explicitly allow bootstrap without a claim
|
|
18
|
-
--no-bootstrap-deps Skip node_modules linking for the new worktree
|
|
19
|
-
--dry-run Print actions without creating anything
|
|
20
|
-
--help Show this help
|
|
21
|
-
EOF
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
branch_name=""
|
|
25
|
-
base_ref=""
|
|
26
|
-
worktree_path=""
|
|
27
|
-
claim_task_id=""
|
|
28
|
-
bootstrap_deps="true"
|
|
29
|
-
allow_unclaimed="false"
|
|
30
|
-
dry_run="false"
|
|
31
|
-
|
|
32
|
-
while [[ $# -gt 0 ]]; do
|
|
33
|
-
case "$1" in
|
|
34
|
-
--branch) branch_name="${2:-}"; shift 2 ;;
|
|
35
|
-
--base) base_ref="${2:-}"; shift 2 ;;
|
|
36
|
-
--path) worktree_path="${2:-}"; shift 2 ;;
|
|
37
|
-
--claim) claim_task_id="${2:-}"; shift 2 ;;
|
|
38
|
-
--allow-unclaimed) allow_unclaimed="true"; shift ;;
|
|
39
|
-
--no-bootstrap-deps) bootstrap_deps="false"; shift ;;
|
|
40
|
-
--dry-run) dry_run="true"; shift ;;
|
|
41
|
-
--help|-h) usage; exit 0 ;;
|
|
42
|
-
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
|
43
|
-
esac
|
|
44
|
-
done
|
|
45
|
-
|
|
46
|
-
if [[ -z "$branch_name" ]]; then
|
|
47
|
-
echo "--branch is required" >&2
|
|
48
|
-
usage >&2
|
|
49
|
-
exit 1
|
|
50
|
-
fi
|
|
51
|
-
|
|
52
|
-
if [[ "$branch_name" == "main" || "$branch_name" == "master" ]]; then
|
|
53
|
-
echo "[agent-init] Refusing to bootstrap protected branch: $branch_name" >&2
|
|
54
|
-
echo "[agent-init] Keep the retained checkout on $branch_name read-only for inspection only." >&2
|
|
55
|
-
echo "[agent-init] Create a dedicated task branch/worktree before doing any write work." >&2
|
|
56
|
-
exit 1
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
if [[ -z "$claim_task_id" && "$allow_unclaimed" != "true" ]]; then
|
|
60
|
-
echo "--claim is required for agent task worktrees. Use --allow-unclaimed only for exceptional preserve/review cases." >&2
|
|
61
|
-
usage >&2
|
|
62
|
-
exit 1
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
if [[ -z "$base_ref" ]]; then
|
|
66
|
-
remote_name="origin"
|
|
67
|
-
remote_head="$(git symbolic-ref --quiet --short "refs/remotes/${remote_name}/HEAD" 2>/dev/null || true)"
|
|
68
|
-
if [[ -n "$remote_head" ]]; then
|
|
69
|
-
base_ref="${remote_head}"
|
|
70
|
-
elif git show-ref --verify --quiet "refs/remotes/${remote_name}/main"; then
|
|
71
|
-
base_ref="${remote_name}/main"
|
|
72
|
-
elif git show-ref --verify --quiet "refs/heads/main"; then
|
|
73
|
-
base_ref="main"
|
|
74
|
-
else
|
|
75
|
-
base_ref="HEAD"
|
|
76
|
-
fi
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
repo_root="$(git rev-parse --show-toplevel)"
|
|
80
|
-
git_common_dir="$(cd "$(git rev-parse --git-common-dir)" && pwd)"
|
|
81
|
-
source_root="$(dirname "$git_common_dir")"
|
|
82
|
-
repo_name="$(basename "$source_root")"
|
|
83
|
-
repo_parent="$(dirname "$source_root")"
|
|
84
|
-
|
|
85
|
-
branch_slug="$(
|
|
86
|
-
printf '%s' "$branch_name" |
|
|
87
|
-
tr '[:upper:]' '[:lower:]' |
|
|
88
|
-
sed 's#[^a-z0-9._/-]#-#g; s#/#-#g; s/-\{2,\}/-/g; s/^-//; s/-$//'
|
|
89
|
-
)"
|
|
90
|
-
|
|
91
|
-
if [[ -z "$branch_slug" ]]; then
|
|
92
|
-
echo "Failed to derive branch slug from: $branch_name" >&2
|
|
93
|
-
exit 1
|
|
94
|
-
fi
|
|
95
|
-
|
|
96
|
-
if [[ -z "$worktree_path" ]]; then
|
|
97
|
-
worktree_path="${repo_parent}/${repo_name}-${branch_slug}"
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
namespace="$(
|
|
101
|
-
printf '%s' "$branch_slug" |
|
|
102
|
-
sed 's/[^a-z0-9]/-/g; s/-\{2,\}/-/g; s/^-//; s/-$//' |
|
|
103
|
-
cut -c1-24
|
|
104
|
-
)"
|
|
105
|
-
|
|
106
|
-
if [[ -z "$namespace" ]]; then
|
|
107
|
-
namespace="agent-local"
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
run_id_raw="${AO_SESSION_ID:-${branch_slug}-$$}"
|
|
111
|
-
env_file="${worktree_path}/.agent-session.env"
|
|
112
|
-
|
|
113
|
-
branch_exists="false"
|
|
114
|
-
if git show-ref --verify --quiet "refs/heads/${branch_name}"; then
|
|
115
|
-
branch_exists="true"
|
|
116
|
-
fi
|
|
117
|
-
|
|
118
|
-
if [[ -e "$worktree_path" ]]; then
|
|
119
|
-
echo "Worktree path already exists: $worktree_path" >&2
|
|
120
|
-
exit 1
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
cat <<EOF
|
|
124
|
-
[agent-init] repo=$repo_root
|
|
125
|
-
[agent-init] source_root=$source_root
|
|
126
|
-
[agent-init] branch=$branch_name
|
|
127
|
-
[agent-init] base_ref=$base_ref
|
|
128
|
-
[agent-init] worktree_path=$worktree_path
|
|
129
|
-
[agent-init] test_namespace=$namespace
|
|
130
|
-
[agent-init] branch_exists=$branch_exists
|
|
131
|
-
[agent-init] bootstrap_deps=$bootstrap_deps
|
|
132
|
-
[agent-init] claim_task_id=${claim_task_id:-<none>}
|
|
133
|
-
[agent-init] allow_unclaimed=$allow_unclaimed
|
|
134
|
-
EOF
|
|
135
|
-
|
|
136
|
-
if [[ "$dry_run" == "true" ]]; then
|
|
137
|
-
echo "[agent-init] dry-run only"
|
|
138
|
-
echo
|
|
139
|
-
echo "Planned commands:"
|
|
140
|
-
if [[ "$branch_exists" == "false" ]]; then
|
|
141
|
-
echo " git worktree add -b $branch_name $worktree_path $base_ref"
|
|
142
|
-
else
|
|
143
|
-
echo " git worktree add $worktree_path $branch_name"
|
|
144
|
-
fi
|
|
145
|
-
cat <<EOF
|
|
146
|
-
|
|
147
|
-
Planned env file: $env_file
|
|
148
|
-
export AGENT_TASK_BRANCH='$branch_name'
|
|
149
|
-
export AGENT_WORKTREE_PATH='$worktree_path'
|
|
150
|
-
export TEST_RUN_ID='$run_id_raw'
|
|
151
|
-
export API_TEST_RUN_ID='$run_id_raw'
|
|
152
|
-
export TEST_SEED_NAMESPACE='$namespace'
|
|
153
|
-
export E2E_SEED_NAMESPACE='$namespace'
|
|
154
|
-
export MOBILE_SEED_NAMESPACE='$namespace'
|
|
155
|
-
EOF
|
|
156
|
-
if [[ "$bootstrap_deps" == "true" ]]; then
|
|
157
|
-
echo " agent-bootstrap-worktree --source-root '$source_root' --path '$worktree_path'"
|
|
158
|
-
fi
|
|
159
|
-
if [[ -n "$claim_task_id" ]]; then
|
|
160
|
-
echo " agent-claim-task --task '$claim_task_id' --branch '$branch_name' --worktree '$worktree_path'"
|
|
161
|
-
fi
|
|
162
|
-
exit 0
|
|
163
|
-
fi
|
|
164
|
-
|
|
165
|
-
if [[ "$branch_exists" == "true" ]]; then
|
|
166
|
-
git worktree add "$worktree_path" "$branch_name"
|
|
167
|
-
else
|
|
168
|
-
git worktree add -b "$branch_name" "$worktree_path" "$base_ref"
|
|
169
|
-
fi
|
|
170
|
-
|
|
171
|
-
cat >"$env_file" <<EOF
|
|
172
|
-
export AGENT_TASK_BRANCH='$branch_name'
|
|
173
|
-
export AGENT_WORKTREE_PATH='$worktree_path'
|
|
174
|
-
export TEST_RUN_ID='$run_id_raw'
|
|
175
|
-
export API_TEST_RUN_ID='$run_id_raw'
|
|
176
|
-
export TEST_SEED_NAMESPACE='$namespace'
|
|
177
|
-
export E2E_SEED_NAMESPACE='$namespace'
|
|
178
|
-
export MOBILE_SEED_NAMESPACE='$namespace'
|
|
179
|
-
EOF
|
|
180
|
-
|
|
181
|
-
if [[ -n "$claim_task_id" ]]; then
|
|
182
|
-
printf "export AGENT_TASK_CLAIM='%s'\n" "$claim_task_id" >>"$env_file"
|
|
183
|
-
fi
|
|
184
|
-
|
|
185
|
-
if [[ "$bootstrap_deps" == "true" ]]; then
|
|
186
|
-
agent-bootstrap-worktree \
|
|
187
|
-
--source-root "$source_root" \
|
|
188
|
-
--path "$worktree_path"
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
if [[ -n "$claim_task_id" ]]; then
|
|
192
|
-
agent-claim-task \
|
|
193
|
-
--task "$claim_task_id" \
|
|
194
|
-
--branch "$branch_name" \
|
|
195
|
-
--worktree "$worktree_path"
|
|
196
|
-
fi
|
|
197
|
-
|
|
198
|
-
if [[ -f "$HOME/.ao/bin/ao-metadata-helper.sh" ]]; then
|
|
199
|
-
# shellcheck source=/dev/null
|
|
200
|
-
source "$HOME/.ao/bin/ao-metadata-helper.sh" || true
|
|
201
|
-
if declare -F update_ao_metadata >/dev/null 2>&1; then
|
|
202
|
-
update_ao_metadata branch "$branch_name" || true
|
|
203
|
-
update_ao_metadata worktree "$worktree_path" || true
|
|
204
|
-
update_ao_metadata test_seed_namespace "$namespace" || true
|
|
205
|
-
fi
|
|
206
|
-
fi
|
|
207
|
-
|
|
208
|
-
cat <<EOF
|
|
209
|
-
[agent-init] created worktree: $worktree_path
|
|
210
|
-
[agent-init] wrote env file: $env_file
|
|
211
|
-
$(if [[ -n "$claim_task_id" ]]; then printf "[agent-init] claimed task: %s\n" "$claim_task_id"; fi)
|
|
212
|
-
|
|
213
|
-
Next:
|
|
214
|
-
cd '$worktree_path'
|
|
215
|
-
source .agent-session.env
|
|
216
|
-
EOF
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
usage() {
|
|
5
|
-
cat <<'EOF'
|
|
6
|
-
Usage:
|
|
7
|
-
agent-project-archive-run --runs-root <path> --history-root <path> --session <id> [--remove-file <path>]
|
|
8
|
-
|
|
9
|
-
Moves a completed run directory into the history root and optionally removes an
|
|
10
|
-
extra file such as a sandbox result file.
|
|
11
|
-
EOF
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
runs_root="${AGENT_PROJECT_RUNS_ROOT:-}"
|
|
15
|
-
history_root="${AGENT_PROJECT_HISTORY_ROOT:-}"
|
|
16
|
-
session=""
|
|
17
|
-
remove_file=""
|
|
18
|
-
|
|
19
|
-
while [[ $# -gt 0 ]]; do
|
|
20
|
-
case "$1" in
|
|
21
|
-
--runs-root) runs_root="${2:-}"; shift 2 ;;
|
|
22
|
-
--history-root) history_root="${2:-}"; shift 2 ;;
|
|
23
|
-
--session) session="${2:-}"; shift 2 ;;
|
|
24
|
-
--remove-file) remove_file="${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 "$runs_root" || -z "$history_root" || -z "$session" ]]; then
|
|
31
|
-
usage >&2
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
run_dir="${runs_root}/${session}"
|
|
36
|
-
archived_dir=""
|
|
37
|
-
|
|
38
|
-
mkdir -p "$history_root"
|
|
39
|
-
|
|
40
|
-
if [[ -d "$run_dir" && "$run_dir" == "${runs_root}/"* ]]; then
|
|
41
|
-
archived_dir="${history_root}/${session}-$(date +%Y%m%d-%H%M%S)"
|
|
42
|
-
mv "$run_dir" "$archived_dir"
|
|
43
|
-
fi
|
|
44
|
-
|
|
45
|
-
if [[ -n "$remove_file" && -f "$remove_file" ]]; then
|
|
46
|
-
rm -f "$remove_file"
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
printf 'SESSION=%s\n' "$session"
|
|
50
|
-
printf 'RUN_DIR=%s\n' "$run_dir"
|
|
51
|
-
printf 'ARCHIVED_DIR=%s\n' "$archived_dir"
|
|
52
|
-
printf 'REMOVED_FILE=%s\n' "$remove_file"
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
usage() {
|
|
5
|
-
cat <<'EOF'
|
|
6
|
-
Usage:
|
|
7
|
-
agent-project-capture-worker --runs-root <path> --session <id> [--lines <n>]
|
|
8
|
-
|
|
9
|
-
Print the latest worker transcript, preferring a live tmux session and falling
|
|
10
|
-
back to the persisted run log.
|
|
11
|
-
EOF
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
runs_root="${AGENT_PROJECT_RUNS_ROOT:-}"
|
|
15
|
-
session=""
|
|
16
|
-
lines="80"
|
|
17
|
-
|
|
18
|
-
while [[ $# -gt 0 ]]; do
|
|
19
|
-
case "$1" in
|
|
20
|
-
--runs-root) runs_root="${2:-}"; shift 2 ;;
|
|
21
|
-
--session) session="${2:-}"; shift 2 ;;
|
|
22
|
-
--lines) lines="${2:-}"; shift 2 ;;
|
|
23
|
-
--help|-h) usage; exit 0 ;;
|
|
24
|
-
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
|
25
|
-
esac
|
|
26
|
-
done
|
|
27
|
-
|
|
28
|
-
if [[ -z "$runs_root" || -z "$session" ]]; then
|
|
29
|
-
usage >&2
|
|
30
|
-
exit 1
|
|
31
|
-
fi
|
|
32
|
-
|
|
33
|
-
output_file="${runs_root}/${session}/${session}.log"
|
|
34
|
-
|
|
35
|
-
if tmux has-session -t "$session" 2>/dev/null; then
|
|
36
|
-
tmux capture-pane -t "$session" -p | tail -n "$lines"
|
|
37
|
-
exit 0
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
if [[ -f "$output_file" ]]; then
|
|
41
|
-
tail -n "$lines" "$output_file"
|
|
42
|
-
exit 0
|
|
43
|
-
fi
|
|
44
|
-
|
|
45
|
-
echo "no tmux session or log found for $session" >&2
|
|
46
|
-
exit 1
|