@sudajs/cli 0.10.4 → 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 +43 -30
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/templates/theme/AGENTS.md +355 -21
- package/templates/theme/src/index.tsx +3 -2
- package/templates/theme/src/locales/en.json +8 -0
- package/templates/theme/src/sections.tsx +70 -2
- package/templates/theme/src/templates.ts +151 -6
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,
|
|
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 =
|
|
1690
|
-
if (
|
|
1693
|
+
const section = createSudaPageAgentRuntime(manifest).getSectionSchemaOutput(sectionType);
|
|
1694
|
+
if (section === null) {
|
|
1691
1695
|
throw new Error(`Unknown section type "${sectionType}".`);
|
|
1692
1696
|
}
|
|
1693
|
-
return
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
2024
|
+
const structuredContent = createSudaPageAgentRuntime(manifest).getPageSchemaOutput({
|
|
2021
2025
|
includeExample: includeExample === true
|
|
2022
2026
|
});
|
|
2023
|
-
return mcpStructured("
|
|
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
|
|
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("
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
2815
|
+
createSudaPageAgentRuntime(manifest).getPageSchemaOutput({
|
|
2816
|
+
includeExample: options.example === true
|
|
2817
|
+
})
|
|
2807
2818
|
);
|
|
2808
2819
|
});
|
|
2809
|
-
const agentPage = agent.command("page").description("
|
|
2810
|
-
agentPage.command("schema").description("Print the
|
|
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
|
-
|
|
2824
|
+
createSudaPageAgentRuntime(manifest).getPageSchemaOutput({
|
|
2825
|
+
includeExample: options.example === true
|
|
2826
|
+
})
|
|
2814
2827
|
);
|
|
2815
2828
|
});
|
|
2816
|
-
agentPage.command("validate").description("Validate
|
|
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
|
|
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
|
});
|