@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "5.7.1",
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 & Memory pane (index view)
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}GOTCHA INDEX${RESET} ${DIM}$(date +%H:%M:%S) · recent=${RECENT_N} · refresh ${REFRESH_SEC}s${RESET}"
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
@@ -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 right → Monitor
157
- set monPane to (split vertically with default profile)
158
- tell monPane
159
- write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-monitor.sh' '${PROJECT_ROOT}'"
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 down → Prompt History (bottom-left)
169
- set histPane to (split horizontally with default profile)
170
- tell histPane
171
- write text "cd '${PROJECT_ROOT}' && bash '${SCRIPT_DIR}/harness-prompt-history.sh' '${PROJECT_ROOT}'"
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 & Memory"
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
- PANE_DASHBOARD=$(tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_ROOT" -x 200 -y 50 -P -F '#{pane_id}' \
216
- "bash --norc --noprofile -c 'exec bash \"${SCRIPT_DIR}/harness-dashboard.sh\" \"${PROJECT_ROOT}\"'")
217
- PANE_MONITOR=$(tmux split-window -h -p 60 -t "$PANE_DASHBOARD" -c "$PROJECT_ROOT" -P -F '#{pane_id}' \
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 30 -t "$PANE_DASHBOARD" -c "$PROJECT_ROOT" -P -F '#{pane_id}' \
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 "$PANE_AGENT" "clear" Enter
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 "$PANE_DASHBOARD" -T "Dashboard"
226
- tmux select-pane -t "$PANE_MONITOR" -T "Monitor"
227
- tmux select-pane -t "$PANE_HISTORY" -T "Prompt History"
228
- tmux select-pane -t "$PANE_AGENT" -T "Agent Session"
229
- tmux select-pane -t "$PANE_AGENT"
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