import { w as resolveStateDir } from "./paths-BBSTUjD5.js";
import { t as formatCliCommand } from "./command-format-HwSAdvXB.js";
import { p as resolveAgentWorkspaceDir } from "./agent-scope-config-adSj-fCz.js";
import { f as resolveAgentIdFromSessionKey } from "./session-key-FEiNVUl9.js";
import "./agent-scope-CB42Y_8g.js";
import { Kt as executeSqliteQuerySync } from "./openclaw-state-db-Cb4e1jdd.js";
import { V as listOpenClawRegisteredAgentDatabases } from "./openclaw-agent-db-maintenance-C4D8xHaF.js";
import { r as resolveOpenClawAgentSqlitePath } from "./openclaw-agent-db.paths-BAQb87PB.js";
import { g as openOpenClawAgentDatabase, i as closeOpenClawAgentDatabaseByPath, p as isOpenClawAgentDatabaseOpen } from "./openclaw-agent-db-DwEkomYQ.js";
import { t as withOpenClawAgentDatabaseReadOnly } from "./openclaw-agent-db-readonly-BNWG1NV8.js";
import { p as patchSessionEntryCore } from "./session-accessor.sqlite-entry-CoLie3L_.js";
import { s as parseReadableSqliteSessionEntryRow } from "./session-accessor.sqlite-entry-store-B5zyYu48.js";
import { c as resolveSqliteScope, i as getSessionKysely, m as toDatabaseOptions, s as resolveSqliteReadScope } from "./session-accessor.sqlite-scope-I8SegJ8n.js";
import { g as isCanonicalSqliteSessionMainKeyCurrent, v as setCanonicalSqliteSessionMainKey } from "./session-accessor.sqlite-transcript-state-CTvnr6Is.js";
import "./session-accessor-Dwfzn6Ej.js";
import { o as resolveAllAgentSessionStoreTargetsSync } from "./targets-UQqmco4C.js";
import { x as listRegistryWorktreesForMigration } from "./registry-VkURAuz0.js";
import { t as migrateLegacyMainSessionKeys } from "./legacy-main-session-migration-DjPyqviB.js";
import { l as resolveProjectRegistry } from "./project-registry-CPmjaJxJ.js";
import fs from "node:fs";
import path from "node:path";
import { sql } from "kysely";
//#region src/config/sessions/worktree-workspace-migration.ts
function isInside(root, target) {
	const relative = path.relative(root, target);
	return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
}
function resolveLegacyCanonicalWorkspace(params) {
	const worktree = params.entry.worktree;
	if (!worktree || worktree.canonicalWorkspaceDir) return;
	const recordedRepoRoot = path.resolve(worktree.repoRoot);
	if (params.entry.projectId) {
		const project = resolveProjectRegistry(params.cfg, params.entry.projectId, { env: params.env });
		const projectRoot = project ? path.resolve(project.repoRoot) : void 0;
		return projectRoot && isInside(recordedRepoRoot, projectRoot) ? projectRoot : void 0;
	}
	const record = params.worktrees.find((candidate) => candidate.id === worktree.id);
	const spawnedCwd = params.entry.spawnedCwd;
	if (record?.ownerKind === "session" && record.ownerId === params.sessionKey && spawnedCwd && path.resolve(record.repoRoot) === path.resolve(worktree.repoRoot)) {
		const relative = path.relative(path.resolve(record.path), path.resolve(spawnedCwd));
		if (relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative)) return path.resolve(recordedRepoRoot, relative);
	}
	const agentWorkspace = path.resolve(resolveAgentWorkspaceDir(params.cfg, params.agentId, params.env));
	return agentWorkspace && agentWorkspace === recordedRepoRoot ? agentWorkspace : void 0;
}
function listLegacyWorktreeSessionEntries(params) {
	const result = withOpenClawAgentDatabaseReadOnly((database) => {
		const db = getSessionKysely(database.db);
		return executeSqliteQuerySync(database.db, db.selectFrom("session_nodes").selectAll().where(sql`session_nodes.entry_valid != 1 OR (
            json_valid(session_nodes.entry_json)
            AND json_type(session_nodes.entry_json, '$.worktree') = 'object'
            AND (
              json_type(session_nodes.entry_json, '$.worktree.canonicalWorkspaceDir') IS NULL
              OR json_extract(session_nodes.entry_json, '$.worktree.canonicalWorkspaceDir') = ''
            )
          )`).orderBy("session_key", "asc")).rows.flatMap((row) => {
			const entry = parseReadableSqliteSessionEntryRow(database, row);
			return entry ? [{
				databasePath: database.path,
				entry,
				sessionKey: row.session_key
			}] : [];
		});
	}, toDatabaseOptions(resolveSqliteScope({
		...params,
		sessionKey: ""
	})));
	return result.found ? result.value : [];
}
async function migrateManagedWorktreeCanonicalWorkspaces(params) {
	const env = params.env ?? process.env;
	const worktrees = listRegistryWorktreesForMigration(env);
	let migrated = 0;
	for (const { databasePath, entry, sessionKey } of listLegacyWorktreeSessionEntries({
		agentId: params.agentId,
		env,
		storePath: params.storePath
	})) {
		const agentId = resolveAgentIdFromSessionKey(sessionKey, params.agentId);
		const canonicalWorkspaceDir = resolveLegacyCanonicalWorkspace({
			agentId,
			cfg: params.cfg,
			entry,
			env,
			sessionKey,
			worktrees
		});
		if (!canonicalWorkspaceDir) continue;
		if ((await patchSessionEntryCore({
			agentId,
			env,
			sessionKey,
			storePath: databasePath
		}, (current) => {
			if (!current.worktree || current.worktree.id !== entry.worktree?.id || current.worktree.canonicalWorkspaceDir) return null;
			return { worktree: {
				...current.worktree,
				canonicalWorkspaceDir
			} };
		}, {
			preserveActivity: true,
			skipMaintenance: true
		}))?.worktree?.canonicalWorkspaceDir === canonicalWorkspaceDir) migrated += 1;
	}
	return migrated;
}
//#endregion
//#region src/config/sessions/startup-migration.ts
/** Maintains existing SQLite stores and returns their physical owners for startup reconciliation. */
async function runSessionStartupMigration(params) {
	const env = params.env ?? process.env;
	const resolveTargets = params.deps?.resolveAllAgentSessionStoreTargetsSync ?? resolveAllAgentSessionStoreTargetsSync;
	let targets = resolveTargets(params.cfg, { env });
	const legacyStore = [path.join(resolveStateDir(env), "sessions", "sessions.json"), ...targets.map((target) => target.storePath)].find((storePath) => !storePath.endsWith(".sqlite") && fs.existsSync(storePath));
	if (legacyStore) throw new Error(`Legacy session store requires migration: ${legacyStore}. Run "${formatCliCommand("openclaw doctor --fix", env)}" against the same state/config before starting OpenClaw.`);
	const result = await (params.deps?.migrateLegacyMainSessionKeys ?? migrateLegacyMainSessionKeys)({
		cfg: params.cfg,
		env,
		mode: "automatic"
	});
	if (result.changes.length > 0) params.log.info(`session: migrated retired main-agent session keys:\n${result.changes.map((change) => `- ${change}`).join("\n")}`);
	if (result.warnings.length > 0) params.log.warn(`session: retired main-agent session migration warnings:\n${result.warnings.map((warning) => `- ${warning}`).join("\n")}`);
	if (result.armed) targets = resolveTargets(params.cfg, { env });
	const databases = /* @__PURE__ */ new Map();
	const migrateWorktreeSessions = params.deps?.migrateManagedWorktreeCanonicalWorkspaces ?? migrateManagedWorktreeCanonicalWorkspaces;
	const registeredDatabases = new Set(listOpenClawRegisteredAgentDatabases({ env }).map((entry) => `${entry.agentId}\0${entry.path}`));
	let migratedWorktreeSessions = 0;
	for (const target of targets) {
		const options = toDatabaseOptions(resolveSqliteReadScope({
			...target,
			env
		}));
		const databasePath = resolveOpenClawAgentSqlitePath(options);
		if (databases.has(databasePath) || !fs.existsSync(databasePath)) continue;
		databases.set(databasePath, options);
		const alreadyOpen = isOpenClawAgentDatabaseOpen(databasePath);
		try {
			if (!registeredDatabases.has(`${options.agentId}\0${databasePath}`) || !isCanonicalSqliteSessionMainKeyCurrent(options, params.cfg.session?.mainKey)) setCanonicalSqliteSessionMainKey(openOpenClawAgentDatabase(options), params.cfg.session?.mainKey);
			if (!result.armed || result.complete) migratedWorktreeSessions += await migrateWorktreeSessions({
				...target,
				cfg: params.cfg,
				env
			});
		} catch (error) {
			params.log.warn(`session: SQLite startup maintenance failed for ${target.agentId}; continuing: ${String(error)}`);
		} finally {
			if (!alreadyOpen && isOpenClawAgentDatabaseOpen(databasePath)) closeOpenClawAgentDatabaseByPath(databasePath);
		}
	}
	if (migratedWorktreeSessions > 0) params.log.info(`session: recorded canonical workspaces for ${migratedWorktreeSessions} managed-worktree session(s)`);
	return [...databases.values()];
}
//#endregion
export { runSessionStartupMigration as t };
