@walwal-harness/cli 5.7.1 → 5.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/package.json +1 -1
- package/scripts/harness-gotcha-memory.sh +64 -2
- package/scripts/harness-tmux.sh +31 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "5.7.
|
|
3
|
+
"version": "5.7.3",
|
|
4
4
|
"description": "Production harness for AI agent engineering — Solo/Team mode, Planner, Generator(BE/FE), Evaluator chain (Code-Quality → Functional → Visual), optional Brainstormer. Supports React, Next.js, and Flutter FE stacks.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# harness-gotcha-memory.sh — Gotcha
|
|
2
|
+
# harness-gotcha-memory.sh — Gotcha · Memory · Conventions pane (index view)
|
|
3
3
|
# 활성 에이전트의 gotcha를 최상단으로, 나머지는 요약(최근 3항목+총개수)으로 표시
|
|
4
|
+
# + Shared Memory 요약 + Conventions 요약 (shared + 활성 에이전트별)
|
|
4
5
|
# Usage: bash scripts/harness-gotcha-memory.sh [project-root]
|
|
5
6
|
|
|
6
7
|
set -uo pipefail
|
|
@@ -16,6 +17,7 @@ fi
|
|
|
16
17
|
|
|
17
18
|
MEMORY_FILE="$PROJECT_ROOT/.harness/memory.md"
|
|
18
19
|
GOTCHAS_DIR="$PROJECT_ROOT/.harness/gotchas"
|
|
20
|
+
CONVENTIONS_DIR="$PROJECT_ROOT/.harness/conventions"
|
|
19
21
|
PROGRESS="$PROJECT_ROOT/.harness/progress.json"
|
|
20
22
|
|
|
21
23
|
BOLD="\033[1m"
|
|
@@ -45,6 +47,12 @@ compute_signature() {
|
|
|
45
47
|
stat -f '%N %m %z' "$f" 2>/dev/null
|
|
46
48
|
done
|
|
47
49
|
fi
|
|
50
|
+
if [ -d "$CONVENTIONS_DIR" ]; then
|
|
51
|
+
for f in "$CONVENTIONS_DIR"/*.md; do
|
|
52
|
+
[ -e "$f" ] || continue
|
|
53
|
+
stat -f '%N %m %z' "$f" 2>/dev/null
|
|
54
|
+
done
|
|
55
|
+
fi
|
|
48
56
|
} | md5 -q 2>/dev/null || echo "$RANDOM"
|
|
49
57
|
}
|
|
50
58
|
|
|
@@ -115,6 +123,55 @@ render_gotcha_entry() {
|
|
|
115
123
|
fi
|
|
116
124
|
}
|
|
117
125
|
|
|
126
|
+
render_conventions_summary() {
|
|
127
|
+
if [ ! -d "$CONVENTIONS_DIR" ]; then
|
|
128
|
+
echo -e "${DIM}(conventions/ 없음)${RESET}"
|
|
129
|
+
return
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
local active="$1"
|
|
133
|
+
local any=false
|
|
134
|
+
|
|
135
|
+
# Shared 먼저, 그다음 활성 에이전트, 그다음 나머지
|
|
136
|
+
local ordered_files=()
|
|
137
|
+
[ -f "$CONVENTIONS_DIR/shared.md" ] && ordered_files+=("$CONVENTIONS_DIR/shared.md")
|
|
138
|
+
if [ -n "$active" ] && [ -f "$CONVENTIONS_DIR/${active}.md" ]; then
|
|
139
|
+
ordered_files+=("$CONVENTIONS_DIR/${active}.md")
|
|
140
|
+
fi
|
|
141
|
+
for cand in "$CONVENTIONS_DIR"/*.md; do
|
|
142
|
+
[ -e "$cand" ] || continue
|
|
143
|
+
local base; base=$(basename "$cand" .md)
|
|
144
|
+
[ "$base" = "README" ] && continue
|
|
145
|
+
[ "$cand" = "$CONVENTIONS_DIR/shared.md" ] && continue
|
|
146
|
+
[ -n "$active" ] && [ "$cand" = "$CONVENTIONS_DIR/${active}.md" ] && continue
|
|
147
|
+
ordered_files+=("$cand")
|
|
148
|
+
done
|
|
149
|
+
|
|
150
|
+
for f in "${ordered_files[@]}"; do
|
|
151
|
+
[ -e "$f" ] || continue
|
|
152
|
+
local name count
|
|
153
|
+
name=$(basename "$f" .md)
|
|
154
|
+
count=$(count_items "$f")
|
|
155
|
+
if [ "$name" = "shared" ]; then
|
|
156
|
+
echo -e "${BOLD}${CYAN}▸ ${name}${RESET} ${DIM}(${count} items · shared)${RESET}"
|
|
157
|
+
elif [ -n "$active" ] && [ "$name" = "$active" ]; then
|
|
158
|
+
echo -e "${BOLD}${BG_YELLOW} ▸ ${name} ${RESET} ${DIM}(${count} items · ACTIVE)${RESET}"
|
|
159
|
+
else
|
|
160
|
+
echo -e "${BOLD}${GREEN}▸ ${name}${RESET} ${DIM}(${count} items)${RESET}"
|
|
161
|
+
fi
|
|
162
|
+
if [ "$count" -eq 0 ]; then
|
|
163
|
+
echo -e " ${DIM}(항목 없음)${RESET}"
|
|
164
|
+
else
|
|
165
|
+
recent_titles "$f" "$RECENT_N" | while IFS= read -r t; do
|
|
166
|
+
echo -e " ${DIM}·${RESET} $t"
|
|
167
|
+
done
|
|
168
|
+
fi
|
|
169
|
+
any=true
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
[ "$any" = "false" ] && echo -e "${DIM}(항목 없음)${RESET}"
|
|
173
|
+
}
|
|
174
|
+
|
|
118
175
|
render_memory_summary() {
|
|
119
176
|
if [ ! -f "$MEMORY_FILE" ]; then
|
|
120
177
|
echo -e "${DIM}(memory.md 없음)${RESET}"
|
|
@@ -145,7 +202,7 @@ render() {
|
|
|
145
202
|
active_file=""
|
|
146
203
|
[ -n "$active" ] && active_file=$(file_for_agent "$active")
|
|
147
204
|
|
|
148
|
-
echo -e "${BOLD}${MAGENTA}
|
|
205
|
+
echo -e "${BOLD}${MAGENTA}RULES INDEX${RESET} ${DIM}Gotcha · Memory · Conventions · $(date +%H:%M:%S) · recent=${RECENT_N} · refresh ${REFRESH_SEC}s${RESET}"
|
|
149
206
|
if [ -n "$active" ]; then
|
|
150
207
|
echo -e "${DIM}active agent:${RESET} ${BOLD}${YELLOW}${active}${RESET}"
|
|
151
208
|
else
|
|
@@ -171,6 +228,11 @@ render() {
|
|
|
171
228
|
done
|
|
172
229
|
fi
|
|
173
230
|
|
|
231
|
+
echo ""
|
|
232
|
+
echo -e "${DIM}${hr}${RESET}"
|
|
233
|
+
echo -e "${BOLD}${CYAN}▣ CONVENTIONS${RESET} ${DIM}(.harness/conventions)${RESET}"
|
|
234
|
+
render_conventions_summary "$active"
|
|
235
|
+
|
|
174
236
|
echo ""
|
|
175
237
|
echo -e "${DIM}${hr}${RESET}"
|
|
176
238
|
render_memory_summary
|
package/scripts/harness-tmux.sh
CHANGED
|
@@ -142,6 +142,10 @@ APPLESCRIPT
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
launch_iterm2_solo() {
|
|
145
|
+
# Solo 레이아웃 (Team 모드와 동일 구조, 우측만 단일 Monitor 패널):
|
|
146
|
+
# Left col : Dashboard (top) + Prompt History (bottom)
|
|
147
|
+
# Middle : Gotcha · Memory · Conventions
|
|
148
|
+
# Right : Monitor (lifecycle stream, 단일 에이전트)
|
|
145
149
|
osascript <<APPLESCRIPT
|
|
146
150
|
tell application "iTerm2"
|
|
147
151
|
activate
|
|
@@ -153,22 +157,22 @@ launch_iterm2_solo() {
|
|
|
153
157
|
set name to "harness-studio"
|
|
154
158
|
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-dashboard.sh' '${PROJECT_ROOT}'"
|
|
155
159
|
|
|
156
|
-
-- Split
|
|
157
|
-
set
|
|
158
|
-
tell
|
|
159
|
-
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-
|
|
160
|
-
|
|
161
|
-
-- Split right → Agent Session
|
|
162
|
-
set agentPane to (split vertically with default profile)
|
|
163
|
-
tell agentPane
|
|
164
|
-
write text "cd '${PROJECT_ROOT}' && clear"
|
|
165
|
-
end tell
|
|
160
|
+
-- Split down (bottom of Dashboard column) → Prompt History
|
|
161
|
+
set archivePane to (split horizontally with default profile)
|
|
162
|
+
tell archivePane
|
|
163
|
+
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-prompt-history.sh' '${PROJECT_ROOT}'"
|
|
166
164
|
end tell
|
|
167
165
|
|
|
168
|
-
-- Split
|
|
169
|
-
set
|
|
170
|
-
tell
|
|
171
|
-
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-
|
|
166
|
+
-- Split right → Gotcha · Memory · Conventions
|
|
167
|
+
set dashPane to (split vertically with default profile)
|
|
168
|
+
tell dashPane
|
|
169
|
+
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-gotcha-memory.sh' '${PROJECT_ROOT}'"
|
|
170
|
+
|
|
171
|
+
-- Split right → Monitor (solo 단일 에이전트 라이프사이클)
|
|
172
|
+
set monPane to (split vertically with default profile)
|
|
173
|
+
tell monPane
|
|
174
|
+
write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-monitor.sh' '${PROJECT_ROOT}'"
|
|
175
|
+
end tell
|
|
172
176
|
end tell
|
|
173
177
|
end tell
|
|
174
178
|
end tell
|
|
@@ -199,7 +203,7 @@ launch_tmux_team() {
|
|
|
199
203
|
|
|
200
204
|
tmux select-pane -t "$PANE_DASH" -T "Dashboard"
|
|
201
205
|
tmux select-pane -t "$PANE_ARCHIVE" -T "Archive Prompt"
|
|
202
|
-
tmux select-pane -t "$PANE_GOTCHA" -T "Gotcha
|
|
206
|
+
tmux select-pane -t "$PANE_GOTCHA" -T "Gotcha · Memory · Conventions"
|
|
203
207
|
tmux select-pane -t "$PANE_T1" -T "TEAM 1"
|
|
204
208
|
tmux select-pane -t "$PANE_T2" -T "TEAM 2"
|
|
205
209
|
tmux select-pane -t "$PANE_T3" -T "TEAM 3"
|
|
@@ -210,23 +214,24 @@ launch_tmux_team() {
|
|
|
210
214
|
}
|
|
211
215
|
|
|
212
216
|
launch_tmux_solo() {
|
|
217
|
+
# Solo 레이아웃 (Team 모드와 동일 구조, 우측만 단일 Monitor 패널).
|
|
213
218
|
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
|
|
214
219
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
PANE_MONITOR=$(tmux split-window -h -p
|
|
220
|
+
PANE_DASH=$(tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 200 -y 50 -P -F '#{pane_id}')
|
|
221
|
+
PANE_GOTCHA=$(tmux split-window -h -p 70 -t "$PANE_DASH" -c "$PROJECT_ROOT" -P -F '#{pane_id}')
|
|
222
|
+
PANE_MONITOR=$(tmux split-window -h -p 50 -t "$PANE_GOTCHA" -c "$PROJECT_ROOT" -P -F '#{pane_id}' \
|
|
218
223
|
"bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-monitor.sh\" \"${PROJECT_ROOT}\"'")
|
|
219
|
-
PANE_HISTORY=$(tmux split-window -v -p
|
|
224
|
+
PANE_HISTORY=$(tmux split-window -v -p 35 -t "$PANE_DASH" -c "$PROJECT_ROOT" -P -F '#{pane_id}' \
|
|
220
225
|
"bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-prompt-history.sh\" \"${PROJECT_ROOT}\"'")
|
|
221
|
-
PANE_AGENT=$(tmux split-window -v -p 85 -t "$PANE_MONITOR" -c "$PROJECT_ROOT" -P -F '#{pane_id}')
|
|
222
226
|
|
|
223
|
-
tmux send-keys -t "$
|
|
227
|
+
tmux send-keys -t "$PANE_DASH" "bash \"${SCRIPT_DIR}/harness-dashboard.sh\" \"${PROJECT_ROOT}\"" Enter
|
|
228
|
+
tmux send-keys -t "$PANE_GOTCHA" "bash \"${SCRIPT_DIR}/harness-gotcha-memory.sh\" \"${PROJECT_ROOT}\"" Enter
|
|
224
229
|
|
|
225
|
-
tmux select-pane -t "$
|
|
226
|
-
tmux select-pane -t "$
|
|
227
|
-
tmux select-pane -t "$
|
|
228
|
-
tmux select-pane -t "$
|
|
229
|
-
tmux select-pane -t "$
|
|
230
|
+
tmux select-pane -t "$PANE_DASH" -T "Dashboard"
|
|
231
|
+
tmux select-pane -t "$PANE_HISTORY" -T "Prompt History"
|
|
232
|
+
tmux select-pane -t "$PANE_GOTCHA" -T "Gotcha · Memory · Conventions"
|
|
233
|
+
tmux select-pane -t "$PANE_MONITOR" -T "Monitor"
|
|
234
|
+
tmux select-pane -t "$PANE_DASH"
|
|
230
235
|
|
|
231
236
|
tmux set-option -t "$SESSION_NAME" pane-border-status top 2>/dev/null || true
|
|
232
237
|
tmux set-option -t "$SESSION_NAME" pane-border-format " #{pane_title} " 2>/dev/null || true
|