@walwal-harness/cli 5.2.0 → 5.3.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/commands/harness-team.md +39 -13
- package/package.json +1 -1
- package/scripts/harness-gotcha-memory.sh +165 -0
- package/scripts/harness-tmux.sh +30 -18
package/commands/harness-team.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
docmeta:
|
|
3
|
+
id: harness-team
|
|
4
|
+
title: /harness-team — Team Mode 시작/재개
|
|
5
|
+
type: input
|
|
6
|
+
createdAt: 2026-04-20T00:00:00Z
|
|
7
|
+
updatedAt: 2026-04-20T00:00:00Z
|
|
8
|
+
source:
|
|
9
|
+
producer: user
|
|
10
|
+
skillId: harness
|
|
11
|
+
inputs: []
|
|
12
|
+
tags: [harness, team-mode, tmux, command]
|
|
13
|
+
---
|
|
14
|
+
|
|
1
15
|
# /harness-team — Team Mode 시작/재개
|
|
2
16
|
|
|
3
17
|
Planner가 완료한 feature-list.json의 피처들을 최대 3개 팀이 병렬로 Gen→Eval 사이클을 수행합니다.
|
|
@@ -40,9 +54,11 @@ bash scripts/harness-queue-manager.sh status .
|
|
|
40
54
|
### Step 2: tmux Studio 레이아웃 구축
|
|
41
55
|
|
|
42
56
|
```bash
|
|
43
|
-
bash scripts/harness-tmux.sh --team
|
|
57
|
+
bash scripts/harness-tmux.sh --team --force-tmux
|
|
44
58
|
```
|
|
45
59
|
|
|
60
|
+
**`--force-tmux` 필수**: iTerm2 감지 경로는 백그라운드에 iTerm2가 떠 있기만 해도 활성화되어 AppleScript 실패 시 팀 레이아웃이 조용히 사라짐. Team Mode는 항상 tmux로 강제하여 재현 가능한 레이아웃을 보장.
|
|
61
|
+
|
|
46
62
|
### Step 3: 초기 Worker 생성
|
|
47
63
|
|
|
48
64
|
Queue에서 ready 피처를 최대 3개 dequeue하고, **각각 background Agent로 생성**합니다.
|
|
@@ -162,18 +178,28 @@ LOG="$HARNESS_ROOT/.harness/progress.log"
|
|
|
162
178
|
logev() { echo "$(date +'%Y-%m-%d %H:%M') | team-{N} | $1 | $2" >> "$LOG"; }
|
|
163
179
|
```
|
|
164
180
|
|
|
165
|
-
| ACTION | 사용 시점 | DETAIL 예시 |
|
|
166
|
-
|
|
167
|
-
| `gen-start` | Gen Phase 시작 | `F-001 start — 6 AC` |
|
|
168
|
-
| `gen-
|
|
169
|
-
| `gen-
|
|
170
|
-
| `gen-
|
|
171
|
-
| `gen-
|
|
172
|
-
| `
|
|
173
|
-
| `eval-
|
|
174
|
-
| `eval-
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
181
|
+
| ACTION | 사용 시점 | DETAIL 예시 (필수 포함 정보) |
|
|
182
|
+
|--------|-----------|------------------------------|
|
|
183
|
+
| `gen-start` | Gen Phase 시작 (1회) | `F-001 "사용자 회원가입 API" start — goal=POST /users, 6 AC` — **Feature 제목+목표** 포함 필수 |
|
|
184
|
+
| `gen-plan` | 작업 계획 공표 (1회) | `plan: create controller+service+dto, wire module, add 3 unit tests` |
|
|
185
|
+
| `gen-read` | 소스/계약 읽기 (매 파일) | `read api-contract.json#/paths/~1users` |
|
|
186
|
+
| `gen-write` | 파일 생성/수정 (**매 파일**) | `write apps/service-user/src/user.controller.ts (+82 LOC, create)` — **경로+LOC+action(create/edit/delete)** 필수 |
|
|
187
|
+
| `gen-test` | 자체 게이트 | `tsc OK · eslint 0 warn · jest 12/12 pass` |
|
|
188
|
+
| `gen-done` | Gen Phase 종료 | `F-001 done — 5 files: controller.ts, service.ts, dto.ts, module.ts, spec.ts (total +142 LOC)` — **변경 파일 전체 나열** 필수 |
|
|
189
|
+
| `eval-start` | Evaluator 시작 | `F-001 evaluating — 6 ACs + regression + security` — **AC 개수+검증 축** 필수 |
|
|
190
|
+
| `eval-ac` | AC 본문 선언 (**매 AC 시작 시 1회**) | `AC-3: "POST /users returns 201 with created user id"` — **AC 원문** 필수 |
|
|
191
|
+
| `eval-check` | AC 검증 수행/증거 | `AC-3 [PASS] — curl POST /users → 201, body.id matches` — **판정+증거** 필수 |
|
|
192
|
+
| `eval-gate` | 자동 게이트 | `gate: tsc OK, eslint OK, security scan 0 high` |
|
|
193
|
+
| `eval-done` | Eval 결과 | `F-001 VERDICT=PASS SCORE=2.95/3.00 (AC 6/6, gates OK)` |
|
|
194
|
+
| `result` | PASS 확정 (**SCORE ≥ 2.80**) | `F-001 PASS score=2.95` |
|
|
195
|
+
| `fail` | FAIL 확정 | `F-001 FAIL #1 — AC-2 "email uniqueness" missing DB constraint` |
|
|
196
|
+
|
|
197
|
+
**중요: 로깅 가독성 규칙 (필수)**
|
|
198
|
+
1. `gen-start`에는 반드시 Feature **제목과 목표**를 함께 기록 (무슨 일을 시작하는가 명확히).
|
|
199
|
+
2. `gen-write`는 **변경되는 파일마다 1건씩** 기록. 묶어서 요약 금지 ("2 files edit" 같은 표기 금지).
|
|
200
|
+
3. `gen-done`은 **변경 파일 전체 목록**을 나열. "(2 files)" 같은 개수만 기록 금지.
|
|
201
|
+
4. `eval-ac`로 **AC 원문을 먼저 선언**한 뒤 `eval-check`로 증거/판정 기록. "AC-1 count=0" 같은 수치 단독 기록 금지.
|
|
202
|
+
5. `result` PASS는 **SCORE ≥ 2.80** 인 경우에만 기록. score=1.00인데 PASS로 기록하는 실수 금지.
|
|
177
203
|
|
|
178
204
|
**queue phase 업데이트:**
|
|
179
205
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Production harness for AI agent engineering — Solo/Team mode, Planner, Generator(BE/FE), Evaluator(Func/Visual), optional Brainstormer. Supports React, Next.js, and Flutter FE stacks.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# harness-gotcha-memory.sh — Gotcha & Memory pane (index view)
|
|
3
|
+
# 활성 에이전트의 gotcha를 최상단으로, 나머지는 요약(최근 3항목+총개수)으로 표시
|
|
4
|
+
# Usage: bash scripts/harness-gotcha-memory.sh [project-root]
|
|
5
|
+
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
source "$SCRIPT_DIR/lib/harness-render-progress.sh"
|
|
10
|
+
|
|
11
|
+
PROJECT_ROOT="${1:-}"
|
|
12
|
+
if [ -z "$PROJECT_ROOT" ]; then
|
|
13
|
+
PROJECT_ROOT="$(resolve_harness_root ".")" || { echo "[gotcha] .harness/ not found."; exit 1; }
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
MEMORY_FILE="$PROJECT_ROOT/.harness/memory.md"
|
|
17
|
+
GOTCHAS_DIR="$PROJECT_ROOT/.harness/gotchas"
|
|
18
|
+
PROGRESS="$PROJECT_ROOT/.harness/progress.json"
|
|
19
|
+
|
|
20
|
+
BOLD="\033[1m"
|
|
21
|
+
DIM="\033[2m"
|
|
22
|
+
GREEN="\033[32m"
|
|
23
|
+
YELLOW="\033[33m"
|
|
24
|
+
RED="\033[31m"
|
|
25
|
+
CYAN="\033[36m"
|
|
26
|
+
MAGENTA="\033[35m"
|
|
27
|
+
RESET="\033[0m"
|
|
28
|
+
BG_YELLOW="\033[43m"
|
|
29
|
+
|
|
30
|
+
REFRESH_SEC="${HARNESS_REFRESH:-5}"
|
|
31
|
+
RECENT_N="${HARNESS_GOTCHA_RECENT:-3}"
|
|
32
|
+
|
|
33
|
+
# 활성 에이전트 결정: current_agent > next_agent
|
|
34
|
+
get_active_agent() {
|
|
35
|
+
[ -f "$PROGRESS" ] || { echo ""; return; }
|
|
36
|
+
command -v jq &>/dev/null || { echo ""; return; }
|
|
37
|
+
local cur nxt
|
|
38
|
+
cur=$(jq -r '.current_agent // ""' "$PROGRESS" 2>/dev/null)
|
|
39
|
+
nxt=$(jq -r '.next_agent // ""' "$PROGRESS" 2>/dev/null)
|
|
40
|
+
if [ -n "$cur" ] && [ "$cur" != "null" ] && [ "$cur" != "none" ]; then
|
|
41
|
+
echo "$cur"
|
|
42
|
+
elif [ -n "$nxt" ] && [ "$nxt" != "null" ] && [ "$nxt" != "none" ]; then
|
|
43
|
+
echo "$nxt"
|
|
44
|
+
else
|
|
45
|
+
echo ""
|
|
46
|
+
fi
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# gotcha 파일에서 '### ' 헤딩 개수 = 항목 총수
|
|
50
|
+
count_items() {
|
|
51
|
+
local f="$1"
|
|
52
|
+
local n
|
|
53
|
+
n=$(grep -c '^### ' "$f" 2>/dev/null)
|
|
54
|
+
echo "${n:-0}"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# 최근 N개 항목 제목 추출 (### 헤딩 — 파일 하단부가 최신이라 tail)
|
|
58
|
+
recent_titles() {
|
|
59
|
+
local f="$1" n="$2"
|
|
60
|
+
grep '^### ' "$f" 2>/dev/null | tail -n "$n" | sed 's/^### //'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# agent 이름 → 파일 basename 매핑 (정확/접두 일치)
|
|
64
|
+
file_for_agent() {
|
|
65
|
+
local agent="$1"
|
|
66
|
+
local f="$GOTCHAS_DIR/${agent}.md"
|
|
67
|
+
[ -f "$f" ] && { echo "$f"; return; }
|
|
68
|
+
# 접두 일치 (예: current_agent=generator → generator-backend/frontend 중 하나)
|
|
69
|
+
for cand in "$GOTCHAS_DIR"/*.md; do
|
|
70
|
+
[ -e "$cand" ] || continue
|
|
71
|
+
local base
|
|
72
|
+
base=$(basename "$cand" .md)
|
|
73
|
+
[ "$base" = "README" ] && continue
|
|
74
|
+
case "$base" in
|
|
75
|
+
"$agent"*|*"$agent"*) echo "$cand"; return ;;
|
|
76
|
+
esac
|
|
77
|
+
done
|
|
78
|
+
echo ""
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
render_gotcha_entry() {
|
|
82
|
+
local f="$1" active="$2"
|
|
83
|
+
local name count
|
|
84
|
+
name=$(basename "$f" .md)
|
|
85
|
+
count=$(count_items "$f")
|
|
86
|
+
if [ "$active" = "true" ]; then
|
|
87
|
+
echo -e "${BOLD}${BG_YELLOW} ▸ ${name} ${RESET} ${DIM}(${count} items · ACTIVE)${RESET}"
|
|
88
|
+
else
|
|
89
|
+
echo -e "${BOLD}${GREEN}▸ ${name}${RESET} ${DIM}(${count} items)${RESET}"
|
|
90
|
+
fi
|
|
91
|
+
if [ "$count" -eq 0 ]; then
|
|
92
|
+
echo -e " ${DIM}(항목 없음)${RESET}"
|
|
93
|
+
else
|
|
94
|
+
recent_titles "$f" "$RECENT_N" | while IFS= read -r t; do
|
|
95
|
+
echo -e " ${DIM}·${RESET} $t"
|
|
96
|
+
done
|
|
97
|
+
fi
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
render_memory_summary() {
|
|
101
|
+
if [ ! -f "$MEMORY_FILE" ]; then
|
|
102
|
+
echo -e "${DIM}(memory.md 없음)${RESET}"
|
|
103
|
+
return
|
|
104
|
+
fi
|
|
105
|
+
local count
|
|
106
|
+
count=$(grep -c '^### ' "$MEMORY_FILE" 2>/dev/null)
|
|
107
|
+
count="${count:-0}"
|
|
108
|
+
echo -e "${BOLD}${CYAN}▣ SHARED MEMORY${RESET} ${DIM}(${count} items · memory.md)${RESET}"
|
|
109
|
+
if [ "$count" -eq 0 ]; then
|
|
110
|
+
echo -e " ${DIM}(항목 없음)${RESET}"
|
|
111
|
+
else
|
|
112
|
+
grep '^### ' "$MEMORY_FILE" | tail -n "$RECENT_N" | sed 's/^### //' | while IFS= read -r t; do
|
|
113
|
+
echo -e " ${DIM}·${RESET} $t"
|
|
114
|
+
done
|
|
115
|
+
fi
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
render() {
|
|
119
|
+
clear
|
|
120
|
+
local cols hr
|
|
121
|
+
cols=$(tput cols 2>/dev/null || echo 80)
|
|
122
|
+
hr=$(printf '─%.0s' $(seq 1 "$cols"))
|
|
123
|
+
|
|
124
|
+
local active active_file
|
|
125
|
+
active=$(get_active_agent)
|
|
126
|
+
active_file=""
|
|
127
|
+
[ -n "$active" ] && active_file=$(file_for_agent "$active")
|
|
128
|
+
|
|
129
|
+
echo -e "${BOLD}${MAGENTA}GOTCHA INDEX${RESET} ${DIM}$(date +%H:%M:%S) · recent=${RECENT_N} · refresh ${REFRESH_SEC}s${RESET}"
|
|
130
|
+
if [ -n "$active" ]; then
|
|
131
|
+
echo -e "${DIM}active agent:${RESET} ${BOLD}${YELLOW}${active}${RESET}"
|
|
132
|
+
else
|
|
133
|
+
echo -e "${DIM}active agent: (none)${RESET}"
|
|
134
|
+
fi
|
|
135
|
+
echo -e "${DIM}${hr}${RESET}"
|
|
136
|
+
|
|
137
|
+
# 활성 에이전트 gotcha 최상단
|
|
138
|
+
if [ -n "$active_file" ]; then
|
|
139
|
+
render_gotcha_entry "$active_file" "true"
|
|
140
|
+
echo ""
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# 나머지 gotcha
|
|
144
|
+
if [ -d "$GOTCHAS_DIR" ]; then
|
|
145
|
+
for f in "$GOTCHAS_DIR"/*.md; do
|
|
146
|
+
[ -e "$f" ] || continue
|
|
147
|
+
[ "$f" = "$active_file" ] && continue
|
|
148
|
+
local base
|
|
149
|
+
base=$(basename "$f" .md)
|
|
150
|
+
[ "$base" = "README" ] && continue
|
|
151
|
+
render_gotcha_entry "$f" "false"
|
|
152
|
+
done
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
echo ""
|
|
156
|
+
echo -e "${DIM}${hr}${RESET}"
|
|
157
|
+
render_memory_summary
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
trap 'exit 0' INT TERM
|
|
161
|
+
|
|
162
|
+
while true; do
|
|
163
|
+
render
|
|
164
|
+
sleep "$REFRESH_SEC"
|
|
165
|
+
done
|
package/scripts/harness-tmux.sh
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
# Team Mode (--team):
|
|
5
5
|
# ┌──────────────┬──────────────┬──────────────┐
|
|
6
6
|
# │ │ │ TEAM 1 │
|
|
7
|
-
# │
|
|
8
|
-
# │
|
|
9
|
-
# │
|
|
10
|
-
# │
|
|
7
|
+
# │ Dashboard │ Gotcha & │ │
|
|
8
|
+
# │ (queue + │ Memory ├──────────────┤
|
|
9
|
+
# │ status + │ │ TEAM 2 │
|
|
10
|
+
# │ archive) │ │ │
|
|
11
11
|
# │ │ ├──────────────┤
|
|
12
12
|
# │ │ │ TEAM 3 │
|
|
13
13
|
# └──────────────┴──────────────┴──────────────┘
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
# Usage:
|
|
21
21
|
# bash scripts/harness-tmux.sh [project-root] --team
|
|
22
22
|
# bash scripts/harness-tmux.sh [project-root] --solo
|
|
23
|
+
# bash scripts/harness-tmux.sh [project-root] --team --force-tmux # skip iTerm2, use tmux
|
|
23
24
|
# bash scripts/harness-tmux.sh --kill
|
|
24
25
|
|
|
25
26
|
set -euo pipefail
|
|
@@ -30,12 +31,14 @@ SESSION_NAME="harness-studio"
|
|
|
30
31
|
PROJECT_ROOT=""
|
|
31
32
|
MODE=""
|
|
32
33
|
DETACH=false
|
|
34
|
+
FORCE_TMUX=false
|
|
33
35
|
|
|
34
36
|
for arg in "$@"; do
|
|
35
37
|
case "$arg" in
|
|
36
38
|
--team) MODE="team" ;;
|
|
37
39
|
--solo) MODE="solo" ;;
|
|
38
40
|
--detach) DETACH=true ;;
|
|
41
|
+
--force-tmux) FORCE_TMUX=true ;;
|
|
39
42
|
--kill)
|
|
40
43
|
tmux kill-session -t "$SESSION_NAME" 2>/dev/null && echo "tmux session killed." || true
|
|
41
44
|
# Also try to close iTerm2 studio tab if exists
|
|
@@ -99,12 +102,12 @@ launch_iterm2_team() {
|
|
|
99
102
|
tell studioWindow
|
|
100
103
|
tell current session of current tab
|
|
101
104
|
set name to "harness-studio"
|
|
102
|
-
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-
|
|
105
|
+
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-dashboard.sh' '${PROJECT_ROOT}'"
|
|
103
106
|
|
|
104
|
-
-- Split right →
|
|
107
|
+
-- Split right → Gotcha & Memory
|
|
105
108
|
set dashPane to (split vertically with default profile)
|
|
106
109
|
tell dashPane
|
|
107
|
-
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-
|
|
110
|
+
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-gotcha-memory.sh' '${PROJECT_ROOT}'"
|
|
108
111
|
|
|
109
112
|
-- Split right → Team 1
|
|
110
113
|
set t1Pane to (split vertically with default profile)
|
|
@@ -171,24 +174,24 @@ APPLESCRIPT
|
|
|
171
174
|
launch_tmux_team() {
|
|
172
175
|
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
|
|
173
176
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
PANE_T1=$(tmux split-window -h -p 60 -t "$
|
|
177
|
+
PANE_DASH=$(tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 220 -y 55 -P -F '#{pane_id}')
|
|
178
|
+
PANE_GOTCHA=$(tmux split-window -h -p 70 -t "$PANE_DASH" -c "$PROJECT_ROOT" -P -F '#{pane_id}')
|
|
179
|
+
PANE_T1=$(tmux split-window -h -p 60 -t "$PANE_GOTCHA" -c "$PROJECT_ROOT" -P -F '#{pane_id}' \
|
|
177
180
|
"bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-monitor.sh\" \"${PROJECT_ROOT}\" --team 1'")
|
|
178
181
|
PANE_T2=$(tmux split-window -v -p 66 -t "$PANE_T1" -c "$PROJECT_ROOT" -P -F '#{pane_id}' \
|
|
179
182
|
"bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-monitor.sh\" \"${PROJECT_ROOT}\" --team 2'")
|
|
180
183
|
PANE_T3=$(tmux split-window -v -p 50 -t "$PANE_T2" -c "$PROJECT_ROOT" -P -F '#{pane_id}' \
|
|
181
184
|
"bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-monitor.sh\" \"${PROJECT_ROOT}\" --team 3'")
|
|
182
185
|
|
|
183
|
-
tmux send-keys -t "$
|
|
184
|
-
tmux send-keys -t "$
|
|
186
|
+
tmux send-keys -t "$PANE_DASH" "bash \"${SCRIPT_DIR}/harness-dashboard.sh\" \"${PROJECT_ROOT}\"" Enter
|
|
187
|
+
tmux send-keys -t "$PANE_GOTCHA" "bash \"${SCRIPT_DIR}/harness-gotcha-memory.sh\" \"${PROJECT_ROOT}\"" Enter
|
|
185
188
|
|
|
186
|
-
tmux select-pane -t "$
|
|
187
|
-
tmux select-pane -t "$
|
|
188
|
-
tmux select-pane -t "$PANE_T1"
|
|
189
|
-
tmux select-pane -t "$PANE_T2"
|
|
190
|
-
tmux select-pane -t "$PANE_T3"
|
|
191
|
-
tmux select-pane -t "$
|
|
189
|
+
tmux select-pane -t "$PANE_DASH" -T "Dashboard"
|
|
190
|
+
tmux select-pane -t "$PANE_GOTCHA" -T "Gotcha & Memory"
|
|
191
|
+
tmux select-pane -t "$PANE_T1" -T "TEAM 1"
|
|
192
|
+
tmux select-pane -t "$PANE_T2" -T "TEAM 2"
|
|
193
|
+
tmux select-pane -t "$PANE_T3" -T "TEAM 3"
|
|
194
|
+
tmux select-pane -t "$PANE_DASH"
|
|
192
195
|
|
|
193
196
|
tmux set-option -t "$SESSION_NAME" pane-border-status top 2>/dev/null || true
|
|
194
197
|
tmux set-option -t "$SESSION_NAME" pane-border-format " #{pane_title} " 2>/dev/null || true
|
|
@@ -237,6 +240,15 @@ if command -v tmux &>/dev/null; then
|
|
|
237
240
|
HAS_TMUX=true
|
|
238
241
|
fi
|
|
239
242
|
|
|
243
|
+
# --force-tmux overrides iTerm2 detection
|
|
244
|
+
if [ "$FORCE_TMUX" = true ]; then
|
|
245
|
+
if [ "$HAS_TMUX" != true ]; then
|
|
246
|
+
echo "ERROR: --force-tmux specified but tmux not installed. Run: brew install tmux"
|
|
247
|
+
exit 1
|
|
248
|
+
fi
|
|
249
|
+
IS_ITERM=false
|
|
250
|
+
fi
|
|
251
|
+
|
|
240
252
|
if [ "$IS_ITERM" = true ]; then
|
|
241
253
|
echo "Strategy: iTerm2 native split panes"
|
|
242
254
|
if [ "$MODE" = "team" ]; then
|