import { a as loadAnvilManifest, h as resolveHubConfig } from "./manifest-CslkSMd8.mjs";
import process from "node:process";
import { Client } from "@notionhq/client";
//#region src/lib/issue-markdown.ts
function parseIssueMarkdown(markdown) {
	if (!markdown) return {};
	const buckets = /* @__PURE__ */ new Map();
	let currentSection = null;
	for (const line of markdown.split(/\r?\n/)) {
		const heading = line.match(/^##\s+(Problem|Intent|Scope|Constraints|Success|Artifacts)\s*$/);
		if (heading) {
			currentSection = heading[1];
			buckets.set(currentSection, []);
			continue;
		}
		if (currentSection) buckets.get(currentSection)?.push(line);
	}
	const getText = (title) => {
		const value = buckets.get(title)?.join("\n").trim();
		return value && value.length > 0 ? value : void 0;
	};
	const artifactBlock = buckets.get("Artifacts")?.join("\n").trim();
	return {
		artifacts: artifactBlock ? artifactBlock.split(/\r?\n/).map((line) => line.replace(/^-\s+/, "").trim()).filter(Boolean) : void 0,
		constraints: getText("Constraints"),
		intent: getText("Intent"),
		problem: getText("Problem"),
		scope: getText("Scope"),
		success: getText("Success")
	};
}
function renderIssueMarkdown(sections) {
	const lines = [];
	appendSection(lines, "Problem", sections.problem);
	appendSection(lines, "Intent", sections.intent);
	appendSection(lines, "Scope", sections.scope);
	appendSection(lines, "Constraints", sections.constraints);
	appendSection(lines, "Success", sections.success);
	appendArtifactsSection(lines, sections.artifacts);
	return lines.join("\n").trim();
}
function appendSection(lines, title, value) {
	if (!value || value.trim().length === 0) return;
	if (lines.length > 0) lines.push("");
	lines.push(`## ${title}`);
	lines.push("");
	lines.push(value.trim());
}
function appendArtifactsSection(lines, artifacts) {
	const values = artifacts?.map((value) => value.trim()).filter(Boolean);
	if (!values || values.length === 0) return;
	if (lines.length > 0) lines.push("");
	lines.push("## Artifacts");
	lines.push("");
	for (const artifact of values) lines.push(`- ${artifact}`);
}
//#endregion
//#region src/lib/issue-selector.ts
const hqIssueIdRegex = /^ISS-(\d+)$/i;
function parseIssueSelector(value) {
	const trimmed = value.trim();
	const match = hqIssueIdRegex.exec(trimmed);
	if (match) return {
		kind: "hq-id",
		value: `ISS-${Number.parseInt(match[1], 10)}`
	};
	return {
		kind: "page-id",
		value: normalizeNotionPageId(trimmed)
	};
}
function normalizeNotionPageId(value) {
	const hex = value.trim().toLowerCase().replace(/[^a-f0-9]/g, "");
	if (hex.length !== 32) throw new Error(`Invalid Notion page id: ${value}`);
	return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}
//#endregion
//#region src/lib/issues.ts
async function createIssue(input, options = {}) {
	const runtime = await createIssueRuntime(options);
	const workspace = await runtime.resolveWorkspaceByName(input.workspace);
	const context = await runtime.loadContext();
	const properties = {
		Condition: selectProperty(normalizeIssueCondition(input.condition) ?? "Reported"),
		Kind: selectProperty(normalizeIssueKind(input.kind)),
		Name: { title: richText(createIssueDisplayName(workspace.name, input.title)) },
		Product: { relation: workspace.productId ? [{ id: workspace.productId }] : [] },
		Progress: statusProperty(normalizeIssueProgress(input.progress) ?? "Idle"),
		Title: { rich_text: richText(input.title) },
		Workspace: { relation: [{ id: workspace.id }] },
		...await buildOptionalProperties(runtime, input, context.issueRows, normalizeIssueLevel(input.level))
	};
	const page = await runtime.client.pages.create({
		parent: { data_source_id: runtime.databases.issues.dataSourceId },
		properties: compactProperties(properties)
	});
	await runtime.client.pages.updateMarkdown({
		page_id: page.id,
		replace_content: { new_str: renderIssueMarkdown(input) },
		type: "replace_content"
	});
	return normalizeIssueRecord(await runtime.getIssueRowByPageId(page.id), await runtime.loadContext());
}
function formatIssueSummary(issue) {
	return [
		issue.hqId ?? "ISS-?",
		issue.normalization,
		issue.progress ?? "-",
		issue.condition ?? "-",
		issue.workspace?.name ?? "-",
		issue.kind ?? "-",
		issue.stage ?? "-",
		issue.title ?? issue.name
	].join(" | ");
}
async function listIssues(filters = {}, options = {}) {
	const context = await (await createIssueRuntime(options)).loadContext();
	const issues = context.issueRows.map((row) => normalizeIssueRecord(row, context));
	const normalizedLevel = filters.level ? normalizeIssueLevel(filters.level) : void 0;
	const normalizedKind = filters.kind ? normalizeIssueKind(filters.kind) : void 0;
	const normalizedCondition = filters.condition ? normalizeIssueCondition(filters.condition) : void 0;
	const normalizedProgress = filters.progress ? normalizeIssueProgress(filters.progress) : void 0;
	const normalizedReporter = filters.reporter ? normalizeIssueReporter(filters.reporter) : void 0;
	const normalizedStage = filters.stage ? normalizeIssueStage(filters.stage, normalizedLevel) : void 0;
	const filtered = issues.filter((issue) => {
		if (normalizedKind && issue.kind !== normalizedKind) return false;
		if (normalizedLevel && issue.level !== normalizedLevel) return false;
		if (normalizedStage && issue.stage !== normalizedStage) return false;
		if (normalizedCondition && issue.condition !== normalizedCondition) return false;
		if (normalizedProgress && issue.progress !== normalizedProgress) return false;
		if (normalizedReporter && issue.reporter !== normalizedReporter) return false;
		if (filters.workspace && issue.workspace?.name.toLowerCase() !== filters.workspace.trim().toLowerCase()) return false;
		if (filters.owner && !containsIgnoreCase(issue.owner, filters.owner)) return false;
		if (filters.query && !matchesIssueQuery(issue, filters.query)) return false;
		return true;
	});
	return typeof filters.limit === "number" && filters.limit >= 0 ? filtered.slice(0, filters.limit) : filtered;
}
function normalizeIssueCondition(value) {
	return normalizeNamedValue(value, [
		"Archived",
		"Backlog",
		"Cancelled",
		"Completed",
		"Pending",
		"Reported",
		"Triaged"
	]);
}
function normalizeIssueKind(value) {
	return normalizeNamedValue(value, [
		"Bug",
		"Feature",
		"Realignment",
		"Research",
		"Task"
	]);
}
function normalizeIssueLevel(value) {
	return normalizeNamedValue(value, [
		"Arc",
		"Beat",
		"Loop"
	]);
}
function normalizeIssueProgress(value) {
	return normalizeNamedValue(value, [
		"Blocked",
		"Finished",
		"Idle",
		"Sprint"
	]);
}
function normalizeIssueReporter(value) {
	return normalizeNamedValue(value, [
		"Agent",
		"Human",
		"System"
	]);
}
function normalizeIssueStage(value, level) {
	if (!value || value.trim().length === 0) return;
	const trimmed = value.trim();
	if (trimmed.includes("/")) {
		const [rawLevel, rawStage] = trimmed.split("/", 2);
		const normalizedLevel = normalizeIssueLevel(rawLevel);
		if (!normalizedLevel) throw new Error(`Unknown issue level in stage: ${value}`);
		return `${normalizedLevel}/${capitalizeWord(rawStage)}`;
	}
	if (!level) throw new Error("Stage values without a level require `--level`.");
	return `${level}/${capitalizeWord(trimmed)}`;
}
async function updateIssue(selectorValue, input, options = {}) {
	const runtime = await createIssueRuntime(options);
	const context = await runtime.loadContext();
	const currentRow = runtime.resolveIssueRow(selectorValue, context.issueRows);
	const currentIssue = normalizeIssueRecord(currentRow, context);
	const nextLevel = normalizeIssueLevel(input.level) ?? currentIssue.level;
	let workspace = currentIssue.workspace;
	if (input.workspace) workspace = await runtime.resolveWorkspaceByName(input.workspace);
	const properties = compactProperties({
		Condition: !input.condition && currentIssue.condition === "Reported" && shouldAutoTriaged(input) ? selectProperty("Triaged") : void 0,
		Name: workspace && (input.title || input.workspace) ? { title: richText(createIssueDisplayName(workspace.name, input.title ?? currentIssue.title ?? currentIssue.name)) } : void 0,
		Product: workspace && input.workspace ? { relation: workspace.productId ? [{ id: workspace.productId }] : [] } : void 0,
		Title: typeof input.title === "string" ? { rich_text: richText(input.title) } : void 0,
		Workspace: workspace && input.workspace ? { relation: [{ id: workspace.id }] } : void 0,
		...await buildOptionalProperties(runtime, input, context.issueRows, nextLevel)
	});
	if (Object.keys(properties).length > 0) await runtime.client.pages.update({
		page_id: currentRow.id,
		properties
	});
	if (hasMarkdownUpdates(input)) {
		const currentSections = parseIssueMarkdown(currentRow.markdown);
		await runtime.client.pages.updateMarkdown({
			page_id: currentRow.id,
			replace_content: { new_str: renderIssueMarkdown({
				artifacts: input.artifacts ?? currentSections.artifacts,
				constraints: input.constraints ?? currentSections.constraints,
				intent: input.intent ?? currentSections.intent,
				problem: input.problem ?? currentSections.problem,
				scope: input.scope ?? currentSections.scope,
				success: input.success ?? currentSections.success
			}) },
			type: "replace_content"
		});
	}
	return normalizeIssueRecord(await runtime.getIssueRowByPageId(currentRow.id), await runtime.loadContext());
}
function shouldAutoTriaged(input) {
	return Boolean(input.kind || input.level || input.stage || input.workspace || input.owner);
}
async function buildOptionalProperties(runtime, input, issueRows, level) {
	const stage = normalizeIssueStage(input.stage, level);
	const properties = compactProperties({
		Condition: selectProperty(normalizeIssueCondition(input.condition)),
		Kind: selectProperty(normalizeIssueKind(input.kind)),
		Level: selectProperty(level),
		Owner: typeof input.owner === "string" ? { rich_text: richText(input.owner) } : void 0,
		Progress: statusProperty(normalizeIssueProgress(input.progress)),
		Ref: typeof input.ref === "string" ? { rich_text: richText(input.ref) } : void 0,
		Reporter: selectProperty(normalizeIssueReporter(input.reporter)),
		Stage: selectProperty(stage),
		URL: typeof input.url === "string" ? { url: input.url } : void 0
	});
	if (input.origin) properties.Origin = { relation: [{ id: (await runtime.resolveWorkspaceByName(input.origin)).id }] };
	if (input.affected && input.affected.length > 0) properties.Affected = { relation: (await runtime.resolveWorkspaceIdsByNames(input.affected)).map((item) => ({ id: item.id })) };
	if (input.instance) properties.Instance = { relation: [{ id: (await runtime.resolveInstanceByName(input.instance)).id }] };
	if (input.parent) properties.Parent = { relation: await runtime.resolveIssueIdsBySelectors([input.parent], issueRows) };
	if (input.related && input.related.length > 0) properties.Related = { relation: await runtime.resolveIssueIdsBySelectors(input.related, issueRows) };
	if (input.blockers && input.blockers.length > 0) properties.Blockers = { relation: await runtime.resolveIssueIdsBySelectors(input.blockers, issueRows) };
	return properties;
}
function compactProperties(properties) {
	return Object.fromEntries(Object.entries(properties).filter(([, value]) => value !== void 0));
}
function containsIgnoreCase(value, query) {
	return value ? value.toLowerCase().includes(query.trim().toLowerCase()) : false;
}
function createIssueClient() {
	const token = process.env.NOTION_TOKEN ?? process.env.NOTION_API_TOKEN;
	if (!token) throw new Error("Missing Notion token. Set NOTION_TOKEN or NOTION_API_TOKEN.");
	return new Client({ auth: token });
}
async function createIssueRuntime(options) {
	const client = options.client ?? createIssueClient();
	const loadedManifest = loadAnvilManifest(options.cwd ?? process.cwd());
	if (!loadedManifest) throw new Error("No anvil.yaml found.");
	const databases = await resolveIssueDatabases(client, resolveIssueRootId(loadedManifest));
	const workspaceRows = await queryAllRows(client, databases.workspaces.dataSourceId);
	const productRows = databases.products ? await queryAllRows(client, databases.products.dataSourceId) : [];
	const instanceRows = databases.instances ? await queryAllRows(client, databases.instances.dataSourceId) : [];
	const relationRowsById = new Map([
		...workspaceRows,
		...productRows,
		...instanceRows
	].map((row) => [row.id, row]));
	return {
		client,
		databases,
		async getIssueRowByPageId(pageId) {
			const row = (await loadIssueRows(client, databases.issues.dataSourceId)).find((entry) => entry.id.toLowerCase() === pageId.toLowerCase());
			if (!row) throw new Error(`Issue page not found: ${pageId}`);
			return row;
		},
		async loadContext() {
			return {
				issueRows: await loadIssueRows(client, databases.issues.dataSourceId),
				relationRowsById
			};
		},
		async resolveInstanceByName(name) {
			if (!databases.instances) throw new Error("The HQ root does not expose an Instances database.");
			return resolveRelationByName(instanceRows, name, "instance");
		},
		async resolveIssueIdsBySelectors(selectors, issueRows) {
			return selectors.map((selectorValue) => {
				return { id: resolveIssueRowFromRows(selectorValue, issueRows).id };
			});
		},
		resolveIssueRow(selectorValue, issueRows) {
			return resolveIssueRowFromRows(selectorValue, issueRows);
		},
		async resolveWorkspaceByName(name) {
			return resolveRelationByName(workspaceRows, name, "workspace");
		},
		async resolveWorkspaceIdsByNames(names) {
			return names.map((name) => resolveRelationByName(workspaceRows, name, "workspace"));
		}
	};
}
function createIssueDisplayName(workspaceName, title) {
	return workspaceName ? `${workspaceName} - ${title}` : title;
}
function deriveIssueNormalization(issue) {
	if (!issue.kind || !issue.workspace || !issue.level || !issue.stage || issue.condition === "Reported") return "untriaged";
	if (!issue.title || !issue.problem || !issue.intent) return "partial";
	return "canonical";
}
function hasMarkdownUpdates(input) {
	return typeof input.problem === "string" || typeof input.intent === "string" || typeof input.scope === "string" || typeof input.constraints === "string" || typeof input.success === "string" || Boolean(input.artifacts);
}
async function loadIssueRows(client, dataSourceId) {
	const rows = await queryAllRows(client, dataSourceId);
	return await Promise.all(rows.map(async (row) => ({
		...row,
		markdown: await client.pages.retrieveMarkdown({ page_id: row.id }).then((result) => result.markdown).catch(() => void 0)
	})));
}
function matchesIssueQuery(issue, query) {
	return [
		issue.hqId,
		issue.id,
		issue.name,
		issue.title,
		issue.kind,
		issue.workspace?.name,
		issue.owner,
		issue.ref,
		issue.url,
		issue.problem,
		issue.intent
	].filter((value) => typeof value === "string" && value.length > 0).join("\n").toLowerCase().includes(query.trim().toLowerCase());
}
function normalizeIssueRecord(row, context) {
	const sections = parseIssueMarkdown(row.markdown);
	const workspace = readRelationInfo(row.properties.Workspace, context.relationRowsById);
	const issue = {
		affected: readRelationInfos(row.properties.Affected, context.relationRowsById),
		artifacts: sections.artifacts ?? [],
		blockers: readLinkedIssues(row.properties.Blockers, context.issueRows),
		condition: readNamedProperty(row.properties.Condition),
		constraints: sections.constraints,
		hqId: readUniqueIdProperty(row.properties.ID),
		id: row.id,
		instance: readRelationInfo(row.properties.Instance, context.relationRowsById),
		intent: sections.intent,
		kind: readNamedProperty(row.properties.Kind),
		level: readNamedProperty(row.properties.Level),
		markdown: row.markdown,
		name: readTitleProperty(row.properties.Name),
		normalization: "partial",
		origin: readRelationInfo(row.properties.Origin, context.relationRowsById),
		owner: readRichTextProperty(row.properties.Owner),
		parent: readLinkedIssues(row.properties.Parent, context.issueRows).at(0),
		problem: sections.problem,
		product: readRelationInfo(row.properties.Product, context.relationRowsById),
		progress: readNamedProperty(row.properties.Progress),
		ref: readRichTextProperty(row.properties.Ref),
		related: readLinkedIssues(row.properties.Related, context.issueRows),
		reporter: readNamedProperty(row.properties.Reporter),
		scope: sections.scope,
		stage: readNamedProperty(row.properties.Stage),
		success: sections.success,
		title: readRichTextProperty(row.properties.Title) ?? stripWorkspacePrefix(readTitleProperty(row.properties.Name), workspace?.name),
		url: readUrlProperty(row.properties.URL) ?? row.url,
		workspace
	};
	issue.normalization = deriveIssueNormalization(issue);
	return issue;
}
function normalizeNamedValue(value, supported) {
	if (!value || value.trim().length === 0) return;
	const normalized = value.trim().toLowerCase();
	const match = supported.find((option) => option.toLowerCase() === normalized);
	if (match) return match;
	throw new Error(`Unsupported value \`${value}\`. Expected one of: ${supported.join(", ")}`);
}
async function queryAllRows(client, dataSourceId) {
	const rows = [];
	let nextCursor;
	while (true) {
		const response = await client.dataSources.query({
			data_source_id: dataSourceId,
			page_size: 100,
			start_cursor: nextCursor
		});
		rows.push(...response.results.filter((result) => result.object === "page"));
		if (!response.has_more || !response.next_cursor) return rows;
		nextCursor = response.next_cursor;
	}
}
function readLinkedIssues(property, issueRows) {
	return readRelationIds(property).map((id) => {
		const row = issueRows.find((entry) => entry.id === id);
		return {
			hqId: row ? readUniqueIdProperty(row.properties.ID) : void 0,
			id,
			name: row ? readTitleProperty(row.properties.Name) : id
		};
	});
}
function readNamedProperty(property) {
	if (!property) return;
	if (property.type === "select") return property.select?.name ?? void 0;
	if (property.type === "status") return property.status?.name ?? void 0;
}
function readRelationIds(property) {
	if (!property || property.type !== "relation" || !Array.isArray(property.relation)) return [];
	return property.relation.map((item) => item.id);
}
function readRelationInfo(property, relationRowsById) {
	const relationId = readRelationIds(property).at(0);
	if (!relationId) return;
	const row = relationRowsById.get(relationId);
	if (!row) return {
		id: relationId,
		name: relationId
	};
	return {
		id: relationId,
		name: readTitleProperty(row.properties.Name),
		productId: readRelationIds(row.properties.Product).at(0)
	};
}
function readRelationInfos(property, relationRowsById) {
	return readRelationIds(property).map((id) => {
		const row = relationRowsById.get(id);
		if (!row) return {
			id,
			name: id
		};
		return {
			id,
			name: readTitleProperty(row.properties.Name),
			productId: readRelationIds(row.properties.Product).at(0)
		};
	});
}
function readRichTextProperty(property) {
	if (!property || property.type !== "rich_text" || !Array.isArray(property.rich_text)) return;
	const value = property.rich_text.map((item) => item.plain_text).join("").trim();
	return value.length > 0 ? value : void 0;
}
function readTitleProperty(property) {
	if (!property || property.type !== "title" || !Array.isArray(property.title)) return "";
	return property.title.map((item) => item.plain_text).join("").trim();
}
function readUniqueIdProperty(property) {
	if (!property || property.type !== "unique_id" || property.unique_id?.number === void 0) return;
	return `${property.unique_id.prefix ?? "ISS"}-${property.unique_id.number}`;
}
function readUrlProperty(property) {
	if (!property || property.type !== "url") return;
	return property.url ?? void 0;
}
function resolveIssueRootId(loadedManifest) {
	const hubConfig = resolveHubConfig(loadedManifest);
	if (hubConfig?.document?.provider !== "notion") throw new Error("anvil issue requires `hub.document.provider: notion` in anvil.yaml.");
	const rootId = hubConfig.document.rootId?.trim();
	if (!rootId) throw new Error("anvil issue requires `hub.document.rootId` in anvil.yaml.");
	return rootId;
}
async function resolveIssueDatabases(client, rootId) {
	const children = await client.blocks.children.list({
		block_id: rootId,
		page_size: 100
	});
	const databasesByTitle = /* @__PURE__ */ new Map();
	for (const block of children.results) {
		if (block.type !== "child_database" || !block.child_database?.title) continue;
		const dataSourceId = (await client.databases.retrieve({ database_id: block.id })).data_sources?.at(0)?.id;
		if (!dataSourceId) continue;
		databasesByTitle.set(block.child_database.title, {
			dataSourceId,
			id: block.id,
			title: block.child_database.title
		});
	}
	const issues = databasesByTitle.get("Issues");
	const workspaces = databasesByTitle.get("Workspaces");
	if (!issues || !workspaces) throw new Error(`Configured Notion root ${rootId} does not expose the required HQ databases. Expected child databases named Issues and Workspaces.`);
	return {
		instances: databasesByTitle.get("Instances"),
		issues,
		products: databasesByTitle.get("Products"),
		workspaces
	};
}
function resolveIssueRowFromRows(selectorValue, rows) {
	const selector = parseIssueSelector(selectorValue);
	const row = selector.kind === "hq-id" ? rows.find((entry) => readUniqueIdProperty(entry.properties.ID)?.toLowerCase() === selector.value.toLowerCase()) : rows.find((entry) => entry.id.toLowerCase() === selector.value.toLowerCase());
	if (!row) throw new Error(`Issue not found for selector ${selectorValue}.`);
	return row;
}
function resolveRelationByName(rows, name, label) {
	const requestedName = name.trim().toLowerCase();
	const row = rows.find((entry) => readTitleProperty(entry.properties.Name).toLowerCase() === requestedName);
	if (!row) throw new Error(`Unknown ${label}: ${name}`);
	return {
		id: row.id,
		name: readTitleProperty(row.properties.Name),
		productId: readRelationIds(row.properties.Product).at(0)
	};
}
function richText(content) {
	return [{ text: { content } }];
}
function selectProperty(name) {
	return name ? { select: { name } } : void 0;
}
function statusProperty(name) {
	return name ? { status: { name } } : void 0;
}
function stripWorkspacePrefix(name, workspaceName) {
	if (!workspaceName) return name || void 0;
	const prefix = `${workspaceName} - `;
	return name.startsWith(prefix) ? name.slice(prefix.length) : name || void 0;
}
function capitalizeWord(value) {
	const trimmed = value.trim();
	if (trimmed.length === 0) return trimmed;
	return trimmed.charAt(0).toUpperCase() + trimmed.slice(1).toLowerCase();
}
//#endregion
export { updateIssue as i, formatIssueSummary as n, listIssues as r, createIssue as t };

//# sourceMappingURL=issues-Db9BW4-6.mjs.map