vibego 0.2.58__py3-none-any.whl → 1.0.10__py3-none-any.whl

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.
scripts/start.sh CHANGED
@@ -3,6 +3,9 @@ set -eo pipefail
3
3
 
4
4
  ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
5
  MASTER_CONFIG_ROOT="${MASTER_CONFIG_ROOT:-$HOME/.config/vibego}"
6
+ RUNTIME_DIR="${VIBEGO_RUNTIME_ROOT:-$MASTER_CONFIG_ROOT/runtime}"
7
+ VENV_DIR="$RUNTIME_DIR/.venv"
8
+ LEGACY_VENV_DIR="$ROOT_DIR/.venv"
6
9
  STATE_DIR="$MASTER_CONFIG_ROOT/state"
7
10
  LOG_DIR="$MASTER_CONFIG_ROOT/logs"
8
11
  LOCK_FILE="$STATE_DIR/master_restart.lock"
@@ -10,8 +13,8 @@ START_LOG="$LOG_DIR/start.log"
10
13
  CODEX_STAMP_FILE="$STATE_DIR/npm_codex_install.stamp"
11
14
  CODEX_INSTALL_TTL="${CODEX_INSTALL_TTL:-86400}"
12
15
 
13
- # 统一重启信号文件路径:使用配置目录而非代码目录
14
- # 这样 pipx 安装的 master 和源码运行的 master 可以共享同一个信号文件
16
+ # Unified restart signal file path: use the configuration directory instead of the code directory
17
+ # In this way, the master installed by pipx and the master run from the source code can share the same signal file.
15
18
  export MASTER_RESTART_SIGNAL_PATH="$STATE_DIR/restart_signal.json"
16
19
  export LOG_ROOT="${LOG_ROOT:-$LOG_DIR}"
17
20
  if [[ -z "${LOG_FILE:-}" ]]; then
@@ -42,34 +45,35 @@ cd "$ROOT_DIR"
42
45
 
43
46
  mkdir -p "$(dirname "$LOCK_FILE")"
44
47
  mkdir -p "$(dirname "$START_LOG")"
48
+ mkdir -p "$RUNTIME_DIR"
45
49
  touch "$START_LOG"
46
50
  exec >>"$START_LOG"
47
51
  exec 2>&1
48
52
 
49
- log_info "start.sh 启动,pid=$$"
53
+ log_info "start.sh start, pid=$$"
50
54
 
51
55
  if [[ -f "$LOCK_FILE" ]]; then
52
- log_error "已有 start.sh 在执行,跳过本次启动。"
56
+ log_error "Already have start.sh During execution, skip this startup."
53
57
  exit 1
54
58
  fi
55
59
 
56
60
  printf '%d\n' $$ > "$LOCK_FILE"
57
61
 
58
- log_info "锁文件已创建:$LOCK_FILE"
62
+ log_info "Lock file created:$LOCK_FILE"
59
63
 
60
64
  ensure_codex_installed() {
61
65
  local need_install=1
62
66
  local now
63
67
  local codex_bin
64
68
  if ! command -v npm >/dev/null 2>&1; then
65
- log_error "未检测到 npm,可执行文件缺失,跳过 @openai/codex 全局安装"
69
+ log_error "npm not detected, executable missing, skipped @openai/codex Global installation"
66
70
  return
67
71
  fi
68
72
 
69
- log_info "检测到 npm 版本:$(npm --version)"
73
+ log_info "npm version detected:$(npm --version)"
70
74
 
71
75
  if [[ ! "$CODEX_INSTALL_TTL" =~ ^[0-9]+$ ]]; then
72
- log_error "CODEX_INSTALL_TTL 非法值:$CODEX_INSTALL_TTL,回退为 86400 "
76
+ log_error "CODEX_INSTALL_TTL Illegal value:$CODEX_INSTALL_TTL, Fallback to 86400 seconds"
73
77
  CODEX_INSTALL_TTL=86400
74
78
  fi
75
79
 
@@ -99,11 +103,11 @@ ensure_codex_installed() {
99
103
  fi
100
104
 
101
105
  if (( need_install )); then
102
- log_info "开始执行 npm install -g @openai/codex@latest"
106
+ log_info "Start executing npm install -g @openai/codex@latest"
103
107
  if npm install -g @openai/codex@latest; then
104
108
  now=$(date +%s)
105
109
  printf '%s\n' "$now" > "$CODEX_STAMP_FILE"
106
- log_info "npm install -g @openai/codex@latest 成功"
110
+ log_info "npm install -g @openai/codex@latest success"
107
111
  else
108
112
  local status=$?
109
113
  log_error "npm install -g @openai/codex@latest failed (exit code ${status}); continuing startup"
@@ -114,8 +118,9 @@ ensure_codex_installed() {
114
118
  ensure_codex_installed
115
119
 
116
120
  select_python_binary() {
117
- # 选择满足 CPython <=3.12 的解释器,默认禁用 3.13(pydantic-core pipx 基础环境下无兼容轮子)
121
+ # Select a compatible CPython version; defaults accept 3.9-3.14 and can be overridden via env variables.
118
122
  local allow_py313="${VIBEGO_ALLOW_PY313:-}"
123
+ local supported_max_minor="${VIBEGO_MAX_MINOR:-14}"
119
124
  local candidates=()
120
125
  local chosen=""
121
126
  local name
@@ -141,121 +146,127 @@ select_python_binary() {
141
146
  local major="${version_raw%%.*}"
142
147
  local minor="${version_raw#*.}"
143
148
  if [[ "$major" != "3" ]]; then
144
- log_line "跳过 ${name} (版本 ${version_raw}):非 CPython 3.x" >&2
149
+ log_line "jump over ${name} (Version ${version_raw}): Non-CPython 3.x" >&2
145
150
  continue
146
151
  fi
147
152
  local explicit_override=0
148
153
  if [[ -n "${VIBEGO_PYTHON:-}" && "$name" == "$VIBEGO_PYTHON" ]]; then
149
154
  explicit_override=1
150
155
  fi
151
- if [[ "$minor" =~ ^[0-9]+$ ]] && (( minor == 13 )) && [[ "$allow_py313" != "1" ]] && (( explicit_override == 0 )); then
152
- log_line "跳过 ${name} (版本 ${version_raw}):默认禁用 Python 3.13,可设置 VIBEGO_ALLOW_PY313=1 覆盖" >&2
153
- continue
156
+ if [[ "$minor" =~ ^[0-9]+$ ]] && (( minor == 13 )) && (( explicit_override == 0 )); then
157
+ if [[ "$allow_py313" == "0" ]]; then
158
+ log_line "Skip ${name} (version ${version_raw}): disabled explicitly by VIBEGO_ALLOW_PY313=0" >&2
159
+ continue
160
+ fi
161
+ log_line "Detected ${name} (version ${version_raw}): Python 3.13 accepted by default; use VIBEGO_ALLOW_PY313=1 to prefer or 0 to disable" >&2
154
162
  fi
155
- if [[ "$minor" =~ ^[0-9]+$ ]] && (( minor > 13 )); then
156
- log_line "跳过 ${name} (版本 ${version_raw}):高于 3.13" >&2
163
+ if [[ "$minor" =~ ^[0-9]+$ ]] && (( minor > supported_max_minor )) && (( explicit_override == 0 )); then
164
+ log_line "Skip ${name} (version ${version_raw}): above supported ceiling 3.${supported_max_minor}; override with VIBEGO_MAX_MINOR if needed" >&2
157
165
  continue
158
166
  fi
159
167
  if [[ "$minor" =~ ^[0-9]+$ ]] && (( minor < 9 )); then
160
- log_line "跳过 ${name} (版本 ${version_raw}):低于 3.9,可能缺少官方轮子" >&2
168
+ log_line "jump over ${name} (Version ${version_raw}): less than 3.9, May be missing official wheels" >&2
161
169
  continue
162
170
  fi
171
+ if [[ "$minor" =~ ^[0-9]+$ ]] && (( minor >= 14 )); then
172
+ log_line "Detected ${name} (version ${version_raw}): ensure dependencies support this Python version" >&2
173
+ fi
163
174
  chosen="$name"
164
- log_line "使用 Python 解释器:${chosen} (版本 ${version_raw})" >&2
175
+ log_line "Using the Python interpreter:${chosen} (Version ${version_raw})" >&2
165
176
  break
166
177
  done
167
178
 
168
179
  if [[ -z "$chosen" ]]; then
169
- log_error "未找到满足 <=3.13 Python 解释器,可通过设置 VIBEGO_PYTHON 指定路径"
180
+ log_error "no satisfaction found <=3.13 The Python interpreter can be set by VIBEGO_PYTHON Specify path"
170
181
  exit 1
171
182
  fi
172
183
 
173
184
  printf '%s' "$chosen"
174
185
  }
175
186
 
176
- # 检查Python依赖是否已安装完整
187
+ # Check whether Python dependencies are installed completely
177
188
  check_deps_installed() {
178
- # 检查虚拟环境是否存在
179
- if [[ ! -d "$ROOT_DIR/.venv" ]]; then
180
- log_info "虚拟环境不存在,需要初始化"
189
+ # Check if the virtual environment exists
190
+ if [[ ! -d "$VENV_DIR" ]]; then
191
+ log_info "The virtual environment does not exist and needs to be initialized."
181
192
  return 1
182
193
  fi
183
194
 
184
- # 检查虚拟环境的Python解释器
185
- if [[ ! -x "$ROOT_DIR/.venv/bin/python" ]]; then
186
- log_info "虚拟环境Python解释器缺失"
195
+ # Check the virtual environment's Python interpreter
196
+ if [[ ! -x "$VENV_DIR/bin/python" ]]; then
197
+ log_info "Virtual environment Python interpreter missing"
187
198
  return 1
188
199
  fi
189
200
 
190
- # 激活虚拟环境并检查关键依赖包
191
- # aiogram: Telegram Bot框架
192
- # aiohttp: 异步HTTP客户端
193
- # aiosqlite: 异步SQLite数据库
194
- if ! "$ROOT_DIR/.venv/bin/python" -c "import aiogram, aiohttp, aiosqlite" 2>/dev/null; then
195
- log_info "关键依赖包缺失或损坏"
201
+ # Activate the virtual environment and check key dependency packages
202
+ # aiogram: Telegram Botframe
203
+ # aiohttp: Asynchronous HTTP client
204
+ # aiosqlite: Asynchronous SQLite database
205
+ if ! "$VENV_DIR/bin/python" -c "import aiogram, aiohttp, aiosqlite" 2>/dev/null; then
206
+ log_info "Key dependency packages are missing or damaged"
196
207
  return 1
197
208
  fi
198
209
 
199
- log_info "依赖检查通过,虚拟环境完整"
210
+ log_info "The dependency check passed and the virtual environment is complete"
200
211
  return 0
201
212
  }
202
213
 
203
- # 清理旧 master 进程的健壮函数(改进版:支持 PID 文件 + pgrep 双保险)
214
+ # Robust function to clean up old master processes (improved version: supports PID files + pgrep Double insurance)
204
215
  cleanup_old_master() {
205
- local max_wait=10 # 最多等待10秒优雅退出
216
+ local max_wait=10 # Wait up to 10 seconds to exit gracefully
206
217
  local waited=0
207
218
  local old_pids=""
208
219
  local master_pid_file="$STATE_DIR/master.pid"
209
220
 
210
- # 方案1:优先从 PID 文件读取
221
+ # Option 1: Read from the PID file first
211
222
  if [[ -f "$master_pid_file" ]]; then
212
223
  local pid_from_file
213
224
  pid_from_file=$(cat "$master_pid_file" 2>/dev/null || true)
214
225
  if [[ "$pid_from_file" =~ ^[0-9]+$ ]]; then
215
226
  if kill -0 "$pid_from_file" 2>/dev/null; then
216
227
  old_pids="$pid_from_file"
217
- log_info " PID 文件检测到旧 master 实例(PID: $old_pids"
228
+ log_info "Old master instance detected from PID file (PID: $old_pids)"
218
229
  else
219
- log_info "PID 文件存在但进程已不在,清理过期 PID 文件"
230
+ log_info "PID The file exists but the process is no longer there, clean up expired PID files"
220
231
  rm -f "$master_pid_file"
221
232
  fi
222
233
  fi
223
234
  fi
224
235
 
225
- # 方案2:使用 pgrep 查找(支持多种运行方式)
236
+ # Option 2: Use pgrep to find (supports multiple running modes)
226
237
  if [[ -z "$old_pids" ]]; then
227
- # 匹配模式:支持源码运行和 pipx 安装的方式
228
- # - python.*master.py(源码运行)
229
- # - Python.*master.pymacOS 上的 Python.app
230
- # - bot.pypipx 安装的 master 别名)
238
+ # Matching mode: supports source code running and pipx installation methods
239
+ # - python.*master.py(Source code running)
240
+ # - Python.*master.py(macOS Python on.app)
241
+ # - bot.py(pipx installed master alias)
231
242
  local pgrep_pids
232
243
  pgrep_pids=$(pgrep -f "master\.py$" 2>/dev/null || true)
233
244
  if [[ -n "$pgrep_pids" ]]; then
234
245
  old_pids="$pgrep_pids"
235
- log_info "通过 pgrep 检测到旧 master 实例(PID: $old_pids"
246
+ log_info "Old master instance detected via pgrep (PID: $old_pids)"
236
247
  fi
237
248
  fi
238
249
 
239
- # 如果两种方式都没找到,说明没有旧进程
250
+ # If neither method is found, it means there is no old process.
240
251
  if [[ -z "$old_pids" ]]; then
241
- log_info "未检测到旧 master 实例"
252
+ log_info "Old master instance not detected"
242
253
  return 0
243
254
  fi
244
255
 
245
- # 开始清理旧进程
246
- log_info "正在优雅终止旧 master 实例(PID: $old_pids)..."
256
+ # Start cleaning up old processes
257
+ log_info "Gracefully terminating old master instance (PID: $old_pids)..."
247
258
 
248
- # 发送 SIGTERM 信号优雅终止
259
+ # Send SIGTERM signal to terminate gracefully
249
260
  for pid in $old_pids; do
250
261
  kill -15 "$pid" 2>/dev/null || true
251
262
  done
252
263
 
253
- # 循环等待进程退出
264
+ # Loop waiting for process to exit
254
265
  while (( waited < max_wait )); do
255
266
  sleep 1
256
267
  ((waited++))
257
268
 
258
- # 检查所有 PID 是否都已退出
269
+ # Check if all PIDs have exited
259
270
  local all_exited=1
260
271
  for pid in $old_pids; do
261
272
  if kill -0 "$pid" 2>/dev/null; then
@@ -265,20 +276,20 @@ cleanup_old_master() {
265
276
  done
266
277
 
267
278
  if (( all_exited )); then
268
- log_info " master 已优雅退出(耗时 ${waited}秒)"
279
+ log_info "OK: The old master exited gracefully (elapsed ${waited}s)"
269
280
  rm -f "$master_pid_file"
270
281
  return 0
271
282
  fi
272
283
  done
273
284
 
274
- # 优雅终止超时,执行强制结束
275
- log_info "优雅终止超时(${max_wait}秒),执行强制结束..."
285
+ # Graceful termination timeout, execution forced end
286
+ log_info "graceful termination timeout (${max_wait}Second), Execute forced end..."
276
287
  for pid in $old_pids; do
277
288
  kill -9 "$pid" 2>/dev/null || true
278
289
  done
279
290
  sleep 2
280
291
 
281
- # 最后检查
292
+ # final check
282
293
  local remaining_pids=""
283
294
  for pid in $old_pids; do
284
295
  if kill -0 "$pid" 2>/dev/null; then
@@ -287,75 +298,91 @@ cleanup_old_master() {
287
298
  done
288
299
 
289
300
  if [[ -n "$remaining_pids" ]]; then
290
- log_error " 无法清理旧 master 进程(残留 PID:$remaining_pids"
291
- log_error "请手动执行: kill -9$remaining_pids"
301
+ log_error "ERROR: Unable to clean up old master process (residual PID:$remaining_pids)"
302
+ log_error "Please execute manually: kill -9$remaining_pids"
292
303
  exit 1
293
304
  fi
294
305
 
295
- log_info " master 实例已强制清理"
306
+ log_info "OK: The old master instance has been forcefully cleaned"
296
307
  rm -f "$master_pid_file"
297
308
  return 0
298
309
  }
299
310
 
300
- # 调用清理函数
311
+ # Call the cleanup function
301
312
  cleanup_old_master
302
313
 
303
- # 智能依赖管理:仅在必要时安装
314
+ # Smart dependency management: install only when necessary
304
315
  REQUIREMENTS_FILE="${VIBEGO_REQUIREMENTS_PATH:-$ROOT_DIR/scripts/requirements.txt}"
305
316
  if [[ ! -f "$REQUIREMENTS_FILE" ]]; then
306
- log_error "依赖文件缺失: $REQUIREMENTS_FILE"
317
+ log_error "Dependency files are missing: $REQUIREMENTS_FILE"
307
318
  exit 1
308
319
  fi
309
320
 
310
321
  PYTHON_BIN="$(select_python_binary)"
311
322
 
312
- # 检查是否需要安装依赖
323
+ # Compatible with oldVersion: If it is detected in the warehouse .venv, then migrate to the runtime directory
324
+ migrate_legacy_venv() {
325
+ if [[ -d "$LEGACY_VENV_DIR" && ! -e "$VENV_DIR" ]]; then
326
+ log_info "Old virtual environment directory detected:$LEGACY_VENV_DIR, Prepare to migrate to $VENV_DIR"
327
+ if mv "$LEGACY_VENV_DIR" "$VENV_DIR"; then
328
+ log_info "The virtual environment has been migrated to:$VENV_DIR"
329
+ else
330
+ log_error "Migration of the old virtual environment failed. Please check manually and try again."
331
+ fi
332
+ fi
333
+ }
334
+
335
+ migrate_legacy_venv
336
+
337
+ # Check if dependencies need to be installed
313
338
  if check_deps_installed; then
314
- log_info "依赖已安装且完整,跳过pip install(加速重启)"
315
- source .venv/bin/activate
339
+ log_info "Dependencies are installed and complete, jump overpip install(accelerated restart)"
340
+ # shellcheck disable=SC1091
341
+ source "$VENV_DIR/bin/activate"
316
342
  else
317
- log_info "首次启动或依赖缺失,正在安装依赖..."
343
+ log_info "First startup or missing dependencies, installing dependencies..."
318
344
 
319
- # 创建或重建虚拟环境
320
- "$PYTHON_BIN" -m venv .venv
321
- source .venv/bin/activate
345
+ # Create or rebuild a virtual environment
346
+ "$PYTHON_BIN" -m venv "$VENV_DIR"
347
+ # shellcheck disable=SC1091
348
+ source "$VENV_DIR/bin/activate"
322
349
 
323
- # 安装依赖
324
- # pip 输出重定向到日志文件,避免 BrokenPipe 错误
325
- log_info "开始执行 pip install -r $REQUIREMENTS_FILE"
350
+ # Install dependencies
351
+ # Redirect pip output to log file to avoid BrokenPipe errors
352
+ log_info "Start executing pip install -r $REQUIREMENTS_FILE"
326
353
  PIP_LOG_FILE="$LOG_DIR/pip_install_$(date +%Y%m%d_%H%M%S).log"
327
354
  if pip install -r "$REQUIREMENTS_FILE" > "$PIP_LOG_FILE" 2>&1; then
328
- log_info "依赖安装完成"
355
+ log_info "Dependency installation completed"
329
356
  else
330
357
  PIP_EXIT_CODE=$?
331
- log_error "pip install 失败,退出码=$PIP_EXIT_CODE,详见 $PIP_LOG_FILE"
332
- # 如果是 BrokenPipe (退出码 141),验证依赖是否实际已安装
358
+ log_error "pip install Failure, exit code=$PIP_EXIT_CODE, See details $PIP_LOG_FILE"
359
+ # If it is BrokenPipe (Exit code 141), Verify that dependencies are actually installed
333
360
  if [[ $PIP_EXIT_CODE -eq 141 ]]; then
334
- log_info "检测到 BrokenPipe 错误,验证依赖完整性..."
335
- # 验证关键依赖包是否可导入
336
- if "$ROOT_DIR/.venv/bin/python" -c "import aiogram, aiohttp, aiosqlite" 2>/dev/null; then
337
- log_info "依赖验证通过,BrokenPipe 可忽略,继续执行"
361
+ log_info "BrokenPipe error detected, dependency integrity verified..."
362
+ # Verify whether key dependency packages can be imported
363
+ if "$VENV_DIR/bin/python" -c "import aiogram, aiohttp, aiosqlite" 2>/dev/null; then
364
+ log_info "Dependency verification passed, BrokenPipe can be ignored and execution continues."
338
365
  else
339
- log_error "依赖验证失败,虽然是 BrokenPipe 但依赖未完整安装"
366
+ log_error "Dependency verification failed. Although it is BrokenPipe, the dependency is not completely installed."
340
367
  exit 1
341
368
  fi
342
369
  else
343
- # 其他错误直接退出
370
+ # If there are other errors, exit directly.
344
371
  exit $PIP_EXIT_CODE
345
372
  fi
346
373
  fi
347
374
  fi
348
375
 
349
- # 后台启动 master,日志落在 vibe.log
350
- # 显式传递重启标记环境变量(如果存在)
376
+ # Start the master in the background, and the log falls in vibe.log
377
+ # Explicitly pass the restart flag environment variable if present
351
378
  if [[ -n "${MASTER_RESTART_EXPECTED:-}" ]]; then
352
- log_info "检测到重启标记环境变量 MASTER_RESTART_EXPECTED=$MASTER_RESTART_EXPECTED"
379
+ log_info "Restart flag environment variable MASTER detected_RESTART_EXPECTED=$MASTER_RESTART_EXPECTED"
353
380
  export MASTER_RESTART_EXPECTED
354
381
  fi
355
382
 
356
- log_info "准备启动 master 进程..."
383
+ log_info "Prepare to start the master process..."
357
384
 
358
- # 清理旧的错误日志(保留最近 10 次)
385
+ # Clean old error logs (keep the last 10)
359
386
  cleanup_old_error_logs() {
360
387
  local error_log_pattern="$LOG_DIR/master_error_*.log"
361
388
  local error_logs
@@ -366,7 +393,7 @@ cleanup_old_error_logs() {
366
393
  ((count++))
367
394
  if (( count > 10 )); then
368
395
  rm -f "$logfile"
369
- log_info "已清理旧错误日志: $logfile"
396
+ log_info "Cleaned old error logs: $logfile"
370
397
  fi
371
398
  done <<< "$error_logs"
372
399
  fi
@@ -374,73 +401,73 @@ cleanup_old_error_logs() {
374
401
 
375
402
  cleanup_old_error_logs
376
403
 
377
- # 创建带时间戳的错误日志文件
404
+ # Create a timestamped error log file
378
405
  MASTER_ERROR_LOG="$LOG_DIR/master_error_$(date +%Y%m%d_%H%M%S).log"
379
406
  MASTER_STDOUT_LOG="$LOG_DIR/master_stdout.log"
380
407
 
381
- # 显式传递环境变量给 nohup 进程,确保重启信号文件路径正确
382
- # 使用虚拟环境的 Python 解释器,避免版本不匹配导致依赖加载失败
383
- # 重要:将 stderr 保存到日志文件,方便排查启动失败问题
384
- MASTER_RESTART_SIGNAL_PATH="$MASTER_RESTART_SIGNAL_PATH" nohup "$ROOT_DIR/.venv/bin/python" master.py > "$MASTER_STDOUT_LOG" 2> "$MASTER_ERROR_LOG" &
408
+ # Explicitly pass environment variables to the nohup process to ensure that the restart signal file path is correct
409
+ # Using virtual environment Python interpreter, avoidVersionMismatch causes dependency loading to fail
410
+ # Important: Save stderr to a log file to facilitate troubleshooting startup failures.
411
+ MASTER_RESTART_SIGNAL_PATH="$MASTER_RESTART_SIGNAL_PATH" nohup "$VENV_DIR/bin/python" master.py > "$MASTER_STDOUT_LOG" 2> "$MASTER_ERROR_LOG" &
385
412
  MASTER_PID=$!
386
413
 
387
- # 健壮性检查:确保进程成功启动
414
+ # Robustness check: ensure processsuccessstart up
388
415
  if [[ -z "${MASTER_PID:-}" ]]; then
389
- log_error " 无法获取 master 进程 PID,启动失败"
390
- log_error "可能原因:python 命令不可用或 master.py 有语法错误"
416
+ log_error "ERROR: Unable to obtain master process PID; startup failed"
417
+ log_error "Possible reasons: python command is not available or master.py There are grammatical errors"
391
418
  exit 1
392
419
  fi
393
420
 
394
- # 短暂等待后检查进程是否仍在运行
421
+ # Check if the process is still running after a short wait
395
422
  sleep 0.5
396
423
  if ! kill -0 "$MASTER_PID" 2>/dev/null; then
397
- log_error " master 进程启动后立即退出(PID=$MASTER_PID"
398
- log_error "请检查:"
399
- log_error " - master.py 是否有语法错误: python master.py"
400
- log_error " - 依赖是否完整: pip list | grep aiogram"
401
- log_error " - 错误日志: $MASTER_ERROR_LOG"
424
+ log_error "ERROR: Master process exited immediately after starting (PID=$MASTER_PID)"
425
+ log_error "Check, please:"
426
+ log_error " - master.py whetherThere are grammatical errors: python master.py"
427
+ log_error " - Are dependencies complete?: pip list | grep aiogram"
428
+ log_error " - error log: $MASTER_ERROR_LOG"
402
429
 
403
- # 输出错误日志的最后 20 行,帮助快速定位问题
430
+ # outputerror logthe end 20 OK, Help locate problems quickly
404
431
  if [[ -s "$MASTER_ERROR_LOG" ]]; then
405
432
  log_error ""
406
- log_error "=== 错误日志最后 20 ==="
433
+ log_error "=== error logat last 20 OK ==="
407
434
  tail -20 "$MASTER_ERROR_LOG" | while IFS= read -r line; do
408
435
  log_error " $line"
409
436
  done
410
437
  log_error "=========================="
411
438
  else
412
- log_error "错误日志文件为空,可能是环境变量或路径问题"
439
+ log_error "error logFile is empty, It may be an environment variable or path problem"
413
440
  fi
414
441
 
415
442
  exit 1
416
443
  fi
417
444
 
418
- log_info "master 已后台启动,PID=$MASTER_PID,日志写入 ${LOG_FILE}"
445
+ log_info "master Started in background, PID=$MASTER_PID, Log writing ${LOG_FILE}"
419
446
 
420
- # 健康检查:等待 master 上线并验证关键 worker
421
- log_info "开始执行健康检查..."
447
+ # Health check: wait for master to come online and verify key workers
448
+ log_info "Start master readiness check..."
422
449
  HEALTHCHECK_START=$(date +%s)
423
450
 
424
- if python scripts/master_healthcheck.py --project hyphavibebotbackend; then
451
+ if python scripts/master_healthcheck.py --master-log "$LOG_FILE"; then
425
452
  HEALTHCHECK_END=$(date +%s)
426
453
  HEALTHCHECK_DURATION=$((HEALTHCHECK_END - HEALTHCHECK_START))
427
- log_info " master 健康检查通过,耗时 ${HEALTHCHECK_DURATION}s"
454
+ log_info "OK: Master readiness confirmed (elapsed ${HEALTHCHECK_DURATION}s)"
428
455
  else
429
456
  HEALTHCHECK_END=$(date +%s)
430
457
  HEALTHCHECK_DURATION=$((HEALTHCHECK_END - HEALTHCHECK_START))
431
- log_error "⚠️ master 健康检查失败,耗时 ${HEALTHCHECK_DURATION}s"
432
- log_error "建议检查:"
433
- log_error " - 进程状态: ps aux | grep 'python.*master.py'"
434
- log_error " - 启动日志: tail -100 $LOG_DIR/start.log"
435
- log_error " - 运行日志: tail -100 $LOG_FILE"
436
- log_error " - 进程 PID: $MASTER_PID"
437
-
438
- # 检查进程是否仍在运行
458
+ log_error "⚠️ master Health check failed, time consuming ${HEALTHCHECK_DURATION}s"
459
+ log_error "It is recommended to check:"
460
+ log_error " - process status: ps aux | grep 'python.*master.py'"
461
+ log_error " - Startup log: tail -100 $LOG_DIR/start.log"
462
+ log_error " - Run log: tail -100 $LOG_FILE"
463
+ log_error " - Process PID: $MASTER_PID"
464
+
465
+ # Check if the process is still running
439
466
  if kill -0 "$MASTER_PID" 2>/dev/null; then
440
- log_info "master 进程仍在运行(PID=$MASTER_PID),允许继续启动"
441
- log_info "⚠️ 请手动验证服务是否正常工作"
467
+ log_info "master The process is still running (PID=$MASTER_PID), Allow startup to continue"
468
+ log_info "⚠️ Please manually verify that the service is working properly"
442
469
  else
443
- log_error " master 进程已退出,启动失败"
470
+ log_error "ERROR: Master process exited and failed to start"
444
471
  exit 1
445
472
  fi
446
473
  fi
@@ -18,8 +18,13 @@ MODEL_WORKDIR="${MODEL_WORKDIR:-$ROOT_DIR}"
18
18
  MODEL_SESSION_ROOT="${MODEL_SESSION_ROOT:-${CODEX_SESSION_ROOT:-$HOME/.codex/sessions}}"
19
19
  MODEL_SESSION_GLOB="${MODEL_SESSION_GLOB:-rollout-*.jsonl}"
20
20
  SESSION_POINTER_FILE="${SESSION_POINTER_FILE:-$LOG_ROOT/${MODEL_NAME:-codex}/${PROJECT_NAME:-project}/current_session.txt}"
21
+ SESSION_LOCK_FILE="${SESSION_LOCK_FILE:-${SESSION_POINTER_FILE%.txt}.lock.json}"
22
+ SESSION_CAPTURE_TIMEOUT="${SESSION_CAPTURE_TIMEOUT:-180}"
23
+ SESSION_CAPTURE_POLL_INTERVAL="${SESSION_CAPTURE_POLL_INTERVAL:-0.5}"
24
+ # Ensure optional CODEX session root is always defined even under `set -u`
25
+ : "${CODEX_SESSIONS_ROOT:=}"
21
26
 
22
- # 避免 oh-my-zsh 在非交互环境弹出更新提示
27
+ # Avoid oh-my-zsh popping up update prompts in non-interactive environments
23
28
  export DISABLE_UPDATE_PROMPT="${DISABLE_UPDATE_PROMPT:-true}"
24
29
 
25
30
  expand_path() {
@@ -40,7 +45,7 @@ KILL_SESSION=0
40
45
 
41
46
  usage() {
42
47
  cat <<USAGE
43
- 用法:${0##*/} [--dry-run] [--force] [--restart] [--kill]
48
+ usage:${0##*/} [--dry-run] [--force] [--restart] [--kill]
44
49
  USAGE
45
50
  }
46
51
 
@@ -51,13 +56,13 @@ while [[ $# -gt 0 ]]; do
51
56
  --restart) RESTART=1; FORCE_START=1 ;;
52
57
  --kill) KILL_SESSION=1 ;;
53
58
  -h|--help) usage; exit 0 ;;
54
- *) echo "未知参数: $1" >&2; usage; exit 1 ;;
59
+ *) echo "unknown parameters: $1" >&2; usage; exit 1 ;;
55
60
  esac
56
61
  shift
57
62
  done
58
63
 
59
64
  if ! command -v tmux >/dev/null 2>&1; then
60
- echo "tmux 未安装" >&2
65
+ echo "tmux Not installed" >&2
61
66
  exit 1
62
67
  fi
63
68
 
@@ -67,6 +72,7 @@ MODEL_SESSION_ROOT=$(expand_path "$MODEL_SESSION_ROOT")
67
72
  SESSION_POINTER_FILE=$(expand_path "$SESSION_POINTER_FILE")
68
73
  ensure_dir "$(dirname "$LOG_PATH")"
69
74
  ensure_dir "$(dirname "$SESSION_POINTER_FILE")"
75
+ ensure_dir "$(dirname "$SESSION_LOCK_FILE")"
70
76
 
71
77
  run_tmux() {
72
78
  if (( DRY_RUN )); then
@@ -98,12 +104,12 @@ else
98
104
  fi
99
105
  fi
100
106
 
101
- # 启动前先进行一次清理,避免旧日志超限
107
+ # Clean up before starting to avoid old logs exceeding the limit.
102
108
  if ! env \
103
109
  MODEL_LOG_MAX_BYTES="$MODEL_LOG_MAX_BYTES" \
104
110
  MODEL_LOG_RETENTION_SECONDS="$MODEL_LOG_RETENTION_SECONDS" \
105
111
  "$PYTHON_EXEC" "$LOG_WRITER" "$LOG_PATH" </dev/null; then
106
- echo "预处理日志文件失败" >&2
112
+ echo "Preprocessing log file failed" >&2
107
113
  exit 1
108
114
  fi
109
115
 
@@ -115,7 +121,7 @@ printf -v PIPE_CMD 'env MODEL_LOG_MAX_BYTES=%q MODEL_LOG_RETENTION_SECONDS=%q %q
115
121
  "$LOG_PATH"
116
122
  run_tmux pipe-pane -o -t "$SESSION_NAME" "$PIPE_CMD"
117
123
 
118
- # 同步环境变量到 tmux 服务端,避免复用旧会话时丢失设置
124
+ # Synchronize environment variables to the tmux server to avoid losing settings when reusing old sessions
119
125
  run_tmux set-environment -t "$SESSION_NAME" DISABLE_UPDATE_PROMPT "${DISABLE_UPDATE_PROMPT:-true}"
120
126
  if [[ -n "${CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING:-}" ]]; then
121
127
  run_tmux set-environment -t "$SESSION_NAME" CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING "${CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING}"
@@ -138,10 +144,29 @@ fi
138
144
 
139
145
 
140
146
  if (( DRY_RUN )); then
141
- printf '[dry-run] 会话日志路径: %s\n' "$SESSION_POINTER_FILE"
147
+ printf '[dry-run] Session log path: %s\n' "$SESSION_POINTER_FILE"
142
148
  exit 0
143
149
  fi
144
150
 
145
151
  : > "$SESSION_POINTER_FILE"
152
+ rm -f "$SESSION_LOCK_FILE"
153
+
154
+ if (( ! DRY_RUN )); then
155
+ WATCH_ARGS=("$PYTHON_EXEC" "$ROOT_DIR/scripts/session_pointer_watch.py" "--pointer" "$SESSION_POINTER_FILE" "--lock" "$SESSION_LOCK_FILE" "--glob" "$MODEL_SESSION_GLOB" "--workdir" "$MODEL_WORKDIR" "--tmux-session" "$SESSION_NAME" "--project" "${PROJECT_NAME:-}")
156
+ if [[ -n "$MODEL_SESSION_ROOT" ]]; then
157
+ WATCH_ARGS+=("--session-root" "$MODEL_SESSION_ROOT")
158
+ fi
159
+ if [[ -n "$CODEX_SESSIONS_ROOT" ]]; then
160
+ WATCH_ARGS+=("--additional-root" "$CODEX_SESSIONS_ROOT")
161
+ fi
162
+ WATCH_ARGS+=("--additional-root" "$(dirname "$SESSION_POINTER_FILE")")
163
+ WATCH_ARGS+=("--additional-root" "$(dirname "$SESSION_POINTER_FILE")/sessions")
164
+ WATCH_ARGS+=("--timeout" "$SESSION_CAPTURE_TIMEOUT")
165
+ WATCH_ARGS+=("--poll" "$SESSION_CAPTURE_POLL_INTERVAL")
166
+ if ! "${WATCH_ARGS[@]}"; then
167
+ echo "Failed to capture Codex/Claude session log for tmux session '$SESSION_NAME'. Please check CLI startup output." >&2
168
+ exit 1
169
+ fi
170
+ fi
146
171
 
147
172
  exit 0