@walwal-harness/cli 3.7.1 → 3.7.3

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/bin/init.js CHANGED
@@ -225,6 +225,7 @@ function installScripts() {
225
225
  'harness-monitor.sh',
226
226
  'harness-eval-watcher.sh',
227
227
  'harness-tmux.sh',
228
+ 'harness-control.sh',
228
229
  ]);
229
230
 
230
231
  if (fs.existsSync(scriptsSrc)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "3.7.1",
3
+ "version": "3.7.3",
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"
@@ -0,0 +1,152 @@
1
+ #!/bin/bash
2
+ # harness-control.sh — Control Center 프롬프트 (하단)
3
+ # 사용자 명령을 받아 Agent Session 관리 + progress.log 기록
4
+ #
5
+ # Commands:
6
+ # next / n 다음 에이전트 세션 시작
7
+ # retry / r 현재 에이전트 재실행
8
+ # stop 에이전트 세션 중지
9
+ # log <message> progress.log에 수동 메모 추가
10
+ # clear-fail failure 상태 클리어
11
+ # status / s 대시보드 즉시 갱신 (상단 pane)
12
+ # help / h 도움말
13
+ # quit / q 종료
14
+ #
15
+ # Usage: bash scripts/harness-control.sh [project-root]
16
+
17
+ set -uo pipefail
18
+
19
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
20
+
21
+ PROJECT_ROOT="${1:-}"
22
+ if [ -z "$PROJECT_ROOT" ]; then
23
+ source "$SCRIPT_DIR/lib/harness-render-progress.sh"
24
+ PROJECT_ROOT="$(resolve_harness_root ".")" || {
25
+ echo "[control] .harness/ not found."
26
+ exit 1
27
+ }
28
+ fi
29
+
30
+ PROGRESS="$PROJECT_ROOT/.harness/progress.json"
31
+ PROGRESS_LOG="$PROJECT_ROOT/.harness/progress.log"
32
+
33
+ BOLD="\033[1m"
34
+ DIM="\033[2m"
35
+ GREEN="\033[32m"
36
+ YELLOW="\033[33m"
37
+ RED="\033[31m"
38
+ CYAN="\033[36m"
39
+ RESET="\033[0m"
40
+
41
+ # ── Agent Session pane target ──
42
+ AGENT_PANE="harness-studio.2"
43
+
44
+ cmd_log() {
45
+ local msg="$1"
46
+ if [ -z "$msg" ]; then
47
+ echo -e " ${RED}Usage: log <message>${RESET}"
48
+ return
49
+ fi
50
+ local ts
51
+ ts=$(date +"%Y-%m-%d")
52
+ echo "${ts} | manual | note | ${msg}" >> "$PROGRESS_LOG"
53
+ echo -e " ${GREEN}Logged:${RESET} ${msg}"
54
+ }
55
+
56
+ cmd_clear_fail() {
57
+ if [ ! -f "$PROGRESS" ]; then return; fi
58
+ jq '.failure = {agent: null, location: null, message: null, retry_target: null} |
59
+ .sprint.status = "in_progress" |
60
+ .sprint.retry_count = 0 |
61
+ .agent_status = "completed"' "$PROGRESS" > "${PROGRESS}.tmp" && mv "${PROGRESS}.tmp" "$PROGRESS"
62
+ echo -e " ${GREEN}Failure state cleared.${RESET}"
63
+ }
64
+
65
+ cmd_next() {
66
+ if ! tmux list-panes -t harness-studio 2>/dev/null | grep -q .; then
67
+ echo -e " ${RED}tmux session not found.${RESET}"
68
+ return
69
+ fi
70
+
71
+ local next_agent
72
+ next_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
73
+ if [ "$next_agent" = "none" ] || [ "$next_agent" = "null" ]; then
74
+ echo -e " ${YELLOW}No next agent in queue.${RESET}"
75
+ return
76
+ fi
77
+
78
+ echo -e " ${CYAN}Starting ${next_agent} in Agent Session...${RESET}"
79
+ local ts
80
+ ts=$(date +"%Y-%m-%d")
81
+ echo "${ts} | manual | start-agent | ${next_agent}" >> "$PROGRESS_LOG"
82
+ tmux send-keys -t "$AGENT_PANE" "/harness-${next_agent}" Enter
83
+ }
84
+
85
+ cmd_retry() {
86
+ if ! tmux list-panes -t harness-studio 2>/dev/null | grep -q .; then
87
+ echo -e " ${RED}tmux session not found.${RESET}"
88
+ return
89
+ fi
90
+
91
+ local current_agent
92
+ current_agent=$(jq -r '.current_agent // "none"' "$PROGRESS" 2>/dev/null)
93
+ if [ "$current_agent" = "none" ] || [ "$current_agent" = "null" ]; then
94
+ echo -e " ${YELLOW}No current agent to retry.${RESET}"
95
+ return
96
+ fi
97
+
98
+ echo -e " ${CYAN}Retrying ${current_agent}...${RESET}"
99
+ local ts
100
+ ts=$(date +"%Y-%m-%d")
101
+ echo "${ts} | manual | retry | ${current_agent}" >> "$PROGRESS_LOG"
102
+ tmux send-keys -t "$AGENT_PANE" "/harness-${current_agent}" Enter
103
+ }
104
+
105
+ cmd_stop() {
106
+ if ! tmux list-panes -t harness-studio 2>/dev/null | grep -q .; then
107
+ echo -e " ${RED}tmux session not found.${RESET}"
108
+ return
109
+ fi
110
+
111
+ echo -e " ${YELLOW}Sending Ctrl+C to Agent Session...${RESET}"
112
+ tmux send-keys -t "$AGENT_PANE" C-c
113
+ local ts
114
+ ts=$(date +"%Y-%m-%d")
115
+ echo "${ts} | manual | stop | user-initiated" >> "$PROGRESS_LOG"
116
+ }
117
+
118
+ show_help() {
119
+ echo ""
120
+ echo -e " ${BOLD}Commands${RESET}"
121
+ echo -e " ${CYAN}next${RESET} / ${CYAN}n${RESET} Start next agent"
122
+ echo -e " ${CYAN}retry${RESET} / ${CYAN}r${RESET} Retry current agent"
123
+ echo -e " ${CYAN}stop${RESET} Send Ctrl+C to agent"
124
+ echo -e " ${CYAN}log${RESET} <message> Add note to progress.log"
125
+ echo -e " ${CYAN}clear-fail${RESET} Clear failure state"
126
+ echo -e " ${CYAN}help${RESET} / ${CYAN}h${RESET} Show this help"
127
+ echo -e " ${CYAN}quit${RESET} / ${CYAN}q${RESET} Exit"
128
+ echo ""
129
+ }
130
+
131
+ # ── Main ──
132
+ echo ""
133
+ echo -e " ${BOLD}Harness Control${RESET} ${DIM}(type 'help' for commands)${RESET}"
134
+ echo ""
135
+
136
+ while true; do
137
+ echo -ne " ${BOLD}harness>${RESET} "
138
+ read -r input || exit 0
139
+ input=$(echo "$input" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
140
+
141
+ case "$input" in
142
+ next|n) cmd_next ;;
143
+ retry|r) cmd_retry ;;
144
+ stop) cmd_stop ;;
145
+ log\ *) cmd_log "${input#log }" ;;
146
+ clear-fail) cmd_clear_fail ;;
147
+ help|h) show_help ;;
148
+ quit|q) echo -e " ${DIM}Goodbye.${RESET}"; exit 0 ;;
149
+ "") ;; # empty — just re-prompt
150
+ *) echo -e " ${DIM}Logging as note.${RESET}"; cmd_log "$input" ;;
151
+ esac
152
+ done
@@ -260,12 +260,9 @@ render_agent_info() {
260
260
  }
261
261
 
262
262
  # ══════════════════════════════════════════
263
- # Full dashboard render
263
+ # Full dashboard render (in-place update)
264
264
  # ══════════════════════════════════════════
265
265
  render_dashboard() {
266
- tput cup 0 0 2>/dev/null
267
- tput civis 2>/dev/null
268
-
269
266
  local buf
270
267
  buf=$(
271
268
  render_header
@@ -280,190 +277,23 @@ render_dashboard() {
280
277
 
281
278
  render_agent_info
282
279
  )
280
+
281
+ tput civis 2>/dev/null
282
+ tput cup 0 0 2>/dev/null
283
283
  echo "$buf"
284
284
  tput ed 2>/dev/null
285
285
  tput cnorm 2>/dev/null
286
286
  }
287
287
 
288
288
  # ══════════════════════════════════════════
289
- # Command handlers
289
+ # Main — Auto-refresh dashboard loop
290
290
  # ══════════════════════════════════════════
291
+ tput civis 2>/dev/null
292
+ trap 'tput cnorm 2>/dev/null; exit 0' EXIT INT TERM
291
293
 
292
- cmd_log() {
293
- local msg="$1"
294
- if [ -z "$msg" ]; then
295
- echo -e " ${RED}Usage: log <message>${RESET}"
296
- return
297
- fi
298
-
299
- local ts
300
- ts=$(date +"%Y-%m-%d")
301
- echo "${ts} | manual | note | ${msg}" >> "$PROGRESS_LOG"
302
- echo -e " ${GREEN}Logged:${RESET} ${msg}"
303
- }
304
-
305
- cmd_clear_fail() {
306
- if [ ! -f "$PROGRESS" ]; then return; fi
307
-
308
- jq '.failure = {agent: null, location: null, message: null, retry_target: null} |
309
- .sprint.status = "in_progress" |
310
- .sprint.retry_count = 0 |
311
- .agent_status = "completed"' "$PROGRESS" > "${PROGRESS}.tmp" && mv "${PROGRESS}.tmp" "$PROGRESS"
312
- echo -e " ${GREEN}Failure state cleared.${RESET}"
313
- }
314
-
315
- cmd_next() {
316
- # Find the Agent Session pane and send the next agent command
317
- local tmux_target="harness-studio.2" # Agent Session pane
318
-
319
- if ! tmux list-panes -t harness-studio 2>/dev/null | grep -q .; then
320
- echo -e " ${RED}tmux session not found. Run inside harness-studio.${RESET}"
321
- return
322
- fi
323
-
324
- local next_agent
325
- next_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
326
-
327
- if [ "$next_agent" = "none" ] || [ "$next_agent" = "null" ]; then
328
- echo -e " ${YELLOW}No next agent in queue.${RESET}"
329
- return
330
- fi
331
-
332
- echo -e " ${CYAN}Starting ${next_agent} in Agent Session pane...${RESET}"
333
-
334
- # Log the manual intervention
335
- local ts
336
- ts=$(date +"%Y-%m-%d")
337
- echo "${ts} | manual | start-agent | ${next_agent}" >> "$PROGRESS_LOG"
338
-
339
- # Send command to Agent Session pane
340
- tmux send-keys -t "$tmux_target" "/harness-${next_agent}" Enter
341
- }
342
-
343
- cmd_retry() {
344
- local tmux_target="harness-studio.2"
345
-
346
- if ! tmux list-panes -t harness-studio 2>/dev/null | grep -q .; then
347
- echo -e " ${RED}tmux session not found.${RESET}"
348
- return
349
- fi
350
-
351
- local current_agent
352
- current_agent=$(jq -r '.current_agent // "none"' "$PROGRESS" 2>/dev/null)
353
-
354
- if [ "$current_agent" = "none" ] || [ "$current_agent" = "null" ]; then
355
- echo -e " ${YELLOW}No current agent to retry.${RESET}"
356
- return
357
- fi
358
-
359
- echo -e " ${CYAN}Retrying ${current_agent} in Agent Session pane...${RESET}"
360
-
361
- local ts
362
- ts=$(date +"%Y-%m-%d")
363
- echo "${ts} | manual | retry | ${current_agent}" >> "$PROGRESS_LOG"
364
-
365
- tmux send-keys -t "$tmux_target" "/harness-${current_agent}" Enter
366
- }
367
-
368
- cmd_stop() {
369
- local tmux_target="harness-studio.2"
370
-
371
- if ! tmux list-panes -t harness-studio 2>/dev/null | grep -q .; then
372
- echo -e " ${RED}tmux session not found.${RESET}"
373
- return
374
- fi
375
-
376
- echo -e " ${YELLOW}Sending Ctrl+C to Agent Session...${RESET}"
377
- tmux send-keys -t "$tmux_target" C-c
378
-
379
- local ts
380
- ts=$(date +"%Y-%m-%d")
381
- echo "${ts} | manual | stop | user-initiated" >> "$PROGRESS_LOG"
382
- }
383
-
384
- show_help() {
385
- echo ""
386
- echo -e " ${BOLD}Commands${RESET}"
387
- echo -e " ${CYAN}status${RESET} / ${CYAN}s${RESET} Refresh dashboard"
388
- echo -e " ${CYAN}next${RESET} / ${CYAN}n${RESET} Start next agent in Agent Session"
389
- echo -e " ${CYAN}retry${RESET} / ${CYAN}r${RESET} Retry current agent"
390
- echo -e " ${CYAN}stop${RESET} Send Ctrl+C to Agent Session"
391
- echo -e " ${CYAN}log${RESET} <message> Add note to progress.log"
392
- echo -e " ${CYAN}clear-fail${RESET} Clear failure state"
393
- echo -e " ${CYAN}help${RESET} / ${CYAN}h${RESET} Show this help"
394
- echo -e " ${CYAN}quit${RESET} / ${CYAN}q${RESET} Exit dashboard"
395
- echo ""
396
- }
397
-
398
- # ══════════════════════════════════════════
399
- # Main — Interactive loop
400
- # ══════════════════════════════════════════
401
294
  clear
402
- render_dashboard
403
-
404
- echo ""
405
- echo -e " ${DIM}Type 'help' for commands. Dashboard auto-refreshes every 5s.${RESET}"
406
- echo ""
407
-
408
- # Background auto-refresh
409
- (
410
- while true; do
411
- sleep 5
412
- # Signal main process to refresh
413
- kill -USR1 $$ 2>/dev/null || exit 0
414
- done
415
- ) &
416
- REFRESH_PID=$!
417
-
418
- # Trap USR1 to refresh dashboard
419
- trap 'render_dashboard' USR1
420
- trap 'kill $REFRESH_PID 2>/dev/null; exit 0' EXIT INT TERM
421
295
 
422
296
  while true; do
423
- echo -ne " ${BOLD}harness>${RESET} "
424
- # Read with timeout so USR1 can interrupt
425
- if read -t 5 -r input; then
426
- # Trim whitespace
427
- input=$(echo "$input" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
428
-
429
- case "$input" in
430
- status|s)
431
- render_dashboard
432
- ;;
433
- next|n)
434
- cmd_next
435
- ;;
436
- retry|r)
437
- cmd_retry
438
- ;;
439
- stop)
440
- cmd_stop
441
- ;;
442
- log\ *)
443
- cmd_log "${input#log }"
444
- ;;
445
- clear-fail)
446
- cmd_clear_fail
447
- ;;
448
- help|h)
449
- show_help
450
- ;;
451
- quit|q)
452
- echo -e " ${DIM}Goodbye.${RESET}"
453
- exit 0
454
- ;;
455
- "")
456
- # Empty input — just refresh
457
- render_dashboard
458
- ;;
459
- *)
460
- # Unknown command — treat as manual note
461
- echo -e " ${DIM}Unknown command. Logging as note.${RESET}"
462
- cmd_log "$input"
463
- ;;
464
- esac
465
- else
466
- # Timeout — auto-refresh
467
- render_dashboard
468
- fi
297
+ render_dashboard
298
+ sleep 3
469
299
  done
@@ -1,22 +1,21 @@
1
1
  #!/bin/bash
2
- # harness-tmux.sh — Harness Studio tmux 4-pane 레이아웃
2
+ # harness-tmux.sh — Harness Studio tmux 5-pane 레이아웃
3
3
  #
4
- # ┌───────────────────────────┬─────────────────────────┐
5
- # │ │ Monitor (compact) │
6
- # │ Main: Control Center ├─────────────────────────┤
7
- # │ (Dashboard + Manual │ Agent Session │
8
- # │ Prompt + Orchestration) │ (claude --skip-perms) │
9
- # │ ├─────────────────────────┤
10
- # │ │ Eval Review │
11
- # │ │ (eval 결과 요약) │
12
- # └───────────────────────────┴─────────────────────────┘
4
+ # ┌─────────────────────────┬────────────────────────┐
5
+ # │ Dashboard (auto-refresh)│ Monitor (compact) │
6
+ # │ ├────────────────────────┤
7
+ # │ │ Agent Session (claude) │
8
+ # ├─────────────────────────┤ │
9
+ # │ Control (harness> _) ├────────────────────────┤
10
+ # │ │ Eval Review │
11
+ # └─────────────────────────┴────────────────────────┘
13
12
  #
14
13
  # Usage:
15
14
  # bash scripts/harness-tmux.sh [project-root]
16
15
  # bash scripts/harness-tmux.sh /path/to/project --ai
17
16
  #
18
17
  # Options:
19
- # --ai Eval Review에서 claude -p 로 AI 요약 생성
18
+ # --ai Eval Review에서 claude -p AI 요약
20
19
  # --detach 세션 생성 후 attach 하지 않음
21
20
  # --kill 기존 harness-studio 세션 종료
22
21
 
@@ -34,7 +33,7 @@ for arg in "$@"; do
34
33
  --ai) USE_AI="--ai" ;;
35
34
  --detach) DETACH=true ;;
36
35
  --kill)
37
- tmux kill-session -t "$SESSION_NAME" 2>/dev/null && echo "Session '$SESSION_NAME' killed." || echo "No session to kill."
36
+ tmux kill-session -t "$SESSION_NAME" 2>/dev/null && echo "Killed." || echo "No session."
38
37
  exit 0
39
38
  ;;
40
39
  *)
@@ -43,7 +42,6 @@ for arg in "$@"; do
43
42
  esac
44
43
  done
45
44
 
46
- # Auto-detect project root
47
45
  if [ -z "$PROJECT_ROOT" ]; then
48
46
  dir="$(pwd)"
49
47
  while [ "$dir" != "/" ]; do
@@ -53,18 +51,16 @@ if [ -z "$PROJECT_ROOT" ]; then
53
51
  fi
54
52
 
55
53
  if [ -z "$PROJECT_ROOT" ] || [ ! -d "$PROJECT_ROOT/.harness" ]; then
56
- echo "Error: .harness/ directory not found."
57
- echo "Usage: bash scripts/harness-tmux.sh [project-root]"
54
+ echo "Error: .harness/ not found."
58
55
  exit 1
59
56
  fi
60
57
 
61
58
  echo "Project: $PROJECT_ROOT"
62
59
  echo "Session: $SESSION_NAME"
63
60
 
64
- # Kill existing session if any
65
61
  tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
66
62
 
67
- # ── Resolve Claude command for Agent Session ──
63
+ # ── Resolve Claude command ──
68
64
  HANDOFF="$PROJECT_ROOT/.harness/handoff.json"
69
65
  CLAUDE_CMD="claude --dangerously-skip-permissions"
70
66
  if [ -f "$HANDOFF" ]; then
@@ -75,57 +71,65 @@ if [ -f "$HANDOFF" ]; then
75
71
  fi
76
72
 
77
73
  # ══════════════════════════════════════════
78
- # Layout Construction
74
+ # Build layout using explicit pane IDs
79
75
  # ══════════════════════════════════════════
80
- # Step 1: Create session → Pane 0 = Main (Control Center)
81
- tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 200 -y 50
82
76
 
83
- # Step 2: Split right column (45% width) → Pane 1 = Monitor (top-right, compact)
84
- tmux split-window -h -p 45 -t "$SESSION_NAME" -c "$PROJECT_ROOT" \
85
- "exec bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-monitor.sh\" \"${PROJECT_ROOT}\"'"
77
+ # 1. Create session → capture Dashboard pane ID
78
+ PANE_DASHBOARD=$(tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 200 -y 50 \
79
+ -P -F '#{pane_id}' \
80
+ "bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-dashboard.sh\" \"${PROJECT_ROOT}\"'")
86
81
 
87
- # Step 3: Split Pane 1 vertically → Pane 2 = Agent Session (mid-right)
88
- # Monitor gets ~20% of right column height, remaining 80% split below
89
- tmux split-window -v -p 80 -t "${SESSION_NAME}.1" -c "$PROJECT_ROOT"
82
+ # 2. Split Dashboard horizontally (55% left / 45% right) → Monitor pane
83
+ PANE_MONITOR=$(tmux split-window -h -p 45 -t "$PANE_DASHBOARD" -c "$PROJECT_ROOT" \
84
+ -P -F '#{pane_id}' \
85
+ "bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-monitor.sh\" \"${PROJECT_ROOT}\"'")
90
86
 
91
- # Pane 2 = Agent Session (interactive shell, will run claude)
92
- tmux send-keys -t "${SESSION_NAME}.2" "$CLAUDE_CMD" Enter
87
+ # 3. Split Dashboard vertically (75% top / 25% bottom) → Control pane
88
+ PANE_CONTROL=$(tmux split-window -v -p 25 -t "$PANE_DASHBOARD" -c "$PROJECT_ROOT" \
89
+ -P -F '#{pane_id}' \
90
+ "bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-control.sh\" \"${PROJECT_ROOT}\"'")
93
91
 
94
- # Step 4: Split Pane 2 vertically → Pane 3 = Eval Review (bottom-right)
95
- # Agent Session and Eval Review split 1:1
96
- tmux split-window -v -p 50 -t "${SESSION_NAME}.2" -c "$PROJECT_ROOT" \
97
- "exec bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-eval-watcher.sh\" \"${PROJECT_ROOT}\" ${USE_AI}'"
92
+ # 4. Split Monitor vertically (15% top / 85% bottom) → Agent Session pane
93
+ PANE_AGENT=$(tmux split-window -v -p 85 -t "$PANE_MONITOR" -c "$PROJECT_ROOT" \
94
+ -P -F '#{pane_id}')
98
95
 
99
- # ── Launch Dashboard in Main pane ──
100
- tmux send-keys -t "${SESSION_NAME}.0" "bash ${SCRIPT_DIR}/harness-dashboard.sh '${PROJECT_ROOT}'" Enter
96
+ # 5. Split Agent Session vertically (55% top / 45% bottom) → Eval Review pane
97
+ PANE_EVAL=$(tmux split-window -v -p 45 -t "$PANE_AGENT" -c "$PROJECT_ROOT" \
98
+ -P -F '#{pane_id}' \
99
+ "bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-eval-watcher.sh\" \"${PROJECT_ROOT}\" ${USE_AI}'")
101
100
 
102
- # ── Select Main pane as active ──
103
- tmux select-pane -t "${SESSION_NAME}.0"
101
+ # 6. Launch Claude in Agent Session (needs interactive shell, so use send-keys)
102
+ # Prefix with unset to avoid nvm warnings
103
+ tmux send-keys -t "$PANE_AGENT" "unset npm_config_prefix 2>/dev/null; $CLAUDE_CMD" Enter
104
104
 
105
105
  # ── Pane titles ──
106
- tmux select-pane -t "${SESSION_NAME}.0" -T "Control Center"
107
- tmux select-pane -t "${SESSION_NAME}.1" -T "Monitor"
108
- tmux select-pane -t "${SESSION_NAME}.2" -T "Agent Session"
109
- tmux select-pane -t "${SESSION_NAME}.3" -T "Eval Review"
106
+ tmux select-pane -t "$PANE_DASHBOARD" -T "Dashboard"
107
+ tmux select-pane -t "$PANE_MONITOR" -T "Monitor"
108
+ tmux select-pane -t "$PANE_CONTROL" -T "Control"
109
+ tmux select-pane -t "$PANE_AGENT" -T "Agent Session"
110
+ tmux select-pane -t "$PANE_EVAL" -T "Eval Review"
110
111
 
111
112
  tmux set-option -t "$SESSION_NAME" pane-border-status top 2>/dev/null || true
112
113
  tmux set-option -t "$SESSION_NAME" pane-border-format " #{pane_title} " 2>/dev/null || true
113
114
 
115
+ # ── Focus on Control pane (where user types) ──
116
+ tmux select-pane -t "$PANE_CONTROL"
117
+
114
118
  # ── Attach ──
115
119
  if [ "$DETACH" = true ]; then
116
120
  echo ""
117
- echo "Session created. Attach with:"
118
- echo " tmux attach -t $SESSION_NAME"
121
+ echo "Session created. Attach: tmux attach -t $SESSION_NAME"
119
122
  else
120
123
  if [ -n "${TMUX:-}" ]; then
121
124
  tmux switch-client -t "$SESSION_NAME"
122
125
  else
123
126
  echo ""
124
127
  echo "Launching harness-studio..."
125
- echo " Control Center (left) : Dashboard + manual prompting"
126
- echo " Monitor (right↑) : Agent lifecycle (compact)"
127
- echo " Agent Session (right↔) : claude --dangerously-skip-permissions"
128
- echo " Eval Review (right↓) : Evaluation summaries"
128
+ echo " Dashboard (left↑) : Auto-refresh progress"
129
+ echo " Control (left↓) : Manual commands (next/retry/stop/log)"
130
+ echo " Monitor (right↑) : Agent lifecycle (compact)"
131
+ echo " Agent Session (right↔): claude --dangerously-skip-permissions"
132
+ echo " Eval Review (right↓): Evaluation summaries"
129
133
  echo ""
130
134
  tmux attach -t "$SESSION_NAME"
131
135
  fi