/** * session-once.js — 会话级执行去重 (P0-2) * 依赖 session-start-restore.js 维护的 .session-restored 文件获取 session_id * 标志文件: session-state/.session-once.json { hookName: sessionId } * 原子写: tmp+rename 防多窗口竞态 */ 'use strict'; const fs = require('fs'); const path = require('path'); let CLAUDE_ROOT; try { CLAUDE_ROOT = require('./root.js'); } catch { CLAUDE_ROOT = path.resolve(__dirname, '..', '..'); } const STATE_DIR = path.join(CLAUDE_ROOT, 'session-state'); const FLAGS_PATH = path.join(STATE_DIR, '.session-once.json'); const SESSION_FILE = path.join(STATE_DIR, '.session-restored'); function getCurrentSessionId() { try { return fs.readFileSync(SESSION_FILE, 'utf8').trim() || ''; } catch { return ''; } } function loadFlags() { try { return JSON.parse(fs.readFileSync(FLAGS_PATH, 'utf8')) || {}; } catch { return {}; } } function saveFlags(flags) { try { if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true }); const tmp = FLAGS_PATH + '.tmp.' + process.pid; fs.writeFileSync(tmp, JSON.stringify(flags), 'utf8'); fs.renameSync(tmp, FLAGS_PATH); } catch {} } function hasRun(hookName) { const sid = getCurrentSessionId(); if (!sid) return false; return loadFlags()[hookName] === sid; } function markRun(hookName) { const sid = getCurrentSessionId(); if (!sid) return; const flags = loadFlags(); flags[hookName] = sid; saveFlags(flags); } module.exports = { hasRun, markRun, getCurrentSessionId };