beeops 0.1.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/LICENSE +21 -0
- package/README.ja.md +156 -0
- package/README.md +80 -0
- package/bin/beeops.js +502 -0
- package/command/bo.md +120 -0
- package/contexts/agent-modes.json +100 -0
- package/contexts/code-reviewer.md +118 -0
- package/contexts/coder.md +247 -0
- package/contexts/default.md +1 -0
- package/contexts/en/agent-modes.json +100 -0
- package/contexts/en/code-reviewer.md +129 -0
- package/contexts/en/coder.md +247 -0
- package/contexts/en/default.md +1 -0
- package/contexts/en/fb.md +15 -0
- package/contexts/en/leader.md +158 -0
- package/contexts/en/log.md +16 -0
- package/contexts/en/queen.md +240 -0
- package/contexts/en/review-leader.md +190 -0
- package/contexts/en/reviewer-base.md +27 -0
- package/contexts/en/security-reviewer.md +200 -0
- package/contexts/en/test-auditor.md +146 -0
- package/contexts/en/tester.md +135 -0
- package/contexts/en/worker-base.md +69 -0
- package/contexts/fb.md +15 -0
- package/contexts/ja/agent-modes.json +100 -0
- package/contexts/ja/code-reviewer.md +129 -0
- package/contexts/ja/coder.md +247 -0
- package/contexts/ja/default.md +1 -0
- package/contexts/ja/fb.md +15 -0
- package/contexts/ja/leader.md +158 -0
- package/contexts/ja/log.md +17 -0
- package/contexts/ja/queen.md +240 -0
- package/contexts/ja/review-leader.md +190 -0
- package/contexts/ja/reviewer-base.md +27 -0
- package/contexts/ja/security-reviewer.md +200 -0
- package/contexts/ja/test-auditor.md +146 -0
- package/contexts/ja/tester.md +135 -0
- package/contexts/ja/worker-base.md +68 -0
- package/contexts/leader.md +158 -0
- package/contexts/log.md +16 -0
- package/contexts/queen.md +240 -0
- package/contexts/review-leader.md +190 -0
- package/contexts/reviewer-base.md +27 -0
- package/contexts/security-reviewer.md +200 -0
- package/contexts/test-auditor.md +146 -0
- package/contexts/tester.md +135 -0
- package/contexts/worker-base.md +69 -0
- package/hooks/checkpoint.py +89 -0
- package/hooks/prompt-context.py +139 -0
- package/hooks/resolve-log-path.py +93 -0
- package/hooks/run-log.py +429 -0
- package/package.json +42 -0
- package/scripts/launch-leader.sh +282 -0
- package/scripts/launch-worker.sh +184 -0
- package/skills/bo-dispatch/SKILL.md +299 -0
- package/skills/bo-issue-sync/SKILL.md +103 -0
- package/skills/bo-leader-dispatch/SKILL.md +211 -0
- package/skills/bo-log-writer/SKILL.md +101 -0
- package/skills/bo-review-backend/SKILL.md +234 -0
- package/skills/bo-review-database/SKILL.md +243 -0
- package/skills/bo-review-frontend/SKILL.md +236 -0
- package/skills/bo-review-operations/SKILL.md +268 -0
- package/skills/bo-review-process/SKILL.md +181 -0
- package/skills/bo-review-security/SKILL.md +214 -0
- package/skills/bo-review-security/references/finance-security.md +351 -0
- package/skills/bo-self-improver/SKILL.md +145 -0
- package/skills/bo-self-improver/refs/agent-manager.md +61 -0
- package/skills/bo-self-improver/refs/command-manager.md +46 -0
- package/skills/bo-self-improver/refs/skill-manager.md +59 -0
- package/skills/bo-self-improver/scripts/analyze.py +359 -0
- package/skills/bo-task-decomposer/SKILL.md +130 -0
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "beeops",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "3-layer multi-agent orchestration system (Queen โ Leader โ Worker) powered by tmux",
|
|
5
|
+
"author": "YuugouOhno",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/YuugouOhno/beeops.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/YuugouOhno/beeops#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/YuugouOhno/beeops/issues"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"beeops": "./bin/beeops.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin/",
|
|
20
|
+
"scripts/",
|
|
21
|
+
"hooks/",
|
|
22
|
+
"contexts/",
|
|
23
|
+
"skills/",
|
|
24
|
+
"command/"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"multi-agent",
|
|
28
|
+
"orchestration",
|
|
29
|
+
"tmux",
|
|
30
|
+
"automation",
|
|
31
|
+
"ai-agents",
|
|
32
|
+
"beeops",
|
|
33
|
+
"claude-code"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "node --test test/cli.test.js",
|
|
37
|
+
"prepublishOnly": "npm test"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# launch-leader.sh - Launch Leader or Review Leader in a tmux window (with git worktree isolation)
|
|
3
|
+
# Usage: launch-leader.sh <role> <issue> <branch> [fix]
|
|
4
|
+
#
|
|
5
|
+
# Part of beeops: 3-layer multi-agent system (Queen โ Leader โ Worker)
|
|
6
|
+
#
|
|
7
|
+
# Features:
|
|
8
|
+
# - tmux new-window: each issue gets its own window (not pane)
|
|
9
|
+
# - Git worktree isolation: impl leader gets isolated copy of the repo
|
|
10
|
+
# - Review leader works on main repo (read-only)
|
|
11
|
+
# - FIX_MODE: reuse existing worktree/branch when called with 'fix'
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
ROLE="$1"
|
|
16
|
+
ISSUE="$2"
|
|
17
|
+
BRANCH="$3"
|
|
18
|
+
FIX_MODE="${4:-}"
|
|
19
|
+
SESSION="bo"
|
|
20
|
+
REPO_DIR="$(git rev-parse --show-toplevel)"
|
|
21
|
+
REPORTS_DIR="$REPO_DIR/.claude/tasks/reports"
|
|
22
|
+
PROMPTS_DIR="$REPO_DIR/.claude/tasks/prompts"
|
|
23
|
+
WORKTREES_DIR="$REPO_DIR/.claude/worktrees"
|
|
24
|
+
|
|
25
|
+
mkdir -p "$REPORTS_DIR/processed" "$PROMPTS_DIR" "$WORKTREES_DIR"
|
|
26
|
+
|
|
27
|
+
# โโ Role configuration โโ
|
|
28
|
+
case "$ROLE" in
|
|
29
|
+
leader)
|
|
30
|
+
ROLE_SHORT="leader"
|
|
31
|
+
ENV_VAR="BO_LEADER"
|
|
32
|
+
WINDOW_NAME="issue-${ISSUE}"
|
|
33
|
+
BORDER_FG="blue"
|
|
34
|
+
ROLE_ICON="๐"
|
|
35
|
+
MAX_TURNS=80
|
|
36
|
+
ALLOWED_TOOLS="Read,Write,Edit,Bash,Glob,Grep,Skill"
|
|
37
|
+
;;
|
|
38
|
+
review-leader)
|
|
39
|
+
ROLE_SHORT="review-leader"
|
|
40
|
+
ENV_VAR="BO_REVIEW_LEADER"
|
|
41
|
+
WINDOW_NAME="review-${ISSUE}"
|
|
42
|
+
BORDER_FG="magenta"
|
|
43
|
+
ROLE_ICON="๐ฎ"
|
|
44
|
+
MAX_TURNS=40
|
|
45
|
+
ALLOWED_TOOLS="Read,Grep,Glob,Bash,Skill"
|
|
46
|
+
;;
|
|
47
|
+
*)
|
|
48
|
+
echo "Unknown role: $ROLE (expected: leader | review-leader)" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
;;
|
|
51
|
+
esac
|
|
52
|
+
|
|
53
|
+
PANE_TITLE="${ROLE_ICON} ${ROLE_SHORT}-${ISSUE}"
|
|
54
|
+
|
|
55
|
+
# โโ Worktree setup (leader only, review-leader uses main repo) โโ
|
|
56
|
+
WORK_DIR="$REPO_DIR"
|
|
57
|
+
WORKTREE_PATH=""
|
|
58
|
+
|
|
59
|
+
if [ "$ROLE" = "leader" ]; then
|
|
60
|
+
WORKTREE_PATH="$WORKTREES_DIR/$BRANCH"
|
|
61
|
+
|
|
62
|
+
if [ "$FIX_MODE" = "fix" ] && [ -d "$WORKTREE_PATH" ]; then
|
|
63
|
+
# FIX_MODE: reuse existing worktree
|
|
64
|
+
WORK_DIR="$WORKTREE_PATH"
|
|
65
|
+
else
|
|
66
|
+
# Clean up stale worktree if exists
|
|
67
|
+
if [ -d "$WORKTREE_PATH" ]; then
|
|
68
|
+
git -C "$REPO_DIR" worktree remove "$WORKTREE_PATH" --force 2>/dev/null || true
|
|
69
|
+
fi
|
|
70
|
+
# Create fresh worktree with new branch from main
|
|
71
|
+
git -C "$REPO_DIR" worktree add "$WORKTREE_PATH" -b "$BRANCH" main 2>/dev/null || \
|
|
72
|
+
git -C "$REPO_DIR" worktree add "$WORKTREE_PATH" "$BRANCH" 2>/dev/null || {
|
|
73
|
+
git -C "$REPO_DIR" branch -D "$BRANCH" 2>/dev/null || true
|
|
74
|
+
git -C "$REPO_DIR" worktree add "$WORKTREE_PATH" -b "$BRANCH" main
|
|
75
|
+
}
|
|
76
|
+
WORK_DIR="$WORKTREE_PATH"
|
|
77
|
+
# Symlink node_modules and other untracked but required dirs
|
|
78
|
+
ln -sfn "$REPO_DIR/node_modules" "$WORKTREE_PATH/node_modules" 2>/dev/null || true
|
|
79
|
+
ln -sfn "$REPO_DIR/.next" "$WORKTREE_PATH/.next" 2>/dev/null || true
|
|
80
|
+
# Ensure reports/prompts dirs are accessible from worktree
|
|
81
|
+
mkdir -p "$WORKTREE_PATH/.claude/tasks"
|
|
82
|
+
ln -sfn "$REPORTS_DIR" "$WORKTREE_PATH/.claude/tasks/reports"
|
|
83
|
+
ln -sfn "$PROMPTS_DIR" "$WORKTREE_PATH/.claude/tasks/prompts"
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# โโ Write prompt file โโ
|
|
88
|
+
PROMPT_FILE="$PROMPTS_DIR/${ROLE_SHORT}-${ISSUE}.md"
|
|
89
|
+
|
|
90
|
+
# Use fix prompt if it exists (written by Queen)
|
|
91
|
+
FIX_PROMPT="$PROMPTS_DIR/fix-${ROLE_SHORT}-${ISSUE}.md"
|
|
92
|
+
if [ "$FIX_MODE" = "fix" ] && [ -f "$FIX_PROMPT" ]; then
|
|
93
|
+
cp "$FIX_PROMPT" "$PROMPT_FILE"
|
|
94
|
+
rm "$FIX_PROMPT"
|
|
95
|
+
else
|
|
96
|
+
case "$ROLE" in
|
|
97
|
+
leader)
|
|
98
|
+
cat > "$PROMPT_FILE" <<PROMPT_EOF
|
|
99
|
+
You are a Leader agent (beeops L2).
|
|
100
|
+
You are responsible for completing the implementation of GitHub Issue #${ISSUE}.
|
|
101
|
+
|
|
102
|
+
## Work Environment
|
|
103
|
+
- Working directory: ${WORK_DIR}
|
|
104
|
+
- Branch '${BRANCH}' is already checked out (git worktree)
|
|
105
|
+
- Report output directory: ${REPORTS_DIR}
|
|
106
|
+
- Prompt output directory: ${PROMPTS_DIR}
|
|
107
|
+
- Issue number: ${ISSUE}
|
|
108
|
+
|
|
109
|
+
## Procedure
|
|
110
|
+
1. Review the issue: gh issue view ${ISSUE} --json body,title,labels
|
|
111
|
+
2. Skill: bo-task-decomposer to decompose into subtasks
|
|
112
|
+
3. Skill: bo-leader-dispatch to launch Workers in parallel
|
|
113
|
+
4. Evaluate Worker reports for quality (re-run up to 2 times if unsatisfactory)
|
|
114
|
+
5. After all subtasks are complete, perform a self-critical review (read the PR diff and verify alignment with Issue requirements)
|
|
115
|
+
6. Write ${REPORTS_DIR}/leader-${ISSUE}-summary.yaml
|
|
116
|
+
7. Send tmux wait-for -S queen-wake
|
|
117
|
+
|
|
118
|
+
## Report Format (leader-${ISSUE}-summary.yaml)
|
|
119
|
+
\`\`\`yaml
|
|
120
|
+
issue: ${ISSUE}
|
|
121
|
+
role: leader
|
|
122
|
+
status: completed # completed | failed
|
|
123
|
+
branch: ${BRANCH}
|
|
124
|
+
pr: "PR URL"
|
|
125
|
+
summary: "High-level overview of the implementation"
|
|
126
|
+
subtasks_completed: 3
|
|
127
|
+
subtasks_total: 3
|
|
128
|
+
concerns: null # Note any concerns if applicable
|
|
129
|
+
key_changes:
|
|
130
|
+
- file: "file path"
|
|
131
|
+
what: "description of change"
|
|
132
|
+
design_decisions:
|
|
133
|
+
- decision: "what was chosen"
|
|
134
|
+
reason: "why"
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
## Critical Rules
|
|
138
|
+
- Never ask the user questions. Make all decisions yourself
|
|
139
|
+
- Delegate work to Workers. Do not write code yourself
|
|
140
|
+
- Have the final worker-coder create the PR
|
|
141
|
+
- Handle errors on your own
|
|
142
|
+
PROMPT_EOF
|
|
143
|
+
;;
|
|
144
|
+
|
|
145
|
+
review-leader)
|
|
146
|
+
cat > "$PROMPT_FILE" <<PROMPT_EOF
|
|
147
|
+
You are a Review Leader agent (beeops L2).
|
|
148
|
+
You are responsible for reviewing the PR for Issue #${ISSUE}.
|
|
149
|
+
|
|
150
|
+
## Work Environment
|
|
151
|
+
- Working directory: ${WORK_DIR}
|
|
152
|
+
- Branch: ${BRANCH}
|
|
153
|
+
- Report output directory: ${REPORTS_DIR}
|
|
154
|
+
- Prompt output directory: ${PROMPTS_DIR}
|
|
155
|
+
- Issue number: ${ISSUE}
|
|
156
|
+
|
|
157
|
+
## Procedure
|
|
158
|
+
1. Review the PR diff: gh pr diff --name-only && gh pr diff
|
|
159
|
+
2. Determine complexity (simple/standard/complex)
|
|
160
|
+
3. Skill: bo-leader-dispatch to launch Review Workers in parallel
|
|
161
|
+
4. Aggregate Worker findings + perform anti-sycophancy check
|
|
162
|
+
5. Write ${REPORTS_DIR}/review-leader-${ISSUE}-verdict.yaml
|
|
163
|
+
6. Send tmux wait-for -S queen-wake
|
|
164
|
+
|
|
165
|
+
## Complexity Rules
|
|
166
|
+
| Complexity | Criteria | Workers to Launch |
|
|
167
|
+
|------------|----------|-------------------|
|
|
168
|
+
| simple | Changed files <= 2 and all are config/docs | worker-code-reviewer only |
|
|
169
|
+
| complex | Changed files >= 5, includes auth/migration | worker-code-reviewer + worker-security + worker-test-auditor |
|
|
170
|
+
| standard | Everything else | worker-code-reviewer + worker-security |
|
|
171
|
+
|
|
172
|
+
## Report Format (review-leader-${ISSUE}-verdict.yaml)
|
|
173
|
+
\`\`\`yaml
|
|
174
|
+
issue: ${ISSUE}
|
|
175
|
+
role: review-leader
|
|
176
|
+
complexity: standard
|
|
177
|
+
council_members: [worker-code-reviewer, worker-security]
|
|
178
|
+
final_verdict: approve # approve | fix_required
|
|
179
|
+
anti_sycophancy_triggered: false
|
|
180
|
+
merged_findings:
|
|
181
|
+
- source: worker-security
|
|
182
|
+
severity: high
|
|
183
|
+
file: "file path"
|
|
184
|
+
line: line number
|
|
185
|
+
message: "description of finding"
|
|
186
|
+
fix_instructions: null # Only populate when fix_required
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
## Critical Rules
|
|
190
|
+
- Never ask the user questions. Make all decisions yourself
|
|
191
|
+
- Delegate reviews to Review Workers. Do not read code yourself (only grasp the diff overview)
|
|
192
|
+
- Only mark fix_required for critical issues
|
|
193
|
+
PROMPT_EOF
|
|
194
|
+
;;
|
|
195
|
+
esac
|
|
196
|
+
fi # end of fix prompt check
|
|
197
|
+
|
|
198
|
+
# โโ Wrapper script (runs inside tmux pane) โโ
|
|
199
|
+
WRAPPER="/tmp/agent-wrapper-${ROLE_SHORT}-${ISSUE}.sh"
|
|
200
|
+
cat > "$WRAPPER" <<'WRAPPER_HEADER'
|
|
201
|
+
#!/bin/bash
|
|
202
|
+
set -uo pipefail
|
|
203
|
+
WRAPPER_HEADER
|
|
204
|
+
|
|
205
|
+
cat >> "$WRAPPER" <<WRAPPER_BODY
|
|
206
|
+
WORK_DIR="${WORK_DIR}"
|
|
207
|
+
REPO_DIR="${REPO_DIR}"
|
|
208
|
+
REPORTS_DIR="${REPORTS_DIR}"
|
|
209
|
+
PROMPT_FILE="${PROMPT_FILE}"
|
|
210
|
+
ROLE="${ROLE}"
|
|
211
|
+
ROLE_SHORT="${ROLE_SHORT}"
|
|
212
|
+
ENV_VAR="${ENV_VAR}"
|
|
213
|
+
ISSUE="${ISSUE}"
|
|
214
|
+
BRANCH="${BRANCH}"
|
|
215
|
+
WORKTREE_PATH="${WORKTREE_PATH}"
|
|
216
|
+
MAX_TURNS="${MAX_TURNS}"
|
|
217
|
+
ALLOWED_TOOLS="${ALLOWED_TOOLS}"
|
|
218
|
+
BO_SCRIPTS_DIR="${BO_SCRIPTS_DIR:-}"
|
|
219
|
+
BO_CONTEXTS_DIR="${BO_CONTEXTS_DIR:-}"
|
|
220
|
+
|
|
221
|
+
cd "\$WORK_DIR"
|
|
222
|
+
|
|
223
|
+
# Run agent
|
|
224
|
+
unset CLAUDECODE
|
|
225
|
+
env \${ENV_VAR}=1 \
|
|
226
|
+
BO_SCRIPTS_DIR="\$BO_SCRIPTS_DIR" \
|
|
227
|
+
BO_CONTEXTS_DIR="\$BO_CONTEXTS_DIR" \
|
|
228
|
+
claude --dangerously-skip-permissions \
|
|
229
|
+
--allowedTools "\$ALLOWED_TOOLS" \
|
|
230
|
+
--max-turns \$MAX_TURNS \
|
|
231
|
+
"\$(cat "\$PROMPT_FILE")"
|
|
232
|
+
EXIT_CODE=\$?
|
|
233
|
+
|
|
234
|
+
# Write basic report
|
|
235
|
+
TIMESTAMP=\$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
236
|
+
STATUS=\$([ \$EXIT_CODE -eq 0 ] && echo completed || echo failed)
|
|
237
|
+
|
|
238
|
+
cat > "\$REPORTS_DIR/\${ROLE_SHORT}-\${ISSUE}.yaml" <<REPORT
|
|
239
|
+
issue: \$ISSUE
|
|
240
|
+
role: \$ROLE
|
|
241
|
+
status: \$STATUS
|
|
242
|
+
exit_code: \$EXIT_CODE
|
|
243
|
+
branch: \$BRANCH
|
|
244
|
+
timestamp: \$TIMESTAMP
|
|
245
|
+
REPORT
|
|
246
|
+
|
|
247
|
+
# Update pane style to indicate completion
|
|
248
|
+
if [ \$EXIT_CODE -eq 0 ]; then
|
|
249
|
+
tmux select-pane -T "โ
\${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
|
|
250
|
+
tmux set-option -p @agent_label "โ
\${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
|
|
251
|
+
else
|
|
252
|
+
tmux select-pane -T "โ \${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
|
|
253
|
+
tmux set-option -p @agent_label "โ \${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
|
|
254
|
+
fi
|
|
255
|
+
tmux set-option -p pane-border-style "fg=colour240" 2>/dev/null || true
|
|
256
|
+
|
|
257
|
+
# Signal Queen
|
|
258
|
+
tmux wait-for -S queen-wake 2>/dev/null || true
|
|
259
|
+
|
|
260
|
+
# Note: worktree is intentionally kept alive after Leader completion.
|
|
261
|
+
# The branch is needed for PR review cycles and CI checks.
|
|
262
|
+
# Cleanup happens after PR merge (managed by Queen via bo-dispatch).
|
|
263
|
+
|
|
264
|
+
echo "--- \$ROLE completed (exit=\$EXIT_CODE) ---"
|
|
265
|
+
WRAPPER_BODY
|
|
266
|
+
|
|
267
|
+
chmod +x "$WRAPPER"
|
|
268
|
+
|
|
269
|
+
# โโ Kill existing window with same name if present โโ
|
|
270
|
+
tmux kill-window -t "$SESSION:$WINDOW_NAME" 2>/dev/null || true
|
|
271
|
+
|
|
272
|
+
# โโ Create new tmux window โโ
|
|
273
|
+
tmux new-window -t "$SESSION" -n "$WINDOW_NAME" "bash '$WRAPPER'; exit 0"
|
|
274
|
+
|
|
275
|
+
# Pane title + styling
|
|
276
|
+
tmux select-pane -t "$SESSION:$WINDOW_NAME.0" -T "$PANE_TITLE"
|
|
277
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" @agent_label "$PANE_TITLE" 2>/dev/null || true
|
|
278
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" allow-rename off 2>/dev/null || true
|
|
279
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" remain-on-exit on 2>/dev/null || true
|
|
280
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" pane-border-style "fg=${BORDER_FG}" 2>/dev/null || true
|
|
281
|
+
|
|
282
|
+
echo "launched:${ROLE_SHORT}-${ISSUE} (window: ${WINDOW_NAME}, worktree: ${WORKTREE_PATH:-none})"
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# launch-worker.sh - Launch Worker in a tmux split-pane (within Leader's window)
|
|
3
|
+
# Usage: launch-worker.sh <role> <issue> <subtask_id> <branch>
|
|
4
|
+
#
|
|
5
|
+
# Part of beeops: 3-layer multi-agent system (Queen โ Leader โ Worker)
|
|
6
|
+
#
|
|
7
|
+
# Features:
|
|
8
|
+
# - tmux split-window -h: adds pane within Leader's window
|
|
9
|
+
# - No worktree creation (shares Leader's worktree)
|
|
10
|
+
# - Signals leader-{issue}-wake on completion
|
|
11
|
+
# - Smaller max_turns (15-30)
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
ROLE="$1"
|
|
16
|
+
ISSUE="$2"
|
|
17
|
+
SUBTASK_ID="$3"
|
|
18
|
+
BRANCH="$4"
|
|
19
|
+
SESSION="bo"
|
|
20
|
+
REPO_DIR="$(git rev-parse --show-toplevel)"
|
|
21
|
+
REPORTS_DIR="$REPO_DIR/.claude/tasks/reports"
|
|
22
|
+
PROMPTS_DIR="$REPO_DIR/.claude/tasks/prompts"
|
|
23
|
+
|
|
24
|
+
mkdir -p "$REPORTS_DIR/processed" "$PROMPTS_DIR"
|
|
25
|
+
|
|
26
|
+
# โโ Role configuration โโ
|
|
27
|
+
case "$ROLE" in
|
|
28
|
+
worker-coder)
|
|
29
|
+
ROLE_SHORT="worker-coder"
|
|
30
|
+
ENV_VAR="BO_WORKER_CODER"
|
|
31
|
+
WINDOW_NAME="issue-${ISSUE}"
|
|
32
|
+
BORDER_FG="green"
|
|
33
|
+
ROLE_ICON="โก"
|
|
34
|
+
MAX_TURNS=30
|
|
35
|
+
ALLOWED_TOOLS="Read,Write,Edit,Bash,Glob,Grep"
|
|
36
|
+
;;
|
|
37
|
+
worker-tester)
|
|
38
|
+
ROLE_SHORT="worker-tester"
|
|
39
|
+
ENV_VAR="BO_WORKER_TESTER"
|
|
40
|
+
WINDOW_NAME="issue-${ISSUE}"
|
|
41
|
+
BORDER_FG="cyan"
|
|
42
|
+
ROLE_ICON="๐งช"
|
|
43
|
+
MAX_TURNS=30
|
|
44
|
+
ALLOWED_TOOLS="Read,Write,Edit,Bash,Glob,Grep"
|
|
45
|
+
;;
|
|
46
|
+
worker-code-reviewer)
|
|
47
|
+
ROLE_SHORT="worker-code-reviewer"
|
|
48
|
+
ENV_VAR="BO_WORKER_CODE_REVIEWER"
|
|
49
|
+
WINDOW_NAME="review-${ISSUE}"
|
|
50
|
+
BORDER_FG="blue"
|
|
51
|
+
ROLE_ICON="๐"
|
|
52
|
+
MAX_TURNS=15
|
|
53
|
+
ALLOWED_TOOLS="Read,Grep,Glob,Bash"
|
|
54
|
+
;;
|
|
55
|
+
worker-security)
|
|
56
|
+
ROLE_SHORT="worker-security"
|
|
57
|
+
ENV_VAR="BO_WORKER_SECURITY"
|
|
58
|
+
WINDOW_NAME="review-${ISSUE}"
|
|
59
|
+
BORDER_FG="red"
|
|
60
|
+
ROLE_ICON="๐ก"
|
|
61
|
+
MAX_TURNS=15
|
|
62
|
+
ALLOWED_TOOLS="Read,Grep,Glob,Bash"
|
|
63
|
+
;;
|
|
64
|
+
worker-test-auditor)
|
|
65
|
+
ROLE_SHORT="worker-test-auditor"
|
|
66
|
+
ENV_VAR="BO_WORKER_TEST_AUDITOR"
|
|
67
|
+
WINDOW_NAME="review-${ISSUE}"
|
|
68
|
+
BORDER_FG="yellow"
|
|
69
|
+
ROLE_ICON="๐งช"
|
|
70
|
+
MAX_TURNS=15
|
|
71
|
+
ALLOWED_TOOLS="Read,Grep,Glob,Bash"
|
|
72
|
+
;;
|
|
73
|
+
*)
|
|
74
|
+
echo "Unknown role: $ROLE (expected: worker-coder | worker-tester | worker-code-reviewer | worker-security | worker-test-auditor)" >&2
|
|
75
|
+
exit 1
|
|
76
|
+
;;
|
|
77
|
+
esac
|
|
78
|
+
|
|
79
|
+
PANE_TITLE="${ROLE_ICON} ${ROLE_SHORT}-${ISSUE}-${SUBTASK_ID}"
|
|
80
|
+
SIGNAL_NAME="leader-${ISSUE}-wake"
|
|
81
|
+
|
|
82
|
+
# โโ Determine work directory (use Leader's worktree if available) โโ
|
|
83
|
+
WORKTREE_PATH="$REPO_DIR/.claude/worktrees/$BRANCH"
|
|
84
|
+
if [ -d "$WORKTREE_PATH" ]; then
|
|
85
|
+
WORK_DIR="$WORKTREE_PATH"
|
|
86
|
+
else
|
|
87
|
+
WORK_DIR="$REPO_DIR"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# โโ Read prompt file (Leader writes this before launching worker) โโ
|
|
91
|
+
PROMPT_FILE="$PROMPTS_DIR/worker-${ISSUE}-${SUBTASK_ID}.md"
|
|
92
|
+
if [ ! -f "$PROMPT_FILE" ]; then
|
|
93
|
+
echo "ERROR: Prompt file not found: $PROMPT_FILE" >&2
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# โโ Wrapper script (runs inside tmux pane) โโ
|
|
98
|
+
WRAPPER="/tmp/agent-wrapper-${ROLE_SHORT}-${ISSUE}-${SUBTASK_ID}.sh"
|
|
99
|
+
cat > "$WRAPPER" <<'WRAPPER_HEADER'
|
|
100
|
+
#!/bin/bash
|
|
101
|
+
set -uo pipefail
|
|
102
|
+
WRAPPER_HEADER
|
|
103
|
+
|
|
104
|
+
cat >> "$WRAPPER" <<WRAPPER_BODY
|
|
105
|
+
WORK_DIR="${WORK_DIR}"
|
|
106
|
+
REPO_DIR="${REPO_DIR}"
|
|
107
|
+
REPORTS_DIR="${REPORTS_DIR}"
|
|
108
|
+
PROMPT_FILE="${PROMPT_FILE}"
|
|
109
|
+
ROLE="${ROLE}"
|
|
110
|
+
ROLE_SHORT="${ROLE_SHORT}"
|
|
111
|
+
ENV_VAR="${ENV_VAR}"
|
|
112
|
+
ISSUE="${ISSUE}"
|
|
113
|
+
SUBTASK_ID="${SUBTASK_ID}"
|
|
114
|
+
BRANCH="${BRANCH}"
|
|
115
|
+
SIGNAL_NAME="${SIGNAL_NAME}"
|
|
116
|
+
MAX_TURNS="${MAX_TURNS}"
|
|
117
|
+
ALLOWED_TOOLS="${ALLOWED_TOOLS}"
|
|
118
|
+
BO_SCRIPTS_DIR="${BO_SCRIPTS_DIR:-}"
|
|
119
|
+
BO_CONTEXTS_DIR="${BO_CONTEXTS_DIR:-}"
|
|
120
|
+
|
|
121
|
+
cd "\$WORK_DIR"
|
|
122
|
+
|
|
123
|
+
# Run agent
|
|
124
|
+
unset CLAUDECODE
|
|
125
|
+
env \${ENV_VAR}=1 \
|
|
126
|
+
BO_SCRIPTS_DIR="\$BO_SCRIPTS_DIR" \
|
|
127
|
+
BO_CONTEXTS_DIR="\$BO_CONTEXTS_DIR" \
|
|
128
|
+
claude --dangerously-skip-permissions \
|
|
129
|
+
--allowedTools "\$ALLOWED_TOOLS" \
|
|
130
|
+
--max-turns \$MAX_TURNS \
|
|
131
|
+
--no-session-persistence \
|
|
132
|
+
"\$(cat "\$PROMPT_FILE")"
|
|
133
|
+
EXIT_CODE=\$?
|
|
134
|
+
|
|
135
|
+
# Write basic report
|
|
136
|
+
TIMESTAMP=\$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
137
|
+
STATUS=\$([ \$EXIT_CODE -eq 0 ] && echo completed || echo failed)
|
|
138
|
+
|
|
139
|
+
cat > "\$REPORTS_DIR/worker-\${ISSUE}-\${SUBTASK_ID}.yaml" <<REPORT
|
|
140
|
+
issue: \$ISSUE
|
|
141
|
+
subtask_id: \$SUBTASK_ID
|
|
142
|
+
role: \$ROLE
|
|
143
|
+
status: \$STATUS
|
|
144
|
+
exit_code: \$EXIT_CODE
|
|
145
|
+
branch: \$BRANCH
|
|
146
|
+
timestamp: \$TIMESTAMP
|
|
147
|
+
REPORT
|
|
148
|
+
|
|
149
|
+
# Update pane style to indicate completion
|
|
150
|
+
if [ \$EXIT_CODE -eq 0 ]; then
|
|
151
|
+
tmux select-pane -T "โ
\${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
|
|
152
|
+
tmux set-option -p @agent_label "โ
\${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
|
|
153
|
+
else
|
|
154
|
+
tmux select-pane -T "โ \${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
|
|
155
|
+
tmux set-option -p @agent_label "โ \${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
|
|
156
|
+
fi
|
|
157
|
+
tmux set-option -p pane-border-style "fg=colour240" 2>/dev/null || true
|
|
158
|
+
|
|
159
|
+
# Signal Leader
|
|
160
|
+
tmux wait-for -S \$SIGNAL_NAME 2>/dev/null || true
|
|
161
|
+
|
|
162
|
+
echo "--- \$ROLE (subtask \$SUBTASK_ID) completed (exit=\$EXIT_CODE) ---"
|
|
163
|
+
WRAPPER_BODY
|
|
164
|
+
|
|
165
|
+
chmod +x "$WRAPPER"
|
|
166
|
+
|
|
167
|
+
# โโ Clean up dead panes from previous runs โโ
|
|
168
|
+
for DEAD_PANE in $(tmux list-panes -t "$SESSION:$WINDOW_NAME" -F '#{pane_index} #{pane_dead}' 2>/dev/null | awk '$2=="1"{print $1}' | sort -rn); do
|
|
169
|
+
tmux kill-pane -t "$SESSION:$WINDOW_NAME.${DEAD_PANE}" 2>/dev/null || true
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
# โโ Launch in tmux split-pane (within Leader's window) โโ
|
|
173
|
+
tmux split-window -h -t "$SESSION:$WINDOW_NAME" "bash '$WRAPPER'; exit 0"
|
|
174
|
+
|
|
175
|
+
# Pane title + styling
|
|
176
|
+
LAST_PANE=$(tmux list-panes -t "$SESSION:$WINDOW_NAME" -F '#{pane_index}' | tail -1)
|
|
177
|
+
tmux select-pane -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" -T "$PANE_TITLE"
|
|
178
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" @agent_label "$PANE_TITLE" 2>/dev/null || true
|
|
179
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" allow-rename off 2>/dev/null || true
|
|
180
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" remain-on-exit on 2>/dev/null || true
|
|
181
|
+
tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" pane-border-style "fg=${BORDER_FG}" 2>/dev/null || true
|
|
182
|
+
tmux select-layout -t "$SESSION:$WINDOW_NAME" tiled 2>/dev/null || true
|
|
183
|
+
|
|
184
|
+
echo "launched:${ROLE_SHORT}-${ISSUE}-${SUBTASK_ID} (window: ${WINDOW_NAME})"
|