@walwal-harness/cli 5.0.3 → 5.0.5

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
@@ -524,16 +524,39 @@ function installAgentTeamsEnv() {
524
524
  try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (e) {}
525
525
  }
526
526
 
527
- if (!settings.env) settings.env = {};
527
+ let changed = false;
528
528
 
529
+ // Enable Agent Teams env var
530
+ if (!settings.env) settings.env = {};
529
531
  if (settings.env['CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS'] !== '1') {
530
532
  settings.env['CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS'] = '1';
531
- ensureDir(path.dirname(settingsPath));
532
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
533
+ changed = true;
533
534
  log('Agent Teams enabled (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)');
534
535
  } else {
535
536
  log('Agent Teams already enabled');
536
537
  }
538
+
539
+ // Add git worktree permission for Team Mode isolation
540
+ if (!settings.permissions) settings.permissions = {};
541
+ if (!settings.permissions.allow) settings.permissions.allow = [];
542
+ const worktreePerms = [
543
+ 'Bash(git worktree *)',
544
+ 'Bash(git checkout *)',
545
+ 'Bash(git merge *)',
546
+ 'Bash(git branch *)'
547
+ ];
548
+ for (const perm of worktreePerms) {
549
+ if (!settings.permissions.allow.includes(perm)) {
550
+ settings.permissions.allow.push(perm);
551
+ changed = true;
552
+ }
553
+ }
554
+
555
+ if (changed) {
556
+ ensureDir(path.dirname(settingsPath));
557
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
558
+ log('Git worktree permissions added for Team Mode isolation');
559
+ }
537
560
  }
538
561
 
539
562
  function setupAgentsMd() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "5.0.3",
3
+ "version": "5.0.5",
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
- echo ""
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 for tmux layout
3
- # progress.log + audit.log에서 유저 프롬프트/에이전트 활동 히스토리를 표시
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
- AUDIT_LOG="$PROJECT_ROOT/.harness/actions/audit.log"
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}PROMPT HISTORY${RESET} ${DIM}$(date +%H:%M:%S)${RESET}"
34
+ echo -e "${BOLD}USER PROMPTS${RESET} ${DIM}$(date +%H:%M:%S)${RESET}"
30
35
  echo ""
31
36
  }
32
37
 
33
- render_progress_log() {
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}(no progress.log yet)${RESET}"
102
+ echo -e " ${DIM}(프롬프트 기록 없음)${RESET}"
36
103
  return
37
104
  fi
38
105
 
39
- grep -v '^#' "$PROGRESS_LOG" 2>/dev/null | grep -v '^$' | tail -20 | while IFS= read -r line; do
40
- local ts agent action detail
41
- ts=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$1); print $1}')
42
- agent=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$2); print $2}')
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
- local short_ts icon color
47
- short_ts=$(echo "$ts" | grep -oE '[0-9]{2}:[0-9]{2}:[0-9]{2}' || echo "$ts")
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
- render_audit_tail() {
74
- if [ ! -f "$AUDIT_LOG" ]; then return; fi
115
+ if [ -z "$prompts" ]; then
116
+ echo -e " ${DIM}(사용자 프롬프트 없음)${RESET}"
117
+ return
118
+ fi
75
119
 
76
- echo ""
77
- echo -e "${BOLD}AUDIT${RESET}"
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
- grep -v '^#' "$AUDIT_LOG" 2>/dev/null | grep -v '^$' | tail -10 | while IFS= read -r line; do
80
- local ts agent action status target
127
+ local ts detail
81
128
  ts=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$1); print $1}')
82
- agent=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$2); print $2}')
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}:[0-9]{2}' || echo "$ts")
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
- if [ ${#target} -gt 25 ]; then target="${target:0:23}.."; fi
142
+ # 처리 상태 찾기: 이 프롬프트 이후의 첫 번째 에이전트 액션
143
+ local processed_by=""
144
+ local prompt_ts_epoch
145
+ prompt_ts_epoch=$(echo "$ts" | sed 's/[^0-9:]//g')
100
146
 
101
- printf " %b%b%b %b%s%b %-10s %b%s%b\n" \
102
- "$color" "$icon" "$RESET" \
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
- render_progress_log
112
- render_audit_tail
157
+ render_processing_status
158
+ render_user_prompts
113
159
  }
114
160
 
115
161
  # ── Main loop ──