import { r as __exportAll } from "./chunk-D_gEzPfs.js";
import { t as createSubsystemLogger } from "./subsystem-hATE68va.js";
import { g as resolveStateDir } from "./paths-VdmjGGyc.js";
import { _ as isSubkoiSessionKey, l as normalizeKoiId, n as DEFAULT_KOI_ID, v as parseKoiSessionKey } from "./session-key-B2OXLVi_.js";
import { h as resolveUserPath } from "./utils-D019Z2NU.js";
import { t as runCommandWithTimeout } from "./exec-BBWSxSu-.js";
import { t as resolveSKYKOIPackageRoot } from "./skykoi-root-Dsv6eLbL.js";
import { t as getRuntimeKoiOverlay } from "./runtime-koi-overlay-DeKEFkkl.js";
import { fileURLToPath } from "node:url";
import path from "node:path";
import os from "node:os";
import fs from "node:fs/promises";

//#region src/koi/workspace-templates.ts
const FALLBACK_TEMPLATE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../docs/reference/templates");
let cachedTemplateDir;
let resolvingTemplateDir;
async function pathExists(candidate) {
	try {
		await fs.access(candidate);
		return true;
	} catch {
		return false;
	}
}
async function resolveWorkspaceTemplateDir(opts) {
	if (cachedTemplateDir) return cachedTemplateDir;
	if (resolvingTemplateDir) return resolvingTemplateDir;
	resolvingTemplateDir = (async () => {
		const moduleUrl = opts?.moduleUrl ?? import.meta.url;
		const argv1 = opts?.argv1 ?? process.argv[1];
		const cwd = opts?.cwd ?? process.cwd();
		const packageRoot = await resolveSKYKOIPackageRoot({
			moduleUrl,
			argv1,
			cwd
		});
		const candidates = [
			packageRoot ? path.join(packageRoot, "docs", "reference", "templates") : null,
			cwd ? path.resolve(cwd, "docs", "reference", "templates") : null,
			FALLBACK_TEMPLATE_DIR
		].filter(Boolean);
		for (const candidate of candidates) if (await pathExists(candidate)) {
			cachedTemplateDir = candidate;
			return candidate;
		}
		cachedTemplateDir = candidates[0] ?? FALLBACK_TEMPLATE_DIR;
		return cachedTemplateDir;
	})();
	try {
		return await resolvingTemplateDir;
	} finally {
		resolvingTemplateDir = void 0;
	}
}

//#endregion
//#region src/koi/workspace.ts
function resolveDefaultKoiWorkspaceDir(env = process.env, homedir = os.homedir) {
	const profile = env.SKYKOI_PROFILE?.trim();
	if (profile && profile.toLowerCase() !== "default") return path.join(homedir(), ".skykoi", `workspace-${profile}`);
	return path.join(homedir(), ".skykoi", "workspace");
}
const DEFAULT_KOI_WORKSPACE_DIR = resolveDefaultKoiWorkspaceDir();
const DEFAULT_KOIS_FILENAME = "KOIS.md";
const DEFAULT_SOUL_FILENAME = "SOUL.md";
const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
const DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
const DEFAULT_USER_FILENAME = "USER.md";
const DEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";
const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
const DEFAULT_MEMORY_FILENAME = "MEMORY.md";
const DEFAULT_MEMORY_ALT_FILENAME = "memory.md";
function stripFrontMatter(content) {
	if (!content.startsWith("---")) return content;
	const endIndex = content.indexOf("\n---", 3);
	if (endIndex === -1) return content;
	const start = endIndex + 4;
	let trimmed = content.slice(start);
	trimmed = trimmed.replace(/^\s+/, "");
	return trimmed;
}
async function loadTemplate(name) {
	const templateDir = await resolveWorkspaceTemplateDir();
	const templatePath = path.join(templateDir, name);
	try {
		return stripFrontMatter(await fs.readFile(templatePath, "utf-8"));
	} catch {
		throw new Error(`Missing workspace template: ${name} (${templatePath}). Ensure docs/reference/templates are packaged.`);
	}
}
async function writeFileIfMissing(filePath, content) {
	try {
		await fs.writeFile(filePath, content, {
			encoding: "utf-8",
			flag: "wx"
		});
	} catch (err) {
		if (err.code !== "EEXIST") throw err;
	}
}
async function hasGitRepo(dir) {
	try {
		await fs.stat(path.join(dir, ".git"));
		return true;
	} catch {
		return false;
	}
}
async function isGitAvailable() {
	try {
		return (await runCommandWithTimeout(["git", "--version"], { timeoutMs: 2e3 })).code === 0;
	} catch {
		return false;
	}
}
async function ensureGitRepo(dir, isBrandNewWorkspace) {
	if (!isBrandNewWorkspace) return;
	if (await hasGitRepo(dir)) return;
	if (!await isGitAvailable()) return;
	try {
		await runCommandWithTimeout(["git", "init"], {
			cwd: dir,
			timeoutMs: 1e4
		});
	} catch {}
}
async function ensureKoiWorkspace(params) {
	const dir = resolveUserPath(params?.dir?.trim() ? params.dir.trim() : DEFAULT_KOI_WORKSPACE_DIR);
	await fs.mkdir(dir, { recursive: true });
	if (!params?.ensureBootstrapFiles) return { dir };
	const koisPath = path.join(dir, DEFAULT_KOIS_FILENAME);
	const soulPath = path.join(dir, DEFAULT_SOUL_FILENAME);
	const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
	const identityPath = path.join(dir, DEFAULT_IDENTITY_FILENAME);
	const userPath = path.join(dir, DEFAULT_USER_FILENAME);
	const heartbeatPath = path.join(dir, DEFAULT_HEARTBEAT_FILENAME);
	const bootstrapPath = path.join(dir, DEFAULT_BOOTSTRAP_FILENAME);
	const isBrandNewWorkspace = await (async () => {
		const paths = [
			koisPath,
			soulPath,
			toolsPath,
			identityPath,
			userPath,
			heartbeatPath
		];
		return (await Promise.all(paths.map(async (p) => {
			try {
				await fs.access(p);
				return true;
			} catch {
				return false;
			}
		}))).every((v) => !v);
	})();
	const koisTemplate = await loadTemplate(DEFAULT_KOIS_FILENAME);
	const soulTemplate = await loadTemplate(DEFAULT_SOUL_FILENAME);
	const toolsTemplate = await loadTemplate(DEFAULT_TOOLS_FILENAME);
	const identityTemplate = await loadTemplate(DEFAULT_IDENTITY_FILENAME);
	const userTemplate = await loadTemplate(DEFAULT_USER_FILENAME);
	const heartbeatTemplate = await loadTemplate(DEFAULT_HEARTBEAT_FILENAME);
	const bootstrapTemplate = await loadTemplate(DEFAULT_BOOTSTRAP_FILENAME);
	await writeFileIfMissing(koisPath, koisTemplate);
	await writeFileIfMissing(soulPath, soulTemplate);
	await writeFileIfMissing(toolsPath, toolsTemplate);
	await writeFileIfMissing(identityPath, identityTemplate);
	await writeFileIfMissing(userPath, userTemplate);
	await writeFileIfMissing(heartbeatPath, heartbeatTemplate);
	if (isBrandNewWorkspace) await writeFileIfMissing(bootstrapPath, bootstrapTemplate);
	await ensureGitRepo(dir, isBrandNewWorkspace);
	return {
		dir,
		koisPath,
		soulPath,
		toolsPath,
		identityPath,
		userPath,
		heartbeatPath,
		bootstrapPath
	};
}
async function loadWorkspaceBootstrapFiles(dir) {
	const resolvedDir = resolveUserPath(dir);
	const entries = [
		{
			name: DEFAULT_KOIS_FILENAME,
			filePath: path.join(resolvedDir, DEFAULT_KOIS_FILENAME)
		},
		{
			name: DEFAULT_SOUL_FILENAME,
			filePath: path.join(resolvedDir, DEFAULT_SOUL_FILENAME)
		},
		{
			name: DEFAULT_TOOLS_FILENAME,
			filePath: path.join(resolvedDir, DEFAULT_TOOLS_FILENAME)
		},
		{
			name: DEFAULT_IDENTITY_FILENAME,
			filePath: path.join(resolvedDir, DEFAULT_IDENTITY_FILENAME)
		},
		{
			name: DEFAULT_USER_FILENAME,
			filePath: path.join(resolvedDir, DEFAULT_USER_FILENAME)
		},
		{
			name: DEFAULT_BOOTSTRAP_FILENAME,
			filePath: path.join(resolvedDir, DEFAULT_BOOTSTRAP_FILENAME)
		},
		{
			name: DEFAULT_MEMORY_FILENAME,
			filePath: path.join(resolvedDir, DEFAULT_MEMORY_FILENAME)
		}
	];
	const result = [];
	for (const entry of entries) try {
		const content = await fs.readFile(entry.filePath, "utf-8");
		result.push({
			name: entry.name,
			path: entry.filePath,
			content,
			missing: false
		});
	} catch {
		result.push({
			name: entry.name,
			path: entry.filePath,
			missing: true
		});
	}
	return result;
}
const SUBKOI_BOOTSTRAP_ALLOWLIST = new Set([DEFAULT_KOIS_FILENAME, DEFAULT_TOOLS_FILENAME]);
function filterBootstrapFilesForSession(files, sessionKey) {
	if (!sessionKey || !isSubkoiSessionKey(sessionKey)) return files;
	return files.filter((file) => SUBKOI_BOOTSTRAP_ALLOWLIST.has(file.name));
}

//#endregion
//#region src/koi/koi-scope.ts
/**
* @module kois/koi-scope
*
* Resolves koi identity and configuration from the SKYKOI config.
* Maps session keys to koi IDs, resolves per-koi settings (model,
* workspace, skills, sandbox), and determines filesystem paths for
* koi workspaces and data directories.
*/
var koi_scope_exports = /* @__PURE__ */ __exportAll({
	listKoiIds: () => listKoiIds,
	resolveDefaultKoiId: () => resolveDefaultKoiId,
	resolveKoiConfig: () => resolveKoiConfig,
	resolveKoiDir: () => resolveKoiDir,
	resolveKoiModelFallbacksOverride: () => resolveKoiModelFallbacksOverride,
	resolveKoiModelPrimary: () => resolveKoiModelPrimary,
	resolveKoiSkillsFilter: () => resolveKoiSkillsFilter,
	resolveKoiWorkspaceDir: () => resolveKoiWorkspaceDir,
	resolveSessionKoiId: () => resolveSessionKoiId,
	resolveSessionKoiIds: () => resolveSessionKoiIds
});
const log = createSubsystemLogger("kois/koi-scope");
let defaultKoiWarned = false;
function listKois(cfg) {
	const list = cfg.kois?.list;
	const fromCfg = Array.isArray(list) ? list.filter((entry) => Boolean(entry && typeof entry === "object")) : [];
	const overlay = getRuntimeKoiOverlay();
	if (overlay.length === 0) return fromCfg;
	const seen = /* @__PURE__ */ new Set();
	for (const entry of fromCfg) {
		const id = (entry?.id)?.trim().toLowerCase();
		if (id) seen.add(id);
	}
	const merged = [...fromCfg];
	for (const entry of overlay) {
		const id = (entry?.id)?.trim().toLowerCase();
		if (!id || seen.has(id)) continue;
		seen.add(id);
		merged.push(entry);
	}
	return merged;
}
/** Returns all configured koi IDs, or [DEFAULT_KOI_ID] if none configured. */
function listKoiIds(cfg) {
	const kois = listKois(cfg);
	if (kois.length === 0) return [DEFAULT_KOI_ID];
	const seen = /* @__PURE__ */ new Set();
	const ids = [];
	for (const entry of kois) {
		const id = normalizeKoiId(entry?.id);
		if (seen.has(id)) continue;
		seen.add(id);
		ids.push(id);
	}
	return ids.length > 0 ? ids : [DEFAULT_KOI_ID];
}
/** Returns the default koi ID (first entry marked `default: true`, or first entry). */
function resolveDefaultKoiId(cfg) {
	const kois = listKois(cfg);
	if (kois.length === 0) return DEFAULT_KOI_ID;
	const defaults = kois.filter((koi) => koi?.default);
	if (defaults.length > 1 && !defaultKoiWarned) {
		defaultKoiWarned = true;
		log.warn("Multiple kois marked default=true; using the first entry as default.");
	}
	const chosen = (defaults[0] ?? kois[0])?.id?.trim();
	return normalizeKoiId(chosen || DEFAULT_KOI_ID);
}
/**
* Extracts the koi ID embedded in a session key (e.g. "koi:foo:session")
* and returns both the default and session-specific koi IDs.
*/
function resolveSessionKoiIds(params) {
	const defaultKoiId = resolveDefaultKoiId(params.config ?? {});
	const sessionKey = params.sessionKey?.trim();
	const normalizedSessionKey = sessionKey ? sessionKey.toLowerCase() : void 0;
	const parsed = normalizedSessionKey ? parseKoiSessionKey(normalizedSessionKey) : null;
	return {
		defaultKoiId,
		sessionKoiId: parsed?.koiId ? normalizeKoiId(parsed.koiId) : defaultKoiId
	};
}
/** Convenience wrapper: returns just the session-specific koi ID. */
function resolveSessionKoiId(params) {
	return resolveSessionKoiIds(params).sessionKoiId;
}
function resolveKoiEntry(cfg, koiId) {
	const id = normalizeKoiId(koiId);
	return listKois(cfg).find((entry) => normalizeKoiId(entry.id) === id);
}
/** Looks up full koi configuration (model, skills, sandbox, etc.) by koi ID. */
function resolveKoiConfig(cfg, koiId) {
	const entry = resolveKoiEntry(cfg, normalizeKoiId(koiId));
	if (!entry) return;
	return {
		name: typeof entry.name === "string" ? entry.name : void 0,
		workspace: typeof entry.workspace === "string" ? entry.workspace : void 0,
		koiDir: typeof entry.koiDir === "string" ? entry.koiDir : void 0,
		model: typeof entry.model === "string" || entry.model && typeof entry.model === "object" ? entry.model : void 0,
		skills: Array.isArray(entry.skills) ? entry.skills : void 0,
		memorySearch: entry.memorySearch,
		humanDelay: entry.humanDelay,
		heartbeat: entry.heartbeat,
		identity: entry.identity,
		groupChat: entry.groupChat,
		subkois: typeof entry.subkois === "object" && entry.subkois ? entry.subkois : void 0,
		sandbox: entry.sandbox,
		tools: entry.tools
	};
}
/** Returns the skills allowlist for a koi, or undefined if unrestricted. */
function resolveKoiSkillsFilter(cfg, koiId) {
	const raw = resolveKoiConfig(cfg, koiId)?.skills;
	if (!raw) return;
	const normalized = raw.map((entry) => String(entry).trim()).filter(Boolean);
	return normalized.length > 0 ? normalized : [];
}
/** Returns the primary model ID for a koi, or undefined to use global default. */
function resolveKoiModelPrimary(cfg, koiId) {
	const raw = resolveKoiConfig(cfg, koiId)?.model;
	if (!raw) return;
	if (typeof raw === "string") return raw.trim() || void 0;
	return raw.primary?.trim() || void 0;
}
/** Returns koi-specific model fallbacks, or undefined to use global fallbacks. */
function resolveKoiModelFallbacksOverride(cfg, koiId) {
	const raw = resolveKoiConfig(cfg, koiId)?.model;
	if (!raw || typeof raw === "string") return;
	if (!Object.hasOwn(raw, "fallbacks")) return;
	return Array.isArray(raw.fallbacks) ? raw.fallbacks : void 0;
}
/** Resolves the workspace directory for a koi (per-koi config → global default → convention). */
function resolveKoiWorkspaceDir(cfg, koiId) {
	const id = normalizeKoiId(koiId);
	const configured = resolveKoiConfig(cfg, id)?.workspace?.trim();
	if (configured) return resolveUserPath(configured);
	if (id === resolveDefaultKoiId(cfg)) {
		const fallback = cfg.kois?.defaults?.workspace?.trim();
		if (fallback) return resolveUserPath(fallback);
		return DEFAULT_KOI_WORKSPACE_DIR;
	}
	return path.join(os.homedir(), ".skykoi", `workspace-${id}`);
}
/** Resolves the koi data directory (for koi-specific state files). */
function resolveKoiDir(cfg, koiId) {
	const id = normalizeKoiId(koiId);
	const configured = resolveKoiConfig(cfg, id)?.koiDir?.trim();
	if (configured) return resolveUserPath(configured);
	const root = resolveStateDir(process.env, os.homedir);
	return path.join(root, "kois", id, "koi");
}

//#endregion
export { filterBootstrapFilesForSession as C, resolveWorkspaceTemplateDir as E, ensureKoiWorkspace as S, resolveDefaultKoiWorkspaceDir as T, DEFAULT_MEMORY_ALT_FILENAME as _, resolveKoiDir as a, DEFAULT_TOOLS_FILENAME as b, resolveKoiSkillsFilter as c, resolveSessionKoiIds as d, DEFAULT_BOOTSTRAP_FILENAME as f, DEFAULT_KOI_WORKSPACE_DIR as g, DEFAULT_KOIS_FILENAME as h, resolveKoiConfig as i, resolveKoiWorkspaceDir as l, DEFAULT_IDENTITY_FILENAME as m, listKoiIds as n, resolveKoiModelFallbacksOverride as o, DEFAULT_HEARTBEAT_FILENAME as p, resolveDefaultKoiId as r, resolveKoiModelPrimary as s, koi_scope_exports as t, resolveSessionKoiId as u, DEFAULT_MEMORY_FILENAME as v, loadWorkspaceBootstrapFiles as w, DEFAULT_USER_FILENAME as x, DEFAULT_SOUL_FILENAME as y };