import { q as assertProjectInitialized } from './paths-2M_UxD_H.js';
import { join } from 'node:path';
import { mkdir, appendFile, readdir, readFile, writeFile, unlink } from 'node:fs/promises';
import 'node:fs';
import 'node:os';
import 'node:events';
import 'node:diagnostics_channel';
import 'fs';
import 'events';
import 'util';
import 'path';
import 'assert';
import 'worker_threads';
import 'module';
import 'node:url';
import 'url';
import 'buffer';
import 'node:module';
import 'node:child_process';
import 'node:crypto';
import 'node:process';
import 'node:async_hooks';

//#region ../core/dist/sessions/session-journal.js
/**
* Session Journal — append-only JSONL writer for `.cleo/session-journals/`.
*
* Provides the core read/write primitives for the session journal substrate
* (T1263 PSYCHE E6). Journals are the 7th CLEO system — they log the other
* six (TASKS, LOOM, BRAIN, NEXUS, CANT, CONDUIT) at session boundaries.
*
* ## File layout
*
* ```
* .cleo/session-journals/
*   2026-04-24.jsonl    ← today — all sessions append here
*   2026-04-23.jsonl    ← yesterday
*   ...
* ```
*
* Each file is append-only JSONL (one JSON object per line terminated by `\n`).
* Multiple simultaneous sessions append to the same daily file safely via
* `appendFile` which uses O_APPEND — atomic for writes under ~4 KB on ext4/APFS.
* No shared file handle; each call opens/appends/closes independently.
*
* ## Retention
*
* | Tier    | Age       | Disposition                               |
* |---------|-----------|-------------------------------------------|
* | Hot     | 0–7 days  | All entries retained verbatim             |
* | Warm    | 8–30 days | Retain `session_end` entries only         |
* | Archive | 31–90 days| Monthly rollup; individual files deleted  |
* | Purge   | >90 days  | Monthly rollups deleted                   |
*
* @module sessions/session-journal
* @task T1263
* @epic T1075
* @see packages/contracts/src/session-journal.ts — schema + types
* @see .cleo/adrs/ADR-013 §9 — runtime-data-safety (no git tracking)
*/
/** Subdirectory under `.cleo/` that stores session journal JSONL files. */
var SESSION_JOURNALS_DIR = "session-journals";
/** Number of hot-tier days (files younger than this are fully retained). */
var HOT_TIER_DAYS = 7;
/** Number of warm-tier days (files between hot and warm retain session_end only). */
var WARM_TIER_DAYS = 30;
/** Number of archive-tier days (files older than this are purged). */
var ARCHIVE_TIER_DAYS = 90;
/**
* Resolve the absolute path to a session journal JSONL file for a given date.
*
* Daily rotation: one file per calendar day. Multiple sessions append to the
* same file; reads scan recent files in reverse-date order.
*
* @param projectRoot - Absolute path to the project root.
* @param date - Target date. Defaults to today (UTC).
* @returns Absolute path to `<projectRoot>/.cleo/session-journals/YYYY-MM-DD.jsonl`.
*
* @example
* ```typescript
* const path = getSessionJournalPath('/my/project');
* // → '/my/project/.cleo/session-journals/2026-04-24.jsonl'
* ```
*/
function getSessionJournalPath(projectRoot, date) {
	return join(projectRoot, ".cleo", SESSION_JOURNALS_DIR, `${(date ?? /* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
}
/**
* Resolve the absolute path to the session-journals directory.
*
* @param projectRoot - Absolute path to the project root.
* @returns Absolute path to `<projectRoot>/.cleo/session-journals/`.
*/
function getSessionJournalsDir(projectRoot) {
	return join(projectRoot, ".cleo", SESSION_JOURNALS_DIR);
}
/**
* Append a single session journal entry to the daily JSONL file.
*
* - Creates the `.cleo/session-journals/` directory if it does not exist
*   (idempotent via `mkdir({recursive:true})`).
* - Appends a single JSON line terminated by `\n` using O_APPEND atomicity.
* - Safe for concurrent writes from multiple processes (worktree sessions).
*
* @param projectRoot - Absolute path to the project root.
* @param entry - Journal entry to append. Must pass `sessionJournalEntrySchema`.
* @param date - Target date file. Defaults to today (UTC).
*
* @throws If the filesystem write fails (disk full, permissions, etc.).
*         Callers MUST wrap in try/catch and handle gracefully — journal
*         writes must never block session lifecycle operations.
*
* @example
* ```typescript
* await appendSessionJournalEntry('/my/project', {
*   schemaVersion: '1.0',
*   timestamp: new Date().toISOString(),
*   sessionId: 'ses_20260424_abc',
*   eventType: 'session_start',
*   agentIdentifier: 'claude-code',
*   scope: 'global',
* });
* ```
*/
async function appendSessionJournalEntry(projectRoot, entry, date) {
	const filePath = getSessionJournalPath(projectRoot, date);
	assertProjectInitialized(projectRoot);
	await mkdir(join(projectRoot, ".cleo", SESSION_JOURNALS_DIR), { recursive: true });
	await appendFile(filePath, `${JSON.stringify(entry)}\n`, { encoding: "utf-8" });
}
/**
* Read the most recent session journal entries across the N most recent daily files.
*
* Scans up to `maxFiles` dated `.jsonl` files in reverse-date order, collecting
* up to `maxEntries` total entries (most recent entries first). Used by
* `initProject` to surface recent session context for the meta-agent.
*
* Unknown schema versions are silently skipped (forward-compatible).
*
* @param projectRoot - Absolute path to the project root.
* @param maxEntries - Maximum total entries to return. Default: 20.
* @param maxFiles - Maximum number of daily files to scan. Default: 5.
* @returns Array of journal entries in reverse-chronological order (newest first).
*          Returns empty array if the journals directory does not exist or is empty.
*
* @example
* ```typescript
* const entries = await readRecentJournals('/my/project', 10);
* ```
*/
async function readRecentJournals(projectRoot, maxEntries = 20, maxFiles = 5) {
	const journalsDir = getSessionJournalsDir(projectRoot);
	let files;
	try {
		files = (await readdir(journalsDir)).filter((f) => f.endsWith(".jsonl") && /^\d{4}-\d{2}-\d{2}\.jsonl$/.test(f)).sort().reverse().slice(0, maxFiles);
	} catch {
		return [];
	}
	const result = [];
	for (const file of files) {
		if (result.length >= maxEntries) break;
		try {
			const lines = (await readFile(join(journalsDir, file), "utf-8")).split("\n").filter((line) => line.trim().length > 0).reverse();
			for (const line of lines) {
				if (result.length >= maxEntries) break;
				try {
					const entry = JSON.parse(line);
					if (entry && typeof entry === "object" && "schemaVersion" in entry) result.push(entry);
				} catch {}
			}
		} catch {}
	}
	return result;
}
/**
* Apply the session journal retention policy to `.cleo/session-journals/`.
*
* Tiers (relative to current UTC date):
*
* | Tier    | Age       | Action                                              |
* |---------|-----------|-----------------------------------------------------|
* | Hot     | 0–7 days  | No-op — all entries retained verbatim               |
* | Warm    | 8–30 days | Rewrite file keeping only `session_end` entries      |
* | Archive | 31–90 days| Delete the individual file (rollup future work)      |
* | Purge   | >90 days  | Delete the file (already archived or stale)          |
*
* Errors for individual files are caught and the rotation continues.
* If the journals directory does not exist, returns immediately (no-op).
*
* @param projectRoot - Absolute path to the project root.
* @param opts - Optional tier cutoff overrides (for testing).
*
* @example
* ```typescript
* await rotateSessionJournals('/my/project');
* ```
*/
async function rotateSessionJournals(projectRoot, opts = {}) {
	const hotDays = opts.hotDays ?? HOT_TIER_DAYS;
	const warmDays = opts.warmDays ?? WARM_TIER_DAYS;
	const archiveDays = opts.archiveDays ?? ARCHIVE_TIER_DAYS;
	const journalsDir = getSessionJournalsDir(projectRoot);
	let files;
	try {
		files = (await readdir(journalsDir)).filter((f) => f.endsWith(".jsonl") && /^\d{4}-\d{2}-\d{2}\.jsonl$/.test(f));
	} catch {
		return;
	}
	const now = Date.now();
	const MS_PER_DAY = 1440 * 60 * 1e3;
	for (const file of files) {
		const filePath = join(journalsDir, file);
		const dateStr = file.replace(".jsonl", "");
		const fileDate = /* @__PURE__ */ new Date(`${dateStr}T00:00:00.000Z`);
		if (Number.isNaN(fileDate.getTime())) continue;
		const ageDays = (now - fileDate.getTime()) / MS_PER_DAY;
		try {
			if (ageDays <= hotDays) {} else if (ageDays <= warmDays) {
				const lines = (await readFile(filePath, "utf-8")).split("\n").filter((l) => l.trim().length > 0);
				const filtered = lines.filter((line) => {
					try {
						return JSON.parse(line)?.eventType === "session_end";
					} catch {
						return false;
					}
				});
				if (filtered.length !== lines.length) await writeFile(filePath, filtered.map((l) => `${l}\n`).join(""), { encoding: "utf-8" });
			} else if (ageDays <= archiveDays) await unlink(filePath);
			else await unlink(filePath);
		} catch {}
	}
}

export { appendSessionJournalEntry, readRecentJournals, rotateSessionJournals };
//# sourceMappingURL=session-journal-Br8tw7nG.js.map
