import * as FS from 'node:fs'; import * as PATH from 'node:path'; import { configDir } from './config.ts'; // What atcli remembers between runs that is neither a setting nor a secret: // where a watch got to (--resume), and the newest item seen in each listing // (--new). One small JSON file beside the config, keyed by account and by // what was listed; it is safe to delete, which only forgets. function stateFile(): string { return PATH.join(configDir(), 'state.json'); } function readAll(): Record { try { return JSON.parse(FS.readFileSync(stateFile(), 'utf-8')) as Record; } catch { return {}; } } export function readState(key: string): string | undefined { return readAll()[key]; } export function writeState(key: string, value: string): void { const state = readAll(); if (state[key] === value) return; state[key] = value; FS.mkdirSync(PATH.dirname(stateFile()), { recursive: true, mode: 0o700 }); const temp = `${stateFile()}.${process.pid}.tmp`; FS.writeFileSync(temp, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 }); FS.renameSync(temp, stateFile()); } /** Forget what is remembered for keys starting with `prefix`; all of it without one. Returns how many. */ export function clearState(prefix = ''): number { const state = readAll(); const gone = Object.keys(state).filter((key) => key.startsWith(prefix)); if (!gone.length) return 0; for (const key of gone) delete state[key]; FS.mkdirSync(PATH.dirname(stateFile()), { recursive: true, mode: 0o700 }); FS.writeFileSync(stateFile(), `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 }); return gone.length; }