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,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