triflux 2.4.6 → 2.5.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.
- package/README.ko.md +9 -7
- package/README.md +9 -7
- package/bin/tfx-doctor.mjs +1 -1
- package/bin/tfx-setup.mjs +1 -1
- package/bin/triflux.mjs +21 -1
- package/hud/hud-qos-status.mjs +208 -101
- package/package.json +1 -1
- package/scripts/cli-route.sh +236 -9
- package/scripts/notion-read.mjs +553 -0
package/scripts/cli-route.sh
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# cli-route.sh v1.
|
|
2
|
+
# cli-route.sh v1.7 — CLI 라우팅 래퍼 (ai-scaffold 템플릿)
|
|
3
3
|
# v1.0: 기본 라우팅 (Codex/Gemini/Claude 분기)
|
|
4
4
|
# v1.1: stderr 분리, 출력 필터링, 타임아웃, MCP 프로필 지원
|
|
5
5
|
# v1.2: effort 동적 라우팅, bg/fg 모드, Opus 직접 수행, Gemini 모델 분기, 실행 로그
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
# v1.4: TFX_CLI_MODE 지원 (codex-only/gemini-only), CLI 미설치 자동 fallback
|
|
8
8
|
# v1.5: MCP 인벤토리 캐싱 — 실제 서버 가용성 기반 동적 힌트 생성
|
|
9
9
|
# v1.6: 토큰 사용량 추출 + sv-accumulator.json 누적
|
|
10
|
-
|
|
10
|
+
# v1.7: 배치 AIMD 전략 — 성공 시 +1, 실패/타임아웃 시 ×0.5, 수렴 감지
|
|
11
|
+
VERSION="1.7"
|
|
11
12
|
#
|
|
12
13
|
# 설치: cp scripts/cli-route.sh ~/.claude/scripts/cli-route.sh
|
|
13
14
|
#
|
|
@@ -35,8 +36,207 @@ GEMINI_BIN="${GEMINI_BIN:-$(command -v gemini 2>/dev/null || echo gemini)}"
|
|
|
35
36
|
# ── 상수 ──
|
|
36
37
|
MAX_STDOUT_BYTES=51200 # 50KB — Claude 컨텍스트 절약
|
|
37
38
|
TIMESTAMP=$(date +%s)
|
|
38
|
-
STDERR_LOG="/tmp/
|
|
39
|
-
STDOUT_LOG="/tmp/
|
|
39
|
+
STDERR_LOG="/tmp/tfx-route-${AGENT_TYPE}-${TIMESTAMP}-stderr.log"
|
|
40
|
+
STDOUT_LOG="/tmp/tfx-route-${AGENT_TYPE}-${TIMESTAMP}-stdout.log"
|
|
41
|
+
|
|
42
|
+
# fallback 시 원래 에이전트/CLI 인자 보존용 (수정 3: review fallback 프로필 유실 방지)
|
|
43
|
+
ORIGINAL_AGENT=""
|
|
44
|
+
ORIGINAL_CLI_ARGS=""
|
|
45
|
+
|
|
46
|
+
# ── 크로스 세션 활성 에이전트 추적 ──
|
|
47
|
+
# 활성 에이전트 레지스트리 경로
|
|
48
|
+
ACTIVE_AGENTS_FILE="${HOME}/.claude/cache/active-agents.json"
|
|
49
|
+
|
|
50
|
+
# 죽은 PID 및 좀비 정리
|
|
51
|
+
cleanup_stale_agents() {
|
|
52
|
+
[[ ! -f "$ACTIVE_AGENTS_FILE" ]] && return
|
|
53
|
+
local now
|
|
54
|
+
now=$(date +%s)
|
|
55
|
+
local tmp="${ACTIVE_AGENTS_FILE}.tmp"
|
|
56
|
+
# jq가 있으면 사용, 없으면 건너뜀
|
|
57
|
+
if command -v jq &>/dev/null; then
|
|
58
|
+
jq --argjson now "$now" '
|
|
59
|
+
.agents |= map(select(
|
|
60
|
+
# PID 생존 확인은 셸에서 하므로 여기선 타임아웃만 체크
|
|
61
|
+
(.started + 1200) > $now
|
|
62
|
+
))
|
|
63
|
+
' "$ACTIVE_AGENTS_FILE" > "$tmp" 2>/dev/null && mv "$tmp" "$ACTIVE_AGENTS_FILE"
|
|
64
|
+
# 추가로 kill -0으로 죽은 PID 제거
|
|
65
|
+
local pids
|
|
66
|
+
pids=$(jq -r '.agents[].pid' "$ACTIVE_AGENTS_FILE" 2>/dev/null)
|
|
67
|
+
local pid
|
|
68
|
+
for pid in $pids; do
|
|
69
|
+
if ! kill -0 "$pid" 2>/dev/null; then
|
|
70
|
+
jq --argjson pid "$pid" '.agents |= map(select(.pid != $pid))' "$ACTIVE_AGENTS_FILE" > "$tmp" 2>/dev/null && mv "$tmp" "$ACTIVE_AGENTS_FILE"
|
|
71
|
+
fi
|
|
72
|
+
done
|
|
73
|
+
fi
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# 에이전트 등록
|
|
77
|
+
register_agent() {
|
|
78
|
+
local pid="$1" cli="$2" agent="$3"
|
|
79
|
+
local now
|
|
80
|
+
now=$(date +%s)
|
|
81
|
+
cleanup_stale_agents
|
|
82
|
+
if command -v jq &>/dev/null; then
|
|
83
|
+
# 캐시 디렉토리가 없으면 생성
|
|
84
|
+
mkdir -p "$(dirname "$ACTIVE_AGENTS_FILE")"
|
|
85
|
+
if [[ -f "$ACTIVE_AGENTS_FILE" ]]; then
|
|
86
|
+
jq --argjson pid "$pid" --arg cli "$cli" --arg agent "$agent" --argjson started "$now" \
|
|
87
|
+
'.agents += [{"pid": $pid, "cli": $cli, "agent": $agent, "started": $started}]' \
|
|
88
|
+
"$ACTIVE_AGENTS_FILE" > "${ACTIVE_AGENTS_FILE}.tmp" && mv "${ACTIVE_AGENTS_FILE}.tmp" "$ACTIVE_AGENTS_FILE"
|
|
89
|
+
else
|
|
90
|
+
echo "{\"agents\":[{\"pid\":$pid,\"cli\":\"$cli\",\"agent\":\"$agent\",\"started\":$now}]}" > "$ACTIVE_AGENTS_FILE"
|
|
91
|
+
fi
|
|
92
|
+
fi
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# 에이전트 등록 해제
|
|
96
|
+
deregister_agent() {
|
|
97
|
+
local pid="$1"
|
|
98
|
+
if command -v jq &>/dev/null && [[ -f "$ACTIVE_AGENTS_FILE" ]]; then
|
|
99
|
+
jq --argjson pid "$pid" '.agents |= map(select(.pid != $pid))' \
|
|
100
|
+
"$ACTIVE_AGENTS_FILE" > "${ACTIVE_AGENTS_FILE}.tmp" && mv "${ACTIVE_AGENTS_FILE}.tmp" "$ACTIVE_AGENTS_FILE"
|
|
101
|
+
fi
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# ── 배치 AIMD 전략 ──
|
|
105
|
+
# 배치 설정 파일: ~/.claude/cache/batch-config.json
|
|
106
|
+
# 초기 batch_size=2, 성공→+1 (AI), 실패/타임아웃→×0.5 (MD), 상한=8, 수렴=3연속 동일
|
|
107
|
+
BATCH_CONFIG_FILE="${HOME}/.claude/cache/batch-config.json"
|
|
108
|
+
|
|
109
|
+
# 현재 batch_size 반환 (파일 없으면 기본값 2)
|
|
110
|
+
get_batch_size() {
|
|
111
|
+
if ! command -v jq &>/dev/null; then
|
|
112
|
+
echo "2"
|
|
113
|
+
return
|
|
114
|
+
fi
|
|
115
|
+
if [[ -f "$BATCH_CONFIG_FILE" ]]; then
|
|
116
|
+
local size
|
|
117
|
+
size=$(jq -r '.batch_size // 2' "$BATCH_CONFIG_FILE" 2>/dev/null)
|
|
118
|
+
# 숫자가 아니거나 비어 있으면 기본값
|
|
119
|
+
if [[ "$size" =~ ^[0-9]+$ ]]; then
|
|
120
|
+
echo "$size"
|
|
121
|
+
else
|
|
122
|
+
echo "2"
|
|
123
|
+
fi
|
|
124
|
+
else
|
|
125
|
+
echo "2"
|
|
126
|
+
fi
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# 현재 활성 에이전트 수 반환 (active-agents.json 기반)
|
|
130
|
+
get_active_agent_count() {
|
|
131
|
+
if ! command -v jq &>/dev/null; then
|
|
132
|
+
echo "0"
|
|
133
|
+
return
|
|
134
|
+
fi
|
|
135
|
+
if [[ -f "$ACTIVE_AGENTS_FILE" ]]; then
|
|
136
|
+
local count
|
|
137
|
+
count=$(jq '.agents | length' "$ACTIVE_AGENTS_FILE" 2>/dev/null)
|
|
138
|
+
echo "${count:-0}"
|
|
139
|
+
else
|
|
140
|
+
echo "0"
|
|
141
|
+
fi
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# AIMD 결과 기록 및 batch_size 업데이트
|
|
145
|
+
# 인자: result (success/failed/timeout), agent
|
|
146
|
+
update_batch_result() {
|
|
147
|
+
local result="$1"
|
|
148
|
+
local agent="${2:-unknown}"
|
|
149
|
+
|
|
150
|
+
if ! command -v jq &>/dev/null; then
|
|
151
|
+
return
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
mkdir -p "$(dirname "$BATCH_CONFIG_FILE")"
|
|
155
|
+
|
|
156
|
+
# 현재 설정 읽기 (없으면 초기값)
|
|
157
|
+
local current_size consecutive_same converged
|
|
158
|
+
if [[ -f "$BATCH_CONFIG_FILE" ]]; then
|
|
159
|
+
current_size=$(jq -r '.batch_size // 2' "$BATCH_CONFIG_FILE" 2>/dev/null)
|
|
160
|
+
consecutive_same=$(jq -r '.consecutive_same // 0' "$BATCH_CONFIG_FILE" 2>/dev/null)
|
|
161
|
+
converged=$(jq -r '.converged // false' "$BATCH_CONFIG_FILE" 2>/dev/null)
|
|
162
|
+
else
|
|
163
|
+
current_size=2
|
|
164
|
+
consecutive_same=0
|
|
165
|
+
converged="false"
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# 숫자 검증
|
|
169
|
+
[[ "$current_size" =~ ^[0-9]+$ ]] || current_size=2
|
|
170
|
+
[[ "$consecutive_same" =~ ^[0-9]+$ ]] || consecutive_same=0
|
|
171
|
+
|
|
172
|
+
# 수렴 상태면 batch_size 고정 (업데이트만 기록)
|
|
173
|
+
local new_size="$current_size"
|
|
174
|
+
if [[ "$converged" != "true" ]]; then
|
|
175
|
+
case "$result" in
|
|
176
|
+
success)
|
|
177
|
+
# Additive Increase: +1, 상한 8
|
|
178
|
+
new_size=$((current_size + 1))
|
|
179
|
+
if [[ $new_size -gt 8 ]]; then new_size=8; fi
|
|
180
|
+
;;
|
|
181
|
+
failed|timeout)
|
|
182
|
+
# Multiplicative Decrease: ×0.5, 하한 1
|
|
183
|
+
new_size=$((current_size / 2))
|
|
184
|
+
if [[ $new_size -lt 1 ]]; then new_size=1; fi
|
|
185
|
+
;;
|
|
186
|
+
esac
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
# 수렴 판단: 3연속 동일하면 converged=true
|
|
190
|
+
if [[ $new_size -eq $current_size ]]; then
|
|
191
|
+
consecutive_same=$((consecutive_same + 1))
|
|
192
|
+
else
|
|
193
|
+
consecutive_same=0
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
local new_converged="false"
|
|
197
|
+
if [[ $consecutive_same -ge 3 ]]; then
|
|
198
|
+
new_converged="true"
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
local now
|
|
202
|
+
now=$(date +%s)
|
|
203
|
+
|
|
204
|
+
# history에 추가 (최대 50건 유지) 후 batch_size 업데이트
|
|
205
|
+
local tmp="${BATCH_CONFIG_FILE}.tmp"
|
|
206
|
+
if [[ -f "$BATCH_CONFIG_FILE" ]]; then
|
|
207
|
+
jq --argjson now "$now" \
|
|
208
|
+
--arg agent "$agent" \
|
|
209
|
+
--arg result "$result" \
|
|
210
|
+
--argjson batch_at_time "$current_size" \
|
|
211
|
+
--argjson new_size "$new_size" \
|
|
212
|
+
--argjson consecutive_same "$consecutive_same" \
|
|
213
|
+
--argjson converged "$new_converged" \
|
|
214
|
+
'
|
|
215
|
+
.history += [{"timestamp": $now, "agent": $agent, "result": $result, "batch_at_time": $batch_at_time}] |
|
|
216
|
+
.history = (.history | if length > 50 then .[-50:] else . end) |
|
|
217
|
+
.batch_size = $new_size |
|
|
218
|
+
.consecutive_same = $consecutive_same |
|
|
219
|
+
.converged = $converged
|
|
220
|
+
' "$BATCH_CONFIG_FILE" > "$tmp" 2>/dev/null && mv "$tmp" "$BATCH_CONFIG_FILE"
|
|
221
|
+
else
|
|
222
|
+
# 파일 신규 생성
|
|
223
|
+
jq -n \
|
|
224
|
+
--argjson now "$now" \
|
|
225
|
+
--arg agent "$agent" \
|
|
226
|
+
--arg result "$result" \
|
|
227
|
+
--argjson new_size "$new_size" \
|
|
228
|
+
--argjson consecutive_same "$consecutive_same" \
|
|
229
|
+
--argjson converged "$new_converged" \
|
|
230
|
+
'{
|
|
231
|
+
batch_size: $new_size,
|
|
232
|
+
history: [{"timestamp": $now, "agent": $agent, "result": $result, "batch_at_time": 2}],
|
|
233
|
+
consecutive_same: $consecutive_same,
|
|
234
|
+
converged: $converged
|
|
235
|
+
}' > "$BATCH_CONFIG_FILE" 2>/dev/null || true
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
echo "[cli-route] AIMD: $result → batch_size $current_size→$new_size (consecutive_same=$consecutive_same, converged=$new_converged)" >&2
|
|
239
|
+
}
|
|
40
240
|
|
|
41
241
|
# ── 라우팅 테이블 ──
|
|
42
242
|
# 반환: CLI_CMD, CLI_ARGS, CLI_TYPE, CLI_EFFORT, DEFAULT_TIMEOUT, RUN_MODE, OPUS_OVERSIGHT
|
|
@@ -373,10 +573,13 @@ apply_cli_mode() {
|
|
|
373
573
|
apply_cli_mode
|
|
374
574
|
return
|
|
375
575
|
else
|
|
576
|
+
# 원래 에이전트 및 MCP 프로필 정보 보존
|
|
577
|
+
ORIGINAL_AGENT="${AGENT_TYPE}"
|
|
578
|
+
ORIGINAL_CLI_ARGS="$CLI_ARGS"
|
|
376
579
|
CLI_TYPE="claude-native"
|
|
377
580
|
CLI_CMD=""
|
|
378
581
|
CLI_ARGS=""
|
|
379
|
-
echo "[cli-route] codex/gemini 모두 미설치: $AGENT_TYPE → claude-native fallback" >&2
|
|
582
|
+
echo "[cli-route] codex/gemini 모두 미설치: $AGENT_TYPE → claude-native fallback (원래 프로필: $MCP_PROFILE)" >&2
|
|
380
583
|
fi
|
|
381
584
|
elif [[ "$CLI_TYPE" == "gemini" ]] && ! command -v "$GEMINI_BIN" &>/dev/null; then
|
|
382
585
|
if command -v "$CODEX_BIN" &>/dev/null; then
|
|
@@ -384,10 +587,13 @@ apply_cli_mode() {
|
|
|
384
587
|
apply_cli_mode
|
|
385
588
|
return
|
|
386
589
|
else
|
|
590
|
+
# 원래 에이전트 및 MCP 프로필 정보 보존
|
|
591
|
+
ORIGINAL_AGENT="${AGENT_TYPE}"
|
|
592
|
+
ORIGINAL_CLI_ARGS="$CLI_ARGS"
|
|
387
593
|
CLI_TYPE="claude-native"
|
|
388
594
|
CLI_CMD=""
|
|
389
595
|
CLI_ARGS=""
|
|
390
|
-
echo "[cli-route] codex/gemini 모두 미설치: $AGENT_TYPE → claude-native fallback" >&2
|
|
596
|
+
echo "[cli-route] codex/gemini 모두 미설치: $AGENT_TYPE → claude-native fallback (원래 프로필: $MCP_PROFILE)" >&2
|
|
391
597
|
fi
|
|
392
598
|
fi
|
|
393
599
|
;;
|
|
@@ -764,6 +970,9 @@ truncate_output() {
|
|
|
764
970
|
|
|
765
971
|
# ── 메인 실행 ──
|
|
766
972
|
main() {
|
|
973
|
+
# 종료 시 활성 에이전트 레지스트리에서 자동 제거
|
|
974
|
+
trap 'deregister_agent $$' EXIT
|
|
975
|
+
|
|
767
976
|
route_agent "$AGENT_TYPE"
|
|
768
977
|
|
|
769
978
|
# CLI 모드 오버라이드 적용 (tfx-codex/tfx-gemini 또는 auto-fallback)
|
|
@@ -782,12 +991,12 @@ main() {
|
|
|
782
991
|
TIMEOUT_SEC="$DEFAULT_TIMEOUT"
|
|
783
992
|
fi
|
|
784
993
|
|
|
785
|
-
# kteam 안정화: Gemini 에이전트 기본 타임아웃
|
|
994
|
+
# kteam 안정화: Gemini 에이전트 기본 타임아웃 하한 적용 (사용자 미지정 시만)
|
|
786
995
|
if [[ -z "$USER_TIMEOUT" ]]; then
|
|
787
996
|
case "$AGENT_TYPE" in
|
|
788
997
|
designer|writer)
|
|
789
|
-
if [[ "$DEFAULT_TIMEOUT" -gt
|
|
790
|
-
TIMEOUT_SEC=
|
|
998
|
+
if [[ "$DEFAULT_TIMEOUT" -gt 300 ]]; then
|
|
999
|
+
TIMEOUT_SEC=300
|
|
791
1000
|
fi
|
|
792
1001
|
;;
|
|
793
1002
|
esac
|
|
@@ -808,6 +1017,12 @@ main() {
|
|
|
808
1017
|
echo "RUN_MODE=$RUN_MODE"
|
|
809
1018
|
echo "OPUS_OVERSIGHT=$OPUS_OVERSIGHT"
|
|
810
1019
|
echo "TIMEOUT=$TIMEOUT_SEC"
|
|
1020
|
+
echo "MCP_PROFILE=$MCP_PROFILE"
|
|
1021
|
+
# fallback 시 원래 에이전트/MCP 프로필 정보를 함께 출력 (수정 3)
|
|
1022
|
+
if [[ -n "$ORIGINAL_AGENT" ]]; then
|
|
1023
|
+
echo "ORIGINAL_AGENT=$ORIGINAL_AGENT"
|
|
1024
|
+
echo "ORIGINAL_CLI_ARGS=$ORIGINAL_CLI_ARGS"
|
|
1025
|
+
fi
|
|
811
1026
|
echo "PROMPT=$PROMPT"
|
|
812
1027
|
echo "--- Claude Task($model) 에이전트로 위임하세요 ---"
|
|
813
1028
|
exit 0
|
|
@@ -825,6 +1040,9 @@ main() {
|
|
|
825
1040
|
echo "[cli-route] type=$CLI_TYPE agent=$AGENT_TYPE effort=$CLI_EFFORT mode=$RUN_MODE timeout=${TIMEOUT_SEC}s" >&2
|
|
826
1041
|
echo "[cli-route] opus_oversight=$OPUS_OVERSIGHT mcp_profile=$MCP_PROFILE stderr_log=$STDERR_LOG" >&2
|
|
827
1042
|
|
|
1043
|
+
# 크로스 세션 활성 에이전트 레지스트리에 등록 (수정 4)
|
|
1044
|
+
register_agent $$ "$CLI_TYPE" "$AGENT_TYPE"
|
|
1045
|
+
|
|
828
1046
|
# CLI 실행 (stderr 분리 + 타임아웃 + 소요시간 측정)
|
|
829
1047
|
local exit_code=0
|
|
830
1048
|
local raw_output=""
|
|
@@ -906,6 +1124,15 @@ main() {
|
|
|
906
1124
|
accumulate_tokens "$CLI_TYPE" "$input_tokens" "$output_tokens" || true
|
|
907
1125
|
fi
|
|
908
1126
|
|
|
1127
|
+
# AIMD 배치 크기 업데이트 (exit code 기반)
|
|
1128
|
+
if [[ $exit_code -eq 0 ]]; then
|
|
1129
|
+
update_batch_result "success" "$AGENT_TYPE" || true
|
|
1130
|
+
elif [[ $exit_code -eq 124 ]]; then
|
|
1131
|
+
update_batch_result "timeout" "$AGENT_TYPE" || true
|
|
1132
|
+
else
|
|
1133
|
+
update_batch_result "failed" "$AGENT_TYPE" || true
|
|
1134
|
+
fi
|
|
1135
|
+
|
|
909
1136
|
# CLI 이슈 자동 수집
|
|
910
1137
|
local _stderr_for_track=""
|
|
911
1138
|
[[ -f "$STDERR_LOG" ]] && _stderr_for_track=$(cat "$STDERR_LOG" 2>/dev/null || echo "")
|