@sudajs/cli 0.10.3 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { createInterface } from 'readline/promises';
7
7
  import { fileURLToPath, pathToFileURL } from 'url';
8
8
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
9
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
- import { createThemeAgentManifest, createAgentPageSchemaOutput, checkThemeModule, formatThemeCheckResult, validateAgentPageContentWithManifest, agentValidationResultSchema, findAgentSection, createAgentComponentSchemaOutput, agentPageSchemaOutputSchema, agentComponentOutputSchema } from '@sudajs/theme-engine';
10
+ import { createThemeAgentManifest, createSudaPageAgentRuntime, checkThemeModule, formatThemeCheckResult, agentValidationResultSchema, agentPageSchemaOutputSchema, agentComponentOutputSchema } from '@sudajs/theme-engine';
11
11
  import { themeManifestSchema } from '@sudajs/theme-engine/server';
12
12
  import { Command } from 'commander';
13
13
  import { build } from 'esbuild';
@@ -691,6 +691,10 @@ ${issues}`);
691
691
  if (!Array.isArray(module.starterPages)) {
692
692
  throw new Error("starterPages must be an array.");
693
693
  }
694
+ const result = checkThemeModule(module);
695
+ if (!result.ok) {
696
+ throw new Error(formatThemeCheckResult(result));
697
+ }
694
698
  }
695
699
  async function validateTheme(root) {
696
700
  const packageJsonPath = path2.join(root, "package.json");
@@ -1686,16 +1690,16 @@ function printJson(value) {
1686
1690
  console.log(JSON.stringify(value, null, 2));
1687
1691
  }
1688
1692
  function createSectionSchema(manifest, sectionType) {
1689
- const section = findAgentSection(manifest, sectionType);
1690
- if (!section) {
1693
+ const section = createSudaPageAgentRuntime(manifest).getSectionSchemaOutput(sectionType);
1694
+ if (section === null) {
1691
1695
  throw new Error(`Unknown section type "${sectionType}".`);
1692
1696
  }
1693
- return createAgentComponentSchemaOutput(section, "section");
1697
+ return section;
1694
1698
  }
1695
1699
  async function validateAgentPage(themeKey, input, options) {
1696
1700
  const manifest = await fetchAgentManifest(themeKey, options);
1697
1701
  const pageContent = await readJson(path2.resolve(input));
1698
- const result = validateAgentPageContentWithManifest(pageContent, manifest);
1702
+ const result = createSudaPageAgentRuntime(manifest).validatePageContent(pageContent);
1699
1703
  printJson(agentValidationResultSchema.parse(result));
1700
1704
  if (!result.valid) {
1701
1705
  process.exitCode = 1;
@@ -1707,9 +1711,9 @@ async function createAgentPage(options) {
1707
1711
  }
1708
1712
  const pageContent = await readJson(path2.resolve(options.input));
1709
1713
  const manifest = await fetchAgentManifest(options.theme, options);
1710
- const validation = validateAgentPageContentWithManifest(pageContent, manifest);
1711
- if (!validation.valid) {
1712
- printJson(agentValidationResultSchema.parse(validation));
1714
+ const prepared = createSudaPageAgentRuntime(manifest).preparePageData(pageContent);
1715
+ if (!prepared.validation.valid) {
1716
+ printJson(agentValidationResultSchema.parse(prepared.validation));
1713
1717
  process.exitCode = 1;
1714
1718
  return;
1715
1719
  }
@@ -2005,7 +2009,7 @@ async function startMcpServer() {
2005
2009
  server.registerTool(
2006
2010
  "get_page_schema",
2007
2011
  {
2008
- description: "Return the AI-first output schema for generating Suda page content, including all section schemas. Field schemas include dynamic visibility metadata for Suda visibleIf fields. If the theme has a contact section, generate only the section placement/content props; public form fields and delivery integrations are project contact form settings exposed to themes as metadata.contactForm. Use get_contact_form_settings and update_contact_form_settings for user-approved contact form changes.",
2012
+ description: "Return the schema for configuring existing Suda theme sections as page content. Use only the returned section types, fields, defaultProps, and slot allowedComponents; never create theme source code or new component types. If the theme has a contact section, generate only the section placement/content props; public form fields and delivery integrations are project contact form settings exposed to themes as metadata.contactForm. Use get_contact_form_settings and update_contact_form_settings for user-approved contact form changes.",
2009
2013
  inputSchema: {
2010
2014
  theme: z.string(),
2011
2015
  version: z.string().optional(),
@@ -2017,16 +2021,16 @@ async function startMcpServer() {
2017
2021
  },
2018
2022
  async ({ theme, version, projectId, themeRoot, includeExample }) => {
2019
2023
  const manifest = await fetchAgentManifest(theme, { version, projectId, themeRoot });
2020
- const structuredContent = createAgentPageSchemaOutput(manifest, {
2024
+ const structuredContent = createSudaPageAgentRuntime(manifest).getPageSchemaOutput({
2021
2025
  includeExample: includeExample === true
2022
2026
  });
2023
- return mcpStructured("AI-first Suda page content output schema.", structuredContent);
2027
+ return mcpStructured("Suda page content configuration schema.", structuredContent);
2024
2028
  }
2025
2029
  );
2026
2030
  server.registerTool(
2027
2031
  "get_section_schema",
2028
2032
  {
2029
- description: "Return the AI-first output schema for one section component in a theme. Field schemas include dynamic visibility metadata for Suda visibleIf fields. For contact sections, use the schema for presentation props only and do not hardcode form field metadata, notification channels, webhook URLs, or recipients into page content. Use contact form tools for project-level contact settings.",
2033
+ description: "Return the schema for configuring one existing section in a theme. Use the returned fields, defaultProps, and slot allowedComponents to set props; do not design or add theme components. For contact sections, use the schema for presentation props only and do not hardcode form field metadata, notification channels, webhook URLs, or recipients into page content. Use contact form tools for project-level contact settings.",
2030
2034
  inputSchema: {
2031
2035
  theme: z.string(),
2032
2036
  section: z.string(),
@@ -2039,13 +2043,13 @@ async function startMcpServer() {
2039
2043
  async ({ theme, section, version, projectId, themeRoot }) => {
2040
2044
  const manifest = await fetchAgentManifest(theme, { version, projectId, themeRoot });
2041
2045
  const structuredContent = createSectionSchema(manifest, section);
2042
- return mcpStructured("AI-first Suda section output schema.", structuredContent);
2046
+ return mcpStructured("Suda section configuration schema.", structuredContent);
2043
2047
  }
2044
2048
  );
2045
2049
  server.registerTool(
2046
2050
  "validate_page_config",
2047
2051
  {
2048
- description: "Validate AI-generated Suda page content against a theme.",
2052
+ description: "Validate Suda page content JSON against an existing theme schema.",
2049
2053
  inputSchema: {
2050
2054
  theme: z.string(),
2051
2055
  data: z.unknown(),
@@ -2058,7 +2062,7 @@ async function startMcpServer() {
2058
2062
  async ({ theme, data, version, projectId, themeRoot }) => {
2059
2063
  const manifest = await fetchAgentManifest(theme, { version, projectId, themeRoot });
2060
2064
  const structuredContent = agentValidationResultSchema.parse(
2061
- validateAgentPageContentWithManifest(data, manifest)
2065
+ createSudaPageAgentRuntime(manifest).validatePageContent(data)
2062
2066
  );
2063
2067
  return mcpStructured("Suda page content validation result.", structuredContent);
2064
2068
  }
@@ -2108,7 +2112,7 @@ async function startMcpServer() {
2108
2112
  server.registerTool(
2109
2113
  "create_page_draft",
2110
2114
  {
2111
- description: "Create a new workspace page draft from AI-generated Suda page content. When creating a complete website, mark exactly one primary landing page with isHome: true so it becomes the public homepage at `/`. After this tool succeeds, tell the user the page is only a draft, explain that they can review it in the SudaCloud workspace by navigating to Pages, opening the created page, previewing it, then clicking Publish, and ask whether they want you to publish it now. Do not call publish_page until the user explicitly confirms.",
2115
+ description: "Create a new workspace page draft from Suda page content JSON that configures existing theme sections. When creating a complete website, mark exactly one primary landing page with isHome: true so it becomes the public homepage at `/`. After this tool succeeds, tell the user the page is only a draft, explain that they can review it in the SudaCloud workspace by navigating to Pages, opening the created page, previewing it, then clicking Publish, and ask whether they want you to publish it now. Do not call publish_page until the user explicitly confirms.",
2112
2116
  inputSchema: {
2113
2117
  projectId: z.string(),
2114
2118
  title: z.string(),
@@ -2122,14 +2126,14 @@ async function startMcpServer() {
2122
2126
  },
2123
2127
  async ({ projectId, title, slug, isHome, theme, data, version }) => {
2124
2128
  const manifest = await fetchAgentManifest(theme, { version, projectId });
2125
- const validation = validateAgentPageContentWithManifest(data, manifest);
2126
- if (!validation.valid) {
2129
+ const prepared = createSudaPageAgentRuntime(manifest).preparePageData(data);
2130
+ if (!prepared.validation.valid) {
2127
2131
  return mcpStructured(
2128
2132
  "Suda page content validation failed. Fix issues before creating a draft.",
2129
2133
  createPageDraftOutputSchema.parse({
2130
2134
  status: "invalid",
2131
2135
  valid: false,
2132
- issues: validation.issues
2136
+ issues: prepared.validation.issues
2133
2137
  })
2134
2138
  );
2135
2139
  }
@@ -2152,7 +2156,7 @@ async function startMcpServer() {
2152
2156
  server.registerTool(
2153
2157
  "update_page_draft",
2154
2158
  {
2155
- description: "Update an existing workspace page draft by slug from AI-generated Suda page content.",
2159
+ description: "Update an existing workspace page draft by slug from Suda page content JSON that configures existing theme sections.",
2156
2160
  inputSchema: {
2157
2161
  projectId: z.string(),
2158
2162
  slug: z.string(),
@@ -2164,14 +2168,14 @@ async function startMcpServer() {
2164
2168
  },
2165
2169
  async ({ projectId, slug, theme, data, version }) => {
2166
2170
  const manifest = await fetchAgentManifest(theme, { version, projectId });
2167
- const validation = validateAgentPageContentWithManifest(data, manifest);
2168
- if (!validation.valid) {
2171
+ const prepared = createSudaPageAgentRuntime(manifest).preparePageData(data);
2172
+ if (!prepared.validation.valid) {
2169
2173
  return mcpStructured(
2170
2174
  "Suda page content validation failed. Fix issues before updating a draft.",
2171
2175
  updatePageDraftOutputSchema.parse({
2172
2176
  status: "invalid",
2173
2177
  valid: false,
2174
- issues: validation.issues
2178
+ issues: prepared.validation.issues
2175
2179
  })
2176
2180
  );
2177
2181
  }
@@ -2282,6 +2286,11 @@ async function writeThemeArtifacts(theme) {
2282
2286
  await writeFile(
2283
2287
  path2.join(dist, "starter-pages.json"),
2284
2288
  `${JSON.stringify(theme.module.starterPages, null, 2)}
2289
+ `
2290
+ );
2291
+ await writeFile(
2292
+ path2.join(dist, "cms-templates.json"),
2293
+ `${JSON.stringify(theme.module.cmsTemplates, null, 2)}
2285
2294
  `
2286
2295
  );
2287
2296
  await writeFile(
@@ -2800,20 +2809,24 @@ function buildProgram() {
2800
2809
  printJson({ themes });
2801
2810
  });
2802
2811
  const agentTheme = agent.command("theme").description("Inspect a single theme.");
2803
- agentTheme.command("describe").description("Describe a theme's AI-first page schema.").argument("<theme>", "Theme key.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").option("--example", "Include example page content.").action(async (themeKey, options) => {
2812
+ agentTheme.command("describe").description("Describe a theme's page content configuration schema.").argument("<theme>", "Theme key.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").option("--example", "Include example page content.").action(async (themeKey, options) => {
2804
2813
  const manifest = await fetchAgentManifest(themeKey, options);
2805
2814
  printJson(
2806
- createAgentPageSchemaOutput(manifest, { includeExample: options.example === true })
2815
+ createSudaPageAgentRuntime(manifest).getPageSchemaOutput({
2816
+ includeExample: options.example === true
2817
+ })
2807
2818
  );
2808
2819
  });
2809
- const agentPage = agent.command("page").description("AI-first page content tooling.");
2810
- agentPage.command("schema").description("Print the AI-first page content output schema for a theme.").argument("<theme>", "Theme key.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").option("--example", "Include example page content.").action(async (themeKey, options) => {
2820
+ const agentPage = agent.command("page").description("Page content configuration tooling.");
2821
+ agentPage.command("schema").description("Print the page content configuration schema for a theme.").argument("<theme>", "Theme key.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").option("--example", "Include example page content.").action(async (themeKey, options) => {
2811
2822
  const manifest = await fetchAgentManifest(themeKey, options);
2812
2823
  printJson(
2813
- createAgentPageSchemaOutput(manifest, { includeExample: options.example === true })
2824
+ createSudaPageAgentRuntime(manifest).getPageSchemaOutput({
2825
+ includeExample: options.example === true
2826
+ })
2814
2827
  );
2815
2828
  });
2816
- agentPage.command("validate").description("Validate an AI-generated Suda page content JSON document.").requiredOption("--theme <theme>", "Theme key.").requiredOption("--input <file>", "JSON file containing Suda page content.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").action(async (options) => {
2829
+ agentPage.command("validate").description("Validate a Suda page content JSON document.").requiredOption("--theme <theme>", "Theme key.").requiredOption("--input <file>", "JSON file containing Suda page content.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").action(async (options) => {
2817
2830
  await validateAgentPage(options.theme, options.input, options);
2818
2831
  });
2819
2832
  agentPage.command("create").description(
@@ -2822,7 +2835,7 @@ function buildProgram() {
2822
2835
  await createAgentPage(options);
2823
2836
  });
2824
2837
  const agentSection = agent.command("section").description("Inspect a single section.");
2825
- agentSection.command("schema").description("Print one AI-first section output schema for a theme.").requiredOption("--theme <theme>", "Theme key.").requiredOption("--section <section>", "Section type.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").action(async (options) => {
2838
+ agentSection.command("schema").description("Print one section configuration schema for a theme.").requiredOption("--theme <theme>", "Theme key.").requiredOption("--section <section>", "Section type.").option("--version <version>", "Theme version.").option("--project-id <projectId>", "Project scope.").option("--theme-root <path>", "Read a local theme.").action(async (options) => {
2826
2839
  const manifest = await fetchAgentManifest(options.theme, options);
2827
2840
  printJson(createSectionSchema(manifest, options.section));
2828
2841
  });