// Interaction Awareness — SessionEnd hook (Layer 2, Node.js) // Finalizes session record, computes duration, cleans up state. import { existsSync } from 'fs'; import { readStdin, initConfig, requireLayer, getSessionId, nowEpoch, nowIso, STATE_DIR, SESSIONS_LOG, readState, sessionStateFile, appendJsonl, removeFile } from './lib.mjs'; readStdin(); initConfig(); requireLayer(2); const sid = getSessionId(); if (!sid) process.exit(0); const nowTs = nowEpoch(); const nowIsoStr = nowIso(); const sf = sessionStateFile(); if (!existsSync(sf)) { appendJsonl(SESSIONS_LOG, { session_id: sid, end: nowIsoStr, note: 'no_state_file' }); process.exit(0); } // Read final state const state = readState(); const startEpoch = Number(state.start_epoch) || 0; const toolCount = Number(state.tool_count) || 0; const editCount = Number(state.edit_count) || 0; const depFlags = Number(state.dep_flags) || 0; const escFlags = Number(state.esc_flags) || 0; const fatFlags = Number(state.fatigue_flags) || 0; const valFlags = Number(state.val_flags) || 0; const startIso = state.start_iso || ''; // Compute duration let durationMin = 0; if (startEpoch > 0) { durationMin = Math.floor((nowTs - startEpoch) / 60); } // Append finalized session record appendJsonl(SESSIONS_LOG, { session_id: sid, start: startIso, end: nowIsoStr, duration_min: durationMin, tool_count: toolCount, edit_count: editCount, flags: { dependency: depFlags, escalation: escFlags, fatigue: fatFlags, validation: valFlags } }); // Clean up state file removeFile(sf); process.exit(0);