@walwal-harness/cli 3.6.3 → 3.6.5
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.5",
|
|
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,6 +1,14 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# harness-dashboard.sh — Panel 1: 실시간 대시보드
|
|
3
|
-
# progress.json + feature-list.json
|
|
3
|
+
# progress.json + feature-list.json + progress.log 를 2초 간격으로 시각화
|
|
4
|
+
#
|
|
5
|
+
# Layout:
|
|
6
|
+
# ┌─────────────────────┬──────────────────────┐
|
|
7
|
+
# │ Sprint Map │ Prompt History │
|
|
8
|
+
# ├─────────────────────┴──────────────────────┤
|
|
9
|
+
# │ Processing Status (features, agent bar) │
|
|
10
|
+
# └────────────────────────────────────────────┘
|
|
11
|
+
#
|
|
4
12
|
# Usage: bash scripts/harness-dashboard.sh [project-root]
|
|
5
13
|
|
|
6
14
|
set -euo pipefail
|
|
@@ -18,6 +26,7 @@ fi
|
|
|
18
26
|
|
|
19
27
|
PROGRESS="$PROJECT_ROOT/.harness/progress.json"
|
|
20
28
|
FEATURES="$PROJECT_ROOT/.harness/actions/feature-list.json"
|
|
29
|
+
PROGRESS_LOG="$PROJECT_ROOT/.harness/progress.log"
|
|
21
30
|
|
|
22
31
|
# ── ANSI helpers ──
|
|
23
32
|
BOLD="\033[1m"
|
|
@@ -26,8 +35,14 @@ GREEN="\033[32m"
|
|
|
26
35
|
YELLOW="\033[33m"
|
|
27
36
|
RED="\033[31m"
|
|
28
37
|
CYAN="\033[36m"
|
|
38
|
+
MAGENTA="\033[35m"
|
|
29
39
|
RESET="\033[0m"
|
|
30
40
|
|
|
41
|
+
# ── Get terminal width for column layout ──
|
|
42
|
+
get_term_width() {
|
|
43
|
+
tput cols 2>/dev/null || echo 80
|
|
44
|
+
}
|
|
45
|
+
|
|
31
46
|
render_header() {
|
|
32
47
|
local now
|
|
33
48
|
now=$(date +"%H:%M:%S")
|
|
@@ -55,7 +70,6 @@ render_sprint_overview() {
|
|
|
55
70
|
agent_status=$(jq -r '.agent_status // "pending"' "$PROGRESS")
|
|
56
71
|
retry_count=$(jq -r '.sprint.retry_count // 0' "$PROGRESS")
|
|
57
72
|
|
|
58
|
-
# Status color
|
|
59
73
|
local status_color="$RESET"
|
|
60
74
|
case "$agent_status" in
|
|
61
75
|
running) status_color="$GREEN" ;;
|
|
@@ -65,62 +79,146 @@ render_sprint_overview() {
|
|
|
65
79
|
*) status_color="$YELLOW" ;;
|
|
66
80
|
esac
|
|
67
81
|
|
|
68
|
-
echo -e " ${BOLD}Pipeline${RESET} ${pipeline}"
|
|
69
|
-
echo -e " ${BOLD}Sprint${RESET} ${sprint_num} (${sprint_status})"
|
|
70
|
-
echo -e " ${BOLD}Agent${RESET} ${status_color}${current_agent} [${agent_status}]${RESET}"
|
|
71
|
-
if [ "$retry_count" -gt 0 ]; then
|
|
72
|
-
echo -e " ${BOLD}Retries${RESET} ${RED}${retry_count}${RESET}"
|
|
73
|
-
fi
|
|
82
|
+
echo -e " ${BOLD}Pipeline${RESET} ${pipeline} | ${BOLD}Sprint${RESET} ${sprint_num} (${sprint_status}) | ${BOLD}Agent${RESET} ${status_color}${current_agent} [${agent_status}]${RESET}$([ "$retry_count" -gt 0 ] && echo -e " | ${RED}R${retry_count}${RESET}")"
|
|
74
83
|
echo ""
|
|
75
84
|
}
|
|
76
85
|
|
|
77
|
-
|
|
86
|
+
# ── Sprint Map column (left) ──
|
|
87
|
+
render_sprint_map_lines() {
|
|
78
88
|
if [ ! -f "$PROGRESS" ]; then return; fi
|
|
79
89
|
|
|
80
90
|
local sprint_keys
|
|
81
91
|
sprint_keys=$(jq -r '.sprint_progress // {} | keys[]' "$PROGRESS" 2>/dev/null | sort -n)
|
|
82
92
|
if [ -z "$sprint_keys" ]; then return; fi
|
|
83
93
|
|
|
84
|
-
echo -e "
|
|
94
|
+
echo -e "${BOLD}Sprint Map${RESET}"
|
|
85
95
|
|
|
86
96
|
while IFS= read -r s; do
|
|
87
|
-
local status
|
|
97
|
+
local status feat_count notes icon
|
|
88
98
|
status=$(jq -r ".sprint_progress[\"${s}\"].status // \"pending\"" "$PROGRESS")
|
|
89
|
-
|
|
99
|
+
feat_count=$(jq ".sprint_progress[\"${s}\"].features // [] | length" "$PROGRESS")
|
|
90
100
|
notes=$(jq -r ".sprint_progress[\"${s}\"].notes // \"\"" "$PROGRESS")
|
|
91
101
|
|
|
92
|
-
# Status icon
|
|
93
|
-
local icon="○"
|
|
94
102
|
case "$status" in
|
|
95
103
|
completed) icon="●" ;;
|
|
96
104
|
in_progress) icon="◐" ;;
|
|
97
105
|
scaffolded) icon="◑" ;;
|
|
98
|
-
|
|
106
|
+
*) icon="○" ;;
|
|
99
107
|
esac
|
|
100
108
|
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
feat_count=$(jq ".sprint_progress[\"${s}\"].features // [] | length" "$PROGRESS")
|
|
104
|
-
|
|
105
|
-
# Truncate notes
|
|
106
|
-
if [ ${#notes} -gt 40 ]; then
|
|
107
|
-
notes="${notes:0:38}.."
|
|
109
|
+
if [ ${#notes} -gt 28 ]; then
|
|
110
|
+
notes="${notes:0:26}.."
|
|
108
111
|
fi
|
|
109
112
|
|
|
110
|
-
printf "
|
|
113
|
+
printf "%s S%-2s %2df %-11s %s\n" "$icon" "$s" "$feat_count" "$status" "$notes"
|
|
111
114
|
done <<< "$sprint_keys"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# ── Prompt History column (right) ──
|
|
118
|
+
render_prompt_history_lines() {
|
|
119
|
+
echo -e "${BOLD}Prompt History${RESET}"
|
|
120
|
+
|
|
121
|
+
# Source 1: progress.log (user/dispatcher interventions)
|
|
122
|
+
if [ -f "$PROGRESS_LOG" ]; then
|
|
123
|
+
grep -v '^#' "$PROGRESS_LOG" | grep -v '^$' | tail -15 | while IFS= read -r line; do
|
|
124
|
+
# Format: 2026-04-13 | agent | action | detail
|
|
125
|
+
local ts agent action detail
|
|
126
|
+
ts=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$1); print $1}')
|
|
127
|
+
agent=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$2); print $2}')
|
|
128
|
+
action=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$3); print $3}')
|
|
129
|
+
detail=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$4); print $4}')
|
|
130
|
+
|
|
131
|
+
# Short date (MM-DD)
|
|
132
|
+
local short_ts
|
|
133
|
+
short_ts=$(echo "$ts" | sed 's/^[0-9]*-//')
|
|
134
|
+
|
|
135
|
+
# Icon by agent/action
|
|
136
|
+
local icon color
|
|
137
|
+
case "$agent" in
|
|
138
|
+
dispatcher*) icon="▸" ; color="$MAGENTA" ;;
|
|
139
|
+
brainstormer) icon="◇" ; color="$CYAN" ;;
|
|
140
|
+
planner*) icon="□" ; color="$YELLOW" ;;
|
|
141
|
+
generator*) icon="▶" ; color="$GREEN" ;;
|
|
142
|
+
eval*) icon="✦" ; color="$RED" ;;
|
|
143
|
+
*) icon="·" ; color="$DIM" ;;
|
|
144
|
+
esac
|
|
145
|
+
|
|
146
|
+
# Truncate detail
|
|
147
|
+
if [ ${#detail} -gt 35 ]; then
|
|
148
|
+
detail="${detail:0:33}.."
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
echo -e "${color}${icon}${RESET} ${DIM}${short_ts}${RESET} ${agent} ${DIM}${action}${RESET}"
|
|
152
|
+
if [ -n "$detail" ]; then
|
|
153
|
+
echo -e " ${DIM}${detail}${RESET}"
|
|
154
|
+
fi
|
|
155
|
+
done
|
|
156
|
+
else
|
|
157
|
+
echo -e "${DIM}(no progress.log yet)${RESET}"
|
|
158
|
+
fi
|
|
159
|
+
}
|
|
112
160
|
|
|
161
|
+
# ── Side-by-side rendering ──
|
|
162
|
+
render_two_columns() {
|
|
163
|
+
local term_width
|
|
164
|
+
term_width=$(get_term_width)
|
|
165
|
+
local col_width=$(( (term_width - 7) / 2 )) # 7 = indent(4) + separator(3)
|
|
166
|
+
if [ "$col_width" -lt 30 ]; then col_width=30; fi
|
|
167
|
+
if [ "$col_width" -gt 60 ]; then col_width=60; fi
|
|
168
|
+
|
|
169
|
+
# Capture each column into temp arrays
|
|
170
|
+
local left_lines=()
|
|
171
|
+
local right_lines=()
|
|
172
|
+
|
|
173
|
+
while IFS= read -r line; do
|
|
174
|
+
left_lines+=("$line")
|
|
175
|
+
done < <(render_sprint_map_lines 2>/dev/null)
|
|
176
|
+
|
|
177
|
+
while IFS= read -r line; do
|
|
178
|
+
right_lines+=("$line")
|
|
179
|
+
done < <(render_prompt_history_lines 2>/dev/null)
|
|
180
|
+
|
|
181
|
+
# Determine max rows
|
|
182
|
+
local left_count=${#left_lines[@]}
|
|
183
|
+
local right_count=${#right_lines[@]}
|
|
184
|
+
local max_rows=$left_count
|
|
185
|
+
if [ "$right_count" -gt "$max_rows" ]; then max_rows=$right_count; fi
|
|
186
|
+
|
|
187
|
+
# Print separator
|
|
188
|
+
local sep=""
|
|
189
|
+
for ((i=0; i<term_width-4; i++)); do sep+="─"; done
|
|
190
|
+
echo -e " ${DIM}${sep}${RESET}"
|
|
191
|
+
|
|
192
|
+
# Print rows side by side
|
|
193
|
+
for ((i=0; i<max_rows; i++)); do
|
|
194
|
+
local left_text="${left_lines[$i]:-}"
|
|
195
|
+
local right_text="${right_lines[$i]:-}"
|
|
196
|
+
|
|
197
|
+
# Strip ANSI for length calculation
|
|
198
|
+
local left_plain
|
|
199
|
+
left_plain=$(echo -e "$left_text" | sed 's/\x1b\[[0-9;]*m//g')
|
|
200
|
+
local left_len=${#left_plain}
|
|
201
|
+
|
|
202
|
+
# Pad left column
|
|
203
|
+
local pad_needed=$(( col_width - left_len ))
|
|
204
|
+
if [ "$pad_needed" -lt 0 ]; then pad_needed=0; fi
|
|
205
|
+
local padding=""
|
|
206
|
+
for ((p=0; p<pad_needed; p++)); do padding+=" "; done
|
|
207
|
+
|
|
208
|
+
echo -e " ${left_text}${padding} ${DIM}│${RESET} ${right_text}"
|
|
209
|
+
done
|
|
210
|
+
|
|
211
|
+
echo -e " ${DIM}${sep}${RESET}"
|
|
113
212
|
echo ""
|
|
114
213
|
}
|
|
115
214
|
|
|
116
215
|
render_build_status() {
|
|
117
216
|
if [ ! -f "$PROGRESS" ]; then return; fi
|
|
118
217
|
|
|
119
|
-
local build_status tsc_status routes_total
|
|
218
|
+
local build_status tsc_status routes_total
|
|
120
219
|
build_status=$(jq -r '.build.build_status // "unknown"' "$PROGRESS" 2>/dev/null)
|
|
121
220
|
tsc_status=$(jq -r '.build.tsc_status // "unknown"' "$PROGRESS" 2>/dev/null)
|
|
122
221
|
routes_total=$(jq -r '.build.routes_total // 0' "$PROGRESS" 2>/dev/null)
|
|
123
|
-
last_build=$(jq -r '.build.last_build // "n/a"' "$PROGRESS" 2>/dev/null)
|
|
124
222
|
|
|
125
223
|
if [ "$build_status" = "null" ] || [ "$build_status" = "unknown" ]; then return; fi
|
|
126
224
|
|
|
@@ -129,11 +227,15 @@ render_build_status() {
|
|
|
129
227
|
local tsc_color="$GREEN"
|
|
130
228
|
if [ "$tsc_status" != "clean" ]; then tsc_color="$RED"; fi
|
|
131
229
|
|
|
132
|
-
echo -e " ${BOLD}Build${RESET}"
|
|
133
|
-
echo -e " Build: ${build_color}${build_status}${RESET} | TSC: ${tsc_color}${tsc_status}${RESET} | Routes: ${routes_total}"
|
|
230
|
+
echo -e " ${BOLD}Build${RESET} ${build_color}${build_status}${RESET} | TSC: ${tsc_color}${tsc_status}${RESET} | Routes: ${routes_total}"
|
|
134
231
|
echo ""
|
|
135
232
|
}
|
|
136
233
|
|
|
234
|
+
# Strip all ANSI escape sequences from a string
|
|
235
|
+
strip_ansi() {
|
|
236
|
+
sed 's/\x1b\[[0-9;]*m//g; s/\x1b\[[0-9;]*[a-zA-Z]//g'
|
|
237
|
+
}
|
|
238
|
+
|
|
137
239
|
render_failure_info() {
|
|
138
240
|
if [ ! -f "$PROGRESS" ]; then return; fi
|
|
139
241
|
|
|
@@ -143,26 +245,31 @@ render_failure_info() {
|
|
|
143
245
|
if [ -n "$failure_agent" ] && [ "$failure_agent" != "null" ]; then
|
|
144
246
|
local failure_loc failure_msg
|
|
145
247
|
failure_loc=$(jq -r '.failure.location // ""' "$PROGRESS")
|
|
146
|
-
|
|
248
|
+
# Get raw message, strip ANSI codes, take first meaningful line
|
|
249
|
+
failure_msg=$(jq -r '.failure.message // ""' "$PROGRESS" | strip_ansi | tr '\n' ' ' | sed 's/ */ /g')
|
|
250
|
+
|
|
251
|
+
# Truncate to 80 chars
|
|
252
|
+
if [ ${#failure_msg} -gt 80 ]; then
|
|
253
|
+
failure_msg="${failure_msg:0:78}.."
|
|
254
|
+
fi
|
|
147
255
|
|
|
148
|
-
echo -e " ${RED}${BOLD}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if [ -n "$failure_msg" ] && [ "$failure_msg" != "null" ]; then
|
|
152
|
-
echo -e " ${RED} ${failure_msg}${RESET}"
|
|
256
|
+
echo -e " ${RED}${BOLD}FAIL${RESET} ${RED}${failure_agent} → ${failure_loc}${RESET}"
|
|
257
|
+
if [ -n "$failure_msg" ]; then
|
|
258
|
+
echo -e " ${DIM}${failure_msg}${RESET}"
|
|
153
259
|
fi
|
|
154
|
-
echo -e " ${RED}${BOLD}╚════════════════════════════════════╝${RESET}"
|
|
155
260
|
echo ""
|
|
156
261
|
fi
|
|
157
262
|
}
|
|
158
263
|
|
|
159
|
-
# ── Render
|
|
264
|
+
# ── Render all sections ──
|
|
160
265
|
render_all() {
|
|
161
266
|
render_header
|
|
162
267
|
render_sprint_overview
|
|
163
268
|
render_build_status
|
|
164
269
|
render_failure_info
|
|
165
|
-
|
|
270
|
+
|
|
271
|
+
# Two-column: Sprint Map | Prompt History
|
|
272
|
+
render_two_columns
|
|
166
273
|
|
|
167
274
|
# Feature progress (reuse existing lib)
|
|
168
275
|
if [ -f "$FEATURES" ]; then
|
|
@@ -177,23 +284,15 @@ render_all() {
|
|
|
177
284
|
}
|
|
178
285
|
|
|
179
286
|
# ── Main Loop ──
|
|
180
|
-
|
|
181
|
-
tput civis 2>/dev/null # hide cursor
|
|
287
|
+
tput civis 2>/dev/null
|
|
182
288
|
trap 'tput cnorm 2>/dev/null; exit 0' EXIT INT TERM
|
|
183
289
|
|
|
184
|
-
# Initial clear
|
|
185
290
|
clear
|
|
186
291
|
|
|
187
292
|
while true; do
|
|
188
|
-
# Capture full output into buffer
|
|
189
293
|
buf=$(render_all 2>/dev/null)
|
|
190
|
-
|
|
191
|
-
# Move cursor to top-left and overwrite (no clear = no flicker)
|
|
192
294
|
tput cup 0 0 2>/dev/null
|
|
193
295
|
echo "$buf"
|
|
194
|
-
|
|
195
|
-
# Clear any leftover lines from previous render
|
|
196
296
|
tput ed 2>/dev/null
|
|
197
|
-
|
|
198
297
|
sleep 2
|
|
199
298
|
done
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Usage: bash scripts/harness-eval-watcher.sh [project-root] [--ai]
|
|
5
5
|
# --ai evaluation 완료 시 claude -p 로 AI 요약 생성 (API 비용 발생)
|
|
6
6
|
|
|
7
|
-
set -
|
|
7
|
+
set -uo pipefail
|
|
8
8
|
|
|
9
9
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
10
|
|
|
@@ -69,7 +69,7 @@ extract_eval_summary() {
|
|
|
69
69
|
|
|
70
70
|
# Extract Verdict (PASS/FAIL)
|
|
71
71
|
local verdict
|
|
72
|
-
verdict=$(grep -i "verdict\|result\|판정" "$file" | head -3)
|
|
72
|
+
verdict=$(grep -i "verdict\|result\|판정" "$file" 2>/dev/null | head -3 || true)
|
|
73
73
|
if [ -n "$verdict" ]; then
|
|
74
74
|
if echo "$verdict" | grep -qi "PASS"; then
|
|
75
75
|
echo -e " ${GREEN}${BOLD}VERDICT: PASS${RESET}"
|
|
@@ -83,7 +83,7 @@ extract_eval_summary() {
|
|
|
83
83
|
|
|
84
84
|
# Extract Score
|
|
85
85
|
local score_line
|
|
86
|
-
score_line=$(grep -iE "score|점수|weighted|가중" "$file" | head -3)
|
|
86
|
+
score_line=$(grep -iE "score|점수|weighted|가중" "$file" 2>/dev/null | head -3 || true)
|
|
87
87
|
if [ -n "$score_line" ]; then
|
|
88
88
|
echo -e " ${BOLD}Score${RESET}"
|
|
89
89
|
echo "$score_line" | while IFS= read -r line; do
|
|
@@ -107,7 +107,7 @@ extract_eval_summary() {
|
|
|
107
107
|
|
|
108
108
|
# Extract individual rubric items (R1-R5 or V1-V5)
|
|
109
109
|
local rubric_lines
|
|
110
|
-
rubric_lines=$(grep -E "^[|#].*[RV][1-5]" "$file" | head -10)
|
|
110
|
+
rubric_lines=$(grep -E "^[|#].*[RV][1-5]" "$file" 2>/dev/null | head -10 || true)
|
|
111
111
|
if [ -n "$rubric_lines" ]; then
|
|
112
112
|
echo -e " ${BOLD}Rubric${RESET}"
|
|
113
113
|
echo "$rubric_lines" | while IFS= read -r line; do
|
|
@@ -118,7 +118,7 @@ extract_eval_summary() {
|
|
|
118
118
|
|
|
119
119
|
# Extract FAIL reasons
|
|
120
120
|
local fail_lines
|
|
121
|
-
fail_lines=$(grep -iE "fail|실패|regression|불일치|위반" "$file" | head -5)
|
|
121
|
+
fail_lines=$(grep -iE "fail|실패|regression|불일치|위반" "$file" 2>/dev/null | head -5 || true)
|
|
122
122
|
if [ -n "$fail_lines" ]; then
|
|
123
123
|
echo -e " ${RED}${BOLD}Issues${RESET}"
|
|
124
124
|
echo "$fail_lines" | while IFS= read -r line; do
|
|
@@ -129,7 +129,7 @@ extract_eval_summary() {
|
|
|
129
129
|
|
|
130
130
|
# Extract action items / recommendations
|
|
131
131
|
local action_lines
|
|
132
|
-
action_lines=$(grep -iE "recommend|action|수정|개선|필요|re-generate" "$file" | head -5)
|
|
132
|
+
action_lines=$(grep -iE "recommend|action|수정|개선|필요|re-generate" "$file" 2>/dev/null | head -5 || true)
|
|
133
133
|
if [ -n "$action_lines" ]; then
|
|
134
134
|
echo -e " ${YELLOW}${BOLD}Actions${RESET}"
|
|
135
135
|
echo "$action_lines" | while IFS= read -r line; do
|
package/scripts/harness-tmux.sh
CHANGED
|
@@ -68,22 +68,17 @@ tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
|
|
|
68
68
|
tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 200 -y 50
|
|
69
69
|
|
|
70
70
|
# Split right column (40% width)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
tmux send-keys -t "${SESSION_NAME}.1" "bash ${SCRIPT_DIR}/harness-dashboard.sh '${PROJECT_ROOT}'" Enter
|
|
71
|
+
# Use direct command execution (not send-keys) to avoid shell init noise (nvm warnings etc.)
|
|
72
|
+
tmux split-window -h -l 80 -t "$SESSION_NAME" -c "$PROJECT_ROOT" \
|
|
73
|
+
"exec bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-dashboard.sh\" \"${PROJECT_ROOT}\"'"
|
|
75
74
|
|
|
76
75
|
# Split pane 1 vertically for Monitor
|
|
77
|
-
tmux split-window -v -t "${SESSION_NAME}.1" -c "$PROJECT_ROOT"
|
|
78
|
-
|
|
79
|
-
# Pane 2 (mid-right): Monitor
|
|
80
|
-
tmux send-keys -t "${SESSION_NAME}.2" "bash ${SCRIPT_DIR}/harness-monitor.sh '${PROJECT_ROOT}'" Enter
|
|
76
|
+
tmux split-window -v -t "${SESSION_NAME}.1" -c "$PROJECT_ROOT" \
|
|
77
|
+
"exec bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-monitor.sh\" \"${PROJECT_ROOT}\"'"
|
|
81
78
|
|
|
82
79
|
# Split pane 2 vertically for Eval
|
|
83
|
-
tmux split-window -v -t "${SESSION_NAME}.2" -c "$PROJECT_ROOT"
|
|
84
|
-
|
|
85
|
-
# Pane 3 (bottom-right): Eval Watcher
|
|
86
|
-
tmux send-keys -t "${SESSION_NAME}.3" "bash ${SCRIPT_DIR}/harness-eval-watcher.sh '${PROJECT_ROOT}' ${USE_AI}" Enter
|
|
80
|
+
tmux split-window -v -t "${SESSION_NAME}.2" -c "$PROJECT_ROOT" \
|
|
81
|
+
"exec bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-eval-watcher.sh\" \"${PROJECT_ROOT}\" ${USE_AI}'"
|
|
87
82
|
|
|
88
83
|
# ── Launch Claude in Main pane ──
|
|
89
84
|
HANDOFF="$PROJECT_ROOT/.harness/handoff.json"
|