/*
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);
}