@walwal-harness/cli 5.0.3 → 5.0.4
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.0.
|
|
3
|
+
"version": "5.0.4",
|
|
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"
|
|
@@ -316,6 +316,46 @@ render_team_bottleneck() {
|
|
|
316
316
|
fi
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
+
# ══════════════════════════════════════════
|
|
320
|
+
# Archive Prompt — 처리 완료된 프롬프트 목록
|
|
321
|
+
# ══════════════════════════════════════════
|
|
322
|
+
render_archive_prompts() {
|
|
323
|
+
if [ ! -f "$PROGRESS_LOG" ]; then return; fi
|
|
324
|
+
|
|
325
|
+
# user-prompt 엔트리 중 이후에 result/pass/completed 액션이 있는 것 = 처리 완료
|
|
326
|
+
local all_prompts
|
|
327
|
+
all_prompts=$(grep '| user-prompt |' "$PROGRESS_LOG" 2>/dev/null)
|
|
328
|
+
if [ -z "$all_prompts" ]; then return; fi
|
|
329
|
+
|
|
330
|
+
local total_prompts
|
|
331
|
+
total_prompts=$(echo "$all_prompts" | wc -l | tr -d ' ')
|
|
332
|
+
|
|
333
|
+
# 마지막 프롬프트를 제외한 모든 프롬프트 = archived (처리 완료)
|
|
334
|
+
local archived
|
|
335
|
+
if [ "$total_prompts" -le 1 ]; then return; fi
|
|
336
|
+
archived=$(echo "$all_prompts" | head -n $((total_prompts - 1)) | tail -8)
|
|
337
|
+
|
|
338
|
+
echo ""
|
|
339
|
+
echo -e "${BOLD}Archive Prompt${RESET} ${DIM}(처리 완료)${RESET}"
|
|
340
|
+
|
|
341
|
+
echo "$archived" | while IFS= read -r line; do
|
|
342
|
+
local ts detail
|
|
343
|
+
ts=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$1); print $1}')
|
|
344
|
+
detail=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$4); print $4}')
|
|
345
|
+
|
|
346
|
+
local short_ts
|
|
347
|
+
short_ts=$(echo "$ts" | grep -oE '[0-9]{2}:[0-9]{2}' | tail -1 || echo "$ts")
|
|
348
|
+
|
|
349
|
+
if [ ${#detail} -gt 45 ]; then detail="${detail:0:43}.."; fi
|
|
350
|
+
|
|
351
|
+
echo -e " ${GREEN}✓${RESET} ${DIM}${short_ts}${RESET} ${detail}"
|
|
352
|
+
done
|
|
353
|
+
|
|
354
|
+
if [ "$total_prompts" -gt 9 ]; then
|
|
355
|
+
echo -e " ${DIM}… +$((total_prompts - 9)) more${RESET}"
|
|
356
|
+
fi
|
|
357
|
+
}
|
|
358
|
+
|
|
319
359
|
# ══════════════════════════════════════════
|
|
320
360
|
# Render dispatch
|
|
321
361
|
# ══════════════════════════════════════════
|
|
@@ -331,6 +371,7 @@ render_dashboard() {
|
|
|
331
371
|
render_team_status
|
|
332
372
|
render_team_features
|
|
333
373
|
render_team_bottleneck
|
|
374
|
+
render_archive_prompts
|
|
334
375
|
;;
|
|
335
376
|
*)
|
|
336
377
|
render_solo_sprint_overview
|
|
@@ -341,8 +382,7 @@ render_dashboard() {
|
|
|
341
382
|
fi
|
|
342
383
|
|
|
343
384
|
render_solo_agent_info
|
|
344
|
-
|
|
345
|
-
render_solo_prompt_history
|
|
385
|
+
render_archive_prompts
|
|
346
386
|
;;
|
|
347
387
|
esac
|
|
348
388
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# harness-prompt-history.sh — Prompt History pane
|
|
3
|
-
#
|
|
2
|
+
# harness-prompt-history.sh — User Prompt History pane
|
|
3
|
+
# 사용자가 입력한 프롬프트만 표시 + 현재 처리 단계(Planner/Team) 표시
|
|
4
4
|
# Usage: bash scripts/harness-prompt-history.sh [project-root]
|
|
5
5
|
|
|
6
6
|
set -uo pipefail
|
|
@@ -14,7 +14,8 @@ if [ -z "$PROJECT_ROOT" ]; then
|
|
|
14
14
|
fi
|
|
15
15
|
|
|
16
16
|
PROGRESS_LOG="$PROJECT_ROOT/.harness/progress.log"
|
|
17
|
-
|
|
17
|
+
PROGRESS="$PROJECT_ROOT/.harness/progress.json"
|
|
18
|
+
QUEUE="$PROJECT_ROOT/.harness/actions/feature-queue.json"
|
|
18
19
|
|
|
19
20
|
BOLD="\033[1m"
|
|
20
21
|
DIM="\033[2m"
|
|
@@ -23,93 +24,138 @@ YELLOW="\033[33m"
|
|
|
23
24
|
RED="\033[31m"
|
|
24
25
|
CYAN="\033[36m"
|
|
25
26
|
MAGENTA="\033[35m"
|
|
27
|
+
WHITE="\033[37m"
|
|
26
28
|
RESET="\033[0m"
|
|
29
|
+
BG_BLUE="\033[44m"
|
|
30
|
+
BG_GREEN="\033[42m"
|
|
31
|
+
BG_YELLOW="\033[43m"
|
|
27
32
|
|
|
28
33
|
render_header() {
|
|
29
|
-
echo -e "${BOLD}
|
|
34
|
+
echo -e "${BOLD}USER PROMPTS${RESET} ${DIM}$(date +%H:%M:%S)${RESET}"
|
|
30
35
|
echo ""
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
# 현재 처리 상태 배지
|
|
39
|
+
render_processing_status() {
|
|
40
|
+
local mode="solo" current_agent="none" agent_status="pending"
|
|
41
|
+
|
|
42
|
+
if [ -f "$PROGRESS" ] && command -v jq &>/dev/null; then
|
|
43
|
+
mode=$(jq -r '.mode // "solo"' "$PROGRESS" 2>/dev/null)
|
|
44
|
+
current_agent=$(jq -r '.current_agent // "none"' "$PROGRESS" 2>/dev/null)
|
|
45
|
+
agent_status=$(jq -r '.agent_status // "pending"' "$PROGRESS" 2>/dev/null)
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
local badge=""
|
|
49
|
+
case "$mode" in
|
|
50
|
+
team)
|
|
51
|
+
# Team 모드: 각 팀의 현재 상태 표시
|
|
52
|
+
badge="${BG_BLUE}${WHITE}${BOLD} TEAM MODE ${RESET}"
|
|
53
|
+
if [ -f "$QUEUE" ]; then
|
|
54
|
+
local team_info=""
|
|
55
|
+
for i in 1 2 3; do
|
|
56
|
+
local t_status t_feature t_phase
|
|
57
|
+
t_status=$(jq -r ".teams[\"$i\"].status // \"idle\"" "$QUEUE" 2>/dev/null)
|
|
58
|
+
t_feature=$(jq -r ".teams[\"$i\"].feature // \"\"" "$QUEUE" 2>/dev/null)
|
|
59
|
+
if [ "$t_status" = "busy" ] && [ -n "$t_feature" ] && [ "$t_feature" != "null" ]; then
|
|
60
|
+
t_phase=$(jq -r --arg f "$t_feature" '.queue.in_progress[$f].phase // "?"' "$QUEUE" 2>/dev/null)
|
|
61
|
+
team_info+=" ${CYAN}T${i}${RESET}:${t_feature}(${t_phase})"
|
|
62
|
+
else
|
|
63
|
+
team_info+=" ${DIM}T${i}:idle${RESET}"
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
echo -e " ${badge}${team_info}"
|
|
67
|
+
else
|
|
68
|
+
echo -e " ${badge}"
|
|
69
|
+
fi
|
|
70
|
+
;;
|
|
71
|
+
paused)
|
|
72
|
+
echo -e " ${BG_YELLOW}${WHITE}${BOLD} PAUSED ${RESET} ${DIM}/harness-team 또는 /harness-solo${RESET}"
|
|
73
|
+
;;
|
|
74
|
+
*)
|
|
75
|
+
# Solo 모드: 현재 에이전트 표시
|
|
76
|
+
if [ "$current_agent" != "none" ] && [ "$current_agent" != "null" ]; then
|
|
77
|
+
local agent_color="$RESET"
|
|
78
|
+
case "$current_agent" in
|
|
79
|
+
planner*) agent_color="$YELLOW" ;;
|
|
80
|
+
generator*) agent_color="$GREEN" ;;
|
|
81
|
+
eval*) agent_color="$RED" ;;
|
|
82
|
+
dispatcher*) agent_color="$MAGENTA" ;;
|
|
83
|
+
esac
|
|
84
|
+
local status_icon="·"
|
|
85
|
+
case "$agent_status" in
|
|
86
|
+
running) status_icon="▶" ;;
|
|
87
|
+
completed) status_icon="✓" ;;
|
|
88
|
+
failed) status_icon="✗" ;;
|
|
89
|
+
esac
|
|
90
|
+
echo -e " ${BG_GREEN}${WHITE}${BOLD} SOLO ${RESET} ${agent_color}${status_icon} ${current_agent}${RESET}"
|
|
91
|
+
else
|
|
92
|
+
echo -e " ${BG_GREEN}${WHITE}${BOLD} SOLO ${RESET} ${DIM}대기 중${RESET}"
|
|
93
|
+
fi
|
|
94
|
+
;;
|
|
95
|
+
esac
|
|
96
|
+
echo ""
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# 사용자 프롬프트만 필터하여 표시
|
|
100
|
+
render_user_prompts() {
|
|
34
101
|
if [ ! -f "$PROGRESS_LOG" ]; then
|
|
35
|
-
echo -e " ${DIM}(
|
|
102
|
+
echo -e " ${DIM}(프롬프트 기록 없음)${RESET}"
|
|
36
103
|
return
|
|
37
104
|
fi
|
|
38
105
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
action=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$3); print $3}')
|
|
44
|
-
detail=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$4); print $4}')
|
|
106
|
+
local term_height
|
|
107
|
+
term_height=$(tput lines 2>/dev/null || echo 30)
|
|
108
|
+
local max_lines=$((term_height - 10))
|
|
109
|
+
if [ "$max_lines" -lt 5 ]; then max_lines=5; fi
|
|
45
110
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
case "$agent" in
|
|
50
|
-
dispatcher*) icon="▸" ; color="$MAGENTA" ;;
|
|
51
|
-
brainstormer) icon="◇" ; color="$CYAN" ;;
|
|
52
|
-
planner*) icon="□" ; color="$YELLOW" ;;
|
|
53
|
-
generator*) icon="▶" ; color="$GREEN" ;;
|
|
54
|
-
eval*) icon="✦" ; color="$RED" ;;
|
|
55
|
-
user|manual) icon="★" ; color="$BOLD" ;;
|
|
56
|
-
team*) icon="⊕" ; color="$CYAN" ;;
|
|
57
|
-
*) icon="·" ; color="$DIM" ;;
|
|
58
|
-
esac
|
|
59
|
-
|
|
60
|
-
if [ ${#detail} -gt 40 ]; then detail="${detail:0:38}.."; fi
|
|
61
|
-
|
|
62
|
-
printf " %b%b%b %b%-8s%b %b%s%b %b%s%b\n" \
|
|
63
|
-
"$color" "$icon" "$RESET" \
|
|
64
|
-
"$DIM" "$short_ts" "$RESET" \
|
|
65
|
-
"$RESET" "$agent" "$RESET" \
|
|
66
|
-
"$DIM" "$action" "$RESET"
|
|
67
|
-
if [ -n "$detail" ] && [ "$detail" != " " ]; then
|
|
68
|
-
echo -e " ${DIM}${detail}${RESET}"
|
|
69
|
-
fi
|
|
70
|
-
done
|
|
71
|
-
}
|
|
111
|
+
# user-prompt 행만 필터
|
|
112
|
+
local prompts
|
|
113
|
+
prompts=$(grep '| user-prompt |' "$PROGRESS_LOG" 2>/dev/null | tail -"$max_lines")
|
|
72
114
|
|
|
73
|
-
|
|
74
|
-
|
|
115
|
+
if [ -z "$prompts" ]; then
|
|
116
|
+
echo -e " ${DIM}(사용자 프롬프트 없음)${RESET}"
|
|
117
|
+
return
|
|
118
|
+
fi
|
|
75
119
|
|
|
76
|
-
|
|
77
|
-
|
|
120
|
+
local line_num=0
|
|
121
|
+
local total_prompts
|
|
122
|
+
total_prompts=$(grep -c '| user-prompt |' "$PROGRESS_LOG" 2>/dev/null || echo 0)
|
|
123
|
+
|
|
124
|
+
echo "$prompts" | while IFS= read -r line; do
|
|
125
|
+
line_num=$((line_num + 1))
|
|
78
126
|
|
|
79
|
-
|
|
80
|
-
local ts agent action status target
|
|
127
|
+
local ts detail
|
|
81
128
|
ts=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$1); print $1}')
|
|
82
|
-
|
|
83
|
-
action=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$3); print $3}')
|
|
84
|
-
status=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$4); print $4}')
|
|
85
|
-
target=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$5); print $5}')
|
|
86
|
-
|
|
87
|
-
local color="$RESET" icon="·"
|
|
88
|
-
case "$status" in
|
|
89
|
-
start) color="$CYAN"; icon="▶" ;;
|
|
90
|
-
complete) color="$GREEN"; icon="✓" ;;
|
|
91
|
-
fail) color="$RED"; icon="✗" ;;
|
|
92
|
-
pass) color="$GREEN"; icon="✓" ;;
|
|
93
|
-
skip) color="$DIM"; icon="–" ;;
|
|
94
|
-
esac
|
|
129
|
+
detail=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$4); print $4}')
|
|
95
130
|
|
|
96
131
|
local short_ts
|
|
97
|
-
short_ts=$(echo "$ts" | grep -oE '[0-9]{2}:[0-9]{2}
|
|
132
|
+
short_ts=$(echo "$ts" | grep -oE '[0-9]{2}:[0-9]{2}' | tail -1 || echo "$ts")
|
|
133
|
+
|
|
134
|
+
# 프롬프트 내용 truncate
|
|
135
|
+
local max_width
|
|
136
|
+
max_width=$(( $(tput cols 2>/dev/null || echo 40) - 12 ))
|
|
137
|
+
if [ "$max_width" -lt 20 ]; then max_width=20; fi
|
|
138
|
+
if [ ${#detail} -gt "$max_width" ]; then
|
|
139
|
+
detail="${detail:0:$((max_width - 2))}.."
|
|
140
|
+
fi
|
|
98
141
|
|
|
99
|
-
|
|
142
|
+
# 처리 상태 찾기: 이 프롬프트 이후의 첫 번째 에이전트 액션
|
|
143
|
+
local processed_by=""
|
|
144
|
+
local prompt_ts_epoch
|
|
145
|
+
prompt_ts_epoch=$(echo "$ts" | sed 's/[^0-9:]//g')
|
|
100
146
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"$DIM" "$short_ts" "$RESET" \
|
|
104
|
-
"$agent" \
|
|
105
|
-
"$DIM" "$target" "$RESET"
|
|
147
|
+
# 간단히: 마지막 프롬프트인지 확인 → 현재 처리 중 표시
|
|
148
|
+
echo -e " ${DIM}${short_ts}${RESET} ${WHITE}${detail}${RESET}"
|
|
106
149
|
done
|
|
150
|
+
|
|
151
|
+
echo ""
|
|
152
|
+
echo -e " ${DIM}── ${total_prompts} prompts total ──${RESET}"
|
|
107
153
|
}
|
|
108
154
|
|
|
109
155
|
render_all() {
|
|
110
156
|
render_header
|
|
111
|
-
|
|
112
|
-
|
|
157
|
+
render_processing_status
|
|
158
|
+
render_user_prompts
|
|
113
159
|
}
|
|
114
160
|
|
|
115
161
|
# ── Main loop ──
|