triflux 10.9.12 → 10.9.13

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.
@@ -88,14 +88,29 @@ cleanup_workers() {
88
88
  }
89
89
 
90
90
  # ── config.toml sandbox/approval_mode 감지 ──
91
- # config.toml에 이미 설정되어 있으면 CLI 플래그 중복 시 Codex가 에러를 던짐
91
+ # config.toml에 이미 설정되어 있으면 CLI 플래그 중복 시 Codex가 에러를 던짐.
92
+ # 단, [mcp_servers.*.tools.*] 섹션 내부의 approval_mode는 tool 단위 승인 설정으로
93
+ # top-level sandbox/approval_mode와 의미가 다르다. 이 값이 "approve"이면
94
+ # codex exec이 non-TTY subprocess에서 승인 대기로 stall하므로 감지 대상에서 제외.
95
+ # (refs: tellang/triflux#66, Yeachan-Heo/oh-my-codex#1478)
92
96
  _CODEX_CONFIG="${HOME}/.codex/config.toml"
93
97
  _CODEX_HAS_SANDBOX=""
94
- if [[ -f "$_CODEX_CONFIG" ]] && grep -qE '^\s*(sandbox|approval_mode)\s*=' "$_CODEX_CONFIG" 2>/dev/null; then
98
+ if [[ -f "$_CODEX_CONFIG" ]] && awk '
99
+ /^\[{1,2}mcp_servers\..*\.tools\./ { in_mcp_tool=1; next }
100
+ /^\[/ { in_mcp_tool=0; next }
101
+ !in_mcp_tool && /^[[:space:]]*(sandbox|approval_mode)[[:space:]]*=/ { found=1; exit }
102
+ END { exit !found }
103
+ ' "$_CODEX_CONFIG" 2>/dev/null; then
95
104
  _CODEX_HAS_SANDBOX="1"
96
105
  fi
97
106
 
98
107
  build_codex_base() {
108
+ # Escape hatch: TFX_FORCE_CODEX_BYPASS=1이면 감지 결과와 무관하게 항상 bypass.
109
+ # CI/디버깅/긴급 상황에서 config.toml 상태에 상관없이 non-TTY codex exec를 보장.
110
+ if [[ "${TFX_FORCE_CODEX_BYPASS:-0}" == "1" ]]; then
111
+ echo "--dangerously-bypass-approvals-and-sandbox --skip-git-repo-check"
112
+ return
113
+ fi
99
114
  if [[ -n "$_CODEX_HAS_SANDBOX" ]]; then
100
115
  echo "--skip-git-repo-check"
101
116
  else
@@ -897,8 +912,9 @@ TFX_CODEX_TRANSPORT="${TFX_CODEX_TRANSPORT:-auto}"
897
912
  # Preflight 캐시 일괄 로드 — CLI/Hub 가용성 + Codex 요금제를 환경변수로 내보냄
898
913
  # 하위 프로세스(스킬 포함)가 TFX_CODEX_OK, TFX_GEMINI_OK, TFX_HUB_OK로 즉시 참조 가능
899
914
  if [[ -z "${TFX_PREFLIGHT_LOADED:-}" ]]; then
900
- # eval 제거 — pipe-delimited read로 인젝션 위험 차단
901
- IFS='|' read -r _pf_codex _pf_gemini _pf_hub _pf_plan _pf_agents < <(
915
+ # eval 제거 — \x1e (ASCII 30, Record Separator) delimited read로 인젝션 위험 차단
916
+ # F05: `|`에서 `\x1e`로 변경 계정 tier/agent 이름 등 값에 `|` 포함 시 필드 분리 오류 방지
917
+ IFS=$'\x1e' read -r _pf_codex _pf_gemini _pf_hub _pf_plan _pf_agents < <(
902
918
  "$NODE_BIN" -e '
903
919
  try {
904
920
  const c = JSON.parse(require("fs").readFileSync(require("path").join(require("os").homedir(),".claude","cache","tfx-preflight.json"),"utf8"));
@@ -909,8 +925,8 @@ if [[ -z "${TFX_PREFLIGHT_LOADED:-}" ]]; then
909
925
  (c?.codex_plan?.plan && c.codex_plan.plan !== "unknown" && c.codex_plan.plan !== "api") ? c.codex_plan.plan : "",
910
926
  Array.isArray(c?.available_agents) ? c.available_agents.join(",") : ""
911
927
  ];
912
- process.stdout.write(parts.join("|"));
913
- } catch { process.stdout.write("0|0|0||"); }
928
+ process.stdout.write(parts.join("\x1e"));
929
+ } catch { process.stdout.write("0\x1e0\x1e0\x1e\x1e"); }
914
930
  ' 2>/dev/null
915
931
  ) || true
916
932
  export TFX_CODEX_OK="${_pf_codex:-0}"
@@ -1699,7 +1715,14 @@ FALLBACK_EOF
1699
1715
 
1700
1716
  run_stream_worker "gemini" "$FULL_PROMPT" "$use_tee" "${gemini_worker_args[@]}" || exit_code=$?
1701
1717
  if [[ "$exit_code" -ne 0 && "$exit_code" -ne 124 ]]; then
1702
- echo "[tfx-route] Gemini stream wrapper 실패(exit=${exit_code}). claude-native fallback." >&2
1718
+ # stderr 내용을 fallback 전에 보존하여 디버깅 가능하게
1719
+ local gemini_stderr_bytes=0
1720
+ [[ -f "$STDERR_LOG" ]] && gemini_stderr_bytes=$(wc -c < "$STDERR_LOG" 2>/dev/null | tr -d ' ')
1721
+ echo "[tfx-route] Gemini stream wrapper 실패(exit=${exit_code}, stderr=${gemini_stderr_bytes}B). claude-native fallback." >&2
1722
+ if [[ "$gemini_stderr_bytes" -gt 0 ]]; then
1723
+ echo "[tfx-route] Gemini stderr 보존:" >&2
1724
+ tail -c 2048 "$STDERR_LOG" >&2
1725
+ fi
1703
1726
  cat > "$STDOUT_LOG" <<EOF
1704
1727
  $(emit_claude_native_metadata)
1705
1728
  EOF
@@ -1721,7 +1744,13 @@ EOF
1721
1744
 
1722
1745
  run_stream_worker "claude" "$FULL_PROMPT" "$use_tee" "${claude_worker_args[@]}" || exit_code=$?
1723
1746
  if [[ "$exit_code" -ne 0 && "$exit_code" -ne 124 ]]; then
1724
- echo "[tfx-route] Claude stream wrapper 실패(exit=${exit_code}). native metadata로 fallback합니다." >&2
1747
+ local claude_stderr_bytes=0
1748
+ [[ -f "$STDERR_LOG" ]] && claude_stderr_bytes=$(wc -c < "$STDERR_LOG" 2>/dev/null | tr -d ' ')
1749
+ echo "[tfx-route] Claude stream wrapper 실패(exit=${exit_code}, stderr=${claude_stderr_bytes}B). native metadata로 fallback합니다." >&2
1750
+ if [[ "$claude_stderr_bytes" -gt 0 ]]; then
1751
+ echo "[tfx-route] Claude stderr 보존:" >&2
1752
+ tail -c 2048 "$STDERR_LOG" >&2
1753
+ fi
1725
1754
  cat > "$STDOUT_LOG" <<EOF
1726
1755
  $(emit_claude_native_metadata)
1727
1756
  EOF