@walwal-harness/cli 3.2.1 → 3.3.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.
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
├── config.json # 하네스 설정
|
|
13
13
|
├── progress.json # 기계 판독 상태 (세션 오케스트레이션)
|
|
14
14
|
├── progress.log # 사람 판독 히스토리 (append-only)
|
|
15
|
-
├──
|
|
15
|
+
├── handoff.json # 세션 전환 문서 (prompt, model, artifacts, regression 등)
|
|
16
16
|
├── actions/ # 현재 활성 문서
|
|
17
17
|
│ ├── pipeline.json # Dispatcher 결정 (어떤 파이프라인인지)
|
|
18
18
|
│ ├── plan.md # 제품 사양
|
|
@@ -143,7 +143,7 @@ pending → draft → reviewed → approved
|
|
|
143
143
|
|------|------|
|
|
144
144
|
| `.harness/progress.json` | 기계 판독 상태 (현재 에이전트, 파이프라인, 실패 정보) |
|
|
145
145
|
| `.harness/progress.log` | 사람 판독 히스토리 (append-only) |
|
|
146
|
-
| `.harness/
|
|
146
|
+
| `.harness/handoff.json` | 세션 전환 문서 (prompt, model, thinking_mode, artifacts, regression) |
|
|
147
147
|
|
|
148
148
|
### 실행 방법
|
|
149
149
|
|
|
@@ -164,7 +164,7 @@ Feature-level 프로그래스를 출력하고 다음 에이전트를 안내합
|
|
|
164
164
|
/harness-generator-backend
|
|
165
165
|
|
|
166
166
|
# 방법 B: claude CLI 자동 실행
|
|
167
|
-
claude --
|
|
167
|
+
claude --model $(jq -r .model .harness/handoff.json) --prompt "$(jq -r .prompt .harness/handoff.json)"
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
#### 4. SessionStart 훅 (자동)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": {
|
|
3
3
|
"name": "6-Agent Production Harness",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.3.0",
|
|
5
5
|
"description": "Dispatcher + NestJS MSA + React/Next.js + Playwright 기반 실무 하네스",
|
|
6
6
|
"source": "https://www.anthropic.com/engineering/harness-design-long-running-apps"
|
|
7
7
|
},
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"role": "사용자 요청 분석 → 파이프라인 결정 (FE-ONLY / BE-ONLY / FULLSTACK)",
|
|
11
11
|
"skill": "harness-dispatcher",
|
|
12
12
|
"outputs": ["actions/pipeline.json"],
|
|
13
|
-
"always_first": true
|
|
13
|
+
"always_first": true,
|
|
14
|
+
"model": "opus",
|
|
15
|
+
"thinking_mode": null
|
|
14
16
|
},
|
|
15
17
|
"brainstorming": {
|
|
16
18
|
"role": "사용자의 러프한 요구사항을 대화형으로 구체화하여 Planner가 바로 쓸 수 있는 brainstorm-spec.md로 변환.",
|
|
@@ -33,6 +35,9 @@
|
|
|
33
35
|
},
|
|
34
36
|
"invoked_by": "dispatcher (user opt-in after suggestion)",
|
|
35
37
|
"next_on_complete": "planner",
|
|
38
|
+
"model": "opus",
|
|
39
|
+
"thinking_mode": "plan",
|
|
40
|
+
"thinking_mode_description": "Claude Code plan 모드로 실행. 구조화된 계획 수립 후 실행.",
|
|
36
41
|
"attribution": "Derived from obra/superpowers skills/brainstorming (MIT License)"
|
|
37
42
|
},
|
|
38
43
|
"planner": {
|
|
@@ -43,21 +48,30 @@
|
|
|
43
48
|
"actions/plan.md",
|
|
44
49
|
"actions/feature-list.json",
|
|
45
50
|
"actions/api-contract.json"
|
|
46
|
-
]
|
|
51
|
+
],
|
|
52
|
+
"model": "opus",
|
|
53
|
+
"thinking_mode": "ultraplan",
|
|
54
|
+
"thinking_mode_description": "최고 수준의 계획 모드. 아키텍처 결정, API 설계, 서비스 분할에 깊은 사고 필요."
|
|
47
55
|
},
|
|
48
56
|
"generator-backend": {
|
|
49
57
|
"role": "NestJS MSA 서비스 구현, API 엔드포인트, DB 스키마",
|
|
50
58
|
"skill": "harness-generator-backend",
|
|
51
59
|
"inputs": ["actions/plan.md", "actions/feature-list.json", "actions/api-contract.json", "actions/sprint-contract.md"],
|
|
52
60
|
"outputs": ["code:backend", "actions/sprint-contract.md"],
|
|
53
|
-
"order": 1
|
|
61
|
+
"order": 1,
|
|
62
|
+
"model": "sonnet",
|
|
63
|
+
"thinking_mode": null,
|
|
64
|
+
"model_rationale": "코드 생성은 Sonnet이 비용 대비 효율적. 계획은 Planner가 이미 완료."
|
|
54
65
|
},
|
|
55
66
|
"generator-frontend": {
|
|
56
67
|
"role": "React/Next.js UI 컴포넌트, 상태관리, API 연동",
|
|
57
68
|
"skill": "harness-generator-frontend",
|
|
58
69
|
"inputs": ["actions/plan.md", "actions/feature-list.json", "actions/api-contract.json", "actions/sprint-contract.md"],
|
|
59
70
|
"outputs": ["code:frontend", "actions/sprint-contract.md"],
|
|
60
|
-
"order": 2
|
|
71
|
+
"order": 2,
|
|
72
|
+
"model": "sonnet",
|
|
73
|
+
"thinking_mode": null,
|
|
74
|
+
"model_rationale": "코드 생성은 Sonnet이 비용 대비 효율적. 계획은 Planner가 이미 완료."
|
|
61
75
|
},
|
|
62
76
|
"evaluator-functional": {
|
|
63
77
|
"role": "Playwright로 E2E 기능 검증, API 응답/DB 상태 확인",
|
|
@@ -65,6 +79,9 @@
|
|
|
65
79
|
"tools": ["playwright:browser_*"],
|
|
66
80
|
"inputs": ["actions/sprint-contract.md", "actions/feature-list.json", "actions/api-contract.json"],
|
|
67
81
|
"outputs": ["actions/evaluation-functional.md"],
|
|
82
|
+
"model": "opus",
|
|
83
|
+
"thinking_mode": "ultrathink",
|
|
84
|
+
"thinking_mode_description": "최고 수준의 사고 모드. 적대적 검증에 깊은 추론이 필요. 각 항목을 비판적으로 분석.",
|
|
68
85
|
"evaluation_template": "assets/templates/evaluation-functional.md.template",
|
|
69
86
|
"adversarial_rules": {
|
|
70
87
|
"comment": "Evaluator 적대적 행동 규칙 — 통과 편향 제거를 위한 강제 규칙",
|
|
@@ -92,6 +109,9 @@
|
|
|
92
109
|
"tools": ["playwright:browser_take_screenshot", "playwright:browser_resize", "playwright:browser_snapshot"],
|
|
93
110
|
"inputs": ["actions/sprint-contract.md", "actions/evaluation-functional.md", "actions/feature-list.json"],
|
|
94
111
|
"outputs": ["actions/evaluation-visual.md"],
|
|
112
|
+
"model": "opus",
|
|
113
|
+
"thinking_mode": "ultrathink",
|
|
114
|
+
"thinking_mode_description": "최고 수준의 사고 모드. 시각적 결함, 접근성, AI슬롭을 비판적으로 탐지.",
|
|
95
115
|
"evaluation_template": "assets/templates/evaluation-visual.md.template",
|
|
96
116
|
"adversarial_rules": {
|
|
97
117
|
"comment": "Visual Evaluator 적대적 행동 규칙",
|
|
@@ -119,7 +139,9 @@
|
|
|
119
139
|
"inputs": ["actions/plan.md", "actions/feature-list.json", "actions/api-contract.json", "actions/sprint-contract.md"],
|
|
120
140
|
"outputs": ["code:flutter", "actions/sprint-contract.md"],
|
|
121
141
|
"order": 2,
|
|
122
|
-
"fe_stack": "flutter"
|
|
142
|
+
"fe_stack": "flutter",
|
|
143
|
+
"model": "sonnet",
|
|
144
|
+
"thinking_mode": null
|
|
123
145
|
},
|
|
124
146
|
"evaluator-functional-flutter": {
|
|
125
147
|
"role": "Flutter 앱 검증 — flutter analyze, flutter test, build_runner 일관성, 안티패턴 정적 검증",
|
|
@@ -127,7 +149,9 @@
|
|
|
127
149
|
"tools": ["bash:flutter", "bash:dart"],
|
|
128
150
|
"inputs": ["actions/sprint-contract.md"],
|
|
129
151
|
"outputs": ["actions/evaluation-functional.md"],
|
|
130
|
-
"fe_stack": "flutter"
|
|
152
|
+
"fe_stack": "flutter",
|
|
153
|
+
"model": "opus",
|
|
154
|
+
"thinking_mode": "ultrathink"
|
|
131
155
|
}
|
|
132
156
|
},
|
|
133
157
|
"flow": {
|
|
@@ -288,7 +312,6 @@
|
|
|
288
312
|
"isolation": true,
|
|
289
313
|
"state_file": ".harness/progress.json",
|
|
290
314
|
"state_log": ".harness/progress.log",
|
|
291
|
-
"next_prompt_file": ".harness/next-prompt.txt",
|
|
292
315
|
"handoff_file": ".harness/handoff.json",
|
|
293
316
|
"context_guard": {
|
|
294
317
|
"comment": "컨텍스트 분리 하드 가드레일. UserPromptSubmit 훅이 위반을 감지하면 경고를 주입한다.",
|
package/bin/init.js
CHANGED
|
@@ -155,10 +155,10 @@ function scaffoldHarness() {
|
|
|
155
155
|
fs.writeFileSync(progressLog, `# Harness Progress Log\n# ${date} — Initialized\n`);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
// Create
|
|
159
|
-
const
|
|
160
|
-
if (!fileExists(
|
|
161
|
-
fs.writeFileSync(
|
|
158
|
+
// Create handoff.json placeholder
|
|
159
|
+
const handoff = path.join(HARNESS_DIR, 'handoff.json');
|
|
160
|
+
if (!fileExists(handoff) || isForce) {
|
|
161
|
+
fs.writeFileSync(handoff, '{}');
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
log('.harness/ scaffolding complete');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "Production harness for AI agent engineering — Planner, Generator(BE/FE), Evaluator(Func/Visual), optional Brainstormer (requirements refinement). Supports React and Flutter FE stacks.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|
|
@@ -36,6 +36,6 @@
|
|
|
36
36
|
"gotchas/"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@walwal-harness/cli": "^3.
|
|
39
|
+
"@walwal-harness/cli": "^3.3.0"
|
|
40
40
|
}
|
|
41
41
|
}
|
package/scripts/harness-next.sh
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# harness-next.sh — 세션 오케스트레이터
|
|
3
3
|
# 현재 progress.json 상태를 읽고 다음 에이전트를 결정한다.
|
|
4
|
-
# Feature-level 프로그래스를 출력하고
|
|
4
|
+
# Feature-level 프로그래스를 출력하고 handoff.json을 생성한다.
|
|
5
5
|
set -e
|
|
6
6
|
|
|
7
7
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
@@ -20,7 +20,7 @@ PROJECT_ROOT="$(resolve_harness_root "${1:-.}")" || {
|
|
|
20
20
|
PROGRESS="$PROJECT_ROOT/.harness/progress.json"
|
|
21
21
|
CONFIG="$PROJECT_ROOT/.harness/config.json"
|
|
22
22
|
PIPELINE_JSON="$PROJECT_ROOT/.harness/actions/pipeline.json"
|
|
23
|
-
|
|
23
|
+
HANDOFF="$PROJECT_ROOT/.harness/handoff.json"
|
|
24
24
|
|
|
25
25
|
check_jq || exit 1
|
|
26
26
|
|
|
@@ -296,7 +296,7 @@ render_agent_bar "$PROJECT_ROOT"
|
|
|
296
296
|
echo ""
|
|
297
297
|
|
|
298
298
|
# ─────────────────────────────────────────
|
|
299
|
-
# Generate
|
|
299
|
+
# Generate handoff.json (unified session transition document)
|
|
300
300
|
# ─────────────────────────────────────────
|
|
301
301
|
if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_status" != "blocked" ]; then
|
|
302
302
|
# ── Escalation check: 3회 실패 시 Planner에게 scope 축소 요청 ──
|
|
@@ -304,14 +304,17 @@ if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_st
|
|
|
304
304
|
if [ "$retry_count" -ge "$escalate_after" ] && [ "$sprint_status" = "failed" ] && [ "$next_agent" != "planner" ]; then
|
|
305
305
|
echo " ⚠ Escalation: ${retry_count}회 실패 — Planner에게 scope 축소/접근 변경 요청"
|
|
306
306
|
next_agent="planner"
|
|
307
|
-
# progress.json에 에스컬레이션 기록
|
|
308
307
|
jq --arg msg "Escalated after ${retry_count} failures. Planner must review scope or approach." \
|
|
309
308
|
'.next_agent = "planner" |
|
|
310
309
|
.failure.message = $msg |
|
|
311
310
|
.failure.retry_target = "planner"' "$PROGRESS" > "${PROGRESS}.tmp" && mv "${PROGRESS}.tmp" "$PROGRESS"
|
|
312
311
|
fi
|
|
313
312
|
|
|
314
|
-
#
|
|
313
|
+
# ── Read model & thinking mode for next agent ──
|
|
314
|
+
agent_model=$(jq -r ".agents[\"${next_agent}\"].model // \"opus\"" "$CONFIG" 2>/dev/null || echo "opus")
|
|
315
|
+
agent_thinking=$(jq -r ".agents[\"${next_agent}\"].thinking_mode // \"null\"" "$CONFIG" 2>/dev/null || echo "null")
|
|
316
|
+
|
|
317
|
+
# ── Build prompt text (embedded in handoff.json) ──
|
|
315
318
|
prompt="/harness-${next_agent} 를 실행하세요."
|
|
316
319
|
|
|
317
320
|
if [ "$sprint_num" -gt 0 ]; then
|
|
@@ -322,22 +325,33 @@ if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_st
|
|
|
322
325
|
prompt+="을 진행합니다."
|
|
323
326
|
fi
|
|
324
327
|
|
|
325
|
-
prompt+=$'\n'".harness/
|
|
328
|
+
prompt+=$'\n'".harness/handoff.json을 읽고 컨텍스트를 확인하세요."
|
|
329
|
+
|
|
330
|
+
# Inject thinking mode instruction
|
|
331
|
+
if [ "$agent_thinking" != "null" ]; then
|
|
332
|
+
case "$agent_thinking" in
|
|
333
|
+
ultraplan)
|
|
334
|
+
prompt+=$'\n\n'"[Thinking Mode: ultraplan] /${agent_thinking} 모드를 사용하세요. 깊은 사고로 아키텍처와 설계를 수행합니다."
|
|
335
|
+
;;
|
|
336
|
+
ultrathink)
|
|
337
|
+
prompt+=$'\n\n'"[Thinking Mode: ultrathink] /${agent_thinking} 모드를 사용하세요. 최대 추론 깊이로 비판적 검증을 수행합니다."
|
|
338
|
+
;;
|
|
339
|
+
plan)
|
|
340
|
+
prompt+=$'\n\n'"[Thinking Mode: plan] /${agent_thinking} 모드를 사용하세요. 구조화된 계획을 수립한 후 실행합니다."
|
|
341
|
+
;;
|
|
342
|
+
esac
|
|
343
|
+
fi
|
|
326
344
|
|
|
327
|
-
# Add failure context if retrying
|
|
345
|
+
# Add failure context if retrying
|
|
328
346
|
failure_msg=$(jq -r '.failure.message // empty' "$PROGRESS")
|
|
329
347
|
if [ -n "$failure_msg" ] && [ "$failure_msg" != "null" ]; then
|
|
330
348
|
prompt+=$'\n\n'"이전 실패 사유: ${failure_msg}"
|
|
331
349
|
prompt+=$'\n'"같은 접근을 반복하지 말고, 실패 원인을 분석한 후 다른 전략으로 시도하세요."
|
|
332
350
|
fi
|
|
333
351
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
# ── Generate structured handoff.json ──
|
|
337
|
-
HANDOFF="$PROJECT_ROOT/.harness/handoff.json"
|
|
352
|
+
# ── Collect artifacts ──
|
|
338
353
|
FEATURE_LIST="$PROJECT_ROOT/.harness/actions/feature-list.json"
|
|
339
354
|
|
|
340
|
-
# Collect available artifacts
|
|
341
355
|
local -a artifacts_ready=()
|
|
342
356
|
for f in plan.md feature-list.json api-contract.json sprint-contract.md evaluation-functional.md evaluation-visual.md; do
|
|
343
357
|
if [ -f "$PROJECT_ROOT/.harness/actions/$f" ]; then
|
|
@@ -353,7 +367,7 @@ if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_st
|
|
|
353
367
|
focus_features=$(jq '[.features[]? | select(.passes == null or (.passes | length) == 0 or ((.passes // []) | map(select(. == "evaluator-functional")) | length == 0)) | .id] | .[0:5]' "$FEATURE_LIST" 2>/dev/null || echo "[]")
|
|
354
368
|
fi
|
|
355
369
|
|
|
356
|
-
# ── Regression data
|
|
370
|
+
# ── Regression data ──
|
|
357
371
|
local regression_source="null"
|
|
358
372
|
local prev_sprint=$((sprint_num - 1))
|
|
359
373
|
local prev_archive="$PROJECT_ROOT/.harness/archive/sprint-$(printf '%03d' $prev_sprint)"
|
|
@@ -367,7 +381,7 @@ if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_st
|
|
|
367
381
|
fi
|
|
368
382
|
fi
|
|
369
383
|
|
|
370
|
-
# ── Eval-specific
|
|
384
|
+
# ── Eval-specific config ──
|
|
371
385
|
local eval_config="null"
|
|
372
386
|
local cross_validation_data="null"
|
|
373
387
|
case "$next_agent" in
|
|
@@ -384,22 +398,24 @@ if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_st
|
|
|
384
398
|
;;
|
|
385
399
|
esac
|
|
386
400
|
|
|
387
|
-
# ── Cross-Validation
|
|
401
|
+
# ── Cross-Validation ──
|
|
388
402
|
if [ "$next_agent" = "evaluator-visual" ]; then
|
|
389
403
|
local func_eval="$PROJECT_ROOT/.harness/actions/evaluation-functional.md"
|
|
390
404
|
if [ -f "$func_eval" ]; then
|
|
391
|
-
# evaluation-functional.md 내 JSON 코드블록에서 Cross-Validation Data 추출
|
|
392
405
|
cross_validation_data=$(sed -n '/```json/,/```/p' "$func_eval" | tail -n +2 | head -n -1 | jq 'select(.evaluator == "functional")' 2>/dev/null || echo "null")
|
|
393
406
|
fi
|
|
394
407
|
fi
|
|
395
408
|
|
|
396
|
-
# Build handoff.json
|
|
409
|
+
# ── Build handoff.json (single source of truth for session transition) ──
|
|
397
410
|
jq -n \
|
|
398
411
|
--arg from "${current_agent:-dispatcher}" \
|
|
399
412
|
--arg to "$next_agent" \
|
|
413
|
+
--arg prompt "$prompt" \
|
|
400
414
|
--argjson sprint "$sprint_num" \
|
|
401
415
|
--argjson retry "$retry_count" \
|
|
402
416
|
--arg status "$sprint_status" \
|
|
417
|
+
--arg agent_model "$agent_model" \
|
|
418
|
+
--arg agent_thinking "$agent_thinking" \
|
|
403
419
|
--arg failure_msg "${failure_msg:-}" \
|
|
404
420
|
--argjson artifacts "$artifacts_json" \
|
|
405
421
|
--argjson focus "$focus_features" \
|
|
@@ -410,9 +426,12 @@ if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_st
|
|
|
410
426
|
'{
|
|
411
427
|
from: $from,
|
|
412
428
|
to: $to,
|
|
429
|
+
prompt: $prompt,
|
|
413
430
|
sprint: $sprint,
|
|
414
431
|
retry_count: $retry,
|
|
415
432
|
sprint_status: $status,
|
|
433
|
+
model: $agent_model,
|
|
434
|
+
thinking_mode: (if $agent_thinking == "null" then null else $agent_thinking end),
|
|
416
435
|
failure_context: (if $failure_msg != "" then $failure_msg else null end),
|
|
417
436
|
artifacts_ready: $artifacts,
|
|
418
437
|
focus_features: $focus,
|
|
@@ -424,12 +443,20 @@ if [ "$next_agent" != "null" ] && [ "$next_agent" != "archive" ] && [ "$agent_st
|
|
|
424
443
|
}' > "$HANDOFF"
|
|
425
444
|
|
|
426
445
|
elif [ "$next_agent" = "archive" ]; then
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
446
|
+
jq -n \
|
|
447
|
+
--arg from "${current_agent:-evaluator}" \
|
|
448
|
+
--argjson sprint "$sprint_num" \
|
|
449
|
+
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
450
|
+
'{
|
|
451
|
+
from: $from,
|
|
452
|
+
to: "archive",
|
|
453
|
+
prompt: "Sprint 문서를 아카이브하세요.\n.harness/actions/의 스프린트 문서를 .harness/archive/sprint-NNN/으로 이동합니다.\n.harness/handoff.json을 읽고 sprint 번호를 확인하세요.",
|
|
454
|
+
sprint: $sprint,
|
|
455
|
+
model: "opus",
|
|
456
|
+
thinking_mode: null,
|
|
457
|
+
timestamp: $timestamp
|
|
458
|
+
}' > "$HANDOFF"
|
|
432
459
|
|
|
433
460
|
else
|
|
434
|
-
echo
|
|
461
|
+
echo '{}' > "$HANDOFF"
|
|
435
462
|
fi
|
|
@@ -88,6 +88,28 @@ if [ "$retry_count" -gt 0 ]; then
|
|
|
88
88
|
retry_str=" R${retry_count}"
|
|
89
89
|
fi
|
|
90
90
|
|
|
91
|
+
# Model/mode for current or next agent
|
|
92
|
+
CONFIG="$PROJECT_ROOT/.harness/config.json"
|
|
93
|
+
active_agent="$current_agent"
|
|
94
|
+
if [ "$active_agent" = "none" ] || [ "$active_agent" = "null" ]; then
|
|
95
|
+
active_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
|
|
96
|
+
fi
|
|
97
|
+
model_short=""
|
|
98
|
+
if [ -f "$CONFIG" ] && [ "$active_agent" != "none" ] && [ "$active_agent" != "null" ]; then
|
|
99
|
+
am=$(jq -r ".agents[\"${active_agent}\"].model // empty" "$CONFIG" 2>/dev/null)
|
|
100
|
+
at=$(jq -r ".agents[\"${active_agent}\"].thinking_mode // empty" "$CONFIG" 2>/dev/null)
|
|
101
|
+
if [ -n "$am" ]; then
|
|
102
|
+
model_short="${am}"
|
|
103
|
+
if [ -n "$at" ] && [ "$at" != "null" ]; then
|
|
104
|
+
model_short+="/${at}"
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
|
|
91
109
|
# Build compact status line
|
|
92
|
-
# Format: [S1] FULL | >backend | 2/5 feat |
|
|
93
|
-
|
|
110
|
+
# Format: [S1] FULL | >backend | sonnet | 2/5 feat | ctx 45% | $1.23
|
|
111
|
+
if [ -n "$model_short" ]; then
|
|
112
|
+
echo "[S${sprint_num}] ${pl} | ${status_icon}${agent_short}${retry_str} | ${model_short} | ${completed_features}/${total_features} feat | ctx ${context_pct}% | \$${cost}"
|
|
113
|
+
else
|
|
114
|
+
echo "[S${sprint_num}] ${pl} | ${status_icon}${agent_short}${retry_str} | ${completed_features}/${total_features} feat | ctx ${context_pct}% | \$${cost}"
|
|
115
|
+
fi
|
|
@@ -268,9 +268,28 @@ render_progress() {
|
|
|
268
268
|
|
|
269
269
|
# ── Next Action ──
|
|
270
270
|
if [ "$next_agent" != "none" ] && [ "$next_agent" != "null" ] && [ "$agent_status" != "blocked" ]; then
|
|
271
|
+
# Read model & thinking mode from config
|
|
272
|
+
local next_model="opus"
|
|
273
|
+
local next_thinking="null"
|
|
274
|
+
if [ -f "$CONFIG" ]; then
|
|
275
|
+
next_model=$(jq -r ".agents[\"${next_agent}\"].model // \"opus\"" "$CONFIG" 2>/dev/null || echo "opus")
|
|
276
|
+
next_thinking=$(jq -r ".agents[\"${next_agent}\"].thinking_mode // \"null\"" "$CONFIG" 2>/dev/null || echo "null")
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
local mode_str=""
|
|
280
|
+
if [ "$next_thinking" != "null" ]; then
|
|
281
|
+
mode_str=" [/${next_thinking}]"
|
|
282
|
+
fi
|
|
283
|
+
|
|
271
284
|
echo ""
|
|
272
|
-
echo " Next → /harness-${next_agent}"
|
|
273
|
-
|
|
285
|
+
echo " Next → /harness-${next_agent} (model: ${next_model}${mode_str})"
|
|
286
|
+
|
|
287
|
+
# Build auto CLI command with model flag, reading prompt from handoff.json
|
|
288
|
+
local model_flag=""
|
|
289
|
+
if [ "$next_model" != "opus" ]; then
|
|
290
|
+
model_flag=" --model ${next_model}"
|
|
291
|
+
fi
|
|
292
|
+
echo " Auto → claude${model_flag} --prompt \"\$(jq -r .prompt .harness/handoff.json)\""
|
|
274
293
|
fi
|
|
275
294
|
|
|
276
295
|
echo ""
|