From 13907292e94e581345551e2ef841074dceda6ac5 Mon Sep 17 00:00:00 2001 From: Moe Charm Date: Thu, 4 Sep 2025 20:14:00 +0900 Subject: [PATCH] =?UTF-8?q?feat(tools):=20=E8=87=AA=E5=BE=8B=E5=9E=8BAI?= =?UTF-8?q?=E9=96=8B=E7=99=BA=E3=82=B7=E3=82=B9=E3=83=86=E3=83=A0=E3=81=AE?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E5=AE=8C=E4=BA=86=20-=20Codex=E9=9D=9E?= =?UTF-8?q?=E5=90=8C=E6=9C=9F=E5=AE=9F=E8=A1=8C=E3=81=A8=E3=83=97=E3=83=AD?= =?UTF-8?q?=E3=82=BB=E3=82=B9=E5=88=B6=E5=BE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - codex-async-notify.sh: tmux paste-buffer方式で安定化 - codex-keep-two.sh: 正確なプロセスカウント実装 - デフォルト2プロセス制限で暴走防止 - 日本語プロンプト「まだタスクがあれば次のタスクお願いします」で無限ループ実現 - count_running_codex_display()でcomm+argsによる正確な検出 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- tools/codex-async-notify.sh | 83 +++++++++++++++++++++++++++++++++---- tools/codex-keep-two.sh | 44 +++++++++++++++++++- 2 files changed, 118 insertions(+), 9 deletions(-) diff --git a/tools/codex-async-notify.sh b/tools/codex-async-notify.sh index 8166a9d4..6d3ade95 100644 --- a/tools/codex-async-notify.sh +++ b/tools/codex-async-notify.sh @@ -22,11 +22,12 @@ NOTIFY_WINDOW_NAME="${CODEX_NOTIFY_WINDOW:-codex-notify}" # 設定 WORK_DIR="$HOME/.codex-async-work" LOG_DIR="$WORK_DIR/logs" +RUN_DIR="$WORK_DIR/running" WORK_ID=$(date +%s%N) LOG_FILE="$LOG_DIR/codex-${WORK_ID}.log" # 作業ディレクトリ準備 -mkdir -p "$LOG_DIR" +mkdir -p "$LOG_DIR" "$RUN_DIR" # === オプショナル並列制御 === # - CODEX_MAX_CONCURRENT: 許容最大同時実行数(デフォルト2) @@ -40,6 +41,8 @@ CODEX_PROC_PATTERN=${CODEX_PROC_PATTERN:-'codex .* exec'} FLOCK_WAIT=${CODEX_FLOCK_WAIT:-5} LOG_RETENTION_DAYS=${CODEX_LOG_RETENTION_DAYS:-0} LOG_MAX_BYTES=${CODEX_LOG_MAX_BYTES:-0} +# 実行中カウント方式: proc(プロセス数) / pgid(プロセスグループ数) / sentinel(将来のための拡張) +CODEX_COUNT_MODE=${CODEX_COUNT_MODE:-sentinel} list_running_codex() { # 実ジョブのみを検出: "codex ... exec ..." を含むコマンドライン @@ -53,9 +56,63 @@ list_running_codex() { } count_running_codex() { - local n - n=$(list_running_codex | wc -l | tr -d ' ') - echo "${n:-0}" + case "$CODEX_COUNT_MODE" in + sentinel) + # Count sentinel files for tasks we launched; clean up stale ones + local cnt=0 + if [ -d "$RUN_DIR" ]; then + for f in "$RUN_DIR"/codex-*.run; do + [ -e "$f" ] || continue + # Optional liveness check by stored pid + pid=$(awk -F': ' '/^pid:/{print $2; exit}' "$f" 2>/dev/null || true) + if [ -n "$pid" ] && ! kill -0 "$pid" 2>/dev/null; then + rm -f "$f" 2>/dev/null || true + continue + fi + cnt=$((cnt+1)) + done + fi + # Fallback: if 0 (older jobs without sentinel), attempt pgid-based count + if [ "${cnt:-0}" -eq 0 ]; then + if command -v pgrep >/dev/null 2>&1; then + pgc=$(pgrep -f -- "$CODEX_PROC_PATTERN" \ + | xargs -r -I {} sh -c 'ps -o pgid= -p "$1" 2>/dev/null' _ {} \ + | awk '{print $1}' | grep -E '^[0-9]+$' | sort -u | wc -l | tr -d ' ' || echo 0) + echo "${pgc:-0}" + else + list_running_codex | wc -l | tr -d ' ' || echo 0 + fi + else + echo "$cnt" + fi + ;; + pgid) + # pgrepで対象PIDsを取得 → 各PIDのPGIDを集計(自分自身のawk/ps行は拾わない) + if command -v pgrep >/dev/null 2>&1; then + pgrep -f -- "$CODEX_PROC_PATTERN" \ + | xargs -r -I {} sh -c 'ps -o pgid= -p "$1" 2>/dev/null' _ {} \ + | awk '{print $1}' | grep -E '^[0-9]+$' | sort -u | wc -l | tr -d ' ' || echo 0 + else + # フォールバック: プロセス数 + list_running_codex | wc -l | tr -d ' ' || echo 0 + fi + ;; + proc|*) + list_running_codex | wc -l | tr -d ' ' || echo 0 + ;; + esac +} + +# Display-oriented counter: count real 'codex exec' processes by comm+args +count_running_codex_display() { + if ps -eo comm=,args= >/dev/null 2>&1; then + ps -eo comm=,args= \ + | awk '($1 ~ /^codex$/) && ($0 ~ / exec[ ]/) {print $0}' \ + | wc -l | tr -d ' ' || echo 0 + else + # Fallback to pattern match + list_running_codex | wc -l | tr -d ' ' || echo 0 + fi } is_same_task_running() { @@ -113,14 +170,25 @@ maybe_wait_for_slot # 非同期実行関数 run_codex_async() { { + # Create sentinel to track running task (removed on exit) + SEN_FILE="$RUN_DIR/codex-${WORK_ID}.run" + { + echo "work_id: $WORK_ID" + echo "task: $TASK" + echo "started: $(date -Is)" + echo "pid: $$" + } > "$SEN_FILE" 2>/dev/null || true + # Ensure sentinel (and dedup file if any) are always cleaned up on exit + trap 'rm -f "$SEN_FILE" "${CODEX_DEDUP_FILE:-}" >/dev/null 2>&1 || true' EXIT # Dedupロック: 子プロセス側で握る(同一TASKの多重起動回避) if [ "${CODEX_DEDUP_FILE:-}" != "" ]; then exec 8>"${CODEX_DEDUP_FILE}" if ! flock -n 8; then echo "⚠️ Duplicate task detected (dedup lock busy). Skipping: $TASK" | tee -a "$LOG_FILE" + rm -f "$SEN_FILE" >/dev/null 2>&1 || true exit 0 fi - trap 'rm -f "${CODEX_DEDUP_FILE}" >/dev/null 2>&1 || true' EXIT + # (cleanup handled by global EXIT trap above) fi # Detach: silence this background subshell's stdout/stderr while still tee-ing to log if [ "${CODEX_ASYNC_DETACH:-0}" = "1" ]; then @@ -186,8 +254,9 @@ run_codex_async() { STATUS_MARK=$([ $EXIT_CODE -eq 0 ] && echo '✅ Success' || echo '❌ Failed') CHAT_FILE="$WORK_DIR/chat-${WORK_ID}.tmp" TASK_ONELINE=$(echo "$TASK" | tr '\n' ' ' | sed 's/ */ /g') - # 現在の実行中プロセス数をカウント - CURRENT_RUNNING=$(count_running_codex) + # 表示用: 実プロセス(comm=codex かつ args に exec を含む)の数を採用 + CURRENT_RUNNING=$(count_running_codex_display) + case "$CURRENT_RUNNING" in (*[!0-9]*) CURRENT_RUNNING=0;; esac { echo "# 🤖 Codex: Done [$(date +%H:%M:%S)] (実行中: $CURRENT_RUNNING)" echo "# Work ID: $WORK_ID" diff --git a/tools/codex-keep-two.sh b/tools/codex-keep-two.sh index 6151e7b3..6a7fa7f8 100644 --- a/tools/codex-keep-two.sh +++ b/tools/codex-keep-two.sh @@ -21,6 +21,9 @@ if [ ${#TASKS[@]} -eq 0 ]; then fi CODEX_PROC_PATTERN=${CODEX_PROC_PATTERN:-'codex .* exec'} +CODEX_COUNT_MODE=${CODEX_COUNT_MODE:-sentinel} +WORK_DIR="$HOME/.codex-async-work" +RUN_DIR="$WORK_DIR/running" list_running() { if command -v pgrep >/dev/null 2>&1; then @@ -31,8 +34,45 @@ list_running() { } count_running() { - list_running | wc -l | tr -d ' '\ - || echo 0 + case "$CODEX_COUNT_MODE" in + sentinel) + local cnt=0 + if [ -d "$RUN_DIR" ]; then + for f in "$RUN_DIR"/codex-*.run; do + [ -e "$f" ] || continue + pid=$(awk -F': ' '/^pid:/{print $2; exit}' "$f" 2>/dev/null || true) + if [ -n "$pid" ] && ! kill -0 "$pid" 2>/dev/null; then + rm -f "$f" 2>/dev/null || true + continue + fi + cnt=$((cnt+1)) + done + fi + if [ "${cnt:-0}" -eq 0 ]; then + if command -v pgrep >/dev/null 2>&1; then + pgrep -f -- "$CODEX_PROC_PATTERN" \ + | xargs -r -I {} sh -c 'ps -o pgid= -p "$1" 2>/dev/null' _ {} \ + | awk '{print $1}' | grep -E '^[0-9]+$' | sort -u | wc -l | tr -d ' ' || echo 0 + else + list_running | wc -l | tr -d ' ' || echo 0 + fi + else + echo "$cnt" + fi + ;; + pgid) + if command -v pgrep >/dev/null 2>&1; then + pgrep -f -- "$CODEX_PROC_PATTERN" \ + | xargs -r -I {} sh -c 'ps -o pgid= -p "$1" 2>/dev/null' _ {} \ + | awk '{print $1}' | grep -E '^[0-9]+$' | sort -u | wc -l | tr -d ' ' || echo 0 + else + list_running | wc -l | tr -d ' ' || echo 0 + fi + ;; + proc|*) + list_running | wc -l | tr -d ' ' || echo 0 + ;; + esac } RUNNING=$(count_running)