@walwal-harness/cli 4.0.0-alpha.16 → 4.0.0-alpha.18
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/package.json +1 -1
- package/scripts/harness-studio-v4.sh +96 -75
- package/skills/team/SKILL.md +63 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.18",
|
|
4
4
|
"description": "Production harness for AI agent engineering — Planner, Generator(BE/FE), Evaluator(Func/Visual), optional Brainstormer (requirements refinement). Supports React and Flutter FE stacks.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# harness-studio-v4.sh — Harness Studio v4
|
|
2
|
+
# harness-studio-v4.sh — Harness Studio v4
|
|
3
3
|
#
|
|
4
4
|
# ┌──────────────┬──────────────┬──────────────┐
|
|
5
5
|
# │ │ Progress │ Team 1 │
|
|
6
|
-
# │ │ (fixed) ├──────────────┤
|
|
7
6
|
# │ Main ├──────────────┤ Team 2 │
|
|
8
|
-
# │ (claude) │ Prompts
|
|
9
|
-
# │ │ (scroll) │ Team 3 │
|
|
7
|
+
# │ (claude) │ Prompts │ Team 3 │
|
|
10
8
|
# └──────────────┴──────────────┴──────────────┘
|
|
11
9
|
|
|
12
10
|
set -euo pipefail
|
|
@@ -15,16 +13,10 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
15
13
|
SESSION_NAME="harness-v4"
|
|
16
14
|
|
|
17
15
|
PROJECT_ROOT=""
|
|
18
|
-
|
|
19
16
|
for arg in "$@"; do
|
|
20
17
|
case "$arg" in
|
|
21
|
-
--kill)
|
|
22
|
-
|
|
23
|
-
exit 0
|
|
24
|
-
;;
|
|
25
|
-
*)
|
|
26
|
-
if [ -d "$arg" ]; then PROJECT_ROOT="$arg"; fi
|
|
27
|
-
;;
|
|
18
|
+
--kill) tmux kill-session -t "$SESSION_NAME" 2>/dev/null && echo "Killed." || echo "No session."; exit 0 ;;
|
|
19
|
+
*) if [ -d "$arg" ]; then PROJECT_ROOT="$arg"; fi ;;
|
|
28
20
|
esac
|
|
29
21
|
done
|
|
30
22
|
|
|
@@ -37,14 +29,14 @@ if [ -z "$PROJECT_ROOT" ]; then
|
|
|
37
29
|
fi
|
|
38
30
|
|
|
39
31
|
if [ -z "$PROJECT_ROOT" ] || [ ! -d "$PROJECT_ROOT/.harness" ]; then
|
|
40
|
-
echo "Error: .harness/ not found."
|
|
41
|
-
exit 1
|
|
32
|
+
echo "Error: .harness/ not found."; exit 1
|
|
42
33
|
fi
|
|
43
34
|
|
|
44
35
|
echo "Project: $PROJECT_ROOT"
|
|
45
36
|
echo "Session: $SESSION_NAME"
|
|
46
37
|
|
|
47
38
|
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
|
|
39
|
+
sleep 0.5
|
|
48
40
|
|
|
49
41
|
# ── Init/recover queue ──
|
|
50
42
|
QUEUE="$PROJECT_ROOT/.harness/actions/feature-queue.json"
|
|
@@ -57,90 +49,119 @@ else
|
|
|
57
49
|
fi
|
|
58
50
|
|
|
59
51
|
# ══════════════════════════════════════════
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
# Step 1: [Main]
|
|
63
|
-
# Step 2: [Main | Right] — h split 66%
|
|
64
|
-
# Step 3: [Main | Mid | Right] — h split Mid from Right at 50%
|
|
65
|
-
# Step 4: [Main | Progress / Prompts | Right] — v split Mid
|
|
66
|
-
# Step 5: [Main | Progress / Prompts | T1 / T2 / T3] — v split Right
|
|
52
|
+
# Build layout — all panes use direct command execution
|
|
53
|
+
# Panes that exit will show "Pane is dead" instead of closing
|
|
67
54
|
# ══════════════════════════════════════════
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
tmux set-option -g remain-on-exit on 2>/dev/null || true
|
|
57
|
+
|
|
58
|
+
# 1. Main (left, 34%)
|
|
70
59
|
PANE_MAIN=$(tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 220 -y 55 \
|
|
71
60
|
-P -F '#{pane_id}')
|
|
72
61
|
|
|
73
|
-
# 2. Right
|
|
62
|
+
# 2. Right area (66%) — will become Teams
|
|
74
63
|
PANE_RIGHT=$(tmux split-window -h -p 66 -t "$PANE_MAIN" -c "$PROJECT_ROOT" \
|
|
75
|
-
-P -F '#{pane_id}'
|
|
64
|
+
-P -F '#{pane_id}' \
|
|
65
|
+
"bash '${SCRIPT_DIR}/harness-team-worker.sh' 1 '${PROJECT_ROOT}'")
|
|
76
66
|
|
|
77
|
-
# 3. Middle column
|
|
67
|
+
# 3. Middle column — split from Right (50/50)
|
|
78
68
|
PANE_MID=$(tmux split-window -h -p 50 -t "$PANE_RIGHT" -c "$PROJECT_ROOT" \
|
|
79
|
-
-P -F '#{pane_id}')
|
|
80
|
-
# Now: PANE_MID is the NEW pane (right side of split), PANE_RIGHT stays left
|
|
81
|
-
# Wait — tmux split-window -h on PANE_RIGHT creates new pane to the RIGHT of PANE_RIGHT
|
|
82
|
-
# So PANE_MID ends up on the right, and PANE_RIGHT is in the middle
|
|
83
|
-
# We need to swap: split PANE_MAIN's right, then the rightmost becomes teams
|
|
84
|
-
|
|
85
|
-
# Actually let me reconsider. After step 2:
|
|
86
|
-
# [Main 33%] [Right 66%]
|
|
87
|
-
# After step 3 (split Right horizontally at 50%):
|
|
88
|
-
# [Main 33%] [Right_left 33%] [Right_right 33%]
|
|
89
|
-
# Right_left = PANE_RIGHT (original), Right_right = PANE_MID (new)
|
|
90
|
-
# We want: Right_left = Dashboard area, Right_right = Team area
|
|
91
|
-
# So PANE_RIGHT becomes Dashboard, PANE_MID becomes Teams. But pane IDs...
|
|
92
|
-
# Actually: split-window creates the NEW pane. -h splits horizontally.
|
|
93
|
-
# The new pane goes to the right. So:
|
|
94
|
-
# PANE_RIGHT (original) = middle column (Dashboard)
|
|
95
|
-
# PANE_MID (new) = right column (Teams)
|
|
96
|
-
# Perfect!
|
|
97
|
-
|
|
98
|
-
# 4. Split middle column (PANE_RIGHT = Dashboard area) into Progress + Prompts
|
|
99
|
-
# Kill the shell in PANE_RIGHT first, replace with Progress
|
|
100
|
-
tmux send-keys -t "$PANE_RIGHT" "exec bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-dashboard-v4.sh\" \"${PROJECT_ROOT}\"'" Enter
|
|
101
|
-
|
|
102
|
-
PANE_PROMPTS=$(tmux split-window -v -p 40 -t "$PANE_RIGHT" -c "$PROJECT_ROOT" \
|
|
103
69
|
-P -F '#{pane_id}' \
|
|
104
|
-
"bash
|
|
70
|
+
"bash '${SCRIPT_DIR}/harness-team-worker.sh' 2 '${PROJECT_ROOT}'")
|
|
105
71
|
|
|
106
|
-
#
|
|
107
|
-
|
|
72
|
+
# Now layout: [Main 34%] [Right 33%] [Mid 33%]
|
|
73
|
+
# Right = Team 1, Mid = Team 2
|
|
74
|
+
# But we need: [Main] [Dashboard area] [Teams area]
|
|
75
|
+
# Swap: Right should be dashboard, Mid should stay as teams
|
|
76
|
+
# Actually after split: PANE_RIGHT stays left (=Team1), PANE_MID is new right (=Team2)
|
|
77
|
+
# We need to rethink...
|
|
108
78
|
|
|
109
|
-
|
|
110
|
-
-P -F '#{pane_id}' \
|
|
111
|
-
"bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-team-worker.sh\" 2 \"${PROJECT_ROOT}\"'")
|
|
79
|
+
# Let me use a cleaner approach: create all columns first with placeholder shells
|
|
112
80
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
81
|
+
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
|
|
82
|
+
sleep 0.3
|
|
83
|
+
|
|
84
|
+
# === Clean rebuild ===
|
|
85
|
+
|
|
86
|
+
# Pane 0: Main
|
|
87
|
+
tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 220 -y 55
|
|
116
88
|
|
|
117
|
-
#
|
|
118
|
-
tmux
|
|
89
|
+
# Split: [Main 34% | Rest 66%]
|
|
90
|
+
tmux split-window -h -p 66 -t "${SESSION_NAME}:0.0" -c "$PROJECT_ROOT"
|
|
119
91
|
|
|
120
|
-
#
|
|
121
|
-
tmux
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
tmux
|
|
126
|
-
|
|
92
|
+
# Split Rest: [Main 34% | Mid 50% | Right 50%] (of the 66%)
|
|
93
|
+
tmux split-window -h -p 50 -t "${SESSION_NAME}:0.1" -c "$PROJECT_ROOT"
|
|
94
|
+
|
|
95
|
+
# Now: pane 0 = Main (left), pane 1 = Mid, pane 2 = Right
|
|
96
|
+
# Split Mid vertically: Progress (60%) / Prompts (40%)
|
|
97
|
+
tmux split-window -v -p 40 -t "${SESSION_NAME}:0.1" -c "$PROJECT_ROOT"
|
|
98
|
+
|
|
99
|
+
# Now: pane 0=Main, pane 1=Mid-top(Progress), pane 2=Right, pane 3=Mid-bottom(Prompts)
|
|
100
|
+
# Split Right into 3 Teams
|
|
101
|
+
tmux split-window -v -p 66 -t "${SESSION_NAME}:0.2" -c "$PROJECT_ROOT"
|
|
102
|
+
tmux split-window -v -p 50 -t "${SESSION_NAME}:0.3" -c "$PROJECT_ROOT"
|
|
103
|
+
|
|
104
|
+
# Now 6 panes. Let's identify them by listing:
|
|
105
|
+
# pane 0 = Main (left)
|
|
106
|
+
# pane 1 = Progress (mid-top)
|
|
107
|
+
# pane 2 = Team area top
|
|
108
|
+
# pane 3 = Prompts (mid-bottom)
|
|
109
|
+
# pane 4 = Team area mid (split from pane 2's bottom sibling? — tmux numbering is tricky)
|
|
110
|
+
|
|
111
|
+
# Instead of guessing pane numbers, send commands to each pane by index after creation
|
|
112
|
+
# First set remain-on-exit for this session
|
|
113
|
+
tmux set-option -t "$SESSION_NAME" remain-on-exit on 2>/dev/null || true
|
|
114
|
+
|
|
115
|
+
# Get all pane IDs in order
|
|
116
|
+
PANES=($(tmux list-panes -t "$SESSION_NAME" -F '#{pane_id}'))
|
|
117
|
+
|
|
118
|
+
# Should be 6 panes. Assign by position:
|
|
119
|
+
# Visual order (left-to-right, top-to-bottom):
|
|
120
|
+
# [0] Main [1] Progress [2] Team-top
|
|
121
|
+
# [3] Prompts [4] Team-mid
|
|
122
|
+
# [5] Team-bottom
|
|
123
|
+
|
|
124
|
+
if [ ${#PANES[@]} -ne 6 ]; then
|
|
125
|
+
echo "ERROR: Expected 6 panes, got ${#PANES[@]}"
|
|
126
|
+
echo "Panes: ${PANES[*]}"
|
|
127
|
+
tmux attach -t "$SESSION_NAME"
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
P_MAIN="${PANES[0]}"
|
|
132
|
+
P_PROGRESS="${PANES[1]}"
|
|
133
|
+
P_TEAM1="${PANES[2]}"
|
|
134
|
+
P_PROMPTS="${PANES[3]}"
|
|
135
|
+
P_TEAM2="${PANES[4]}"
|
|
136
|
+
P_TEAM3="${PANES[5]}"
|
|
137
|
+
|
|
138
|
+
# Send commands to each pane
|
|
139
|
+
tmux send-keys -t "$P_MAIN" "unset npm_config_prefix 2>/dev/null; clear && claude --dangerously-skip-permissions" Enter
|
|
140
|
+
tmux send-keys -t "$P_PROGRESS" "bash '${SCRIPT_DIR}/harness-dashboard-v4.sh' '${PROJECT_ROOT}'" Enter
|
|
141
|
+
tmux send-keys -t "$P_PROMPTS" "bash '${SCRIPT_DIR}/harness-prompts-v4.sh' '${PROJECT_ROOT}'" Enter
|
|
142
|
+
tmux send-keys -t "$P_TEAM1" "bash '${SCRIPT_DIR}/harness-team-worker.sh' 1 '${PROJECT_ROOT}'" Enter
|
|
143
|
+
tmux send-keys -t "$P_TEAM2" "bash '${SCRIPT_DIR}/harness-team-worker.sh' 2 '${PROJECT_ROOT}'" Enter
|
|
144
|
+
tmux send-keys -t "$P_TEAM3" "bash '${SCRIPT_DIR}/harness-team-worker.sh' 3 '${PROJECT_ROOT}'" Enter
|
|
145
|
+
|
|
146
|
+
# Titles
|
|
147
|
+
tmux select-pane -t "$P_MAIN" -T "Main"
|
|
148
|
+
tmux select-pane -t "$P_PROGRESS" -T "Progress"
|
|
149
|
+
tmux select-pane -t "$P_PROMPTS" -T "Prompts"
|
|
150
|
+
tmux select-pane -t "$P_TEAM1" -T "Team 1"
|
|
151
|
+
tmux select-pane -t "$P_TEAM2" -T "Team 2"
|
|
152
|
+
tmux select-pane -t "$P_TEAM3" -T "Team 3"
|
|
127
153
|
|
|
128
154
|
tmux set-option -t "$SESSION_NAME" pane-border-status top 2>/dev/null || true
|
|
129
155
|
tmux set-option -t "$SESSION_NAME" pane-border-format " #{pane_title} " 2>/dev/null || true
|
|
130
156
|
|
|
131
|
-
#
|
|
132
|
-
tmux select-pane -t "$
|
|
157
|
+
# Focus Main
|
|
158
|
+
tmux select-pane -t "$P_MAIN"
|
|
133
159
|
|
|
134
|
-
#
|
|
160
|
+
# Attach
|
|
135
161
|
if [ -n "${TMUX:-}" ]; then
|
|
136
162
|
tmux switch-client -t "$SESSION_NAME"
|
|
137
163
|
else
|
|
138
164
|
echo ""
|
|
139
165
|
echo "Launching Harness Studio v4..."
|
|
140
|
-
echo " Main (left) : Claude interactive"
|
|
141
|
-
echo " Progress (mid↑) : Queue + Teams + Features"
|
|
142
|
-
echo " Prompts (mid↓) : Manual prompts + activity"
|
|
143
|
-
echo " Team 1-3 (right) : Parallel workers"
|
|
144
|
-
echo ""
|
|
145
166
|
tmux attach -t "$SESSION_NAME"
|
|
146
167
|
fi
|
package/skills/team/SKILL.md
CHANGED
|
@@ -1,27 +1,77 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: harness-team
|
|
3
|
-
description: "v4 Parallel Agent Teams 모드
|
|
3
|
+
description: "v4 Parallel Agent Teams 모드 활성화. feature-queue 초기화 후 3개 Team worker를 백그라운드 실행한다. 트리거: '/harness-team', 'agent team 시작', 'team 모드'"
|
|
4
|
+
disable-model-invocation: false
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
# /harness-team — Parallel Agent Teams
|
|
7
|
+
# /harness-team — Parallel Agent Teams 활성화
|
|
7
8
|
|
|
8
|
-
이 스킬이 호출되면
|
|
9
|
+
## 이 스킬이 호출되면
|
|
10
|
+
|
|
11
|
+
1. **feature-queue.json 확인/초기화** — 없으면 feature-list.json에서 생성, 있으면 stale 복구
|
|
12
|
+
2. **3개 Team Worker를 백그라운드로 시작** — 각각 claude -p로 Gen→Eval 루프 자율 실행
|
|
13
|
+
3. **현재 세션은 유지** — 사용자는 오케스트레이터 역할 (모니터링, 실패 대응, 수동 개입)
|
|
9
14
|
|
|
10
15
|
## 실행 절차
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
아래 명령을 순서대로 실행하세요:
|
|
18
|
+
|
|
19
|
+
### Step 1: Queue 초기화/복구
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bash scripts/harness-queue-manager.sh init .
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
이미 queue가 있으면:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bash scripts/harness-queue-manager.sh recover .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Step 2: Team Worker 백그라운드 실행
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
nohup bash scripts/harness-team-worker.sh 1 . > /tmp/harness-team-1.log 2>&1 &
|
|
35
|
+
nohup bash scripts/harness-team-worker.sh 2 . > /tmp/harness-team-2.log 2>&1 &
|
|
36
|
+
nohup bash scripts/harness-team-worker.sh 3 . > /tmp/harness-team-3.log 2>&1 &
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Step 3: 상태 확인
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bash scripts/harness-queue-manager.sh status .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 실행 후 역할
|
|
46
|
+
|
|
47
|
+
이 세션은 **오케스트레이터**입니다:
|
|
48
|
+
- `/harness-generator-*`, `/harness-evaluator-*` 스킬 호출 금지 (Teams가 처리)
|
|
49
|
+
- 할 수 있는 것: 큐 상태 확인, 실패 분석, 코드 리뷰, gotcha 등록, requeue
|
|
50
|
+
|
|
51
|
+
### 유용한 명령
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# 큐 상태
|
|
55
|
+
bash scripts/harness-queue-manager.sh status .
|
|
56
|
+
|
|
57
|
+
# 실패한 feature 재큐
|
|
58
|
+
bash scripts/harness-queue-manager.sh requeue F-XXX .
|
|
59
|
+
|
|
60
|
+
# Team 로그 실시간 확인
|
|
61
|
+
tail -f /tmp/harness-team-1.log
|
|
62
|
+
tail -f /tmp/harness-team-2.log
|
|
63
|
+
tail -f /tmp/harness-team-3.log
|
|
64
|
+
|
|
65
|
+
# 모든 Team 중지
|
|
66
|
+
pkill -f harness-team-worker || true
|
|
67
|
+
```
|
|
18
68
|
|
|
19
|
-
##
|
|
69
|
+
## tmux Studio (선택사항)
|
|
20
70
|
|
|
21
|
-
|
|
71
|
+
별도 터미널에서 tmux 레이아웃을 원하면:
|
|
22
72
|
|
|
23
73
|
```bash
|
|
24
|
-
|
|
74
|
+
npx walwal-harness v4
|
|
25
75
|
```
|
|
26
76
|
|
|
27
|
-
|
|
77
|
+
이 명령은 **Claude 세션 밖에서** (일반 터미널에서) 실행해야 합니다.
|