diff --git a/src/gateway.ts b/src/gateway.ts index 1e78a0d..4eb097a 100644 --- a/src/gateway.ts +++ b/src/gateway.ts @@ -353,20 +353,21 @@ function buildAttachmentSummaries( // 区分 gateway restart(进程重启)和 health-monitor 断线重连 const accountFirstReadySet = new Set(); -const STARTUP_MARKER_FILE = path.join(getQQBotDataDir("data"), "startup-marker.json"); - /** * 判断是否为首次安装或版本更新,返回对应的问候语。 * - 首次安装 / 版本变更 → "Haha,我的'灵魂'已上线,随时等你吩咐。" * - 普通重启(同版本) → null(不发送) + * + * marker 文件按 accountId 隔离,避免多账号场景下第一个账号写入后其他账号被跳过。 */ -function getStartupGreeting(): string | null { +function getStartupGreeting(accountId: string): string | null { + const markerFile = path.join(getQQBotDataDir("data"), `startup-marker-${accountId}.json`); const currentVersion = getPluginVersion(); let isFirstOrUpdated = true; try { - if (fs.existsSync(STARTUP_MARKER_FILE)) { - const data = JSON.parse(fs.readFileSync(STARTUP_MARKER_FILE, "utf8")); + if (fs.existsSync(markerFile)) { + const data = JSON.parse(fs.readFileSync(markerFile, "utf8")); if (data.version === currentVersion) { isFirstOrUpdated = false; } @@ -382,7 +383,7 @@ function getStartupGreeting(): string | null { // 更新 marker 文件 try { - fs.writeFileSync(STARTUP_MARKER_FILE, JSON.stringify({ + fs.writeFileSync(markerFile, JSON.stringify({ version: currentVersion, startedAt: new Date().toISOString(), greetedAt: new Date().toISOString(), @@ -531,7 +532,7 @@ export async function startGateway(ctx: GatewayContext): Promise { const sendStartupGreetings = (trigger: "READY" | "RESUMED") => { (async () => { try { - const greeting = getStartupGreeting(); + const greeting = getStartupGreeting(account.accountId); if (!greeting) { log?.info(`[qqbot:${account.accountId}] Skipping startup greeting (debounced, trigger=${trigger})`); return; diff --git a/tests/e2e.sh b/tests/e2e.sh index 0b36d60..cb71446 100644 --- a/tests/e2e.sh +++ b/tests/e2e.sh @@ -718,17 +718,33 @@ else record_result "runtime.slash_command_intercepted" "skip" "gateway.log not found" fi -# 8.10 startup-marker.json 文件验证 -MARKER_FILE="$HOME/.openclaw/qqbot/data/startup-marker.json" -if [ -f "$MARKER_FILE" ]; then - MARKER_CONTENT=$(cat "$MARKER_FILE" 2>/dev/null || echo "{}") +# 8.10 startup-marker-{accountId}.json 文件验证(per-account marker) +# 现在每个账号各自有一个 startup-marker 文件 +MARKER_DIR="$HOME/.openclaw/qqbot/data" +MARKER_FOUND=0 +if [ -d "$MARKER_DIR" ]; then + for mf in "$MARKER_DIR"/startup-marker-*.json; do + [ -f "$mf" ] || continue + MARKER_FOUND=1 + MF_BASE=$(basename "$mf") + MARKER_CONTENT=$(cat "$mf" 2>/dev/null || echo "{}") + if echo "$MARKER_CONTENT" | jq -e '.version' &>/dev/null; then + record_result "runtime.startup_marker_valid.${MF_BASE}" "pass" + else + record_result "runtime.startup_marker_valid.${MF_BASE}" "fail" "${MF_BASE} exists but has no 'version' field" + fi + done +fi +# 兼容旧版单文件 marker +if [ "$MARKER_FOUND" -eq 0 ] && [ -f "$MARKER_DIR/startup-marker.json" ]; then + MARKER_CONTENT=$(cat "$MARKER_DIR/startup-marker.json" 2>/dev/null || echo "{}") if echo "$MARKER_CONTENT" | jq -e '.version' &>/dev/null; then - record_result "runtime.startup_marker_valid" "pass" + record_result "runtime.startup_marker_valid" "pass" "(legacy single-file marker)" else record_result "runtime.startup_marker_valid" "fail" "startup-marker.json exists but has no 'version' field" fi -else - record_result "runtime.startup_marker_valid" "skip" "startup-marker.json not yet created (first run may not have completed)" +elif [ "$MARKER_FOUND" -eq 0 ]; then + record_result "runtime.startup_marker_valid" "skip" "no startup-marker files found (first run may not have completed)" fi # 8.11 update-checker 模块单元验证(Node.js import 测试)