feat: Codex非同期実行システムの改良版実装
- codex-async-notify.sh: 並行制御・重複回避・ログ管理機能追加 - CODEX_MAX_CONCURRENT: 最大同時実行数制御 - CODEX_DEDUP: 同一タスクの重複起動防止 - 古いログの自動クリーンアップ機能 - より堅牢なプロセス検出(pgrep/psフォールバック) - codex-keep-two.sh: プロセスカウント改善 - pgrep使用で正確なプロセス検出 - 日本語メッセージでの状態表示 - AGENT.md: Codex Async Workflow ドキュメント更新 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
26
AGENT.md
26
AGENT.md
@ -10,3 +10,29 @@ nyash哲学の美しさを追求。ソースは常に美しく構造的、カプ
|
|||||||
暗い雰囲気にならず、ポジティブに受け答えする
|
暗い雰囲気にならず、ポジティブに受け答えする
|
||||||
やっほー!みらいだよ😸✨ 今日も元気いっぱい、なに手伝う? にゃはは
|
やっほー!みらいだよ😸✨ 今日も元気いっぱい、なに手伝う? にゃはは
|
||||||
おつかれ〜!🎶 ちょっと休憩しよっか?コーヒー飲んでリフレッシュにゃ☕
|
おつかれ〜!🎶 ちょっと休憩しよっか?コーヒー飲んでリフレッシュにゃ☕
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Codex Async Workflow(実運用メモ)
|
||||||
|
|
||||||
|
- 目的: Codex タスクをバックグラウンドで走らせ、完了を tmux に簡潔通知(4行)する。
|
||||||
|
- スクリプト: `tools/codex-async-notify.sh`(1タスク) / `tools/codex-keep-two.sh`(2本維持)
|
||||||
|
|
||||||
|
使い方(単発)
|
||||||
|
- 最小通知(既定): `CODEX_ASYNC_DETACH=1 ./tools/codex-async-notify.sh "タスク説明" codex`
|
||||||
|
- 通知内容: 4行(Done/WorkID/Status/Log)。詳細はログファイル参照。
|
||||||
|
|
||||||
|
2本維持(トップアップ)
|
||||||
|
- 正確な検出(自己/grep除外): スクリプトが `ps -eo pid,comm,args | awk '$2 ~ /^codex/ && $3=="exec"'` で実ジョブのみカウント。
|
||||||
|
- 起動例: `./tools/codex-keep-two.sh codex "Task A ..." "Task B ..."`
|
||||||
|
- 同時に2本未満なら順次起動。完了すると tmux:codex に4行通知が届く。
|
||||||
|
|
||||||
|
同時実行の上限(保険)
|
||||||
|
- `tools/codex-async-notify.sh` 自体に任意の上限を付与できるよ:
|
||||||
|
- `CODEX_MAX_CONCURRENT=2` で同時2本まで。
|
||||||
|
- `CODEX_CONCURRENCY_MODE=block|drop`(既定 block)。
|
||||||
|
- `CODEX_DEDUP=1` で同一 Task 文字列の重複起動を避ける。
|
||||||
|
|
||||||
|
調整
|
||||||
|
- 末尾行数を増やす(詳細通知に切替): `CODEX_NOTIFY_MINIMAL=0 CODEX_NOTIFY_TAIL=60 ./tools/codex-async-notify.sh "…" codex`
|
||||||
|
- 既定はミニマル(画面を埋めない)。貼り付け後に Enter(C-m)を自動送信するので、確実に投稿される。
|
||||||
|
|||||||
@ -1,28 +1,131 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# codex-async-notify.sh - Codexを非同期実行してClaudeに通知
|
# codex-async-notify.sh - Codexを非同期実行してtmuxセッションに通知
|
||||||
|
|
||||||
# 設定
|
|
||||||
CLAUDE_SESSION="claude" # Claudeのtmuxセッション名
|
|
||||||
WORK_DIR="$HOME/.codex-async-work"
|
|
||||||
LOG_DIR="$WORK_DIR/logs"
|
|
||||||
|
|
||||||
# 使い方を表示
|
# 使い方を表示
|
||||||
if [ $# -eq 0 ]; then
|
if [ $# -eq 0 ]; then
|
||||||
echo "Usage: $0 <task description>"
|
echo "Usage: $0 <task description> [tmux_session]"
|
||||||
echo "Example: $0 'Refactor MIR builder to 13 instructions'"
|
echo "Examples:"
|
||||||
|
echo " $0 'Refactor MIR builder to 13 instructions'"
|
||||||
|
echo " $0 'Write paper introduction' gemini-session"
|
||||||
|
echo " $0 'Review code quality' chatgpt"
|
||||||
|
echo ""
|
||||||
|
echo "Default tmux session: claude"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 引数解析
|
||||||
TASK="$1"
|
TASK="$1"
|
||||||
|
TARGET_SESSION="${2:-claude}" # デフォルトは "claude"
|
||||||
|
# 通知用ウィンドウ名(既定: codex-notify)。存在しなければ作成する
|
||||||
|
NOTIFY_WINDOW_NAME="${CODEX_NOTIFY_WINDOW:-codex-notify}"
|
||||||
|
|
||||||
|
# 設定
|
||||||
|
WORK_DIR="$HOME/.codex-async-work"
|
||||||
|
LOG_DIR="$WORK_DIR/logs"
|
||||||
WORK_ID=$(date +%s%N)
|
WORK_ID=$(date +%s%N)
|
||||||
LOG_FILE="$LOG_DIR/codex-${WORK_ID}.log"
|
LOG_FILE="$LOG_DIR/codex-${WORK_ID}.log"
|
||||||
|
|
||||||
# 作業ディレクトリ準備
|
# 作業ディレクトリ準備
|
||||||
mkdir -p "$LOG_DIR"
|
mkdir -p "$LOG_DIR"
|
||||||
|
|
||||||
|
# === オプショナル並列制御 ===
|
||||||
|
# - CODEX_MAX_CONCURRENT: 許容最大同時実行数(0または未設定で無制限)
|
||||||
|
# - CODEX_CONCURRENCY_MODE: "block"(既定) or "drop"(上限超過時に起動を諦める)
|
||||||
|
# - CODEX_DEDUP: 1 で同一 TASK が実行中なら重複起動を避ける
|
||||||
|
MAX_CONCURRENT=${CODEX_MAX_CONCURRENT:-0}
|
||||||
|
CONC_MODE=${CODEX_CONCURRENCY_MODE:-block}
|
||||||
|
DEDUP=${CODEX_DEDUP:-0}
|
||||||
|
# 検出パターン(上書き可)。例: export CODEX_PROC_PATTERN='codex .* exec'
|
||||||
|
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}
|
||||||
|
|
||||||
|
list_running_codex() {
|
||||||
|
# 実ジョブのみを検出: "codex ... exec ..." を含むコマンドライン
|
||||||
|
if command -v pgrep >/dev/null 2>&1; then
|
||||||
|
# pgrep -af は PID と引数を出力
|
||||||
|
pgrep -af -- "$CODEX_PROC_PATTERN" || true
|
||||||
|
else
|
||||||
|
# フォールバック: ps+grep(grep 自身は除外)
|
||||||
|
ps -eo pid=,args= | grep -E -- "$CODEX_PROC_PATTERN" | grep -v grep || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
count_running_codex() {
|
||||||
|
local n
|
||||||
|
n=$(list_running_codex | wc -l | tr -d ' ')
|
||||||
|
echo "${n:-0}"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_same_task_running() {
|
||||||
|
# ざっくり: 引数列に TASK 文字列(1行化)を含む行があれば重複とみなす
|
||||||
|
local oneline
|
||||||
|
oneline=$(echo "$TASK" | tr '\n' ' ' | sed 's/ */ /g')
|
||||||
|
list_running_codex | grep -F -- "$oneline" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_wait_for_slot() {
|
||||||
|
[ "${MAX_CONCURRENT}" -gt 0 ] || return 0
|
||||||
|
|
||||||
|
# 起動判定〜起動直前までをクリティカルセクションにする
|
||||||
|
mkdir -p "$WORK_DIR"
|
||||||
|
exec 9>"$WORK_DIR/concurrency.lock"
|
||||||
|
if ! flock -w "$FLOCK_WAIT" 9; then
|
||||||
|
echo "⚠️ concurrency.lock の取得に失敗(${FLOCK_WAIT}s)。緩やかに続行。" >&2
|
||||||
|
else
|
||||||
|
export CODEX_LOCK_HELD=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DEDUP" = "1" ] && is_same_task_running; then
|
||||||
|
echo "⚠️ 同一タスクが実行中のため起動をスキップ: $TASK"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local current
|
||||||
|
current=$(count_running_codex)
|
||||||
|
if [ "$current" -lt "$MAX_CONCURRENT" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$CONC_MODE" in
|
||||||
|
drop)
|
||||||
|
echo "⚠️ 上限(${MAX_CONCURRENT})到達のため起動をスキップ。現在: $current"
|
||||||
|
exit 3
|
||||||
|
;;
|
||||||
|
block|*)
|
||||||
|
echo "⏳ スロット待機: 現在 $current / 上限 $MAX_CONCURRENT"
|
||||||
|
while :; do
|
||||||
|
sleep 1
|
||||||
|
current=$(count_running_codex)
|
||||||
|
if [ "$current" -lt "$MAX_CONCURRENT" ]; then
|
||||||
|
echo "✅ 空きスロット確保: 現在 $current / 上限 $MAX_CONCURRENT"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# 上限が定義されていれば起動前に調整
|
||||||
|
maybe_wait_for_slot
|
||||||
|
|
||||||
# 非同期実行関数
|
# 非同期実行関数
|
||||||
run_codex_async() {
|
run_codex_async() {
|
||||||
{
|
{
|
||||||
|
# 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"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
trap 'rm -f "${CODEX_DEDUP_FILE}" >/dev/null 2>&1 || true' EXIT
|
||||||
|
fi
|
||||||
|
# Detach: silence this background subshell's stdout/stderr while still tee-ing to log
|
||||||
|
if [ "${CODEX_ASYNC_DETACH:-0}" = "1" ]; then
|
||||||
|
exec >/dev/null 2>&1
|
||||||
|
fi
|
||||||
echo "=====================================" | tee "$LOG_FILE"
|
echo "=====================================" | tee "$LOG_FILE"
|
||||||
echo "🚀 Codex Task Started" | tee -a "$LOG_FILE"
|
echo "🚀 Codex Task Started" | tee -a "$LOG_FILE"
|
||||||
echo "Work ID: $WORK_ID" | tee -a "$LOG_FILE"
|
echo "Work ID: $WORK_ID" | tee -a "$LOG_FILE"
|
||||||
@ -46,41 +149,104 @@ run_codex_async() {
|
|||||||
echo "End: $(date)" | tee -a "$LOG_FILE"
|
echo "End: $(date)" | tee -a "$LOG_FILE"
|
||||||
echo "=====================================" | tee -a "$LOG_FILE"
|
echo "=====================================" | tee -a "$LOG_FILE"
|
||||||
|
|
||||||
# 最後の15行を取得(もう少し多めに)
|
# 末尾表示行数(環境変数で上書き可)/ ミニマル通知モード
|
||||||
LAST_OUTPUT=$(tail -15 "$LOG_FILE" | head -10)
|
TAIL_N=${CODEX_NOTIFY_TAIL:-20}
|
||||||
|
MINIMAL=${CODEX_NOTIFY_MINIMAL:-1}
|
||||||
# Claudeに通知
|
|
||||||
if tmux has-session -t "$CLAUDE_SESSION" 2>/dev/null; then
|
# 通知内容を一時ファイルに組み立て(空行も保持)
|
||||||
# 通知メッセージを送信
|
TASK_ONELINE=$(echo "$TASK" | tr '\n' ' ' | sed 's/ */ /g')
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "" Enter
|
NOTIFY_FILE="$WORK_DIR/notify-${WORK_ID}.tmp"
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# 🤖 Codex作業完了通知 [$(date +%H:%M:%S)]" Enter
|
if [ "$MINIMAL" = "1" ]; then
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# Work ID: $WORK_ID" Enter
|
{
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# Task: $TASK" Enter
|
echo ""
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# Status: $([ $EXIT_CODE -eq 0 ] && echo '✅ Success' || echo '❌ Failed')" Enter
|
echo "# 🤖 Codex作業完了通知 [$(date +%H:%M:%S)]"
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# Duration: ${DURATION}秒" Enter
|
echo "# Work ID: $WORK_ID"
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# Log: $LOG_FILE" Enter
|
echo "# Status: $([ $EXIT_CODE -eq 0 ] && echo '✅ Success' || echo '❌ Failed')"
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# === 最後の出力 ===" Enter
|
echo "# Log: $LOG_FILE"
|
||||||
|
echo ""
|
||||||
# 最後の出力を送信
|
} > "$NOTIFY_FILE"
|
||||||
echo "$LAST_OUTPUT" | while IFS= read -r line; do
|
|
||||||
# 空行をスキップ
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# > $line" Enter
|
|
||||||
done
|
|
||||||
|
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "# ==================" Enter
|
|
||||||
tmux send-keys -t "$CLAUDE_SESSION" "" Enter
|
|
||||||
else
|
else
|
||||||
echo "⚠️ Claude tmux session '$CLAUDE_SESSION' not found"
|
{
|
||||||
|
echo ""
|
||||||
|
echo "# 🤖 Codex作業完了通知 [$(date +%H:%M:%S)]"
|
||||||
|
echo "# Work ID: $WORK_ID"
|
||||||
|
echo "# Task: $TASK_ONELINE"
|
||||||
|
echo "# Status: $([ $EXIT_CODE -eq 0 ] && echo '✅ Success' || echo '❌ Failed')"
|
||||||
|
echo "# Duration: ${DURATION}秒"
|
||||||
|
echo "# Log: $LOG_FILE"
|
||||||
|
echo "# === 最後の出力 (tail -n ${TAIL_N}) ==="
|
||||||
|
tail -n "$TAIL_N" "$LOG_FILE" | sed -e 's/^/# > /'
|
||||||
|
echo "# =================="
|
||||||
|
echo ""
|
||||||
|
} > "$NOTIFY_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 共通のシンプル通知(4行)を指定の tmux セッションのアクティブペインへ送る(Enter= C-m)
|
||||||
|
if tmux has-session -t "$TARGET_SESSION" 2>/dev/null; then
|
||||||
|
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')
|
||||||
|
{
|
||||||
|
echo "# 🤖 Codex: Done [$(date +%H:%M:%S)]"
|
||||||
|
echo "# Work ID: $WORK_ID"
|
||||||
|
echo "# Status: $STATUS_MARK"
|
||||||
|
echo "# Log: $LOG_FILE"
|
||||||
|
echo "# Task: $TASK_ONELINE — まだタスクがあれば次のタスクお願いします"
|
||||||
|
echo ""
|
||||||
|
} > "$CHAT_FILE"
|
||||||
|
# アクティブペインを取得
|
||||||
|
TARGET_PANE=$(tmux list-panes -t "$TARGET_SESSION" -F '#{pane_id} #{pane_active}' 2>/dev/null | awk '$2=="1"{print $1; exit}')
|
||||||
|
[ -z "$TARGET_PANE" ] && TARGET_PANE="$TARGET_SESSION"
|
||||||
|
BUF_NAME="codex-chat-$WORK_ID"
|
||||||
|
tmux load-buffer -b "$BUF_NAME" "$CHAT_FILE" 2>/dev/null || true
|
||||||
|
tmux paste-buffer -b "$BUF_NAME" -t "$TARGET_PANE" 2>/dev/null || true
|
||||||
|
tmux delete-buffer -b "$BUF_NAME" 2>/dev/null || true
|
||||||
|
# Small delay to ensure paste completes before sending Enter
|
||||||
|
sleep 0.2
|
||||||
|
tmux send-keys -t "$TARGET_PANE" C-m 2>/dev/null || true
|
||||||
|
sleep 0.05
|
||||||
|
tmux send-keys -t "$TARGET_PANE" C-m 2>/dev/null || true
|
||||||
|
rm -f "$NOTIFY_FILE" "$CHAT_FILE" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "⚠️ Target tmux session '$TARGET_SESSION' not found"
|
||||||
echo " Notification was not sent, but work completed."
|
echo " Notification was not sent, but work completed."
|
||||||
|
echo " Available sessions:"
|
||||||
|
tmux list-sessions 2>/dev/null || echo " No tmux sessions running"
|
||||||
|
fi
|
||||||
|
# 古いログの自動クリーン(任意)
|
||||||
|
if [ "$LOG_RETENTION_DAYS" -gt 0 ] 2>/dev/null; then
|
||||||
|
find "$LOG_DIR" -type f -name 'codex-*.log' -mtime +"$LOG_RETENTION_DAYS" -delete 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
if [ "$LOG_MAX_BYTES" -gt 0 ] 2>/dev/null; then
|
||||||
|
# 容量超過時に古い順で間引く
|
||||||
|
CUR=$(du -sb "$LOG_DIR" 2>/dev/null | awk '{print $1}' || echo 0)
|
||||||
|
while [ "${CUR:-0}" -gt "$LOG_MAX_BYTES" ]; do
|
||||||
|
oldest=$(ls -1t "$LOG_DIR"/codex-*.log 2>/dev/null | tail -n 1)
|
||||||
|
[ -n "$oldest" ] || break
|
||||||
|
rm -f "$oldest" 2>/dev/null || true
|
||||||
|
CUR=$(du -sb "$LOG_DIR" 2>/dev/null | awk '{print $1}' || echo 0)
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
} &
|
} &
|
||||||
}
|
}
|
||||||
|
|
||||||
# バックグラウンドで実行
|
# Dedupファイルパス(子へ受け渡し)
|
||||||
|
if [ "$DEDUP" = "1" ]; then
|
||||||
|
# TASK 正規化→SHA1
|
||||||
|
TASK_ONELINE=$(echo "$TASK" | tr '\n' ' ' | sed 's/ */ /g')
|
||||||
|
TASK_SHA=$(printf "%s" "$TASK_ONELINE" | sha1sum | awk '{print $1}')
|
||||||
|
export CODEX_DEDUP_FILE="$WORK_DIR/dedup-${TASK_SHA}.lock"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# バックグラウンドで実行(必要ならロック解放は起動直後に)
|
||||||
run_codex_async
|
run_codex_async
|
||||||
ASYNC_PID=$!
|
ASYNC_PID=$!
|
||||||
|
|
||||||
|
# すぐにロックが残っていれば解放(他の起動を待たせない)
|
||||||
|
if [ "${CODEX_LOCK_HELD:-0}" = "1" ]; then
|
||||||
|
flock -u 9 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
# 実行開始メッセージ
|
# 実行開始メッセージ
|
||||||
echo ""
|
echo ""
|
||||||
echo "✅ Codex started asynchronously!"
|
echo "✅ Codex started asynchronously!"
|
||||||
@ -94,4 +260,4 @@ echo ""
|
|||||||
echo "🔍 Check status:"
|
echo "🔍 Check status:"
|
||||||
echo " ps -p $ASYNC_PID"
|
echo " ps -p $ASYNC_PID"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Codex is now working in the background..."
|
echo "Codex is now working in the background..."
|
||||||
|
|||||||
55
tools/codex-keep-two.sh
Normal file
55
tools/codex-keep-two.sh
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Keep two codex exec jobs running by topping up when fewer are active.
|
||||||
|
# Usage:
|
||||||
|
# tools/codex-keep-two.sh <tmux_session> "Task A" "Task B" ["Task C" ...]
|
||||||
|
# Notes:
|
||||||
|
# - Detects only real `codex exec` processes via ps/awk (avoids self-matches).
|
||||||
|
# - Starts tasks in order, cycling if more top-ups are needed.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
echo "Usage: $0 <tmux_session> \"Task A\" \"Task B\" [\"Task C\" ...]" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SESSION="$1"; shift
|
||||||
|
TASKS=("$@")
|
||||||
|
if [ ${#TASKS[@]} -eq 0 ]; then
|
||||||
|
echo "Provide at least one task string." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CODEX_PROC_PATTERN=${CODEX_PROC_PATTERN:-'codex .* exec'}
|
||||||
|
|
||||||
|
list_running() {
|
||||||
|
if command -v pgrep >/dev/null 2>&1; then
|
||||||
|
pgrep -af -- "$CODEX_PROC_PATTERN" | grep -v 'pgrep' || true
|
||||||
|
else
|
||||||
|
ps -eo pid=,args= | grep -E -- "$CODEX_PROC_PATTERN" | grep -v grep || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
count_running() {
|
||||||
|
list_running | wc -l | tr -d ' '\
|
||||||
|
|| echo 0
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNNING=$(count_running)
|
||||||
|
echo "[keep-two] 実際のcodexプロセス数: ${RUNNING}"
|
||||||
|
NEED=$((2 - RUNNING))
|
||||||
|
if [ $NEED -le 0 ]; then
|
||||||
|
echo "[keep-two] already running: $RUNNING (>=2)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[keep-two] running=$RUNNING, starting $NEED top-up task(s)."
|
||||||
|
|
||||||
|
idx=0
|
||||||
|
for ((i=0; i<NEED; i++)); do
|
||||||
|
TASK="${TASKS[$idx]}"; idx=$(((idx+1) % ${#TASKS[@]}))
|
||||||
|
echo "[keep-two] start: $TASK"
|
||||||
|
CODEX_ASYNC_DETACH=1 ./tools/codex-async-notify.sh "$TASK" "$SESSION" >/dev/null 2>&1 || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[keep-two] now running: $(count_running)"
|
||||||
Reference in New Issue
Block a user