/* Facilitates loading and parsing of the canonical system.md manifest per RFC-0047. Stack-agnostic utility used by both engine and site plugin (RFC-0868). Do not validate system manifest content (handled by validators). Do not handle system manifest generation or modification. RFC-0868: extracted from werkstatt-site/src/content/system-manifest.ts. RFC-0911: add seo?.anchorText?.extraStopPhrases for anchor-text stop-list extension. RFC-1106: step 3 — sole SystemManifest definition, loaders parse() Delete the hand-written SystemManifest interface; content/system-manifest.ts re-exports the schema-inferred type. Both loaders switch from 'as unknown as' to systemManifestSchema.parse() — the schema now executes at load. system.manifest.validate catches ZodError and maps issues into structured diagnostics; the post-load safeParse was dead code. Zero consumer breaks: all growth/release/tagline readers were already optional-safe. New adjacent test pins parse-at-load (AC-7). RFC-1149: migrate ambient filesystem and process IO to the WorkspaceIO port across engine and shared */ import { join } from "node:path"; import { createDefaultIO, type WorkspaceIO } from "../kernel/workspace-io.ts"; import { parseMarkdownFrontmatter } from "./markdown-frontmatter.ts"; import { systemManifestSchema } from "../ontology/schemas/system/manifest.ts"; import type { SystemManifest } from "../ontology/schemas/system/manifest.ts"; // RFC-1106: systemManifestSchema is the sole SystemManifest definition. // The inferred output type materializes .default()s (pages, constellations, // clientEditable, retiredRoutes, planets stay non-optional) and keeps // growth/release/tagline optional — the old interface lied about those. export type { SystemManifest }; export interface SystemManifestLoadResult { manifest: SystemManifest; source: "system.md"; filePath: string; } /** * Loads and parses the canonical system.md manifest from src/content/system.md. * * @param contentDirectory The src/content directory path * @returns Parsed system manifest with source information */ export async function loadSystemManifest( contentDirectory: string, io: WorkspaceIO = createDefaultIO().io, ): Promise { const systemMdPath = join(contentDirectory, "system.md"); const content = await io.readFile(systemMdPath); const parsed = parseMarkdownFrontmatter(content); return { manifest: systemManifestSchema.parse(parsed.data), source: "system.md", filePath: systemMdPath, }; } /** * Checks if the canonical system.md manifest exists. * * @param contentDirectory The src/content directory path * @returns true if src/content/system.md exists */ export async function isUsingSystemMd( contentDirectory: string, io: WorkspaceIO = createDefaultIO().io, ): Promise { const systemMdPath = join(contentDirectory, "system.md"); return io.exists(systemMdPath); }