@walwal-harness/cli 6.0.5 → 6.1.1

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/commands/harness-solo.md +20 -20
  3. package/commands/harness-team.md +1 -1
  4. package/gotchas/coo-developer.md +13 -0
  5. package/gotchas/documentationer.md +13 -0
  6. package/package.json +1 -1
  7. package/scripts/conductor-tick.sh +416 -0
  8. package/scripts/harness-archive.sh +123 -0
  9. package/scripts/harness-dashboard-up.sh +72 -0
  10. package/scripts/harness-dashboard.sh +509 -0
  11. package/scripts/harness-goal-init.sh +72 -0
  12. package/scripts/harness-goal-show.sh +37 -0
  13. package/scripts/harness-gotcha-memory.sh +348 -0
  14. package/scripts/harness-gotcha-register.sh +393 -0
  15. package/scripts/harness-meeting-doc.sh +153 -0
  16. package/scripts/harness-monitor.sh +398 -0
  17. package/scripts/harness-next.sh +577 -0
  18. package/scripts/harness-progress-set.sh +41 -0
  19. package/scripts/harness-prompt-history.sh +164 -0
  20. package/scripts/harness-queue-manager.sh +694 -0
  21. package/scripts/harness-session-start.sh +140 -0
  22. package/scripts/harness-statusline.sh +139 -0
  23. package/scripts/harness-task-session.sh +48 -0
  24. package/scripts/harness-tmux.sh +372 -0
  25. package/scripts/harness-user-prompt-submit.sh +123 -0
  26. package/scripts/init-agents-md.sh +337 -0
  27. package/scripts/init-ref-docs.sh +262 -0
  28. package/scripts/lib/harness-audit.sh +113 -0
  29. package/scripts/lib/harness-guardrail.sh +148 -0
  30. package/scripts/lib/harness-keywait.sh +57 -0
  31. package/scripts/lib/harness-render-progress.sh +346 -0
  32. package/scripts/scan-project.sh +367 -0
  33. package/skills/brainstorming/SKILL.md +4 -4
  34. package/skills/conductor/SKILL.md +19 -16
  35. package/skills/coo-developer/SKILL.md +42 -0
  36. package/skills/cqo/SKILL.md +7 -0
  37. package/skills/cto/SKILL.md +7 -0
  38. package/skills/dispatcher/SKILL.md +17 -28
  39. package/skills/dispatcher/persona-ceo.md +2 -1
  40. package/skills/documentationer/SKILL.md +46 -0
  41. package/skills/evaluator-code-quality/SKILL.md +1 -1
  42. package/skills/evaluator-functional/SKILL.md +1 -1
  43. package/skills/evaluator-visual/SKILL.md +1 -1
  44. package/skills/generator-backend/SKILL.md +1 -1
  45. package/skills/generator-frontend/SKILL.md +1 -1
  46. package/skills/meeting-manager/SKILL.md +34 -1
  47. package/skills/planner/SKILL.md +23 -9
  48. package/skills/planner/persona-coo-hr.md +17 -0
  49. package/skills/service-ops/SKILL.md +19 -4
@@ -0,0 +1,140 @@
1
+ #!/bin/bash
2
+ # harness-session-start.sh — SessionStart 훅
3
+ # 새 세션 시작 시 자동으로:
4
+ # 1) 이전 에이전트가 completed이면 harness-next.sh 실행 (게이트 + handoff)
5
+ # 2) Planner/Dispatcher 사이클이면 audit 리셋
6
+ # 3) 모드별 안내 출력
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
9
+ LIB="$SCRIPT_DIR/lib/harness-render-progress.sh"
10
+ AUDIT_LIB="$SCRIPT_DIR/lib/harness-audit.sh"
11
+
12
+ if [ ! -f "$LIB" ]; then exit 0; fi
13
+ source "$LIB"
14
+ [ -f "$AUDIT_LIB" ] && source "$AUDIT_LIB"
15
+ command -v jq &>/dev/null || exit 0
16
+
17
+ PROJECT_ROOT="$(resolve_harness_root "." 2>/dev/null)" || exit 0
18
+ PROGRESS="$PROJECT_ROOT/.harness/progress.json"
19
+ CONFIG="$PROJECT_ROOT/.harness/config.json"
20
+ HANDOFF="$PROJECT_ROOT/.harness/handoff.json"
21
+ [ -f "$PROGRESS" ] || exit 0
22
+
23
+ sprint_status=$(jq -r '.sprint.status // "init"' "$PROGRESS" 2>/dev/null)
24
+ sprint_num=$(jq -r '.sprint.number // 0' "$PROGRESS" 2>/dev/null)
25
+ current_agent=$(jq -r '.current_agent // "none"' "$PROGRESS" 2>/dev/null)
26
+ next_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
27
+ agent_status=$(jq -r '.agent_status // "pending"' "$PROGRESS" 2>/dev/null)
28
+ mode=$(jq -r '.mode // "team"' "$PROGRESS" 2>/dev/null)
29
+ conductor_state=$(jq -r '.conductor.state // "idle"' "$PROGRESS" 2>/dev/null)
30
+
31
+ # ─────────────────────────────────────────
32
+ # Auto-heal mode drift — Team 상태 유실 복구
33
+ # feature-queue.json 에 활성 작업(in_progress)이 있는데 mode 가 solo/paused 면
34
+ # 누군가 progress.json 을 통째로 덮어써서 team_state 를 날린 것. mode=team 으로
35
+ # 자동 복원하고 경고 로그 남김.
36
+ # ─────────────────────────────────────────
37
+ FEATURE_QUEUE_HEAL="$PROJECT_ROOT/.harness/actions/feature-queue.json"
38
+ if [ -f "$FEATURE_QUEUE_HEAL" ] && [ "$mode" != "team" ]; then
39
+ active_count=$(jq -r '(.queue.in_progress | length) // 0' "$FEATURE_QUEUE_HEAL" 2>/dev/null || echo 0)
40
+ if [ "${active_count:-0}" -gt 0 ]; then
41
+ heal_teams=$active_count
42
+ [ "$heal_teams" -gt 3 ] && heal_teams=3
43
+ bash "$SCRIPT_DIR/harness-progress-set.sh" "$PROJECT_ROOT" \
44
+ ".mode = \"team\" | .team_state.active_teams = ${heal_teams} | .team_state.paused_at = null" \
45
+ 2>/dev/null
46
+ mode="team"
47
+ echo "# Harness: mode auto-healed to 'team' (feature-queue has ${active_count} active, but mode was drifted)" >&2
48
+ if [ -f "$PROJECT_ROOT/.harness/progress.log" ]; then
49
+ echo "$(date +'%Y-%m-%d %H:%M') | system | heal | mode | reset solo→team (queue had ${active_count} in_progress)" >> "$PROJECT_ROOT/.harness/progress.log"
50
+ fi
51
+ fi
52
+ fi
53
+
54
+ # ─────────────────────────────────────────
55
+ # Team Mode — 팀이 자율 실행 중이면 오케스트레이터 안내
56
+ # ─────────────────────────────────────────
57
+ if [ "$mode" = "team" ]; then
58
+ FEATURE_QUEUE="$PROJECT_ROOT/.harness/actions/feature-queue.json"
59
+ passed=0; total=0; in_prog=0; failed=0
60
+ if [ -f "$FEATURE_QUEUE" ]; then
61
+ passed=$(jq '.queue.passed | length' "$FEATURE_QUEUE" 2>/dev/null || echo 0)
62
+ total=$(jq '[.queue.ready, (.queue.blocked | keys), (.queue.in_progress | keys), .queue.passed, .queue.failed] | flatten | length' "$FEATURE_QUEUE" 2>/dev/null || echo 0)
63
+ in_prog=$(jq '.queue.in_progress | length' "$FEATURE_QUEUE" 2>/dev/null || echo 0)
64
+ failed=$(jq '.queue.failed | length' "$FEATURE_QUEUE" 2>/dev/null || echo 0)
65
+ fi
66
+
67
+ echo "# Harness Team Mode active"
68
+ echo "# Queue: ${passed}/${total} passed, ${in_prog} in progress, ${failed} failed"
69
+ echo "# Worker pool runs autonomously (Gen-Eval loop, max 5 retries). Control-plane Cxx agents are outside this limit."
70
+ echo "# Stop: /harness-stop | Emergency fallback: /harness-solo"
71
+ exit 0
72
+ fi
73
+
74
+ # ─────────────────────────────────────────
75
+ # Paused Mode — 중단 상태 안내
76
+ # ─────────────────────────────────────────
77
+ if [ "$mode" = "paused" ]; then
78
+ echo "# Harness paused — resume with /harness-team"
79
+ exit 0
80
+ fi
81
+
82
+ # ─────────────────────────────────────────
83
+ # init 상태: 첫 안내
84
+ # ─────────────────────────────────────────
85
+ if [ "$sprint_status" = "init" ]; then
86
+ echo "# Harness ready — say \"하네스 엔지니어링 시작\" or /harness-dispatcher"
87
+ echo "# 기본 경로는 회사 루프입니다: dispatch -> CEO meeting -> COO/CTO 분배 -> gen/eval -> CQO -> service-ops -> batch meeting."
88
+ exit 0
89
+ fi
90
+
91
+ # ─────────────────────────────────────────
92
+ # Audit lifecycle: Planner/Dispatcher 시작 시 리셋
93
+ # ─────────────────────────────────────────
94
+ init_audit "$PROJECT_ROOT"
95
+ if [ "$next_agent" = "planner" ] || [ "$next_agent" = "dispatcher" ]; then
96
+ # 새 사이클 — 이전 audit을 archive로 이동하고 새로 시작
97
+ reset_audit "$PROJECT_ROOT" "$sprint_num"
98
+ audit_log "system" "cycle" "start" "sprint-${sprint_num}" "new plan/dispatch cycle"
99
+ fi
100
+
101
+ # ─────────────────────────────────────────
102
+ # 이전 에이전트가 completed/failed → 자동 전환
103
+ # ─────────────────────────────────────────
104
+ if [ "$agent_status" = "completed" ] || [ "$agent_status" = "failed" ]; then
105
+ bash "$SCRIPT_DIR/harness-next.sh" "$PROJECT_ROOT" 2>/dev/null
106
+
107
+ next_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
108
+ agent_status=$(jq -r '.agent_status // "pending"' "$PROGRESS" 2>/dev/null)
109
+ fi
110
+
111
+ # ─────────────────────────────────────────
112
+ # Conductor running/queued → refresh routing once on session start
113
+ # ─────────────────────────────────────────
114
+ if [ "$conductor_state" = "running" ] || [ "$next_agent" = "conductor" ]; then
115
+ if [ -x "$SCRIPT_DIR/conductor-tick.sh" ]; then
116
+ bash "$SCRIPT_DIR/conductor-tick.sh" "$PROJECT_ROOT" >/dev/null 2>&1 || true
117
+ next_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
118
+ fi
119
+ fi
120
+
121
+ # ─────────────────────────────────────────
122
+ # 상태별 안내 출력
123
+ # ─────────────────────────────────────────
124
+ if [ "$agent_status" = "blocked" ]; then
125
+ echo "# Harness BLOCKED — retry limit reached, user intervention required"
126
+
127
+ elif [ -f "$HANDOFF" ] && [ "$next_agent" != "none" ] && [ "$next_agent" != "null" ]; then
128
+ handoff_model=$(jq -r '.model // "opus"' "$HANDOFF" 2>/dev/null)
129
+ handoff_thinking=$(jq -r '.thinking_mode // empty' "$HANDOFF" 2>/dev/null)
130
+
131
+ mode_str=""
132
+ if [ -n "$handoff_thinking" ] && [ "$handoff_thinking" != "null" ]; then
133
+ mode_str=" /${handoff_thinking}"
134
+ fi
135
+
136
+ echo "# Harness: next → /harness-${next_agent} (${handoff_model}${mode_str})"
137
+
138
+ elif [ "$current_agent" != "none" ] && [ "$current_agent" != "null" ]; then
139
+ echo "# Harness: ${current_agent} [${agent_status}]"
140
+ fi
@@ -0,0 +1,139 @@
1
+ #!/bin/bash
2
+ # harness-statusline.sh — Claude Code statusline hook (v5 unified)
3
+ # 터미널 하단에 항상 고정되는 1줄 compact 상태 표시.
4
+ # Solo: [S1] FULL | solo | >backend | sonnet | 2/5 feat | ctx 45% | $1.23
5
+ # Team: [S1] FULL | team | T1:gen T2:eval T3:idle | 2/5 feat | ctx 45% | $1.23
6
+
7
+ # Read Claude Code session data from stdin
8
+ input=$(cat)
9
+
10
+ # Extract Claude Code built-in data
11
+ context_pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0' 2>/dev/null | cut -d. -f1)
12
+ cost=$(echo "$input" | jq -r '.cost.total_cost_usd // 0' 2>/dev/null)
13
+
14
+ # Resolve project root (walk up from cwd)
15
+ CWD=$(echo "$input" | jq -r '.workspace.current_dir // empty' 2>/dev/null)
16
+ if [ -z "$CWD" ]; then CWD="$PWD"; fi
17
+
18
+ PROJECT_ROOT="$CWD"
19
+ while [ "$PROJECT_ROOT" != "/" ]; do
20
+ if [ -d "$PROJECT_ROOT/.harness" ]; then break; fi
21
+ PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
22
+ done
23
+
24
+ PROGRESS="$PROJECT_ROOT/.harness/progress.json"
25
+ FEATURE_LIST="$PROJECT_ROOT/.harness/actions/feature-list.json"
26
+ PIPELINE_JSON="$PROJECT_ROOT/.harness/actions/pipeline.json"
27
+
28
+ # No harness → minimal status
29
+ if [ ! -f "$PROGRESS" ]; then
30
+ echo "harness: not initialized | ctx ${context_pct}%"
31
+ exit 0
32
+ fi
33
+
34
+ # Read harness state
35
+ sprint_num=$(jq -r '.sprint.number // 0' "$PROGRESS" 2>/dev/null)
36
+ sprint_status=$(jq -r '.sprint.status // "init"' "$PROGRESS" 2>/dev/null)
37
+ pipeline=$(jq -r '.pipeline // "?"' "$PROGRESS" 2>/dev/null)
38
+ current_agent=$(jq -r '.current_agent // "none"' "$PROGRESS" 2>/dev/null)
39
+ agent_status=$(jq -r '.agent_status // "pending"' "$PROGRESS" 2>/dev/null)
40
+ next_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
41
+ retry_count=$(jq -r '.sprint.retry_count // 0' "$PROGRESS" 2>/dev/null)
42
+ harness_mode=$(jq -r '.mode // "solo"' "$PROGRESS" 2>/dev/null)
43
+
44
+ # Pipeline short name
45
+ case "$pipeline" in
46
+ FULLSTACK) pl="FULL" ;;
47
+ FE-ONLY) pl="FE" ;;
48
+ BE-ONLY) pl="BE" ;;
49
+ null|"?") pl="?" ;;
50
+ *) pl="$pipeline" ;;
51
+ esac
52
+
53
+ # Agent short name (strip harness prefix)
54
+ agent_short="${current_agent#generator-}"
55
+ agent_short="${agent_short#evaluator-}"
56
+ if [ "$current_agent" = "none" ] || [ "$current_agent" = "null" ]; then
57
+ agent_short="$next_agent"
58
+ if [ "$agent_short" = "none" ] || [ "$agent_short" = "null" ]; then
59
+ agent_short="idle"
60
+ fi
61
+ fi
62
+
63
+ # Feature progress
64
+ total_features=0
65
+ completed_features=0
66
+ if [ -f "$FEATURE_LIST" ]; then
67
+ total_features=$(jq '.features | length' "$FEATURE_LIST" 2>/dev/null || echo 0)
68
+ completed_features=$(jq '[.features[]? | select(
69
+ (.passes // []) | (
70
+ (map(select(. == "evaluator-code-quality")) | length > 0) and
71
+ (map(select(. == "evaluator-functional")) | length > 0) and
72
+ (map(select(. == "evaluator-visual")) | length > 0)
73
+ )
74
+ )] | length' "$FEATURE_LIST" 2>/dev/null || echo 0)
75
+ fi
76
+
77
+ # Status indicator
78
+ status_icon=""
79
+ case "$agent_status" in
80
+ running) status_icon=">" ;;
81
+ completed) status_icon="v" ;;
82
+ failed) status_icon="x" ;;
83
+ blocked) status_icon="!" ;;
84
+ *) status_icon="-" ;;
85
+ esac
86
+
87
+ # Retry indicator
88
+ retry_str=""
89
+ if [ "$retry_count" -gt 0 ]; then
90
+ retry_str=" R${retry_count}"
91
+ fi
92
+
93
+ # Model/mode for current or next agent
94
+ CONFIG="$PROJECT_ROOT/.harness/config.json"
95
+ active_agent="$current_agent"
96
+ if [ "$active_agent" = "none" ] || [ "$active_agent" = "null" ]; then
97
+ active_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
98
+ fi
99
+ model_short=""
100
+ if [ -f "$CONFIG" ] && [ "$active_agent" != "none" ] && [ "$active_agent" != "null" ]; then
101
+ am=$(jq -r ".agents[\"${active_agent}\"].model // empty" "$CONFIG" 2>/dev/null)
102
+ at=$(jq -r ".agents[\"${active_agent}\"].thinking_mode // empty" "$CONFIG" 2>/dev/null)
103
+ if [ -n "$am" ]; then
104
+ model_short="${am}"
105
+ if [ -n "$at" ] && [ "$at" != "null" ]; then
106
+ model_short+="/${at}"
107
+ fi
108
+ fi
109
+ fi
110
+
111
+ # Build compact status line based on mode
112
+ FEATURE_QUEUE="$PROJECT_ROOT/.harness/actions/feature-queue.json"
113
+
114
+ if [ "$harness_mode" = "team" ] && [ -f "$FEATURE_QUEUE" ]; then
115
+ # Team mode: show team status instead of single agent
116
+ team_info=""
117
+ for i in 1 2 3; do
118
+ t_status=$(jq -r ".teams[\"$i\"].status // \"idle\"" "$FEATURE_QUEUE" 2>/dev/null)
119
+ t_feature=$(jq -r ".teams[\"$i\"].feature // \"\"" "$FEATURE_QUEUE" 2>/dev/null)
120
+ if [ "$t_status" = "busy" ] && [ -n "$t_feature" ] && [ "$t_feature" != "null" ]; then
121
+ t_phase=$(jq -r --arg f "$t_feature" '.queue.in_progress[$f].phase // "?"' "$FEATURE_QUEUE" 2>/dev/null)
122
+ team_info+="T${i}:${t_phase} "
123
+ else
124
+ team_info+="T${i}:- "
125
+ fi
126
+ done
127
+ t_passed=$(jq '.queue.passed | length' "$FEATURE_QUEUE" 2>/dev/null || echo 0)
128
+ t_total=$(jq '[.queue.ready, (.queue.blocked | keys), (.queue.in_progress | keys), .queue.passed, .queue.failed] | flatten | length' "$FEATURE_QUEUE" 2>/dev/null || echo 0)
129
+
130
+ echo "[S${sprint_num}] ${pl} | team | ${team_info}| ${t_passed}/${t_total} feat | ctx ${context_pct}% | \$${cost}"
131
+ else
132
+ # Solo/paused mode: show single agent status
133
+ mode_tag="${harness_mode}"
134
+ if [ -n "$model_short" ]; then
135
+ echo "[S${sprint_num}] ${pl} | ${mode_tag} | ${status_icon}${agent_short}${retry_str} | ${model_short} | ${completed_features}/${total_features} feat | ctx ${context_pct}% | \$${cost}"
136
+ else
137
+ echo "[S${sprint_num}] ${pl} | ${mode_tag} | ${status_icon}${agent_short}${retry_str} | ${completed_features}/${total_features} feat | ctx ${context_pct}% | \$${cost}"
138
+ fi
139
+ fi
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # harness-task-session.sh — create per-agent task session document
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ source "$SCRIPT_DIR/lib/harness-render-progress.sh"
7
+
8
+ PROJECT_ROOT="$(resolve_harness_root "${1:-.}")" || exit 1
9
+ AGENT="${2:-}"
10
+ SOURCE="${3:-}"
11
+
12
+ [ -n "$AGENT" ] || exit 2
13
+ command -v jq >/dev/null 2>&1 || exit 1
14
+
15
+ PROGRESS="$PROJECT_ROOT/.harness/progress.json"
16
+ TASK_ROOT="$PROJECT_ROOT/.harness/actions/task-sessions/$AGENT"
17
+ mkdir -p "$TASK_ROOT"
18
+
19
+ dispatch_id=$(jq -r '.dispatch.id // "D-000"' "$PROGRESS")
20
+ sprint_num=$(jq -r '.sprint.number // 0' "$PROGRESS")
21
+ ts=$(date -u +%Y%m%dT%H%M%SZ)
22
+ session_id="${AGENT}-S$(printf '%03d' "$sprint_num")-${ts}"
23
+ session_path="$TASK_ROOT/${session_id}.md"
24
+
25
+ cat > "$session_path" <<EOF
26
+ # Task Session — $session_id
27
+
28
+ - agent: $AGENT
29
+ - dispatch: $dispatch_id
30
+ - sprint: $sprint_num
31
+ - source: ${SOURCE:-none}
32
+ - created_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
33
+
34
+ ## Allowed Inputs
35
+ - .harness/handoff.json
36
+ - .harness/progress.json
37
+ - assigned evidence documents only
38
+
39
+ ## Rule
40
+ - 이전 대화 기억이 아니라 문서와 evidence만 근거로 판단할 것
41
+ - 사실과 추론을 분리해서 기록할 것
42
+ EOF
43
+
44
+ bash "$SCRIPT_DIR/harness-progress-set.sh" "$PROJECT_ROOT" \
45
+ ".task_sessions.current = {\"agent\":\"$AGENT\",\"id\":\"$session_id\",\"path\":\"${session_path#$PROJECT_ROOT/}\",\"source\":$(jq -Rn --arg v "${SOURCE:-}" '$v')} |
46
+ .task_sessions.history = ((.task_sessions.history // []) + [{\"agent\":\"$AGENT\",\"id\":\"$session_id\",\"path\":\"${session_path#$PROJECT_ROOT/}\",\"source\":$(jq -Rn --arg v "${SOURCE:-}" '$v')}])" >/dev/null
47
+
48
+ echo "${session_path#$PROJECT_ROOT/}"