flashbacker
Version:
Claude Code state management with session continuity and AI personas
99 lines • 4.23 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.shouldRunSessionAnalysis = shouldRunSessionAnalysis;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const conversation_logs_1 = require("../../utils/conversation-logs");
function getStatePath(projectDir) {
return path_1.default.join(projectDir, '.claude', 'flashback', 'state', 'session-analysis.json');
}
async function readLastRunState(projectDir) {
try {
const p = getStatePath(projectDir);
const raw = await fs_extra_1.default.readFile(p, 'utf-8');
return JSON.parse(raw);
}
catch {
return null;
}
}
async function writeLastRunState(projectDir, state) {
const p = getStatePath(projectDir);
await fs_extra_1.default.ensureDir(path_1.default.dirname(p));
await fs_extra_1.default.writeFile(p, JSON.stringify(state, null, 2));
}
async function countFileLines(filePath) {
try {
const content = await fs_extra_1.default.readFile(filePath, 'utf-8');
return content.split('\n').filter(Boolean).length;
}
catch {
return 0;
}
}
async function shouldRunSessionAnalysis(projectDir, opts = {}) {
const { minMessages = 5, minElapsedMs = 30 * 60 * 1000, minBytesDelta = 4096, keywords = [] } = opts;
const files = await (0, conversation_logs_1.getJSONLFiles)(projectDir);
const latest = files[0];
const prev = files[1];
const now = Date.now();
const last = (await readLastRunState(projectDir)) || { lastRunAtMs: 0, files: {} };
let latestStats = { lines: 0, bytes: 0, mtimeMs: 0 };
let prevStats = { lines: 0, bytes: 0, mtimeMs: 0 };
if (latest) {
const stat = await fs_extra_1.default.stat(latest.path);
latestStats.bytes = stat.size;
latestStats.mtimeMs = stat.mtimeMs;
latestStats.lines = await countFileLines(latest.path);
}
if (prev) {
const stat = await fs_extra_1.default.stat(prev.path);
prevStats.bytes = stat.size;
prevStats.mtimeMs = stat.mtimeMs;
prevStats.lines = await countFileLines(prev.path);
}
const lastLatest = latest ? last.files[latest.path] : undefined;
const bytesDelta = latest && lastLatest ? latestStats.bytes - lastLatest.bytes : latestStats.bytes;
const newMessages = latest && lastLatest ? Math.max(0, latestStats.lines - lastLatest.lines) : latestStats.lines;
const elapsed = now - (last.lastRunAtMs || 0);
let keywordHit = false;
if (keywords.length && latest) {
try {
const content = await fs_extra_1.default.readFile(latest.path, 'utf-8');
const tail = content.split('\n').slice(-Math.max(50, minMessages * 2)).join('\n');
keywordHit = keywords.some(k => new RegExp(k, 'i').test(tail));
}
catch { }
}
const enoughMessages = newMessages >= minMessages;
const enoughElapsed = elapsed >= minElapsedMs;
const enoughBytes = bytesDelta >= minBytesDelta;
const shouldRun = (enoughMessages && enoughElapsed) || keywordHit || (enoughBytes && enoughElapsed);
const reason = shouldRun
? `run: newMsgs=${newMessages} bytesΔ=${bytesDelta} elapsedMs=${elapsed} keywordHit=${keywordHit}`
: `skip: newMsgs=${newMessages} (<${minMessages}) bytesΔ=${bytesDelta} (<${minBytesDelta}) elapsedMs=${elapsed} (<${minElapsedMs}) keywordHit=${keywordHit}`;
const updateState = async () => {
const next = {
lastRunAtMs: now,
files: {
...(last.files || {}),
...(latest ? { [latest.path]: latestStats } : {}),
...(prev ? { [prev.path]: prevStats } : {}),
},
};
await writeLastRunState(projectDir, next);
};
const stats = {
latest: latest?.path || null,
prev: prev?.path || null,
newMessages,
bytesDelta,
elapsedMs: elapsed,
keywordHit,
};
return { shouldRun, reason, stats, updateState };
}
//# sourceMappingURL=significance.js.map
;