import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import {
CapabilityClassification,
CapabilitySupport,
type OptionDescriptor,
type StaticCapabilityFact,
WORKFLOW_CAPABILITY_CONTRACT,
} from "./workflow-capability-contract.js";
const GENERATED_MARKER = "";
const TABLE_START = "";
const TABLE_END = "";
/** Package-relative compact capability index generated from the contract. */
export const CAPABILITY_INDEX_PATH = "skills/workflow-authoring/references/capabilities.md";
/** Package-relative exhaustive generated capability reference. */
export const CAPABILITY_DETAIL_PATH = "skills/workflow-authoring/references/capability-details.md";
/** Documents that embed the byte-identical supported-capability table. */
export const CAPABILITY_TABLE_PUBLICATION_PATHS = [
CAPABILITY_INDEX_PATH,
"README.md",
"docs/workflow-authoring.md",
] as const;
/** All generated capability publication surfaces checked for drift. */
export const CAPABILITY_PUBLICATION_PATHS = [...CAPABILITY_TABLE_PUBLICATION_PATHS, CAPABILITY_DETAIL_PATH] as const;
function escapeTable(value: string): string {
return value.replaceAll("|", "\\|").replaceAll("\n", " ");
}
function display(value: string | null): string {
return value === null ? "—" : `\`${escapeTable(value)}\``;
}
function optionText(option: OptionDescriptor): string {
const required = option.optional ? "optional" : "required";
const defaultValue = option.default === null ? "" : `; default: ${option.default}`;
const constraints = option.constraints.length === 0 ? "" : `; ${option.constraints.join("; ")}`;
const dynamic = option.dynamicReference === null ? "" : `; dynamic reference: ${option.dynamicReference}`;
return `- \`${option.name}\`: ${option.type} (${required}${defaultValue}${constraints}${dynamic})`;
}
function compactOptions(fact: StaticCapabilityFact): string {
if (!fact.options) return "—";
return fact.options.options
.map((option) => {
const optionality = option.optional ? "optional" : "required";
const defaultValue = option.default === null ? "" : `; default: ${option.default}`;
return `\`${escapeTable(option.name)}\`: ${escapeTable(option.type)} (${optionality}${escapeTable(defaultValue)})`;
})
.join("
");
}
function publishedFacts(): readonly StaticCapabilityFact[] {
return WORKFLOW_CAPABILITY_CONTRACT.projectStaticReferenceFacts().filter(
(fact) =>
fact.support === CapabilitySupport.SUPPORTED &&
(fact.classification === CapabilityClassification.RUNTIME_GLOBAL ||
fact.classification === CapabilityClassification.WORKFLOW_TOOL_INPUT),
);
}
/** The byte-identical generated block embedded in every public documentation surface. */
export function renderSupportedCapabilityTable(): string {
const rows = publishedFacts().map(
(fact) =>
`| ${escapeTable(fact.label)} | ${fact.classification} | ${display(fact.signature)} | ${compactOptions(fact)} |`,
);
return `${TABLE_START}
| Name | Classification | Signature | Options and defaults |
| --- | --- | --- | --- |
${rows.join("\n")}
${TABLE_END}`;
}
function replaceSupportedCapabilityTable(document: string): string | null {
const start = document.indexOf(TABLE_START);
const end = document.indexOf(TABLE_END, start + TABLE_START.length);
if (start < 0 || end < 0 || document.indexOf(TABLE_START, start + TABLE_START.length) >= 0) return null;
const after = end + TABLE_END.length;
return `${document.slice(0, start)}${renderSupportedCapabilityTable()}${document.slice(after)}`;
}
/** Regenerates only contract-owned content, preserving hand-written prose around marked blocks. */
export function writeWorkflowCapabilityPublications(root: string): void {
for (const path of CAPABILITY_TABLE_PUBLICATION_PATHS) {
const absolutePath = join(root, path);
if (path === CAPABILITY_INDEX_PATH) {
writeFileSync(absolutePath, renderWorkflowCapabilityReference());
continue;
}
const source = readFileSync(absolutePath, "utf8");
const refreshed = replaceSupportedCapabilityTable(source);
if (refreshed === null) throw new Error(`Missing or duplicate generated capability-table anchors in ${path}.`);
writeFileSync(absolutePath, refreshed);
}
writeFileSync(join(root, CAPABILITY_DETAIL_PATH), renderWorkflowCapabilityDetails());
}
/** Returns every stale surface in stable publication order. Overrides are useful to CI callers and tests. */
export function checkWorkflowCapabilityPublications(
root: string,
overrides: Readonly>> = {},
): string[] {
const stale: string[] = [];
for (const path of CAPABILITY_TABLE_PUBLICATION_PATHS) {
const actual = overrides[path] ?? readFileSync(join(root, path), "utf8");
if (path === CAPABILITY_INDEX_PATH) {
if (actual !== renderWorkflowCapabilityReference()) stale.push(path);
continue;
}
const refreshed = replaceSupportedCapabilityTable(actual);
if (refreshed === null || refreshed !== actual) stale.push(path);
}
const details = overrides[CAPABILITY_DETAIL_PATH] ?? readFileSync(join(root, CAPABILITY_DETAIL_PATH), "utf8");
if (details !== renderWorkflowCapabilityDetails()) stale.push(CAPABILITY_DETAIL_PATH);
return stale;
}
function anchorFor(fact: StaticCapabilityFact): string {
const anchor = fact.reference?.split("#")[1];
if (!anchor) throw new Error(`Static capability fact ${fact.id} has no reference anchor.`);
return anchor;
}
function detail(fact: StaticCapabilityFact): string {
const lines = [
``,
`## ${fact.label}`,
"",
`- Classification: \`${fact.classification}\``,
`- Support: \`${fact.support}\``,
`- Signature: ${display(fact.signature)}`,
];
if (fact.options) {
lines.push(`- Option shape: \`${fact.options.id}\``, ...fact.options.options.map(optionText));
}
if (fact.constraints.length > 0) lines.push(...fact.constraints.map((constraint) => `- Constraint: ${constraint}`));
if (fact.dynamicReference) {
lines.push(
`- Dynamic reference owner: \`${fact.dynamicReference.owner}\``,
`- Item shape: \`${fact.dynamicReference.itemShape}\``,
`- Future lookup connection: \`${fact.dynamicReference.connection}\``,
"- Live values are intentionally absent from this static reference.",
);
}
return `${lines.join("\n")}\n`;
}
/** Compact generated entrypoint for ordinary exact-name and signature lookup. */
/** Render the compact index that routes exact lookups to exhaustive details. */
export function renderWorkflowCapabilityReference(): string {
const { definition } = WORKFLOW_CAPABILITY_CONTRACT;
return `${GENERATED_MARKER}
# Workflow capability index
Contract format: \`${definition.versions.format.version}\`
Contract content / skill / extension: \`${definition.versions.content.version}\`
This compact generated index covers supported runtime globals and workflow-tool inputs. For constraints, compatibility behavior, internal boundaries, and dynamic-reference ownership, follow the [exhaustive generated facts](capability-details.md).
## Supported capability index
${renderSupportedCapabilityTable()}
`;
}
/** Exhaustive generated fact projection and stable anchor owner. */
/** Render exhaustive static facts while leaving live catalogues as dynamic references. */
export function renderWorkflowCapabilityDetails(): string {
const { definition } = WORKFLOW_CAPABILITY_CONTRACT;
const facts = WORKFLOW_CAPABILITY_CONTRACT.projectStaticReferenceFacts();
return `${GENERATED_MARKER}
# Exhaustive workflow capability facts
Contract format: \`${definition.versions.format.version}\`
Contract content / skill / extension: \`${definition.versions.content.version}\`
Every exact fact below is projected from the installed extension's capability contract. Explanatory judgment belongs in the hand-written references next to this file.
${facts.map(detail).join("\n")}`;
}