import { i as writeTextAtomic } from "./json-files-kvH2Eboc.js";
import { existsSync } from "node:fs";
import { join } from "node:path";
import { mkdir, readFile, readdir, rename, stat } from "node:fs/promises";
import { z } from "zod";
//#region src/cognitive/persona/persona-schema.ts
const insightCategorySchema = z.enum([
	"domain_knowledge",
	"behavioral_pattern",
	"stated_preference",
	"tool_config",
	"contextual_fact",
	"goal_or_aspiration"
]);
const typedInsightSchema = z.object({
	text: z.string(),
	category: insightCategorySchema,
	confidence: z.number(),
	source: z.enum([
		"explicit",
		"inferred",
		"observed"
	]),
	firstObserved: z.number(),
	lastReinforced: z.number(),
	evidenceCount: z.number(),
	halfLifeDays: z.number()
});
const interestPhaseSchema = z.enum([
	"emergent",
	"stable",
	"declining",
	"dormant",
	"revived"
]);
const confidenceValueSchema = z.object({
	value: z.unknown(),
	confidence: z.number(),
	evidenceCount: z.number(),
	lastUpdated: z.number(),
	source: z.enum([
		"explicit",
		"inferred",
		"observed"
	])
});
const communicationStyleSchema = z.object({
	formality: z.enum([
		"formal",
		"casual",
		"mixed"
	]),
	verbosity: z.enum([
		"concise",
		"moderate",
		"detailed"
	]),
	technicalLevel: z.enum([
		"beginner",
		"intermediate",
		"expert"
	]),
	preferredLanguage: z.enum([
		"zh",
		"en",
		"mixed"
	])
});
const domainNodeSchema = z.object({
	depth: z.number(),
	recurrence: z.number(),
	lastMentioned: z.number(),
	keyInsights: z.array(z.string()),
	insights: z.array(typedInsightSchema).optional(),
	activeQuestions: z.array(z.string()),
	negationSignals: z.number().optional().default(0),
	lastNegatedAt: z.number().optional(),
	phase: interestPhaseSchema.optional(),
	phaseEnteredAt: z.number().optional()
});
const topicBanditSchema = z.object({
	alpha: z.number(),
	beta: z.number(),
	lastUpdated: z.number().optional()
});
const feedbackProfileSchema = z.object({
	topicBandits: z.record(z.string(), topicBanditSchema),
	optimalFrequencyHours: z.number(),
	lastProactiveAt: z.number(),
	suppressUntil: z.number().optional(),
	recentInsightIds: z.array(z.string()).optional().default([]),
	recentInsightContents: z.array(z.string()).optional().default([]),
	recentInsightDomains: z.array(z.array(z.string())).optional().default([]),
	recentInsightTypes: z.array(z.string()).optional().default([]),
	recentInsightQueryHistory: z.array(z.string()).optional().default([]),
	promptBandits: z.record(z.string(), topicBanditSchema).optional(),
	modeBandits: z.record(z.string(), topicBanditSchema).optional(),
	consecutiveNoResponses: z.number().optional(),
	recentInsightModes: z.array(z.string()).optional().default([])
});
const rapportMetricsSchema = z.object({
	trustScore: z.number().min(0).max(1),
	totalExchanges: z.number(),
	avgResponseLength: z.number(),
	selfDisclosureLevel: z.number().min(0).max(1)
});
const userLifecycleSchema = z.object({
	stage: z.enum([
		"new",
		"active",
		"dormant",
		"lapsed"
	]).optional().default("new"),
	lastActiveAt: z.number().optional().default(0),
	lastStageTransitionAt: z.number().optional().default(0),
	totalActiveDays: z.number().optional().default(0)
});
const calibrationRecordSchema = z.object({
	insightId: z.string(),
	predictedPAccept: z.number(),
	actualOutcome: z.enum([
		"positive",
		"negative",
		"neutral",
		"engaged",
		"no_response"
	]),
	timestamp: z.number()
});
const personaTreeSchema = z.object({
	identity: z.object({
		displayName: z.string().optional(),
		coreTraits: z.record(z.string(), confidenceValueSchema),
		communicationStyle: communicationStyleSchema.optional(),
		primaryLanguage: z.string().optional(),
		expertDomains: z.array(z.string()),
		interestDomains: z.array(z.string()),
		curiosityDomains: z.array(z.string())
	}),
	domains: z.record(z.string(), domainNodeSchema),
	recentFocus: z.array(z.string()),
	feedbackProfile: feedbackProfileSchema,
	rapport: rapportMetricsSchema,
	domainBlacklist: z.array(z.string()).optional().default([]),
	lifecycle: userLifecycleSchema.optional().default({
		stage: "new",
		lastActiveAt: 0,
		lastStageTransitionAt: 0,
		totalActiveDays: 0
	}),
	moodHistory: z.array(z.any()).optional().default([]),
	calibrationHistory: z.array(calibrationRecordSchema).optional().default([])
}).strip();
function safeParsePersona(json) {
	const result = personaTreeSchema.safeParse(json);
	if (!result.success) return null;
	return result.data;
}
//#endregion
//#region src/cognitive/persona/store.ts
const COGNITIVE_DIR = "cognitive";
const PERSONA_DIR = "persona";
const MIGRATION_SKIP_USER_IDS = new Set([
	"main",
	"kaijibot-tui",
	"slug-generator"
]);
function backfillStalePhases(persona) {
	const now = Date.now();
	const SEVEN_DAYS_MS = 10080 * 60 * 1e3;
	for (const domain of Object.values(persona.domains)) {
		const insightCount = domain.keyInsights.length + (domain.insights?.length ?? 0);
		if (domain.phase === "emergent" && (domain.depth >= 2 || insightCount >= 3)) {
			if (now - domain.lastMentioned < SEVEN_DAYS_MS) {
				domain.phase = "stable";
				domain.phaseEnteredAt ??= domain.lastMentioned;
			}
		}
	}
}
function inferPhase(domain) {
	const age = Date.now() - domain.lastMentioned;
	const dayMs = 864e5;
	if (domain.depth <= 1 && domain.recurrence <= 1) return {
		phase: "emergent",
		phaseEnteredAt: domain.lastMentioned
	};
	if (domain.negationSignals >= 3) return {
		phase: "declining",
		phaseEnteredAt: domain.lastNegatedAt ?? domain.lastMentioned
	};
	if (age > 30 * dayMs) return {
		phase: "dormant",
		phaseEnteredAt: domain.lastMentioned + 30 * dayMs
	};
	return {
		phase: "stable",
		phaseEnteredAt: domain.lastMentioned
	};
}
function migrateToTypedInsights(persona) {
	for (const domain of Object.values(persona.domains)) {
		if (domain.insights && domain.insights.length > 0) continue;
		domain.insights = domain.keyInsights.map((text) => ({
			text,
			category: "domain_knowledge",
			confidence: .5,
			source: "inferred",
			firstObserved: domain.lastMentioned,
			lastReinforced: domain.lastMentioned,
			evidenceCount: 1,
			halfLifeDays: 30
		}));
		if (domain.phase === void 0) {
			const { phase, phaseEnteredAt } = inferPhase(domain);
			domain.phase = phase;
			domain.phaseEnteredAt = phaseEnteredAt;
		}
	}
	return persona;
}
function shouldMigrateFlatFile(userId, persona) {
	if (MIGRATION_SKIP_USER_IDS.has(userId)) return false;
	if (!persona) return false;
	if (userId.startsWith("ou_")) return true;
	return Object.keys(persona.domains).length > 0 || persona.rapport.totalExchanges > 0;
}
var PersonaStore = class {
	constructor(configDir) {
		this.configDir = configDir;
	}
	/**
	* Migrate legacy flat persona files from `persona/{userId}.json`
	* to the new directory layout `persona/main/{userId}.json`.
	* Safe to call multiple times — no-ops if already migrated.
	*/
	async migrateFromFlatLayout() {
		const personaDir = join(this.configDir, COGNITIVE_DIR, PERSONA_DIR);
		if (!existsSync(personaDir)) return {
			migrated: [],
			skipped: []
		};
		const jsonFiles = (await readdir(personaDir)).filter((name) => name.endsWith(".json"));
		if (jsonFiles.length === 0) return {
			migrated: [],
			skipped: []
		};
		const migrated = [];
		const skipped = [];
		for (const fileName of jsonFiles) {
			const userId = fileName.slice(0, -5);
			const srcPath = join(personaDir, fileName);
			const dstPath = this.personaPath("main", userId);
			if (existsSync(dstPath)) {
				skipped.push(userId);
				continue;
			}
			let persona = null;
			try {
				const raw = await readFile(srcPath, "utf-8");
				persona = safeParsePersona(JSON.parse(raw));
			} catch {
				skipped.push(userId);
				continue;
			}
			if (shouldMigrateFlatFile(userId, persona)) {
				await mkdir(join(this.configDir, COGNITIVE_DIR, PERSONA_DIR, "main"), { recursive: true });
				await rename(srcPath, dstPath);
				migrated.push(userId);
			} else skipped.push(userId);
		}
		if (migrated.length > 0) console.info(`[PersonaStore] Migrated ${migrated.length} persona(s) to main/ subdirectory: ${migrated.join(", ")}`);
		return {
			migrated,
			skipped
		};
	}
	personaPath(agentId, userId) {
		return join(this.configDir, COGNITIVE_DIR, PERSONA_DIR, agentId, `${userId}.json`);
	}
	async load(agentId, userId) {
		const path = this.personaPath(agentId, userId);
		if (!existsSync(path)) return;
		const raw = await readFile(path, "utf-8");
		let parsed;
		try {
			parsed = JSON.parse(raw);
		} catch {
			console.warn(`[PersonaStore] Malformed JSON for ${agentId}/${userId}, ignoring`);
			return;
		}
		const validated = safeParsePersona(parsed);
		if (validated === null) {
			console.warn(`[PersonaStore] Invalid persona JSON for ${agentId}/${userId}, ignoring`);
			return;
		}
		if (!validated.identity.userId) validated.identity.userId = userId;
		backfillStalePhases(validated);
		return migrateToTypedInsights(validated);
	}
	async save(agentId, userId, persona) {
		await writeTextAtomic(this.personaPath(agentId, userId), JSON.stringify(persona, null, 2));
	}
	async loadOrCreate(agentId, userId) {
		const existing = await this.load(agentId, userId);
		if (existing) return existing;
		const persona = migrateToTypedInsights(createDefaultPersona());
		persona.identity.userId = userId;
		return persona;
	}
	async listUserIds(agentId) {
		const dir = join(this.configDir, COGNITIVE_DIR, PERSONA_DIR, agentId);
		try {
			return (await readdir(dir)).filter((name) => name.endsWith(".json") && !name.endsWith(".bak")).map((name) => name.slice(0, -5)).filter((userId) => {
				if (userId === agentId) return false;
				if (userId.includes("-control-ui")) return false;
				return true;
			}).toSorted();
		} catch {
			return [];
		}
	}
	async listAgentIds() {
		const dir = join(this.configDir, COGNITIVE_DIR, PERSONA_DIR);
		try {
			const entries = await readdir(dir);
			const result = [];
			for (const name of entries) if ((await stat(join(dir, name))).isDirectory()) result.push(name);
			return result.toSorted();
		} catch {
			return [];
		}
	}
};
function createDefaultPersona() {
	return {
		identity: {
			coreTraits: {},
			expertDomains: [],
			interestDomains: [],
			curiosityDomains: []
		},
		domains: {},
		recentFocus: [],
		moodHistory: [],
		feedbackProfile: {
			topicBandits: {},
			optimalFrequencyHours: 4,
			lastProactiveAt: 0,
			recentInsightIds: [],
			recentInsightContents: [],
			recentInsightDomains: [],
			recentInsightTypes: []
		},
		rapport: {
			trustScore: .1,
			totalExchanges: 0,
			avgResponseLength: 0,
			selfDisclosureLevel: 0
		},
		domainBlacklist: [],
		lifecycle: {
			stage: "new",
			lastActiveAt: 0,
			lastStageTransitionAt: 0,
			totalActiveDays: 0
		},
		calibrationHistory: []
	};
}
//#endregion
export { PersonaStore };
