@otl-core/cli 1.1.35 → 1.1.37
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.cjs +44 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +44 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -121,8 +121,6 @@ var SIMPLE_TYPE_MAP = {
|
|
|
121
121
|
"form-selector": "string",
|
|
122
122
|
"form-page": "string",
|
|
123
123
|
json: "Record<string, unknown>",
|
|
124
|
-
object: "Record<string, unknown>",
|
|
125
|
-
array: "unknown[]",
|
|
126
124
|
"container-behavior": '"boxed" | "edged" | "ignore"'
|
|
127
125
|
};
|
|
128
126
|
function resolveFieldType(field, imports) {
|
|
@@ -158,6 +156,14 @@ function resolveFieldType(field, imports) {
|
|
|
158
156
|
case "localized-text":
|
|
159
157
|
imports.LocalizedString = true;
|
|
160
158
|
return "LocalizedString";
|
|
159
|
+
// Array -- will be handled by the interface generator to produce a nested
|
|
160
|
+
// item interface when sub-fields are present.
|
|
161
|
+
case "array":
|
|
162
|
+
return "__ARRAY__";
|
|
163
|
+
// Object -- will be handled by the interface generator to produce a nested
|
|
164
|
+
// interface when properties are present.
|
|
165
|
+
case "object":
|
|
166
|
+
return "__OBJECT__";
|
|
161
167
|
// Group -- will be handled by the interface generator to produce a nested
|
|
162
168
|
// interface. At the type level we return the interface name.
|
|
163
169
|
case "group":
|
|
@@ -186,6 +192,42 @@ function buildInterfaceLines(parentName, fields, imports, extraInterfaces) {
|
|
|
186
192
|
for (const field of fields) {
|
|
187
193
|
const camelId = fieldIdToCamel(field.id);
|
|
188
194
|
let tsType = resolveFieldType(field, imports);
|
|
195
|
+
if (tsType === "__OBJECT__" && field.properties && field.properties.length > 0) {
|
|
196
|
+
const nestedName = parentName + kebabToPascal(field.id);
|
|
197
|
+
const nestedLines = buildInterfaceLines(
|
|
198
|
+
nestedName,
|
|
199
|
+
field.properties,
|
|
200
|
+
imports,
|
|
201
|
+
extraInterfaces
|
|
202
|
+
);
|
|
203
|
+
const nestedDecl = [
|
|
204
|
+
`interface ${nestedName} {`,
|
|
205
|
+
...nestedLines,
|
|
206
|
+
"}"
|
|
207
|
+
].join("\n");
|
|
208
|
+
extraInterfaces.push(nestedDecl);
|
|
209
|
+
tsType = nestedName;
|
|
210
|
+
} else if (tsType === "__OBJECT__") {
|
|
211
|
+
tsType = "Record<string, unknown>";
|
|
212
|
+
}
|
|
213
|
+
if (tsType === "__ARRAY__" && field.fields && field.fields.length > 0) {
|
|
214
|
+
const nestedName = parentName + kebabToPascal(field.id) + "Item";
|
|
215
|
+
const nestedLines = buildInterfaceLines(
|
|
216
|
+
nestedName,
|
|
217
|
+
field.fields,
|
|
218
|
+
imports,
|
|
219
|
+
extraInterfaces
|
|
220
|
+
);
|
|
221
|
+
const nestedDecl = [
|
|
222
|
+
`interface ${nestedName} {`,
|
|
223
|
+
...nestedLines,
|
|
224
|
+
"}"
|
|
225
|
+
].join("\n");
|
|
226
|
+
extraInterfaces.push(nestedDecl);
|
|
227
|
+
tsType = `${nestedName}[]`;
|
|
228
|
+
} else if (tsType === "__ARRAY__") {
|
|
229
|
+
tsType = "unknown[]";
|
|
230
|
+
}
|
|
189
231
|
if (tsType === "__GROUP__" && field.fields && field.fields.length > 0) {
|
|
190
232
|
const nestedName = parentName + kebabToPascal(field.id);
|
|
191
233
|
const nestedLines = buildInterfaceLines(
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/api/client.ts","../src/utils/naming.ts","../src/codegen/type-mapper.ts","../src/codegen/generate-block.ts","../src/codegen/generate-section.ts","../src/codegen/registry-updater.ts","../src/utils/env.ts","../src/utils/project.ts","../src/commands/customize.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/upgrade.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * OTL CMS CLI\n *\n * Schema-driven component scaffolder for the OTL engine.\n */\n\nimport { Command } from \"commander\";\nimport { registerAddCommands } from \"./commands/add\";\nimport { registerCustomizeCommands } from \"./commands/customize\";\nimport { registerInitCommand } from \"./commands/init\";\nimport { registerListCommands } from \"./commands/list\";\nimport { registerUpgradeCommand } from \"./commands/upgrade\";\n// import { registerSetupCommands } from \"./commands/setup\";\n\nconst program = new Command();\n\nprogram\n .name(\"otl-cli\")\n .description(\"OTL CMS CLI -- scaffold and manage engine components\")\n .version(\"0.1.0\");\n\n// Register command groups\nregisterAddCommands(program);\nregisterCustomizeCommands(program);\nregisterListCommands(program);\nregisterInitCommand(program);\nregisterUpgradeCommand(program);\n// registerSetupCommands(program);\n\nprogram.parse();\n","/**\n * `otl-cli add` command group.\n *\n * Generates block or section components from their schema definitions\n * and registers them in the appropriate registry file.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { findBlockSchemaByType, findSectionSchemaByType } from \"../api/client\";\nimport { generateBlockComponent } from \"../codegen/generate-block\";\nimport { generateSectionComponent } from \"../codegen/generate-section\";\nimport {\n addToBlockRegistry,\n addToSectionRegistry,\n} from \"../codegen/registry-updater\";\nimport { loadConfig } from \"../utils/env\";\nimport { requireEngineProject } from \"../utils/project\";\n\nexport function registerAddCommands(program: Command): void {\n const add = program\n .command(\"add\")\n .description(\"Generate a component from a schema definition\");\n\n add\n .command(\"block <name>\")\n .description(\"Generate a block component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findBlockSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No block schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list blocks' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.blocksDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateBlockComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.blockRegistryFile)) {\n addToBlockRegistry(paths.blockRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.blockRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n add\n .command(\"section <name>\")\n .description(\"Generate a section component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findSectionSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No section schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list sections' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.sectionsDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateSectionComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.sectionRegistryFile)) {\n addToSectionRegistry(paths.sectionRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.sectionRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n","/**\n * API client for fetching schemas from the OTL backend.\n * Uses native fetch (Node 18+) with site token authentication.\n */\n\nimport type {\n ApiSuccessResponse,\n BlockSchemaListData,\n BlockSchemaResponse,\n CliConfig,\n SectionSchemaResponse,\n} from \"../types\";\n\nfunction buildUrl(config: CliConfig, path: string): string {\n const base = config.apiUrl.replace(/\\/+$/, \"\");\n return `${base}/api/v1/public/sites/${encodeURIComponent(config.siteId)}${path}`;\n}\n\nfunction authHeaders(config: CliConfig): Record<string, string> {\n return {\n Authorization: `Bearer ${config.accessToken}`,\n Accept: \"application/json\",\n };\n}\n\nasync function fetchJson<T>(\n url: string,\n headers: Record<string, string>,\n): Promise<T> {\n const response = await fetch(url, { headers });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `API request failed (${response.status} ${response.statusText}): ${body}`,\n );\n }\n\n return response.json() as Promise<T>;\n}\n\n/**\n * Fetch all block schemas for the configured site.\n */\nexport async function fetchBlockSchemas(\n config: CliConfig,\n): Promise<BlockSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/blocks\");\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaListData>>(\n url,\n authHeaders(config),\n );\n return result.data.schemas;\n}\n\n/**\n * Fetch a single block schema by its ID.\n */\nexport async function fetchBlockSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<BlockSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/blocks/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a block schema by its type name (e.g. \"pricing-card\").\n * Fetches the full list and filters client-side, since the API indexes by ID.\n */\nexport async function findBlockSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<BlockSchemaResponse | undefined> {\n const schemas = await fetchBlockSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n\n/**\n * Fetch all section schemas for the configured site.\n * The backend returns the array directly (not wrapped in { schemas, total }).\n */\nexport async function fetchSectionSchemas(\n config: CliConfig,\n): Promise<SectionSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/sections\");\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse[]>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Fetch a single section schema by its ID.\n */\nexport async function fetchSectionSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<SectionSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/sections/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a section schema by its type name (e.g. \"pricing-table\").\n * Fetches the full list and filters client-side.\n */\nexport async function findSectionSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<SectionSchemaResponse | undefined> {\n const schemas = await fetchSectionSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n","/**\n * Naming utilities for converting between different case conventions.\n */\n\n/**\n * Convert a kebab-case string to PascalCase.\n * Example: \"pricing-card\" -> \"PricingCard\"\n */\nexport function kebabToPascal(kebab: string): string {\n return kebab\n .split(\"-\")\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join(\"\");\n}\n\n/**\n * Convert a snake_case or kebab-case field ID to camelCase.\n * Example: \"plan_name\" -> \"planName\"\n * Example: \"plan-name\" -> \"planName\"\n */\nexport function fieldIdToCamel(id: string): string {\n return id.replace(/[-_]([a-z])/g, (_, char: string) => char.toUpperCase());\n}\n\n/**\n * Convert a PascalCase string to a display-friendly name.\n * Example: \"PricingCard\" -> \"Pricing Card\"\n */\nexport function pascalToDisplay(pascal: string): string {\n return pascal.replace(/([A-Z])/g, \" $1\").trim();\n}\n","/**\n * Maps schema field types (InputFieldType from @otl-core/cms-types) to\n * TypeScript type strings used in generated component interfaces.\n *\n * Also tracks which imports from @otl-core/cms-types are needed.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\n\nexport interface TypeImports {\n ColorReference: boolean;\n MediaReference: boolean;\n ResponsiveValue: boolean;\n BlockInstance: boolean;\n LocalizedString: boolean;\n}\n\nexport function createEmptyImports(): TypeImports {\n return {\n ColorReference: false,\n MediaReference: false,\n ResponsiveValue: false,\n BlockInstance: false,\n LocalizedString: false,\n };\n}\n\n/**\n * Produce the import statement for @otl-core/cms-types based on which types\n * are actually used in the generated interface.\n */\nexport function buildTypeImportLine(imports: TypeImports): string | null {\n const needed: string[] = [];\n if (imports.ColorReference) needed.push(\"ColorReference\");\n if (imports.MediaReference) needed.push(\"MediaReference\");\n if (imports.ResponsiveValue) needed.push(\"ResponsiveValue\");\n if (imports.BlockInstance) needed.push(\"BlockInstance\");\n if (imports.LocalizedString) needed.push(\"LocalizedString\");\n\n if (needed.length === 0) {\n return null;\n }\n return `import type { ${needed.join(\", \")} } from \"@otl-core/cms-types\";`;\n}\n\n/** Simple field types that map directly to a TS primitive or literal. */\nconst SIMPLE_TYPE_MAP: Record<string, string> = {\n text: \"string\",\n textarea: \"string\",\n url: \"string\",\n markdown: \"string\",\n html: \"string\",\n code: \"string\",\n richtext: \"string\",\n date: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n color: \"string\",\n \"form-selector\": \"string\",\n \"form-page\": \"string\",\n json: \"Record<string, unknown>\",\n object: \"Record<string, unknown>\",\n array: \"unknown[]\",\n \"container-behavior\": '\"boxed\" | \"edged\" | \"ignore\"',\n};\n\n/**\n * Resolve the TypeScript type string for a single schema field.\n * Mutates `imports` to track which types need importing.\n * Returns the TS type string (e.g. `\"string\"`, `\"ColorReference\"`, etc.).\n */\nexport function resolveFieldType(\n field: SchemaField,\n imports: TypeImports,\n): string {\n const simple = SIMPLE_TYPE_MAP[field.type];\n if (simple !== undefined) {\n return simple;\n }\n\n switch (field.type) {\n // Select can be single or multi\n case \"select\":\n return field.multiple ? \"string[]\" : \"string\";\n\n // Theme color types\n case \"theme-color\":\n case \"theme-background-color\":\n case \"theme-foreground-color\":\n imports.ColorReference = true;\n return \"ColorReference\";\n\n // Image / media\n case \"image\":\n imports.MediaReference = true;\n return \"MediaReference\";\n\n // Responsive value types\n case \"spacing\":\n case \"css-value\":\n case \"columns\": // GridColumnsInputField type is \"columns\"\n imports.ResponsiveValue = true;\n return \"ResponsiveValue<string>\";\n\n // Blocks\n case \"blocks\":\n imports.BlockInstance = true;\n return \"BlockInstance[]\";\n\n // Localized text\n case \"localized-text\":\n imports.LocalizedString = true;\n return \"LocalizedString\";\n\n // Group -- will be handled by the interface generator to produce a nested\n // interface. At the type level we return the interface name.\n case \"group\":\n return \"__GROUP__\";\n\n default:\n // Unknown field types fall back to unknown\n return \"unknown\";\n }\n}\n\nexport interface GeneratedInterface {\n /** The main interface name (e.g. \"PricingCardConfig\") */\n name: string;\n /** All interface declarations (main + nested), joined as a string */\n declarations: string;\n /** Tracked imports */\n imports: TypeImports;\n}\n\n/**\n * Generate TypeScript interface declarations from a list of schema fields.\n *\n * @param interfaceName The name for the top-level interface\n * @param fields The schema fields to map\n */\nexport function generateInterface(\n interfaceName: string,\n fields: SchemaField[],\n): GeneratedInterface {\n const imports = createEmptyImports();\n const extraInterfaces: string[] = [];\n\n const lines = buildInterfaceLines(\n interfaceName,\n fields,\n imports,\n extraInterfaces,\n );\n\n const mainInterface = [`interface ${interfaceName} {`, ...lines, \"}\"].join(\n \"\\n\",\n );\n\n const declarations = [...extraInterfaces, mainInterface].join(\"\\n\\n\");\n\n return { name: interfaceName, declarations, imports };\n}\n\nfunction buildInterfaceLines(\n parentName: string,\n fields: SchemaField[],\n imports: TypeImports,\n extraInterfaces: string[],\n): string[] {\n const lines: string[] = [];\n\n for (const field of fields) {\n const camelId = fieldIdToCamel(field.id);\n let tsType = resolveFieldType(field, imports);\n\n // Handle group fields -- generate a nested interface\n if (tsType === \"__GROUP__\" && field.fields && field.fields.length > 0) {\n const nestedName = parentName + kebabToPascal(field.id);\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.fields,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = nestedName;\n } else if (tsType === \"__GROUP__\") {\n // Group with no sub-fields\n tsType = \"Record<string, unknown>\";\n }\n\n // Build the property line with optional JSDoc description\n if (field.description) {\n lines.push(` /** ${field.description} */`);\n }\n lines.push(` ${camelId}?: ${tsType};`);\n }\n\n return lines;\n}\n","/**\n * Generates a block component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a block component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-card\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateBlockComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Block`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n // Merge BlockComponentProps into the same import if there are other cms-types imports\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { BlockComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { BlockComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: BlockComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} block */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Generates a section component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a section component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-table\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateSectionComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Section`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { SectionComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { SectionComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: SectionComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} section */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Updates block/section registry files by adding an import statement\n * and a registration call for a newly generated component.\n */\n\nimport * as fs from \"fs\";\nimport { kebabToPascal } from \"../utils/naming\";\n\n/**\n * Add a block component import and registration to the block registry file.\n *\n * @param registryPath Absolute path to block-registry.ts\n * @param typeName The kebab-case block type (e.g. \"pricing-card\")\n */\nexport function addToBlockRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Block`;\n const importPath = `@/components/blocks/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `blockRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Add a section component import and registration to the section registry file.\n *\n * @param registryPath Absolute path to section-registry.ts\n * @param typeName The kebab-case section type (e.g. \"pricing-table\")\n */\nexport function addToSectionRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Section`;\n const importPath = `@/components/sections/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `sectionRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Insert an import line and a registration line into a registry file.\n *\n * Strategy:\n * 1. Check that the import and registration don't already exist.\n * 2. Find the \"Custom Blocks/Sections\" comment block at the end of the file.\n * 3. Insert the import at the end of the existing import section (before the\n * first blank line after imports or before \"// Create instance\").\n * 4. Insert the registration line just before the closing comment block,\n * or at the very end if no comment block is found.\n */\nfunction updateRegistryFile(\n filePath: string,\n importLine: string,\n registerLine: string,\n): void {\n let content = fs.readFileSync(filePath, \"utf-8\");\n\n // Bail if already registered\n if (content.includes(registerLine)) {\n return;\n }\n\n // --- Insert the import ---\n // Find the last import statement and insert after it\n const importRegex = /^import .+$/gm;\n let lastImportMatch: RegExpExecArray | null = null;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n lastImportMatch = match;\n }\n\n if (lastImportMatch) {\n const insertPos = lastImportMatch.index + lastImportMatch[0].length;\n content =\n content.slice(0, insertPos) +\n \"\\n\" +\n importLine +\n content.slice(insertPos);\n } else {\n // No imports found; prepend\n content = importLine + \"\\n\" + content;\n }\n\n // --- Insert the registration ---\n // Look for the \"Custom Blocks\" or \"Custom Sections\" comment block\n const customCommentIndex = content.indexOf(\"/**\\n * Custom \");\n if (customCommentIndex !== -1) {\n // Insert just before the comment block, with a blank line\n content =\n content.slice(0, customCommentIndex) +\n registerLine +\n \"\\n\\n\" +\n content.slice(customCommentIndex);\n } else {\n // Append at end\n content = content.trimEnd() + \"\\n\" + registerLine + \"\\n\";\n }\n\n fs.writeFileSync(filePath, content, \"utf-8\");\n}\n","/**\n * Environment utilities for reading CLI configuration from .env.local or process.env.\n */\n\nimport * as dotenv from \"dotenv\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { CliConfig } from \"../types\";\n\n/**\n * Load CLI configuration from .env.local (in the current directory) and\n * process.env. The .env.local file takes precedence for values it defines;\n * process.env acts as a fallback.\n *\n * Returns the resolved config, or throws an error with a user-friendly\n * message when required values are missing.\n */\nexport function loadConfig(): CliConfig {\n // Try to load .env.local from cwd\n const envLocalPath = path.resolve(process.cwd(), \".env.local\");\n let fileEnv: Record<string, string> = {};\n\n if (fs.existsSync(envLocalPath)) {\n const parsed = dotenv.parse(fs.readFileSync(envLocalPath, \"utf-8\"));\n fileEnv = parsed;\n }\n\n const siteId = fileEnv[\"SITE_ID\"] || process.env[\"SITE_ID\"] || \"\";\n const accessToken =\n fileEnv[\"SITE_ACCESS_TOKEN\"] || process.env[\"SITE_ACCESS_TOKEN\"] || \"\";\n const apiUrl =\n fileEnv[\"API_URL\"] || process.env[\"API_URL\"] || \"http://localhost:8080\";\n\n if (!siteId || !accessToken) {\n console.error(\"Error: Missing SITE_ID and/or SITE_ACCESS_TOKEN.\");\n console.error(\n \"Run 'npx @otl-core/cli init' to configure your environment.\",\n );\n process.exit(1);\n }\n\n return { siteId, accessToken, apiUrl };\n}\n","/**\n * Engine project detection and path resolution.\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { EnginePaths } from \"../types\";\n\n/** OTL package names that indicate an engine project. */\nconst ENGINE_MARKERS = [\n \"@otl-core/block-registry\",\n \"@otl-core/section-registry\",\n];\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\n/**\n * Read and parse a package.json file. Returns null if it cannot be read.\n */\nfunction readPackageJson(dir: string): PackageJson | null {\n const filePath = path.join(dir, \"package.json\");\n if (!fs.existsSync(filePath)) {\n return null;\n }\n try {\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/**\n * Check whether a directory looks like a OTL engine project.\n */\nfunction isEngineProject(dir: string): boolean {\n const pkg = readPackageJson(dir);\n if (!pkg) {\n return false;\n }\n\n const allDeps: Record<string, string> = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n\n return ENGINE_MARKERS.some((marker) => marker in allDeps);\n}\n\n/**\n * Detect the engine project root starting from the current working directory.\n * Walks up the directory tree until it finds a matching package.json or hits\n * the filesystem root.\n *\n * Returns the resolved EnginePaths, or prints an error and exits.\n */\nexport function requireEngineProject(): EnginePaths {\n let current = process.cwd();\n\n // Walk up at most 10 levels\n for (let i = 0; i < 10; i++) {\n if (isEngineProject(current)) {\n return {\n root: current,\n blocksDir: path.join(current, \"src\", \"components\", \"blocks\"),\n sectionsDir: path.join(current, \"src\", \"components\", \"sections\"),\n blockRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"block-registry.ts\",\n ),\n sectionRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"section-registry.ts\",\n ),\n };\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n console.error(\"Error: Not in a OTL engine project.\");\n console.error(\"Could not find a package.json with @otl-core/ dependencies.\");\n console.error(\"Run this command from your engine project root.\");\n process.exit(1);\n}\n","/**\n * `otl-cli customize` command.\n *\n * Vendor any @otl-core/* package locally for customization.\n * Derives the GitHub repo URL from the package name by convention:\n * @otl-core/<name> → github.com/otl-core/<name>\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst GITHUB_ORG = \"otl-core\";\n\ninterface PkgJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nfunction readPkgJson(): { pkgJson: PkgJson; pkgPath: string } {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n if (!fs.existsSync(pkgPath)) {\n console.error(\"Error: No package.json found in current directory.\");\n process.exit(1);\n }\n const pkgJson = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as PkgJson;\n return { pkgJson, pkgPath };\n}\n\nfunction getOtlDeps(pkgJson: PkgJson): Map<string, string> {\n const deps = new Map<string, string>();\n for (const [name, version] of Object.entries(pkgJson.dependencies || {})) {\n if (name.startsWith(\"@otl-core/\")) {\n deps.set(name, version);\n }\n }\n return deps;\n}\n\nfunction packageNameToShort(fullName: string): string {\n return fullName.replace(\"@otl-core/\", \"\");\n}\n\nexport function registerCustomizeCommands(program: Command): void {\n const cmd = program\n .command(\"customize [packages...]\")\n .description(\"Vendor @otl-core/* packages locally for customization\")\n .option(\"--force\", \"Overwrite existing local packages\", false)\n .option(\"--list\", \"List all customizable @otl-core/* dependencies\")\n .option(\"--restore <packages...>\", \"Restore packages to their npm versions\")\n .action(\n async (\n packages: string[],\n options: { force: boolean; list: boolean; restore?: string[] },\n ) => {\n try {\n const { pkgJson, pkgPath } = readPkgJson();\n const otlDeps = getOtlDeps(pkgJson);\n\n if (options.list) {\n listPackages(otlDeps);\n return;\n }\n\n if (options.restore) {\n restorePackages(options.restore, pkgJson, pkgPath, otlDeps);\n return;\n }\n\n if (packages.length === 0) {\n console.error(\n \"Error: Specify packages to customize, or use --list to see available packages.\",\n );\n cmd.help();\n return;\n }\n\n customizePackages(packages, pkgJson, pkgPath, otlDeps, options.force);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n },\n );\n}\n\nfunction listPackages(otlDeps: Map<string, string>): void {\n if (otlDeps.size === 0) {\n console.log(\"No @otl-core/* dependencies found in package.json.\");\n return;\n }\n\n console.log(\"Customizable @otl-core/* packages:\\n\");\n for (const [name, version] of otlDeps) {\n const isLocal = version.startsWith(\"file:\");\n const status = isLocal ? \" (customized)\" : \"\";\n console.log(` ${packageNameToShort(name)}${status}`);\n }\n console.log(\"\\nUsage: otl-cli customize <package-name> [<package-name> ...]\");\n}\n\nfunction customizePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n force: boolean,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (currentVersion.startsWith(\"file:\") && !force) {\n console.log(\n `Skipping ${shortName} — already customized (${currentVersion}). Use --force to re-clone.`,\n );\n continue;\n }\n\n const targetDir = path.resolve(process.cwd(), \"packages\", shortName);\n\n if (fs.existsSync(targetDir)) {\n if (!force) {\n console.error(\n `Error: ./packages/${shortName}/ already exists. Use --force to overwrite.`,\n );\n process.exit(1);\n }\n fs.rmSync(targetDir, { recursive: true, force: true });\n }\n\n // Ensure packages/ directory exists\n const packagesDir = path.resolve(process.cwd(), \"packages\");\n if (!fs.existsSync(packagesDir)) {\n fs.mkdirSync(packagesDir, { recursive: true });\n }\n\n const repoUrl = `https://github.com/${GITHUB_ORG}/${shortName}.git`;\n console.log(`Cloning ${repoUrl} into ./packages/${shortName}/...`);\n execSync(`git clone --depth 1 ${repoUrl} ${targetDir}`, {\n stdio: \"inherit\",\n });\n\n // Remove .git directory\n const gitDir = path.join(targetDir, \".git\");\n if (fs.existsSync(gitDir)) {\n fs.rmSync(gitDir, { recursive: true, force: true });\n }\n\n // Update package.json dependency to point to local copy\n pkgJson.dependencies![fullName] = `file:./packages/${shortName}`;\n console.log(`Customized ${shortName} → ./packages/${shortName}/`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n\n console.log(\"\");\n console.log(\"Next steps:\");\n console.log(\" 1. Run `npm install` to link the local packages\");\n console.log(\" 2. Customize the source in ./packages/\");\n console.log(\" 3. Rebuild with `npm run build` inside the package directory\");\n}\n\nfunction restorePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (!currentVersion.startsWith(\"file:\")) {\n console.log(\n `${shortName} is already using npm version (${currentVersion}).`,\n );\n continue;\n }\n\n // Restore to latest\n pkgJson.dependencies![fullName] = \"*\";\n console.log(`Restored ${shortName} to npm registry version.`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n console.log(\"\\nRun `npm install` to fetch the packages from npm.\");\n}\n","/**\n * `otl-cli init` command.\n *\n * Interactive setup that writes SITE_ID, SITE_ACCESS_TOKEN,\n * and API_URL into .env.local.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as readline from \"readline\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Configure site credentials in .env.local\")\n .action(async () => {\n try {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n\n console.log(\"OTL CMS -- Engine Configuration\");\n console.log(\"\");\n\n const siteId = await ask(\"Site ID: \");\n if (!siteId) {\n console.error(\"Error: Site ID is required.\");\n rl.close();\n process.exit(1);\n }\n\n const accessToken = await ask(\"Site Access Token: \");\n if (!accessToken) {\n console.error(\"Error: Access token is required.\");\n rl.close();\n process.exit(1);\n }\n\n const apiUrlInput = await ask(\"API URL [http://localhost:8080]: \");\n const apiUrl = apiUrlInput || \"http://localhost:8080\";\n\n rl.close();\n\n // Write or update .env.local\n const envPath = path.resolve(process.cwd(), \".env.local\");\n let content = \"\";\n\n if (fs.existsSync(envPath)) {\n content = fs.readFileSync(envPath, \"utf-8\");\n content = upsertEnvVar(content, \"SITE_ID\", siteId);\n content = upsertEnvVar(content, \"SITE_ACCESS_TOKEN\", accessToken);\n content = upsertEnvVar(content, \"API_URL\", apiUrl);\n } else {\n content = [\n \"# OTL CMS Engine Configuration\",\n `SITE_ID=${siteId}`,\n `SITE_ACCESS_TOKEN=${accessToken}`,\n `API_URL=${apiUrl}`,\n \"\",\n ].join(\"\\n\");\n }\n\n fs.writeFileSync(envPath, content, \"utf-8\");\n console.log(\"\");\n console.log(\"Written to .env.local\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/**\n * Update or insert an environment variable in a .env file string.\n * If the variable already exists, its value is replaced.\n * If it doesn't exist, it's appended at the end.\n */\nfunction upsertEnvVar(content: string, key: string, value: string): string {\n const regex = new RegExp(`^${key}=.*$`, \"m\");\n if (regex.test(content)) {\n return content.replace(regex, `${key}=${value}`);\n }\n // Ensure trailing newline before appending\n const base = content.endsWith(\"\\n\") ? content : content + \"\\n\";\n return base + `${key}=${value}\\n`;\n}\n","/**\n * `otl-cli list` command group.\n *\n * Lists available block or section schemas for the configured site.\n */\n\nimport type { Command } from \"commander\";\nimport { fetchBlockSchemas, fetchSectionSchemas } from \"../api/client\";\nimport { loadConfig } from \"../utils/env\";\n\nexport function registerListCommands(program: Command): void {\n const list = program\n .command(\"list\")\n .description(\"List available schemas for the site\");\n\n list\n .command(\"blocks\")\n .description(\"List all block schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchBlockSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No block schemas found for this site.\");\n return;\n }\n\n // Print header\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n list\n .command(\"sections\")\n .description(\"List all section schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchSectionSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No section schemas found for this site.\");\n return;\n }\n\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/** Pad a string to a minimum width with trailing spaces. */\nfunction padRight(str: string, width: number): string {\n if (str.length >= width) {\n return str + \" \";\n }\n return str + \" \".repeat(width - str.length);\n}\n","/**\n * `otl-cli upgrade` command.\n *\n * Fetches the diff between the current engine version and the latest\n * stable release, applies source patches, and updates package.json\n * dependencies programmatically.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst VERSION_FILE = \".otl-engine-version\";\nconst REPO = \"otl-core/engine-next\";\n\nfunction getCurrentVersion(): string | null {\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n if (!fs.existsSync(versionPath)) return null;\n return fs.readFileSync(versionPath, \"utf-8\").trim();\n}\n\nasync function getLatestRelease(): Promise<string | null> {\n const res = await fetch(\n `https://api.github.com/repos/${REPO}/releases/latest`,\n { headers: { Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { tag_name: string };\n return data.tag_name;\n}\n\nasync function fetchDiff(from: string, to: string): Promise<string | null> {\n const url = `https://github.com/${REPO}/compare/${from}...${to}.diff`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.text();\n}\n\nasync function fetchPackageJson(\n tag: string,\n): Promise<Record<string, unknown> | null> {\n const url = `https://raw.githubusercontent.com/${REPO}/${tag}/package.json`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n}\n\nfunction filterDiff(diff: string, excludeFiles: string[]): string {\n const lines = diff.split(\"\\n\");\n const result: string[] = [];\n let skip = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n const match = line.match(/b\\/(.+)$/);\n skip = match ? excludeFiles.includes(match[1]) : false;\n }\n if (!skip) {\n result.push(line);\n }\n }\n return result.join(\"\\n\");\n}\n\nfunction updatePackageJson(\n localPkg: Record<string, unknown>,\n sourcePkg: Record<string, unknown>,\n targetPkg: Record<string, unknown>,\n): void {\n const localDeps = (localPkg.dependencies ?? {}) as Record<string, string>;\n const targetDeps = (targetPkg.dependencies ?? {}) as Record<string, string>;\n\n // Update @otl-core/* dependency versions\n for (const [key, value] of Object.entries(targetDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDeps) {\n localDeps[key] = value;\n }\n }\n\n // Add new dependencies from target\n for (const [key, value] of Object.entries(targetDeps)) {\n if (!(key in localDeps)) {\n localDeps[key] = value;\n console.log(` Added dependency: ${key}@${value}`);\n }\n }\n\n // Remove deps that upstream removed (existed in source but not in target)\n const sourceDeps = (sourcePkg.dependencies ?? {}) as Record<string, string>;\n for (const key of Object.keys(localDeps)) {\n if (key in sourceDeps && !(key in targetDeps)) {\n delete localDeps[key];\n console.log(` Removed dependency: ${key}`);\n }\n }\n\n localPkg.dependencies = localDeps;\n\n // Handle devDependencies the same way\n const localDevDeps = (localPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const sourceDevDeps = (sourcePkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const targetDevDeps = (targetPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n\n // Add new devDependencies from target\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (!(key in localDevDeps)) {\n localDevDeps[key] = value;\n console.log(` Added devDependency: ${key}@${value}`);\n }\n }\n\n // Remove devDependencies that upstream removed\n for (const key of Object.keys(localDevDeps)) {\n if (key in sourceDevDeps && !(key in targetDevDeps)) {\n delete localDevDeps[key];\n console.log(` Removed devDependency: ${key}`);\n }\n }\n\n // Update @otl-core/* devDependency versions\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDevDeps) {\n localDevDeps[key] = value;\n }\n }\n\n localPkg.devDependencies = localDevDeps;\n\n // Update version\n if (targetPkg.version) {\n localPkg.version = targetPkg.version;\n }\n}\n\nexport function registerUpgradeCommand(program: Command): void {\n program\n .command(\"upgrade\")\n .description(\"Update the engine to the latest stable version\")\n .option(\"--dry-run\", \"Show what would change without applying\")\n .action(async (opts: { dryRun?: boolean }) => {\n try {\n const currentVersion = getCurrentVersion();\n if (!currentVersion) {\n console.error(\n `Error: ${VERSION_FILE} not found. Are you in an OTL Engine project?`,\n );\n process.exit(1);\n }\n\n console.log(`Current version: ${currentVersion}`);\n console.log(\"Checking for updates...\");\n\n const latest = await getLatestRelease();\n if (!latest) {\n console.error(\"Error: Could not fetch latest release.\");\n process.exit(1);\n }\n\n if (latest === currentVersion) {\n console.log(`Already up to date (${currentVersion}).`);\n return;\n }\n\n console.log(`New version available: ${latest}`);\n console.log(`Fetching changes ${currentVersion} -> ${latest}...`);\n\n // Fetch diff, source and target package.json in parallel\n const [diff, sourcePkg, targetPkg] = await Promise.all([\n fetchDiff(currentVersion, latest),\n fetchPackageJson(currentVersion),\n fetchPackageJson(latest),\n ]);\n\n if (!diff) {\n console.error(\"Error: Could not fetch diff between versions.\");\n process.exit(1);\n }\n\n if (opts.dryRun) {\n console.log(\"\\n--- Dry run (changes not applied) ---\\n\");\n console.log(diff);\n return;\n }\n\n // 1. Apply source code patches (exclude package.json and .otl-engine-version)\n const sourceDiff = filterDiff(diff, [\n \"package.json\",\n \".otl-engine-version\",\n ]);\n if (sourceDiff.trim()) {\n const tmpDiff = path.resolve(process.cwd(), \".otl-upgrade.patch\");\n fs.writeFileSync(tmpDiff, sourceDiff, \"utf-8\");\n\n try {\n execSync(`git apply --reject \"${tmpDiff}\" 2>&1 || true`, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n shell: true,\n });\n // Clean up .rej files and report\n const rejFiles: string[] = [];\n const findRej = (dir: string) => {\n for (const entry of fs.readdirSync(dir, {\n withFileTypes: true,\n })) {\n const full = path.join(dir, entry.name);\n if (\n entry.isDirectory() &&\n entry.name !== \"node_modules\" &&\n entry.name !== \".git\"\n ) {\n findRej(full);\n } else if (entry.name.endsWith(\".rej\")) {\n rejFiles.push(full);\n fs.unlinkSync(full);\n }\n }\n };\n findRej(process.cwd());\n if (rejFiles.length > 0) {\n console.log(\n `${rejFiles.length} file(s) had conflicts (skipped). Review manually if needed.`,\n );\n } else {\n console.log(\"Source patches applied successfully.\");\n }\n } finally {\n fs.unlinkSync(tmpDiff);\n }\n }\n\n // 2. Update package.json programmatically\n if (targetPkg && sourcePkg) {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n const localPkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n\n console.log(\"\\nUpdating package.json...\");\n updatePackageJson(localPkg, sourcePkg, targetPkg);\n fs.writeFileSync(\n pkgPath,\n JSON.stringify(localPkg, null, 2) + \"\\n\",\n \"utf-8\",\n );\n console.log(\"package.json updated.\");\n }\n\n // 3. Update version file\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n fs.writeFileSync(versionPath, latest + \"\\n\", \"utf-8\");\n\n console.log(`\\nUpgraded to ${latest}.`);\n console.log(\"Run 'npm install' then review and commit the changes.\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":["fs","path","path","fs","fs","path","program","fs","path","program","fs","path","program","resolve","program","fs","path","import_child_process","program"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/api/client.ts","../src/utils/naming.ts","../src/codegen/type-mapper.ts","../src/codegen/generate-block.ts","../src/codegen/generate-section.ts","../src/codegen/registry-updater.ts","../src/utils/env.ts","../src/utils/project.ts","../src/commands/customize.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/upgrade.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * OTL CMS CLI\n *\n * Schema-driven component scaffolder for the OTL engine.\n */\n\nimport { Command } from \"commander\";\nimport { registerAddCommands } from \"./commands/add\";\nimport { registerCustomizeCommands } from \"./commands/customize\";\nimport { registerInitCommand } from \"./commands/init\";\nimport { registerListCommands } from \"./commands/list\";\nimport { registerUpgradeCommand } from \"./commands/upgrade\";\n// import { registerSetupCommands } from \"./commands/setup\";\n\nconst program = new Command();\n\nprogram\n .name(\"otl-cli\")\n .description(\"OTL CMS CLI -- scaffold and manage engine components\")\n .version(\"0.1.0\");\n\n// Register command groups\nregisterAddCommands(program);\nregisterCustomizeCommands(program);\nregisterListCommands(program);\nregisterInitCommand(program);\nregisterUpgradeCommand(program);\n// registerSetupCommands(program);\n\nprogram.parse();\n","/**\n * `otl-cli add` command group.\n *\n * Generates block or section components from their schema definitions\n * and registers them in the appropriate registry file.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { findBlockSchemaByType, findSectionSchemaByType } from \"../api/client\";\nimport { generateBlockComponent } from \"../codegen/generate-block\";\nimport { generateSectionComponent } from \"../codegen/generate-section\";\nimport {\n addToBlockRegistry,\n addToSectionRegistry,\n} from \"../codegen/registry-updater\";\nimport { loadConfig } from \"../utils/env\";\nimport { requireEngineProject } from \"../utils/project\";\n\nexport function registerAddCommands(program: Command): void {\n const add = program\n .command(\"add\")\n .description(\"Generate a component from a schema definition\");\n\n add\n .command(\"block <name>\")\n .description(\"Generate a block component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findBlockSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No block schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list blocks' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.blocksDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateBlockComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.blockRegistryFile)) {\n addToBlockRegistry(paths.blockRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.blockRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n add\n .command(\"section <name>\")\n .description(\"Generate a section component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findSectionSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No section schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list sections' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.sectionsDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateSectionComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.sectionRegistryFile)) {\n addToSectionRegistry(paths.sectionRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.sectionRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n","/**\n * API client for fetching schemas from the OTL backend.\n * Uses native fetch (Node 18+) with site token authentication.\n */\n\nimport type {\n ApiSuccessResponse,\n BlockSchemaListData,\n BlockSchemaResponse,\n CliConfig,\n SectionSchemaResponse,\n} from \"../types\";\n\nfunction buildUrl(config: CliConfig, path: string): string {\n const base = config.apiUrl.replace(/\\/+$/, \"\");\n return `${base}/api/v1/public/sites/${encodeURIComponent(config.siteId)}${path}`;\n}\n\nfunction authHeaders(config: CliConfig): Record<string, string> {\n return {\n Authorization: `Bearer ${config.accessToken}`,\n Accept: \"application/json\",\n };\n}\n\nasync function fetchJson<T>(\n url: string,\n headers: Record<string, string>,\n): Promise<T> {\n const response = await fetch(url, { headers });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `API request failed (${response.status} ${response.statusText}): ${body}`,\n );\n }\n\n return response.json() as Promise<T>;\n}\n\n/**\n * Fetch all block schemas for the configured site.\n */\nexport async function fetchBlockSchemas(\n config: CliConfig,\n): Promise<BlockSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/blocks\");\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaListData>>(\n url,\n authHeaders(config),\n );\n return result.data.schemas;\n}\n\n/**\n * Fetch a single block schema by its ID.\n */\nexport async function fetchBlockSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<BlockSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/blocks/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a block schema by its type name (e.g. \"pricing-card\").\n * Fetches the full list and filters client-side, since the API indexes by ID.\n */\nexport async function findBlockSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<BlockSchemaResponse | undefined> {\n const schemas = await fetchBlockSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n\n/**\n * Fetch all section schemas for the configured site.\n * The backend returns the array directly (not wrapped in { schemas, total }).\n */\nexport async function fetchSectionSchemas(\n config: CliConfig,\n): Promise<SectionSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/sections\");\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse[]>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Fetch a single section schema by its ID.\n */\nexport async function fetchSectionSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<SectionSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/sections/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a section schema by its type name (e.g. \"pricing-table\").\n * Fetches the full list and filters client-side.\n */\nexport async function findSectionSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<SectionSchemaResponse | undefined> {\n const schemas = await fetchSectionSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n","/**\n * Naming utilities for converting between different case conventions.\n */\n\n/**\n * Convert a kebab-case string to PascalCase.\n * Example: \"pricing-card\" -> \"PricingCard\"\n */\nexport function kebabToPascal(kebab: string): string {\n return kebab\n .split(\"-\")\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join(\"\");\n}\n\n/**\n * Convert a snake_case or kebab-case field ID to camelCase.\n * Example: \"plan_name\" -> \"planName\"\n * Example: \"plan-name\" -> \"planName\"\n */\nexport function fieldIdToCamel(id: string): string {\n return id.replace(/[-_]([a-z])/g, (_, char: string) => char.toUpperCase());\n}\n\n/**\n * Convert a PascalCase string to a display-friendly name.\n * Example: \"PricingCard\" -> \"Pricing Card\"\n */\nexport function pascalToDisplay(pascal: string): string {\n return pascal.replace(/([A-Z])/g, \" $1\").trim();\n}\n","/**\n * Maps schema field types (InputFieldType from @otl-core/cms-types) to\n * TypeScript type strings used in generated component interfaces.\n *\n * Also tracks which imports from @otl-core/cms-types are needed.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\n\nexport interface TypeImports {\n ColorReference: boolean;\n MediaReference: boolean;\n ResponsiveValue: boolean;\n BlockInstance: boolean;\n LocalizedString: boolean;\n}\n\nexport function createEmptyImports(): TypeImports {\n return {\n ColorReference: false,\n MediaReference: false,\n ResponsiveValue: false,\n BlockInstance: false,\n LocalizedString: false,\n };\n}\n\n/**\n * Produce the import statement for @otl-core/cms-types based on which types\n * are actually used in the generated interface.\n */\nexport function buildTypeImportLine(imports: TypeImports): string | null {\n const needed: string[] = [];\n if (imports.ColorReference) needed.push(\"ColorReference\");\n if (imports.MediaReference) needed.push(\"MediaReference\");\n if (imports.ResponsiveValue) needed.push(\"ResponsiveValue\");\n if (imports.BlockInstance) needed.push(\"BlockInstance\");\n if (imports.LocalizedString) needed.push(\"LocalizedString\");\n\n if (needed.length === 0) {\n return null;\n }\n return `import type { ${needed.join(\", \")} } from \"@otl-core/cms-types\";`;\n}\n\n/** Simple field types that map directly to a TS primitive or literal. */\nconst SIMPLE_TYPE_MAP: Record<string, string> = {\n text: \"string\",\n textarea: \"string\",\n url: \"string\",\n markdown: \"string\",\n html: \"string\",\n code: \"string\",\n richtext: \"string\",\n date: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n color: \"string\",\n \"form-selector\": \"string\",\n \"form-page\": \"string\",\n json: \"Record<string, unknown>\",\n \"container-behavior\": '\"boxed\" | \"edged\" | \"ignore\"',\n};\n\n/**\n * Resolve the TypeScript type string for a single schema field.\n * Mutates `imports` to track which types need importing.\n * Returns the TS type string (e.g. `\"string\"`, `\"ColorReference\"`, etc.).\n */\nexport function resolveFieldType(\n field: SchemaField,\n imports: TypeImports,\n): string {\n const simple = SIMPLE_TYPE_MAP[field.type];\n if (simple !== undefined) {\n return simple;\n }\n\n switch (field.type) {\n // Select can be single or multi\n case \"select\":\n return field.multiple ? \"string[]\" : \"string\";\n\n // Theme color types\n case \"theme-color\":\n case \"theme-background-color\":\n case \"theme-foreground-color\":\n imports.ColorReference = true;\n return \"ColorReference\";\n\n // Image / media\n case \"image\":\n imports.MediaReference = true;\n return \"MediaReference\";\n\n // Responsive value types\n case \"spacing\":\n case \"css-value\":\n case \"columns\": // GridColumnsInputField type is \"columns\"\n imports.ResponsiveValue = true;\n return \"ResponsiveValue<string>\";\n\n // Blocks\n case \"blocks\":\n imports.BlockInstance = true;\n return \"BlockInstance[]\";\n\n // Localized text\n case \"localized-text\":\n imports.LocalizedString = true;\n return \"LocalizedString\";\n\n // Array -- will be handled by the interface generator to produce a nested\n // item interface when sub-fields are present.\n case \"array\":\n return \"__ARRAY__\";\n\n // Object -- will be handled by the interface generator to produce a nested\n // interface when properties are present.\n case \"object\":\n return \"__OBJECT__\";\n\n // Group -- will be handled by the interface generator to produce a nested\n // interface. At the type level we return the interface name.\n case \"group\":\n return \"__GROUP__\";\n\n default:\n // Unknown field types fall back to unknown\n return \"unknown\";\n }\n}\n\nexport interface GeneratedInterface {\n /** The main interface name (e.g. \"PricingCardConfig\") */\n name: string;\n /** All interface declarations (main + nested), joined as a string */\n declarations: string;\n /** Tracked imports */\n imports: TypeImports;\n}\n\n/**\n * Generate TypeScript interface declarations from a list of schema fields.\n *\n * @param interfaceName The name for the top-level interface\n * @param fields The schema fields to map\n */\nexport function generateInterface(\n interfaceName: string,\n fields: SchemaField[],\n): GeneratedInterface {\n const imports = createEmptyImports();\n const extraInterfaces: string[] = [];\n\n const lines = buildInterfaceLines(\n interfaceName,\n fields,\n imports,\n extraInterfaces,\n );\n\n const mainInterface = [`interface ${interfaceName} {`, ...lines, \"}\"].join(\n \"\\n\",\n );\n\n const declarations = [...extraInterfaces, mainInterface].join(\"\\n\\n\");\n\n return { name: interfaceName, declarations, imports };\n}\n\nfunction buildInterfaceLines(\n parentName: string,\n fields: SchemaField[],\n imports: TypeImports,\n extraInterfaces: string[],\n): string[] {\n const lines: string[] = [];\n\n for (const field of fields) {\n const camelId = fieldIdToCamel(field.id);\n let tsType = resolveFieldType(field, imports);\n\n // Handle object fields -- generate a nested interface from properties\n if (\n tsType === \"__OBJECT__\" &&\n field.properties &&\n field.properties.length > 0\n ) {\n const nestedName = parentName + kebabToPascal(field.id);\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.properties,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = nestedName;\n } else if (tsType === \"__OBJECT__\") {\n // Object with no properties\n tsType = \"Record<string, unknown>\";\n }\n\n // Handle array fields -- generate a nested item interface\n if (tsType === \"__ARRAY__\" && field.fields && field.fields.length > 0) {\n const nestedName = parentName + kebabToPascal(field.id) + \"Item\";\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.fields,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = `${nestedName}[]`;\n } else if (tsType === \"__ARRAY__\") {\n // Array with no sub-fields\n tsType = \"unknown[]\";\n }\n\n // Handle group fields -- generate a nested interface\n if (tsType === \"__GROUP__\" && field.fields && field.fields.length > 0) {\n const nestedName = parentName + kebabToPascal(field.id);\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.fields,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = nestedName;\n } else if (tsType === \"__GROUP__\") {\n // Group with no sub-fields\n tsType = \"Record<string, unknown>\";\n }\n\n // Build the property line with optional JSDoc description\n if (field.description) {\n lines.push(` /** ${field.description} */`);\n }\n lines.push(` ${camelId}?: ${tsType};`);\n }\n\n return lines;\n}\n","/**\n * Generates a block component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a block component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-card\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateBlockComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Block`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n // Merge BlockComponentProps into the same import if there are other cms-types imports\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { BlockComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { BlockComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: BlockComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} block */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Generates a section component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a section component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-table\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateSectionComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Section`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { SectionComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { SectionComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: SectionComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} section */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Updates block/section registry files by adding an import statement\n * and a registration call for a newly generated component.\n */\n\nimport * as fs from \"fs\";\nimport { kebabToPascal } from \"../utils/naming\";\n\n/**\n * Add a block component import and registration to the block registry file.\n *\n * @param registryPath Absolute path to block-registry.ts\n * @param typeName The kebab-case block type (e.g. \"pricing-card\")\n */\nexport function addToBlockRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Block`;\n const importPath = `@/components/blocks/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `blockRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Add a section component import and registration to the section registry file.\n *\n * @param registryPath Absolute path to section-registry.ts\n * @param typeName The kebab-case section type (e.g. \"pricing-table\")\n */\nexport function addToSectionRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Section`;\n const importPath = `@/components/sections/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `sectionRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Insert an import line and a registration line into a registry file.\n *\n * Strategy:\n * 1. Check that the import and registration don't already exist.\n * 2. Find the \"Custom Blocks/Sections\" comment block at the end of the file.\n * 3. Insert the import at the end of the existing import section (before the\n * first blank line after imports or before \"// Create instance\").\n * 4. Insert the registration line just before the closing comment block,\n * or at the very end if no comment block is found.\n */\nfunction updateRegistryFile(\n filePath: string,\n importLine: string,\n registerLine: string,\n): void {\n let content = fs.readFileSync(filePath, \"utf-8\");\n\n // Bail if already registered\n if (content.includes(registerLine)) {\n return;\n }\n\n // --- Insert the import ---\n // Find the last import statement and insert after it\n const importRegex = /^import .+$/gm;\n let lastImportMatch: RegExpExecArray | null = null;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n lastImportMatch = match;\n }\n\n if (lastImportMatch) {\n const insertPos = lastImportMatch.index + lastImportMatch[0].length;\n content =\n content.slice(0, insertPos) +\n \"\\n\" +\n importLine +\n content.slice(insertPos);\n } else {\n // No imports found; prepend\n content = importLine + \"\\n\" + content;\n }\n\n // --- Insert the registration ---\n // Look for the \"Custom Blocks\" or \"Custom Sections\" comment block\n const customCommentIndex = content.indexOf(\"/**\\n * Custom \");\n if (customCommentIndex !== -1) {\n // Insert just before the comment block, with a blank line\n content =\n content.slice(0, customCommentIndex) +\n registerLine +\n \"\\n\\n\" +\n content.slice(customCommentIndex);\n } else {\n // Append at end\n content = content.trimEnd() + \"\\n\" + registerLine + \"\\n\";\n }\n\n fs.writeFileSync(filePath, content, \"utf-8\");\n}\n","/**\n * Environment utilities for reading CLI configuration from .env.local or process.env.\n */\n\nimport * as dotenv from \"dotenv\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { CliConfig } from \"../types\";\n\n/**\n * Load CLI configuration from .env.local (in the current directory) and\n * process.env. The .env.local file takes precedence for values it defines;\n * process.env acts as a fallback.\n *\n * Returns the resolved config, or throws an error with a user-friendly\n * message when required values are missing.\n */\nexport function loadConfig(): CliConfig {\n // Try to load .env.local from cwd\n const envLocalPath = path.resolve(process.cwd(), \".env.local\");\n let fileEnv: Record<string, string> = {};\n\n if (fs.existsSync(envLocalPath)) {\n const parsed = dotenv.parse(fs.readFileSync(envLocalPath, \"utf-8\"));\n fileEnv = parsed;\n }\n\n const siteId = fileEnv[\"SITE_ID\"] || process.env[\"SITE_ID\"] || \"\";\n const accessToken =\n fileEnv[\"SITE_ACCESS_TOKEN\"] || process.env[\"SITE_ACCESS_TOKEN\"] || \"\";\n const apiUrl =\n fileEnv[\"API_URL\"] || process.env[\"API_URL\"] || \"http://localhost:8080\";\n\n if (!siteId || !accessToken) {\n console.error(\"Error: Missing SITE_ID and/or SITE_ACCESS_TOKEN.\");\n console.error(\n \"Run 'npx @otl-core/cli init' to configure your environment.\",\n );\n process.exit(1);\n }\n\n return { siteId, accessToken, apiUrl };\n}\n","/**\n * Engine project detection and path resolution.\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { EnginePaths } from \"../types\";\n\n/** OTL package names that indicate an engine project. */\nconst ENGINE_MARKERS = [\n \"@otl-core/block-registry\",\n \"@otl-core/section-registry\",\n];\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\n/**\n * Read and parse a package.json file. Returns null if it cannot be read.\n */\nfunction readPackageJson(dir: string): PackageJson | null {\n const filePath = path.join(dir, \"package.json\");\n if (!fs.existsSync(filePath)) {\n return null;\n }\n try {\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/**\n * Check whether a directory looks like a OTL engine project.\n */\nfunction isEngineProject(dir: string): boolean {\n const pkg = readPackageJson(dir);\n if (!pkg) {\n return false;\n }\n\n const allDeps: Record<string, string> = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n\n return ENGINE_MARKERS.some((marker) => marker in allDeps);\n}\n\n/**\n * Detect the engine project root starting from the current working directory.\n * Walks up the directory tree until it finds a matching package.json or hits\n * the filesystem root.\n *\n * Returns the resolved EnginePaths, or prints an error and exits.\n */\nexport function requireEngineProject(): EnginePaths {\n let current = process.cwd();\n\n // Walk up at most 10 levels\n for (let i = 0; i < 10; i++) {\n if (isEngineProject(current)) {\n return {\n root: current,\n blocksDir: path.join(current, \"src\", \"components\", \"blocks\"),\n sectionsDir: path.join(current, \"src\", \"components\", \"sections\"),\n blockRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"block-registry.ts\",\n ),\n sectionRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"section-registry.ts\",\n ),\n };\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n console.error(\"Error: Not in a OTL engine project.\");\n console.error(\"Could not find a package.json with @otl-core/ dependencies.\");\n console.error(\"Run this command from your engine project root.\");\n process.exit(1);\n}\n","/**\n * `otl-cli customize` command.\n *\n * Vendor any @otl-core/* package locally for customization.\n * Derives the GitHub repo URL from the package name by convention:\n * @otl-core/<name> → github.com/otl-core/<name>\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst GITHUB_ORG = \"otl-core\";\n\ninterface PkgJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nfunction readPkgJson(): { pkgJson: PkgJson; pkgPath: string } {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n if (!fs.existsSync(pkgPath)) {\n console.error(\"Error: No package.json found in current directory.\");\n process.exit(1);\n }\n const pkgJson = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as PkgJson;\n return { pkgJson, pkgPath };\n}\n\nfunction getOtlDeps(pkgJson: PkgJson): Map<string, string> {\n const deps = new Map<string, string>();\n for (const [name, version] of Object.entries(pkgJson.dependencies || {})) {\n if (name.startsWith(\"@otl-core/\")) {\n deps.set(name, version);\n }\n }\n return deps;\n}\n\nfunction packageNameToShort(fullName: string): string {\n return fullName.replace(\"@otl-core/\", \"\");\n}\n\nexport function registerCustomizeCommands(program: Command): void {\n const cmd = program\n .command(\"customize [packages...]\")\n .description(\"Vendor @otl-core/* packages locally for customization\")\n .option(\"--force\", \"Overwrite existing local packages\", false)\n .option(\"--list\", \"List all customizable @otl-core/* dependencies\")\n .option(\"--restore <packages...>\", \"Restore packages to their npm versions\")\n .action(\n async (\n packages: string[],\n options: { force: boolean; list: boolean; restore?: string[] },\n ) => {\n try {\n const { pkgJson, pkgPath } = readPkgJson();\n const otlDeps = getOtlDeps(pkgJson);\n\n if (options.list) {\n listPackages(otlDeps);\n return;\n }\n\n if (options.restore) {\n restorePackages(options.restore, pkgJson, pkgPath, otlDeps);\n return;\n }\n\n if (packages.length === 0) {\n console.error(\n \"Error: Specify packages to customize, or use --list to see available packages.\",\n );\n cmd.help();\n return;\n }\n\n customizePackages(packages, pkgJson, pkgPath, otlDeps, options.force);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n },\n );\n}\n\nfunction listPackages(otlDeps: Map<string, string>): void {\n if (otlDeps.size === 0) {\n console.log(\"No @otl-core/* dependencies found in package.json.\");\n return;\n }\n\n console.log(\"Customizable @otl-core/* packages:\\n\");\n for (const [name, version] of otlDeps) {\n const isLocal = version.startsWith(\"file:\");\n const status = isLocal ? \" (customized)\" : \"\";\n console.log(` ${packageNameToShort(name)}${status}`);\n }\n console.log(\"\\nUsage: otl-cli customize <package-name> [<package-name> ...]\");\n}\n\nfunction customizePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n force: boolean,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (currentVersion.startsWith(\"file:\") && !force) {\n console.log(\n `Skipping ${shortName} — already customized (${currentVersion}). Use --force to re-clone.`,\n );\n continue;\n }\n\n const targetDir = path.resolve(process.cwd(), \"packages\", shortName);\n\n if (fs.existsSync(targetDir)) {\n if (!force) {\n console.error(\n `Error: ./packages/${shortName}/ already exists. Use --force to overwrite.`,\n );\n process.exit(1);\n }\n fs.rmSync(targetDir, { recursive: true, force: true });\n }\n\n // Ensure packages/ directory exists\n const packagesDir = path.resolve(process.cwd(), \"packages\");\n if (!fs.existsSync(packagesDir)) {\n fs.mkdirSync(packagesDir, { recursive: true });\n }\n\n const repoUrl = `https://github.com/${GITHUB_ORG}/${shortName}.git`;\n console.log(`Cloning ${repoUrl} into ./packages/${shortName}/...`);\n execSync(`git clone --depth 1 ${repoUrl} ${targetDir}`, {\n stdio: \"inherit\",\n });\n\n // Remove .git directory\n const gitDir = path.join(targetDir, \".git\");\n if (fs.existsSync(gitDir)) {\n fs.rmSync(gitDir, { recursive: true, force: true });\n }\n\n // Update package.json dependency to point to local copy\n pkgJson.dependencies![fullName] = `file:./packages/${shortName}`;\n console.log(`Customized ${shortName} → ./packages/${shortName}/`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n\n console.log(\"\");\n console.log(\"Next steps:\");\n console.log(\" 1. Run `npm install` to link the local packages\");\n console.log(\" 2. Customize the source in ./packages/\");\n console.log(\" 3. Rebuild with `npm run build` inside the package directory\");\n}\n\nfunction restorePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (!currentVersion.startsWith(\"file:\")) {\n console.log(\n `${shortName} is already using npm version (${currentVersion}).`,\n );\n continue;\n }\n\n // Restore to latest\n pkgJson.dependencies![fullName] = \"*\";\n console.log(`Restored ${shortName} to npm registry version.`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n console.log(\"\\nRun `npm install` to fetch the packages from npm.\");\n}\n","/**\n * `otl-cli init` command.\n *\n * Interactive setup that writes SITE_ID, SITE_ACCESS_TOKEN,\n * and API_URL into .env.local.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as readline from \"readline\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Configure site credentials in .env.local\")\n .action(async () => {\n try {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n\n console.log(\"OTL CMS -- Engine Configuration\");\n console.log(\"\");\n\n const siteId = await ask(\"Site ID: \");\n if (!siteId) {\n console.error(\"Error: Site ID is required.\");\n rl.close();\n process.exit(1);\n }\n\n const accessToken = await ask(\"Site Access Token: \");\n if (!accessToken) {\n console.error(\"Error: Access token is required.\");\n rl.close();\n process.exit(1);\n }\n\n const apiUrlInput = await ask(\"API URL [http://localhost:8080]: \");\n const apiUrl = apiUrlInput || \"http://localhost:8080\";\n\n rl.close();\n\n // Write or update .env.local\n const envPath = path.resolve(process.cwd(), \".env.local\");\n let content = \"\";\n\n if (fs.existsSync(envPath)) {\n content = fs.readFileSync(envPath, \"utf-8\");\n content = upsertEnvVar(content, \"SITE_ID\", siteId);\n content = upsertEnvVar(content, \"SITE_ACCESS_TOKEN\", accessToken);\n content = upsertEnvVar(content, \"API_URL\", apiUrl);\n } else {\n content = [\n \"# OTL CMS Engine Configuration\",\n `SITE_ID=${siteId}`,\n `SITE_ACCESS_TOKEN=${accessToken}`,\n `API_URL=${apiUrl}`,\n \"\",\n ].join(\"\\n\");\n }\n\n fs.writeFileSync(envPath, content, \"utf-8\");\n console.log(\"\");\n console.log(\"Written to .env.local\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/**\n * Update or insert an environment variable in a .env file string.\n * If the variable already exists, its value is replaced.\n * If it doesn't exist, it's appended at the end.\n */\nfunction upsertEnvVar(content: string, key: string, value: string): string {\n const regex = new RegExp(`^${key}=.*$`, \"m\");\n if (regex.test(content)) {\n return content.replace(regex, `${key}=${value}`);\n }\n // Ensure trailing newline before appending\n const base = content.endsWith(\"\\n\") ? content : content + \"\\n\";\n return base + `${key}=${value}\\n`;\n}\n","/**\n * `otl-cli list` command group.\n *\n * Lists available block or section schemas for the configured site.\n */\n\nimport type { Command } from \"commander\";\nimport { fetchBlockSchemas, fetchSectionSchemas } from \"../api/client\";\nimport { loadConfig } from \"../utils/env\";\n\nexport function registerListCommands(program: Command): void {\n const list = program\n .command(\"list\")\n .description(\"List available schemas for the site\");\n\n list\n .command(\"blocks\")\n .description(\"List all block schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchBlockSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No block schemas found for this site.\");\n return;\n }\n\n // Print header\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n list\n .command(\"sections\")\n .description(\"List all section schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchSectionSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No section schemas found for this site.\");\n return;\n }\n\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/** Pad a string to a minimum width with trailing spaces. */\nfunction padRight(str: string, width: number): string {\n if (str.length >= width) {\n return str + \" \";\n }\n return str + \" \".repeat(width - str.length);\n}\n","/**\n * `otl-cli upgrade` command.\n *\n * Fetches the diff between the current engine version and the latest\n * stable release, applies source patches, and updates package.json\n * dependencies programmatically.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst VERSION_FILE = \".otl-engine-version\";\nconst REPO = \"otl-core/engine-next\";\n\nfunction getCurrentVersion(): string | null {\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n if (!fs.existsSync(versionPath)) return null;\n return fs.readFileSync(versionPath, \"utf-8\").trim();\n}\n\nasync function getLatestRelease(): Promise<string | null> {\n const res = await fetch(\n `https://api.github.com/repos/${REPO}/releases/latest`,\n { headers: { Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { tag_name: string };\n return data.tag_name;\n}\n\nasync function fetchDiff(from: string, to: string): Promise<string | null> {\n const url = `https://github.com/${REPO}/compare/${from}...${to}.diff`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.text();\n}\n\nasync function fetchPackageJson(\n tag: string,\n): Promise<Record<string, unknown> | null> {\n const url = `https://raw.githubusercontent.com/${REPO}/${tag}/package.json`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n}\n\nfunction filterDiff(diff: string, excludeFiles: string[]): string {\n const lines = diff.split(\"\\n\");\n const result: string[] = [];\n let skip = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n const match = line.match(/b\\/(.+)$/);\n skip = match ? excludeFiles.includes(match[1]) : false;\n }\n if (!skip) {\n result.push(line);\n }\n }\n return result.join(\"\\n\");\n}\n\nfunction updatePackageJson(\n localPkg: Record<string, unknown>,\n sourcePkg: Record<string, unknown>,\n targetPkg: Record<string, unknown>,\n): void {\n const localDeps = (localPkg.dependencies ?? {}) as Record<string, string>;\n const targetDeps = (targetPkg.dependencies ?? {}) as Record<string, string>;\n\n // Update @otl-core/* dependency versions\n for (const [key, value] of Object.entries(targetDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDeps) {\n localDeps[key] = value;\n }\n }\n\n // Add new dependencies from target\n for (const [key, value] of Object.entries(targetDeps)) {\n if (!(key in localDeps)) {\n localDeps[key] = value;\n console.log(` Added dependency: ${key}@${value}`);\n }\n }\n\n // Remove deps that upstream removed (existed in source but not in target)\n const sourceDeps = (sourcePkg.dependencies ?? {}) as Record<string, string>;\n for (const key of Object.keys(localDeps)) {\n if (key in sourceDeps && !(key in targetDeps)) {\n delete localDeps[key];\n console.log(` Removed dependency: ${key}`);\n }\n }\n\n localPkg.dependencies = localDeps;\n\n // Handle devDependencies the same way\n const localDevDeps = (localPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const sourceDevDeps = (sourcePkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const targetDevDeps = (targetPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n\n // Add new devDependencies from target\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (!(key in localDevDeps)) {\n localDevDeps[key] = value;\n console.log(` Added devDependency: ${key}@${value}`);\n }\n }\n\n // Remove devDependencies that upstream removed\n for (const key of Object.keys(localDevDeps)) {\n if (key in sourceDevDeps && !(key in targetDevDeps)) {\n delete localDevDeps[key];\n console.log(` Removed devDependency: ${key}`);\n }\n }\n\n // Update @otl-core/* devDependency versions\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDevDeps) {\n localDevDeps[key] = value;\n }\n }\n\n localPkg.devDependencies = localDevDeps;\n\n // Update version\n if (targetPkg.version) {\n localPkg.version = targetPkg.version;\n }\n}\n\nexport function registerUpgradeCommand(program: Command): void {\n program\n .command(\"upgrade\")\n .description(\"Update the engine to the latest stable version\")\n .option(\"--dry-run\", \"Show what would change without applying\")\n .action(async (opts: { dryRun?: boolean }) => {\n try {\n const currentVersion = getCurrentVersion();\n if (!currentVersion) {\n console.error(\n `Error: ${VERSION_FILE} not found. Are you in an OTL Engine project?`,\n );\n process.exit(1);\n }\n\n console.log(`Current version: ${currentVersion}`);\n console.log(\"Checking for updates...\");\n\n const latest = await getLatestRelease();\n if (!latest) {\n console.error(\"Error: Could not fetch latest release.\");\n process.exit(1);\n }\n\n if (latest === currentVersion) {\n console.log(`Already up to date (${currentVersion}).`);\n return;\n }\n\n console.log(`New version available: ${latest}`);\n console.log(`Fetching changes ${currentVersion} -> ${latest}...`);\n\n // Fetch diff, source and target package.json in parallel\n const [diff, sourcePkg, targetPkg] = await Promise.all([\n fetchDiff(currentVersion, latest),\n fetchPackageJson(currentVersion),\n fetchPackageJson(latest),\n ]);\n\n if (!diff) {\n console.error(\"Error: Could not fetch diff between versions.\");\n process.exit(1);\n }\n\n if (opts.dryRun) {\n console.log(\"\\n--- Dry run (changes not applied) ---\\n\");\n console.log(diff);\n return;\n }\n\n // 1. Apply source code patches (exclude package.json and .otl-engine-version)\n const sourceDiff = filterDiff(diff, [\n \"package.json\",\n \".otl-engine-version\",\n ]);\n if (sourceDiff.trim()) {\n const tmpDiff = path.resolve(process.cwd(), \".otl-upgrade.patch\");\n fs.writeFileSync(tmpDiff, sourceDiff, \"utf-8\");\n\n try {\n execSync(`git apply --reject \"${tmpDiff}\" 2>&1 || true`, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n shell: true,\n });\n // Clean up .rej files and report\n const rejFiles: string[] = [];\n const findRej = (dir: string) => {\n for (const entry of fs.readdirSync(dir, {\n withFileTypes: true,\n })) {\n const full = path.join(dir, entry.name);\n if (\n entry.isDirectory() &&\n entry.name !== \"node_modules\" &&\n entry.name !== \".git\"\n ) {\n findRej(full);\n } else if (entry.name.endsWith(\".rej\")) {\n rejFiles.push(full);\n fs.unlinkSync(full);\n }\n }\n };\n findRej(process.cwd());\n if (rejFiles.length > 0) {\n console.log(\n `${rejFiles.length} file(s) had conflicts (skipped). Review manually if needed.`,\n );\n } else {\n console.log(\"Source patches applied successfully.\");\n }\n } finally {\n fs.unlinkSync(tmpDiff);\n }\n }\n\n // 2. Update package.json programmatically\n if (targetPkg && sourcePkg) {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n const localPkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n\n console.log(\"\\nUpdating package.json...\");\n updatePackageJson(localPkg, sourcePkg, targetPkg);\n fs.writeFileSync(\n pkgPath,\n JSON.stringify(localPkg, null, 2) + \"\\n\",\n \"utf-8\",\n );\n console.log(\"package.json updated.\");\n }\n\n // 3. Update version file\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n fs.writeFileSync(versionPath, latest + \"\\n\", \"utf-8\");\n\n console.log(`\\nUpgraded to ${latest}.`);\n console.log(\"Run 'npm install' then review and commit the changes.\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":["fs","path","path","fs","fs","path","program","fs","path","program","fs","path","program","resolve","program","fs","path","import_child_process","program"]}
|
package/dist/index.js
CHANGED
|
@@ -98,8 +98,6 @@ var SIMPLE_TYPE_MAP = {
|
|
|
98
98
|
"form-selector": "string",
|
|
99
99
|
"form-page": "string",
|
|
100
100
|
json: "Record<string, unknown>",
|
|
101
|
-
object: "Record<string, unknown>",
|
|
102
|
-
array: "unknown[]",
|
|
103
101
|
"container-behavior": '"boxed" | "edged" | "ignore"'
|
|
104
102
|
};
|
|
105
103
|
function resolveFieldType(field, imports) {
|
|
@@ -135,6 +133,14 @@ function resolveFieldType(field, imports) {
|
|
|
135
133
|
case "localized-text":
|
|
136
134
|
imports.LocalizedString = true;
|
|
137
135
|
return "LocalizedString";
|
|
136
|
+
// Array -- will be handled by the interface generator to produce a nested
|
|
137
|
+
// item interface when sub-fields are present.
|
|
138
|
+
case "array":
|
|
139
|
+
return "__ARRAY__";
|
|
140
|
+
// Object -- will be handled by the interface generator to produce a nested
|
|
141
|
+
// interface when properties are present.
|
|
142
|
+
case "object":
|
|
143
|
+
return "__OBJECT__";
|
|
138
144
|
// Group -- will be handled by the interface generator to produce a nested
|
|
139
145
|
// interface. At the type level we return the interface name.
|
|
140
146
|
case "group":
|
|
@@ -163,6 +169,42 @@ function buildInterfaceLines(parentName, fields, imports, extraInterfaces) {
|
|
|
163
169
|
for (const field of fields) {
|
|
164
170
|
const camelId = fieldIdToCamel(field.id);
|
|
165
171
|
let tsType = resolveFieldType(field, imports);
|
|
172
|
+
if (tsType === "__OBJECT__" && field.properties && field.properties.length > 0) {
|
|
173
|
+
const nestedName = parentName + kebabToPascal(field.id);
|
|
174
|
+
const nestedLines = buildInterfaceLines(
|
|
175
|
+
nestedName,
|
|
176
|
+
field.properties,
|
|
177
|
+
imports,
|
|
178
|
+
extraInterfaces
|
|
179
|
+
);
|
|
180
|
+
const nestedDecl = [
|
|
181
|
+
`interface ${nestedName} {`,
|
|
182
|
+
...nestedLines,
|
|
183
|
+
"}"
|
|
184
|
+
].join("\n");
|
|
185
|
+
extraInterfaces.push(nestedDecl);
|
|
186
|
+
tsType = nestedName;
|
|
187
|
+
} else if (tsType === "__OBJECT__") {
|
|
188
|
+
tsType = "Record<string, unknown>";
|
|
189
|
+
}
|
|
190
|
+
if (tsType === "__ARRAY__" && field.fields && field.fields.length > 0) {
|
|
191
|
+
const nestedName = parentName + kebabToPascal(field.id) + "Item";
|
|
192
|
+
const nestedLines = buildInterfaceLines(
|
|
193
|
+
nestedName,
|
|
194
|
+
field.fields,
|
|
195
|
+
imports,
|
|
196
|
+
extraInterfaces
|
|
197
|
+
);
|
|
198
|
+
const nestedDecl = [
|
|
199
|
+
`interface ${nestedName} {`,
|
|
200
|
+
...nestedLines,
|
|
201
|
+
"}"
|
|
202
|
+
].join("\n");
|
|
203
|
+
extraInterfaces.push(nestedDecl);
|
|
204
|
+
tsType = `${nestedName}[]`;
|
|
205
|
+
} else if (tsType === "__ARRAY__") {
|
|
206
|
+
tsType = "unknown[]";
|
|
207
|
+
}
|
|
166
208
|
if (tsType === "__GROUP__" && field.fields && field.fields.length > 0) {
|
|
167
209
|
const nestedName = parentName + kebabToPascal(field.id);
|
|
168
210
|
const nestedLines = buildInterfaceLines(
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/api/client.ts","../src/utils/naming.ts","../src/codegen/type-mapper.ts","../src/codegen/generate-block.ts","../src/codegen/generate-section.ts","../src/codegen/registry-updater.ts","../src/utils/env.ts","../src/utils/project.ts","../src/commands/customize.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/upgrade.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * OTL CMS CLI\n *\n * Schema-driven component scaffolder for the OTL engine.\n */\n\nimport { Command } from \"commander\";\nimport { registerAddCommands } from \"./commands/add\";\nimport { registerCustomizeCommands } from \"./commands/customize\";\nimport { registerInitCommand } from \"./commands/init\";\nimport { registerListCommands } from \"./commands/list\";\nimport { registerUpgradeCommand } from \"./commands/upgrade\";\n// import { registerSetupCommands } from \"./commands/setup\";\n\nconst program = new Command();\n\nprogram\n .name(\"otl-cli\")\n .description(\"OTL CMS CLI -- scaffold and manage engine components\")\n .version(\"0.1.0\");\n\n// Register command groups\nregisterAddCommands(program);\nregisterCustomizeCommands(program);\nregisterListCommands(program);\nregisterInitCommand(program);\nregisterUpgradeCommand(program);\n// registerSetupCommands(program);\n\nprogram.parse();\n","/**\n * `otl-cli add` command group.\n *\n * Generates block or section components from their schema definitions\n * and registers them in the appropriate registry file.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { findBlockSchemaByType, findSectionSchemaByType } from \"../api/client\";\nimport { generateBlockComponent } from \"../codegen/generate-block\";\nimport { generateSectionComponent } from \"../codegen/generate-section\";\nimport {\n addToBlockRegistry,\n addToSectionRegistry,\n} from \"../codegen/registry-updater\";\nimport { loadConfig } from \"../utils/env\";\nimport { requireEngineProject } from \"../utils/project\";\n\nexport function registerAddCommands(program: Command): void {\n const add = program\n .command(\"add\")\n .description(\"Generate a component from a schema definition\");\n\n add\n .command(\"block <name>\")\n .description(\"Generate a block component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findBlockSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No block schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list blocks' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.blocksDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateBlockComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.blockRegistryFile)) {\n addToBlockRegistry(paths.blockRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.blockRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n add\n .command(\"section <name>\")\n .description(\"Generate a section component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findSectionSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No section schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list sections' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.sectionsDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateSectionComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.sectionRegistryFile)) {\n addToSectionRegistry(paths.sectionRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.sectionRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n","/**\n * API client for fetching schemas from the OTL backend.\n * Uses native fetch (Node 18+) with site token authentication.\n */\n\nimport type {\n ApiSuccessResponse,\n BlockSchemaListData,\n BlockSchemaResponse,\n CliConfig,\n SectionSchemaResponse,\n} from \"../types\";\n\nfunction buildUrl(config: CliConfig, path: string): string {\n const base = config.apiUrl.replace(/\\/+$/, \"\");\n return `${base}/api/v1/public/sites/${encodeURIComponent(config.siteId)}${path}`;\n}\n\nfunction authHeaders(config: CliConfig): Record<string, string> {\n return {\n Authorization: `Bearer ${config.accessToken}`,\n Accept: \"application/json\",\n };\n}\n\nasync function fetchJson<T>(\n url: string,\n headers: Record<string, string>,\n): Promise<T> {\n const response = await fetch(url, { headers });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `API request failed (${response.status} ${response.statusText}): ${body}`,\n );\n }\n\n return response.json() as Promise<T>;\n}\n\n/**\n * Fetch all block schemas for the configured site.\n */\nexport async function fetchBlockSchemas(\n config: CliConfig,\n): Promise<BlockSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/blocks\");\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaListData>>(\n url,\n authHeaders(config),\n );\n return result.data.schemas;\n}\n\n/**\n * Fetch a single block schema by its ID.\n */\nexport async function fetchBlockSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<BlockSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/blocks/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a block schema by its type name (e.g. \"pricing-card\").\n * Fetches the full list and filters client-side, since the API indexes by ID.\n */\nexport async function findBlockSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<BlockSchemaResponse | undefined> {\n const schemas = await fetchBlockSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n\n/**\n * Fetch all section schemas for the configured site.\n * The backend returns the array directly (not wrapped in { schemas, total }).\n */\nexport async function fetchSectionSchemas(\n config: CliConfig,\n): Promise<SectionSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/sections\");\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse[]>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Fetch a single section schema by its ID.\n */\nexport async function fetchSectionSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<SectionSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/sections/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a section schema by its type name (e.g. \"pricing-table\").\n * Fetches the full list and filters client-side.\n */\nexport async function findSectionSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<SectionSchemaResponse | undefined> {\n const schemas = await fetchSectionSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n","/**\n * Naming utilities for converting between different case conventions.\n */\n\n/**\n * Convert a kebab-case string to PascalCase.\n * Example: \"pricing-card\" -> \"PricingCard\"\n */\nexport function kebabToPascal(kebab: string): string {\n return kebab\n .split(\"-\")\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join(\"\");\n}\n\n/**\n * Convert a snake_case or kebab-case field ID to camelCase.\n * Example: \"plan_name\" -> \"planName\"\n * Example: \"plan-name\" -> \"planName\"\n */\nexport function fieldIdToCamel(id: string): string {\n return id.replace(/[-_]([a-z])/g, (_, char: string) => char.toUpperCase());\n}\n\n/**\n * Convert a PascalCase string to a display-friendly name.\n * Example: \"PricingCard\" -> \"Pricing Card\"\n */\nexport function pascalToDisplay(pascal: string): string {\n return pascal.replace(/([A-Z])/g, \" $1\").trim();\n}\n","/**\n * Maps schema field types (InputFieldType from @otl-core/cms-types) to\n * TypeScript type strings used in generated component interfaces.\n *\n * Also tracks which imports from @otl-core/cms-types are needed.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\n\nexport interface TypeImports {\n ColorReference: boolean;\n MediaReference: boolean;\n ResponsiveValue: boolean;\n BlockInstance: boolean;\n LocalizedString: boolean;\n}\n\nexport function createEmptyImports(): TypeImports {\n return {\n ColorReference: false,\n MediaReference: false,\n ResponsiveValue: false,\n BlockInstance: false,\n LocalizedString: false,\n };\n}\n\n/**\n * Produce the import statement for @otl-core/cms-types based on which types\n * are actually used in the generated interface.\n */\nexport function buildTypeImportLine(imports: TypeImports): string | null {\n const needed: string[] = [];\n if (imports.ColorReference) needed.push(\"ColorReference\");\n if (imports.MediaReference) needed.push(\"MediaReference\");\n if (imports.ResponsiveValue) needed.push(\"ResponsiveValue\");\n if (imports.BlockInstance) needed.push(\"BlockInstance\");\n if (imports.LocalizedString) needed.push(\"LocalizedString\");\n\n if (needed.length === 0) {\n return null;\n }\n return `import type { ${needed.join(\", \")} } from \"@otl-core/cms-types\";`;\n}\n\n/** Simple field types that map directly to a TS primitive or literal. */\nconst SIMPLE_TYPE_MAP: Record<string, string> = {\n text: \"string\",\n textarea: \"string\",\n url: \"string\",\n markdown: \"string\",\n html: \"string\",\n code: \"string\",\n richtext: \"string\",\n date: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n color: \"string\",\n \"form-selector\": \"string\",\n \"form-page\": \"string\",\n json: \"Record<string, unknown>\",\n object: \"Record<string, unknown>\",\n array: \"unknown[]\",\n \"container-behavior\": '\"boxed\" | \"edged\" | \"ignore\"',\n};\n\n/**\n * Resolve the TypeScript type string for a single schema field.\n * Mutates `imports` to track which types need importing.\n * Returns the TS type string (e.g. `\"string\"`, `\"ColorReference\"`, etc.).\n */\nexport function resolveFieldType(\n field: SchemaField,\n imports: TypeImports,\n): string {\n const simple = SIMPLE_TYPE_MAP[field.type];\n if (simple !== undefined) {\n return simple;\n }\n\n switch (field.type) {\n // Select can be single or multi\n case \"select\":\n return field.multiple ? \"string[]\" : \"string\";\n\n // Theme color types\n case \"theme-color\":\n case \"theme-background-color\":\n case \"theme-foreground-color\":\n imports.ColorReference = true;\n return \"ColorReference\";\n\n // Image / media\n case \"image\":\n imports.MediaReference = true;\n return \"MediaReference\";\n\n // Responsive value types\n case \"spacing\":\n case \"css-value\":\n case \"columns\": // GridColumnsInputField type is \"columns\"\n imports.ResponsiveValue = true;\n return \"ResponsiveValue<string>\";\n\n // Blocks\n case \"blocks\":\n imports.BlockInstance = true;\n return \"BlockInstance[]\";\n\n // Localized text\n case \"localized-text\":\n imports.LocalizedString = true;\n return \"LocalizedString\";\n\n // Group -- will be handled by the interface generator to produce a nested\n // interface. At the type level we return the interface name.\n case \"group\":\n return \"__GROUP__\";\n\n default:\n // Unknown field types fall back to unknown\n return \"unknown\";\n }\n}\n\nexport interface GeneratedInterface {\n /** The main interface name (e.g. \"PricingCardConfig\") */\n name: string;\n /** All interface declarations (main + nested), joined as a string */\n declarations: string;\n /** Tracked imports */\n imports: TypeImports;\n}\n\n/**\n * Generate TypeScript interface declarations from a list of schema fields.\n *\n * @param interfaceName The name for the top-level interface\n * @param fields The schema fields to map\n */\nexport function generateInterface(\n interfaceName: string,\n fields: SchemaField[],\n): GeneratedInterface {\n const imports = createEmptyImports();\n const extraInterfaces: string[] = [];\n\n const lines = buildInterfaceLines(\n interfaceName,\n fields,\n imports,\n extraInterfaces,\n );\n\n const mainInterface = [`interface ${interfaceName} {`, ...lines, \"}\"].join(\n \"\\n\",\n );\n\n const declarations = [...extraInterfaces, mainInterface].join(\"\\n\\n\");\n\n return { name: interfaceName, declarations, imports };\n}\n\nfunction buildInterfaceLines(\n parentName: string,\n fields: SchemaField[],\n imports: TypeImports,\n extraInterfaces: string[],\n): string[] {\n const lines: string[] = [];\n\n for (const field of fields) {\n const camelId = fieldIdToCamel(field.id);\n let tsType = resolveFieldType(field, imports);\n\n // Handle group fields -- generate a nested interface\n if (tsType === \"__GROUP__\" && field.fields && field.fields.length > 0) {\n const nestedName = parentName + kebabToPascal(field.id);\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.fields,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = nestedName;\n } else if (tsType === \"__GROUP__\") {\n // Group with no sub-fields\n tsType = \"Record<string, unknown>\";\n }\n\n // Build the property line with optional JSDoc description\n if (field.description) {\n lines.push(` /** ${field.description} */`);\n }\n lines.push(` ${camelId}?: ${tsType};`);\n }\n\n return lines;\n}\n","/**\n * Generates a block component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a block component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-card\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateBlockComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Block`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n // Merge BlockComponentProps into the same import if there are other cms-types imports\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { BlockComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { BlockComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: BlockComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} block */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Generates a section component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a section component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-table\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateSectionComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Section`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { SectionComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { SectionComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: SectionComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} section */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Updates block/section registry files by adding an import statement\n * and a registration call for a newly generated component.\n */\n\nimport * as fs from \"fs\";\nimport { kebabToPascal } from \"../utils/naming\";\n\n/**\n * Add a block component import and registration to the block registry file.\n *\n * @param registryPath Absolute path to block-registry.ts\n * @param typeName The kebab-case block type (e.g. \"pricing-card\")\n */\nexport function addToBlockRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Block`;\n const importPath = `@/components/blocks/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `blockRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Add a section component import and registration to the section registry file.\n *\n * @param registryPath Absolute path to section-registry.ts\n * @param typeName The kebab-case section type (e.g. \"pricing-table\")\n */\nexport function addToSectionRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Section`;\n const importPath = `@/components/sections/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `sectionRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Insert an import line and a registration line into a registry file.\n *\n * Strategy:\n * 1. Check that the import and registration don't already exist.\n * 2. Find the \"Custom Blocks/Sections\" comment block at the end of the file.\n * 3. Insert the import at the end of the existing import section (before the\n * first blank line after imports or before \"// Create instance\").\n * 4. Insert the registration line just before the closing comment block,\n * or at the very end if no comment block is found.\n */\nfunction updateRegistryFile(\n filePath: string,\n importLine: string,\n registerLine: string,\n): void {\n let content = fs.readFileSync(filePath, \"utf-8\");\n\n // Bail if already registered\n if (content.includes(registerLine)) {\n return;\n }\n\n // --- Insert the import ---\n // Find the last import statement and insert after it\n const importRegex = /^import .+$/gm;\n let lastImportMatch: RegExpExecArray | null = null;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n lastImportMatch = match;\n }\n\n if (lastImportMatch) {\n const insertPos = lastImportMatch.index + lastImportMatch[0].length;\n content =\n content.slice(0, insertPos) +\n \"\\n\" +\n importLine +\n content.slice(insertPos);\n } else {\n // No imports found; prepend\n content = importLine + \"\\n\" + content;\n }\n\n // --- Insert the registration ---\n // Look for the \"Custom Blocks\" or \"Custom Sections\" comment block\n const customCommentIndex = content.indexOf(\"/**\\n * Custom \");\n if (customCommentIndex !== -1) {\n // Insert just before the comment block, with a blank line\n content =\n content.slice(0, customCommentIndex) +\n registerLine +\n \"\\n\\n\" +\n content.slice(customCommentIndex);\n } else {\n // Append at end\n content = content.trimEnd() + \"\\n\" + registerLine + \"\\n\";\n }\n\n fs.writeFileSync(filePath, content, \"utf-8\");\n}\n","/**\n * Environment utilities for reading CLI configuration from .env.local or process.env.\n */\n\nimport * as dotenv from \"dotenv\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { CliConfig } from \"../types\";\n\n/**\n * Load CLI configuration from .env.local (in the current directory) and\n * process.env. The .env.local file takes precedence for values it defines;\n * process.env acts as a fallback.\n *\n * Returns the resolved config, or throws an error with a user-friendly\n * message when required values are missing.\n */\nexport function loadConfig(): CliConfig {\n // Try to load .env.local from cwd\n const envLocalPath = path.resolve(process.cwd(), \".env.local\");\n let fileEnv: Record<string, string> = {};\n\n if (fs.existsSync(envLocalPath)) {\n const parsed = dotenv.parse(fs.readFileSync(envLocalPath, \"utf-8\"));\n fileEnv = parsed;\n }\n\n const siteId = fileEnv[\"SITE_ID\"] || process.env[\"SITE_ID\"] || \"\";\n const accessToken =\n fileEnv[\"SITE_ACCESS_TOKEN\"] || process.env[\"SITE_ACCESS_TOKEN\"] || \"\";\n const apiUrl =\n fileEnv[\"API_URL\"] || process.env[\"API_URL\"] || \"http://localhost:8080\";\n\n if (!siteId || !accessToken) {\n console.error(\"Error: Missing SITE_ID and/or SITE_ACCESS_TOKEN.\");\n console.error(\n \"Run 'npx @otl-core/cli init' to configure your environment.\",\n );\n process.exit(1);\n }\n\n return { siteId, accessToken, apiUrl };\n}\n","/**\n * Engine project detection and path resolution.\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { EnginePaths } from \"../types\";\n\n/** OTL package names that indicate an engine project. */\nconst ENGINE_MARKERS = [\n \"@otl-core/block-registry\",\n \"@otl-core/section-registry\",\n];\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\n/**\n * Read and parse a package.json file. Returns null if it cannot be read.\n */\nfunction readPackageJson(dir: string): PackageJson | null {\n const filePath = path.join(dir, \"package.json\");\n if (!fs.existsSync(filePath)) {\n return null;\n }\n try {\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/**\n * Check whether a directory looks like a OTL engine project.\n */\nfunction isEngineProject(dir: string): boolean {\n const pkg = readPackageJson(dir);\n if (!pkg) {\n return false;\n }\n\n const allDeps: Record<string, string> = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n\n return ENGINE_MARKERS.some((marker) => marker in allDeps);\n}\n\n/**\n * Detect the engine project root starting from the current working directory.\n * Walks up the directory tree until it finds a matching package.json or hits\n * the filesystem root.\n *\n * Returns the resolved EnginePaths, or prints an error and exits.\n */\nexport function requireEngineProject(): EnginePaths {\n let current = process.cwd();\n\n // Walk up at most 10 levels\n for (let i = 0; i < 10; i++) {\n if (isEngineProject(current)) {\n return {\n root: current,\n blocksDir: path.join(current, \"src\", \"components\", \"blocks\"),\n sectionsDir: path.join(current, \"src\", \"components\", \"sections\"),\n blockRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"block-registry.ts\",\n ),\n sectionRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"section-registry.ts\",\n ),\n };\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n console.error(\"Error: Not in a OTL engine project.\");\n console.error(\"Could not find a package.json with @otl-core/ dependencies.\");\n console.error(\"Run this command from your engine project root.\");\n process.exit(1);\n}\n","/**\n * `otl-cli customize` command.\n *\n * Vendor any @otl-core/* package locally for customization.\n * Derives the GitHub repo URL from the package name by convention:\n * @otl-core/<name> → github.com/otl-core/<name>\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst GITHUB_ORG = \"otl-core\";\n\ninterface PkgJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nfunction readPkgJson(): { pkgJson: PkgJson; pkgPath: string } {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n if (!fs.existsSync(pkgPath)) {\n console.error(\"Error: No package.json found in current directory.\");\n process.exit(1);\n }\n const pkgJson = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as PkgJson;\n return { pkgJson, pkgPath };\n}\n\nfunction getOtlDeps(pkgJson: PkgJson): Map<string, string> {\n const deps = new Map<string, string>();\n for (const [name, version] of Object.entries(pkgJson.dependencies || {})) {\n if (name.startsWith(\"@otl-core/\")) {\n deps.set(name, version);\n }\n }\n return deps;\n}\n\nfunction packageNameToShort(fullName: string): string {\n return fullName.replace(\"@otl-core/\", \"\");\n}\n\nexport function registerCustomizeCommands(program: Command): void {\n const cmd = program\n .command(\"customize [packages...]\")\n .description(\"Vendor @otl-core/* packages locally for customization\")\n .option(\"--force\", \"Overwrite existing local packages\", false)\n .option(\"--list\", \"List all customizable @otl-core/* dependencies\")\n .option(\"--restore <packages...>\", \"Restore packages to their npm versions\")\n .action(\n async (\n packages: string[],\n options: { force: boolean; list: boolean; restore?: string[] },\n ) => {\n try {\n const { pkgJson, pkgPath } = readPkgJson();\n const otlDeps = getOtlDeps(pkgJson);\n\n if (options.list) {\n listPackages(otlDeps);\n return;\n }\n\n if (options.restore) {\n restorePackages(options.restore, pkgJson, pkgPath, otlDeps);\n return;\n }\n\n if (packages.length === 0) {\n console.error(\n \"Error: Specify packages to customize, or use --list to see available packages.\",\n );\n cmd.help();\n return;\n }\n\n customizePackages(packages, pkgJson, pkgPath, otlDeps, options.force);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n },\n );\n}\n\nfunction listPackages(otlDeps: Map<string, string>): void {\n if (otlDeps.size === 0) {\n console.log(\"No @otl-core/* dependencies found in package.json.\");\n return;\n }\n\n console.log(\"Customizable @otl-core/* packages:\\n\");\n for (const [name, version] of otlDeps) {\n const isLocal = version.startsWith(\"file:\");\n const status = isLocal ? \" (customized)\" : \"\";\n console.log(` ${packageNameToShort(name)}${status}`);\n }\n console.log(\"\\nUsage: otl-cli customize <package-name> [<package-name> ...]\");\n}\n\nfunction customizePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n force: boolean,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (currentVersion.startsWith(\"file:\") && !force) {\n console.log(\n `Skipping ${shortName} — already customized (${currentVersion}). Use --force to re-clone.`,\n );\n continue;\n }\n\n const targetDir = path.resolve(process.cwd(), \"packages\", shortName);\n\n if (fs.existsSync(targetDir)) {\n if (!force) {\n console.error(\n `Error: ./packages/${shortName}/ already exists. Use --force to overwrite.`,\n );\n process.exit(1);\n }\n fs.rmSync(targetDir, { recursive: true, force: true });\n }\n\n // Ensure packages/ directory exists\n const packagesDir = path.resolve(process.cwd(), \"packages\");\n if (!fs.existsSync(packagesDir)) {\n fs.mkdirSync(packagesDir, { recursive: true });\n }\n\n const repoUrl = `https://github.com/${GITHUB_ORG}/${shortName}.git`;\n console.log(`Cloning ${repoUrl} into ./packages/${shortName}/...`);\n execSync(`git clone --depth 1 ${repoUrl} ${targetDir}`, {\n stdio: \"inherit\",\n });\n\n // Remove .git directory\n const gitDir = path.join(targetDir, \".git\");\n if (fs.existsSync(gitDir)) {\n fs.rmSync(gitDir, { recursive: true, force: true });\n }\n\n // Update package.json dependency to point to local copy\n pkgJson.dependencies![fullName] = `file:./packages/${shortName}`;\n console.log(`Customized ${shortName} → ./packages/${shortName}/`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n\n console.log(\"\");\n console.log(\"Next steps:\");\n console.log(\" 1. Run `npm install` to link the local packages\");\n console.log(\" 2. Customize the source in ./packages/\");\n console.log(\" 3. Rebuild with `npm run build` inside the package directory\");\n}\n\nfunction restorePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (!currentVersion.startsWith(\"file:\")) {\n console.log(\n `${shortName} is already using npm version (${currentVersion}).`,\n );\n continue;\n }\n\n // Restore to latest\n pkgJson.dependencies![fullName] = \"*\";\n console.log(`Restored ${shortName} to npm registry version.`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n console.log(\"\\nRun `npm install` to fetch the packages from npm.\");\n}\n","/**\n * `otl-cli init` command.\n *\n * Interactive setup that writes SITE_ID, SITE_ACCESS_TOKEN,\n * and API_URL into .env.local.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as readline from \"readline\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Configure site credentials in .env.local\")\n .action(async () => {\n try {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n\n console.log(\"OTL CMS -- Engine Configuration\");\n console.log(\"\");\n\n const siteId = await ask(\"Site ID: \");\n if (!siteId) {\n console.error(\"Error: Site ID is required.\");\n rl.close();\n process.exit(1);\n }\n\n const accessToken = await ask(\"Site Access Token: \");\n if (!accessToken) {\n console.error(\"Error: Access token is required.\");\n rl.close();\n process.exit(1);\n }\n\n const apiUrlInput = await ask(\"API URL [http://localhost:8080]: \");\n const apiUrl = apiUrlInput || \"http://localhost:8080\";\n\n rl.close();\n\n // Write or update .env.local\n const envPath = path.resolve(process.cwd(), \".env.local\");\n let content = \"\";\n\n if (fs.existsSync(envPath)) {\n content = fs.readFileSync(envPath, \"utf-8\");\n content = upsertEnvVar(content, \"SITE_ID\", siteId);\n content = upsertEnvVar(content, \"SITE_ACCESS_TOKEN\", accessToken);\n content = upsertEnvVar(content, \"API_URL\", apiUrl);\n } else {\n content = [\n \"# OTL CMS Engine Configuration\",\n `SITE_ID=${siteId}`,\n `SITE_ACCESS_TOKEN=${accessToken}`,\n `API_URL=${apiUrl}`,\n \"\",\n ].join(\"\\n\");\n }\n\n fs.writeFileSync(envPath, content, \"utf-8\");\n console.log(\"\");\n console.log(\"Written to .env.local\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/**\n * Update or insert an environment variable in a .env file string.\n * If the variable already exists, its value is replaced.\n * If it doesn't exist, it's appended at the end.\n */\nfunction upsertEnvVar(content: string, key: string, value: string): string {\n const regex = new RegExp(`^${key}=.*$`, \"m\");\n if (regex.test(content)) {\n return content.replace(regex, `${key}=${value}`);\n }\n // Ensure trailing newline before appending\n const base = content.endsWith(\"\\n\") ? content : content + \"\\n\";\n return base + `${key}=${value}\\n`;\n}\n","/**\n * `otl-cli list` command group.\n *\n * Lists available block or section schemas for the configured site.\n */\n\nimport type { Command } from \"commander\";\nimport { fetchBlockSchemas, fetchSectionSchemas } from \"../api/client\";\nimport { loadConfig } from \"../utils/env\";\n\nexport function registerListCommands(program: Command): void {\n const list = program\n .command(\"list\")\n .description(\"List available schemas for the site\");\n\n list\n .command(\"blocks\")\n .description(\"List all block schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchBlockSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No block schemas found for this site.\");\n return;\n }\n\n // Print header\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n list\n .command(\"sections\")\n .description(\"List all section schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchSectionSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No section schemas found for this site.\");\n return;\n }\n\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/** Pad a string to a minimum width with trailing spaces. */\nfunction padRight(str: string, width: number): string {\n if (str.length >= width) {\n return str + \" \";\n }\n return str + \" \".repeat(width - str.length);\n}\n","/**\n * `otl-cli upgrade` command.\n *\n * Fetches the diff between the current engine version and the latest\n * stable release, applies source patches, and updates package.json\n * dependencies programmatically.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst VERSION_FILE = \".otl-engine-version\";\nconst REPO = \"otl-core/engine-next\";\n\nfunction getCurrentVersion(): string | null {\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n if (!fs.existsSync(versionPath)) return null;\n return fs.readFileSync(versionPath, \"utf-8\").trim();\n}\n\nasync function getLatestRelease(): Promise<string | null> {\n const res = await fetch(\n `https://api.github.com/repos/${REPO}/releases/latest`,\n { headers: { Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { tag_name: string };\n return data.tag_name;\n}\n\nasync function fetchDiff(from: string, to: string): Promise<string | null> {\n const url = `https://github.com/${REPO}/compare/${from}...${to}.diff`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.text();\n}\n\nasync function fetchPackageJson(\n tag: string,\n): Promise<Record<string, unknown> | null> {\n const url = `https://raw.githubusercontent.com/${REPO}/${tag}/package.json`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n}\n\nfunction filterDiff(diff: string, excludeFiles: string[]): string {\n const lines = diff.split(\"\\n\");\n const result: string[] = [];\n let skip = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n const match = line.match(/b\\/(.+)$/);\n skip = match ? excludeFiles.includes(match[1]) : false;\n }\n if (!skip) {\n result.push(line);\n }\n }\n return result.join(\"\\n\");\n}\n\nfunction updatePackageJson(\n localPkg: Record<string, unknown>,\n sourcePkg: Record<string, unknown>,\n targetPkg: Record<string, unknown>,\n): void {\n const localDeps = (localPkg.dependencies ?? {}) as Record<string, string>;\n const targetDeps = (targetPkg.dependencies ?? {}) as Record<string, string>;\n\n // Update @otl-core/* dependency versions\n for (const [key, value] of Object.entries(targetDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDeps) {\n localDeps[key] = value;\n }\n }\n\n // Add new dependencies from target\n for (const [key, value] of Object.entries(targetDeps)) {\n if (!(key in localDeps)) {\n localDeps[key] = value;\n console.log(` Added dependency: ${key}@${value}`);\n }\n }\n\n // Remove deps that upstream removed (existed in source but not in target)\n const sourceDeps = (sourcePkg.dependencies ?? {}) as Record<string, string>;\n for (const key of Object.keys(localDeps)) {\n if (key in sourceDeps && !(key in targetDeps)) {\n delete localDeps[key];\n console.log(` Removed dependency: ${key}`);\n }\n }\n\n localPkg.dependencies = localDeps;\n\n // Handle devDependencies the same way\n const localDevDeps = (localPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const sourceDevDeps = (sourcePkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const targetDevDeps = (targetPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n\n // Add new devDependencies from target\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (!(key in localDevDeps)) {\n localDevDeps[key] = value;\n console.log(` Added devDependency: ${key}@${value}`);\n }\n }\n\n // Remove devDependencies that upstream removed\n for (const key of Object.keys(localDevDeps)) {\n if (key in sourceDevDeps && !(key in targetDevDeps)) {\n delete localDevDeps[key];\n console.log(` Removed devDependency: ${key}`);\n }\n }\n\n // Update @otl-core/* devDependency versions\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDevDeps) {\n localDevDeps[key] = value;\n }\n }\n\n localPkg.devDependencies = localDevDeps;\n\n // Update version\n if (targetPkg.version) {\n localPkg.version = targetPkg.version;\n }\n}\n\nexport function registerUpgradeCommand(program: Command): void {\n program\n .command(\"upgrade\")\n .description(\"Update the engine to the latest stable version\")\n .option(\"--dry-run\", \"Show what would change without applying\")\n .action(async (opts: { dryRun?: boolean }) => {\n try {\n const currentVersion = getCurrentVersion();\n if (!currentVersion) {\n console.error(\n `Error: ${VERSION_FILE} not found. Are you in an OTL Engine project?`,\n );\n process.exit(1);\n }\n\n console.log(`Current version: ${currentVersion}`);\n console.log(\"Checking for updates...\");\n\n const latest = await getLatestRelease();\n if (!latest) {\n console.error(\"Error: Could not fetch latest release.\");\n process.exit(1);\n }\n\n if (latest === currentVersion) {\n console.log(`Already up to date (${currentVersion}).`);\n return;\n }\n\n console.log(`New version available: ${latest}`);\n console.log(`Fetching changes ${currentVersion} -> ${latest}...`);\n\n // Fetch diff, source and target package.json in parallel\n const [diff, sourcePkg, targetPkg] = await Promise.all([\n fetchDiff(currentVersion, latest),\n fetchPackageJson(currentVersion),\n fetchPackageJson(latest),\n ]);\n\n if (!diff) {\n console.error(\"Error: Could not fetch diff between versions.\");\n process.exit(1);\n }\n\n if (opts.dryRun) {\n console.log(\"\\n--- Dry run (changes not applied) ---\\n\");\n console.log(diff);\n return;\n }\n\n // 1. Apply source code patches (exclude package.json and .otl-engine-version)\n const sourceDiff = filterDiff(diff, [\n \"package.json\",\n \".otl-engine-version\",\n ]);\n if (sourceDiff.trim()) {\n const tmpDiff = path.resolve(process.cwd(), \".otl-upgrade.patch\");\n fs.writeFileSync(tmpDiff, sourceDiff, \"utf-8\");\n\n try {\n execSync(`git apply --reject \"${tmpDiff}\" 2>&1 || true`, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n shell: true,\n });\n // Clean up .rej files and report\n const rejFiles: string[] = [];\n const findRej = (dir: string) => {\n for (const entry of fs.readdirSync(dir, {\n withFileTypes: true,\n })) {\n const full = path.join(dir, entry.name);\n if (\n entry.isDirectory() &&\n entry.name !== \"node_modules\" &&\n entry.name !== \".git\"\n ) {\n findRej(full);\n } else if (entry.name.endsWith(\".rej\")) {\n rejFiles.push(full);\n fs.unlinkSync(full);\n }\n }\n };\n findRej(process.cwd());\n if (rejFiles.length > 0) {\n console.log(\n `${rejFiles.length} file(s) had conflicts (skipped). Review manually if needed.`,\n );\n } else {\n console.log(\"Source patches applied successfully.\");\n }\n } finally {\n fs.unlinkSync(tmpDiff);\n }\n }\n\n // 2. Update package.json programmatically\n if (targetPkg && sourcePkg) {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n const localPkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n\n console.log(\"\\nUpdating package.json...\");\n updatePackageJson(localPkg, sourcePkg, targetPkg);\n fs.writeFileSync(\n pkgPath,\n JSON.stringify(localPkg, null, 2) + \"\\n\",\n \"utf-8\",\n );\n console.log(\"package.json updated.\");\n }\n\n // 3. Update version file\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n fs.writeFileSync(versionPath, latest + \"\\n\", \"utf-8\");\n\n console.log(`\\nUpgraded to ${latest}.`);\n console.log(\"Run 'npm install' then review and commit the changes.\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":["fs","path","path","fs","fs","path","program","fs","path","program","fs","path","program","resolve","program","fs","path","execSync","program"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/api/client.ts","../src/utils/naming.ts","../src/codegen/type-mapper.ts","../src/codegen/generate-block.ts","../src/codegen/generate-section.ts","../src/codegen/registry-updater.ts","../src/utils/env.ts","../src/utils/project.ts","../src/commands/customize.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/upgrade.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * OTL CMS CLI\n *\n * Schema-driven component scaffolder for the OTL engine.\n */\n\nimport { Command } from \"commander\";\nimport { registerAddCommands } from \"./commands/add\";\nimport { registerCustomizeCommands } from \"./commands/customize\";\nimport { registerInitCommand } from \"./commands/init\";\nimport { registerListCommands } from \"./commands/list\";\nimport { registerUpgradeCommand } from \"./commands/upgrade\";\n// import { registerSetupCommands } from \"./commands/setup\";\n\nconst program = new Command();\n\nprogram\n .name(\"otl-cli\")\n .description(\"OTL CMS CLI -- scaffold and manage engine components\")\n .version(\"0.1.0\");\n\n// Register command groups\nregisterAddCommands(program);\nregisterCustomizeCommands(program);\nregisterListCommands(program);\nregisterInitCommand(program);\nregisterUpgradeCommand(program);\n// registerSetupCommands(program);\n\nprogram.parse();\n","/**\n * `otl-cli add` command group.\n *\n * Generates block or section components from their schema definitions\n * and registers them in the appropriate registry file.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { findBlockSchemaByType, findSectionSchemaByType } from \"../api/client\";\nimport { generateBlockComponent } from \"../codegen/generate-block\";\nimport { generateSectionComponent } from \"../codegen/generate-section\";\nimport {\n addToBlockRegistry,\n addToSectionRegistry,\n} from \"../codegen/registry-updater\";\nimport { loadConfig } from \"../utils/env\";\nimport { requireEngineProject } from \"../utils/project\";\n\nexport function registerAddCommands(program: Command): void {\n const add = program\n .command(\"add\")\n .description(\"Generate a component from a schema definition\");\n\n add\n .command(\"block <name>\")\n .description(\"Generate a block component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findBlockSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No block schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list blocks' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.blocksDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateBlockComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.blockRegistryFile)) {\n addToBlockRegistry(paths.blockRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.blockRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n add\n .command(\"section <name>\")\n .description(\"Generate a section component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findSectionSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No section schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list sections' to see available schemas.\",\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.sectionsDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`,\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateSectionComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.sectionRegistryFile)) {\n addToSectionRegistry(paths.sectionRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.sectionRegistryFile)}`,\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n","/**\n * API client for fetching schemas from the OTL backend.\n * Uses native fetch (Node 18+) with site token authentication.\n */\n\nimport type {\n ApiSuccessResponse,\n BlockSchemaListData,\n BlockSchemaResponse,\n CliConfig,\n SectionSchemaResponse,\n} from \"../types\";\n\nfunction buildUrl(config: CliConfig, path: string): string {\n const base = config.apiUrl.replace(/\\/+$/, \"\");\n return `${base}/api/v1/public/sites/${encodeURIComponent(config.siteId)}${path}`;\n}\n\nfunction authHeaders(config: CliConfig): Record<string, string> {\n return {\n Authorization: `Bearer ${config.accessToken}`,\n Accept: \"application/json\",\n };\n}\n\nasync function fetchJson<T>(\n url: string,\n headers: Record<string, string>,\n): Promise<T> {\n const response = await fetch(url, { headers });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `API request failed (${response.status} ${response.statusText}): ${body}`,\n );\n }\n\n return response.json() as Promise<T>;\n}\n\n/**\n * Fetch all block schemas for the configured site.\n */\nexport async function fetchBlockSchemas(\n config: CliConfig,\n): Promise<BlockSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/blocks\");\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaListData>>(\n url,\n authHeaders(config),\n );\n return result.data.schemas;\n}\n\n/**\n * Fetch a single block schema by its ID.\n */\nexport async function fetchBlockSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<BlockSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/blocks/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a block schema by its type name (e.g. \"pricing-card\").\n * Fetches the full list and filters client-side, since the API indexes by ID.\n */\nexport async function findBlockSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<BlockSchemaResponse | undefined> {\n const schemas = await fetchBlockSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n\n/**\n * Fetch all section schemas for the configured site.\n * The backend returns the array directly (not wrapped in { schemas, total }).\n */\nexport async function fetchSectionSchemas(\n config: CliConfig,\n): Promise<SectionSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/sections\");\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse[]>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Fetch a single section schema by its ID.\n */\nexport async function fetchSectionSchemaById(\n config: CliConfig,\n schemaId: string,\n): Promise<SectionSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/sections/${encodeURIComponent(schemaId)}`,\n );\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse>>(\n url,\n authHeaders(config),\n );\n return result.data;\n}\n\n/**\n * Find a section schema by its type name (e.g. \"pricing-table\").\n * Fetches the full list and filters client-side.\n */\nexport async function findSectionSchemaByType(\n config: CliConfig,\n typeName: string,\n): Promise<SectionSchemaResponse | undefined> {\n const schemas = await fetchSectionSchemas(config);\n return schemas.find((s) => s.type === typeName);\n}\n","/**\n * Naming utilities for converting between different case conventions.\n */\n\n/**\n * Convert a kebab-case string to PascalCase.\n * Example: \"pricing-card\" -> \"PricingCard\"\n */\nexport function kebabToPascal(kebab: string): string {\n return kebab\n .split(\"-\")\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join(\"\");\n}\n\n/**\n * Convert a snake_case or kebab-case field ID to camelCase.\n * Example: \"plan_name\" -> \"planName\"\n * Example: \"plan-name\" -> \"planName\"\n */\nexport function fieldIdToCamel(id: string): string {\n return id.replace(/[-_]([a-z])/g, (_, char: string) => char.toUpperCase());\n}\n\n/**\n * Convert a PascalCase string to a display-friendly name.\n * Example: \"PricingCard\" -> \"Pricing Card\"\n */\nexport function pascalToDisplay(pascal: string): string {\n return pascal.replace(/([A-Z])/g, \" $1\").trim();\n}\n","/**\n * Maps schema field types (InputFieldType from @otl-core/cms-types) to\n * TypeScript type strings used in generated component interfaces.\n *\n * Also tracks which imports from @otl-core/cms-types are needed.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\n\nexport interface TypeImports {\n ColorReference: boolean;\n MediaReference: boolean;\n ResponsiveValue: boolean;\n BlockInstance: boolean;\n LocalizedString: boolean;\n}\n\nexport function createEmptyImports(): TypeImports {\n return {\n ColorReference: false,\n MediaReference: false,\n ResponsiveValue: false,\n BlockInstance: false,\n LocalizedString: false,\n };\n}\n\n/**\n * Produce the import statement for @otl-core/cms-types based on which types\n * are actually used in the generated interface.\n */\nexport function buildTypeImportLine(imports: TypeImports): string | null {\n const needed: string[] = [];\n if (imports.ColorReference) needed.push(\"ColorReference\");\n if (imports.MediaReference) needed.push(\"MediaReference\");\n if (imports.ResponsiveValue) needed.push(\"ResponsiveValue\");\n if (imports.BlockInstance) needed.push(\"BlockInstance\");\n if (imports.LocalizedString) needed.push(\"LocalizedString\");\n\n if (needed.length === 0) {\n return null;\n }\n return `import type { ${needed.join(\", \")} } from \"@otl-core/cms-types\";`;\n}\n\n/** Simple field types that map directly to a TS primitive or literal. */\nconst SIMPLE_TYPE_MAP: Record<string, string> = {\n text: \"string\",\n textarea: \"string\",\n url: \"string\",\n markdown: \"string\",\n html: \"string\",\n code: \"string\",\n richtext: \"string\",\n date: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n color: \"string\",\n \"form-selector\": \"string\",\n \"form-page\": \"string\",\n json: \"Record<string, unknown>\",\n \"container-behavior\": '\"boxed\" | \"edged\" | \"ignore\"',\n};\n\n/**\n * Resolve the TypeScript type string for a single schema field.\n * Mutates `imports` to track which types need importing.\n * Returns the TS type string (e.g. `\"string\"`, `\"ColorReference\"`, etc.).\n */\nexport function resolveFieldType(\n field: SchemaField,\n imports: TypeImports,\n): string {\n const simple = SIMPLE_TYPE_MAP[field.type];\n if (simple !== undefined) {\n return simple;\n }\n\n switch (field.type) {\n // Select can be single or multi\n case \"select\":\n return field.multiple ? \"string[]\" : \"string\";\n\n // Theme color types\n case \"theme-color\":\n case \"theme-background-color\":\n case \"theme-foreground-color\":\n imports.ColorReference = true;\n return \"ColorReference\";\n\n // Image / media\n case \"image\":\n imports.MediaReference = true;\n return \"MediaReference\";\n\n // Responsive value types\n case \"spacing\":\n case \"css-value\":\n case \"columns\": // GridColumnsInputField type is \"columns\"\n imports.ResponsiveValue = true;\n return \"ResponsiveValue<string>\";\n\n // Blocks\n case \"blocks\":\n imports.BlockInstance = true;\n return \"BlockInstance[]\";\n\n // Localized text\n case \"localized-text\":\n imports.LocalizedString = true;\n return \"LocalizedString\";\n\n // Array -- will be handled by the interface generator to produce a nested\n // item interface when sub-fields are present.\n case \"array\":\n return \"__ARRAY__\";\n\n // Object -- will be handled by the interface generator to produce a nested\n // interface when properties are present.\n case \"object\":\n return \"__OBJECT__\";\n\n // Group -- will be handled by the interface generator to produce a nested\n // interface. At the type level we return the interface name.\n case \"group\":\n return \"__GROUP__\";\n\n default:\n // Unknown field types fall back to unknown\n return \"unknown\";\n }\n}\n\nexport interface GeneratedInterface {\n /** The main interface name (e.g. \"PricingCardConfig\") */\n name: string;\n /** All interface declarations (main + nested), joined as a string */\n declarations: string;\n /** Tracked imports */\n imports: TypeImports;\n}\n\n/**\n * Generate TypeScript interface declarations from a list of schema fields.\n *\n * @param interfaceName The name for the top-level interface\n * @param fields The schema fields to map\n */\nexport function generateInterface(\n interfaceName: string,\n fields: SchemaField[],\n): GeneratedInterface {\n const imports = createEmptyImports();\n const extraInterfaces: string[] = [];\n\n const lines = buildInterfaceLines(\n interfaceName,\n fields,\n imports,\n extraInterfaces,\n );\n\n const mainInterface = [`interface ${interfaceName} {`, ...lines, \"}\"].join(\n \"\\n\",\n );\n\n const declarations = [...extraInterfaces, mainInterface].join(\"\\n\\n\");\n\n return { name: interfaceName, declarations, imports };\n}\n\nfunction buildInterfaceLines(\n parentName: string,\n fields: SchemaField[],\n imports: TypeImports,\n extraInterfaces: string[],\n): string[] {\n const lines: string[] = [];\n\n for (const field of fields) {\n const camelId = fieldIdToCamel(field.id);\n let tsType = resolveFieldType(field, imports);\n\n // Handle object fields -- generate a nested interface from properties\n if (\n tsType === \"__OBJECT__\" &&\n field.properties &&\n field.properties.length > 0\n ) {\n const nestedName = parentName + kebabToPascal(field.id);\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.properties,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = nestedName;\n } else if (tsType === \"__OBJECT__\") {\n // Object with no properties\n tsType = \"Record<string, unknown>\";\n }\n\n // Handle array fields -- generate a nested item interface\n if (tsType === \"__ARRAY__\" && field.fields && field.fields.length > 0) {\n const nestedName = parentName + kebabToPascal(field.id) + \"Item\";\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.fields,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = `${nestedName}[]`;\n } else if (tsType === \"__ARRAY__\") {\n // Array with no sub-fields\n tsType = \"unknown[]\";\n }\n\n // Handle group fields -- generate a nested interface\n if (tsType === \"__GROUP__\" && field.fields && field.fields.length > 0) {\n const nestedName = parentName + kebabToPascal(field.id);\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.fields,\n imports,\n extraInterfaces,\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = nestedName;\n } else if (tsType === \"__GROUP__\") {\n // Group with no sub-fields\n tsType = \"Record<string, unknown>\";\n }\n\n // Build the property line with optional JSDoc description\n if (field.description) {\n lines.push(` /** ${field.description} */`);\n }\n lines.push(` ${camelId}?: ${tsType};`);\n }\n\n return lines;\n}\n","/**\n * Generates a block component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a block component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-card\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateBlockComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Block`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n // Merge BlockComponentProps into the same import if there are other cms-types imports\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { BlockComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { BlockComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: BlockComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} block */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Generates a section component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a section component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-table\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateSectionComponent(\n typeName: string,\n fields: SchemaField[],\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Section`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { SectionComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`,\n );\n } else {\n importLines.push(\n 'import type { SectionComponentProps } from \"@otl-core/cms-types\";',\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map((f) => fieldIdToCamel(f.id))\n .filter((id) => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: SectionComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} section */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Updates block/section registry files by adding an import statement\n * and a registration call for a newly generated component.\n */\n\nimport * as fs from \"fs\";\nimport { kebabToPascal } from \"../utils/naming\";\n\n/**\n * Add a block component import and registration to the block registry file.\n *\n * @param registryPath Absolute path to block-registry.ts\n * @param typeName The kebab-case block type (e.g. \"pricing-card\")\n */\nexport function addToBlockRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Block`;\n const importPath = `@/components/blocks/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `blockRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Add a section component import and registration to the section registry file.\n *\n * @param registryPath Absolute path to section-registry.ts\n * @param typeName The kebab-case section type (e.g. \"pricing-table\")\n */\nexport function addToSectionRegistry(\n registryPath: string,\n typeName: string,\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Section`;\n const importPath = `@/components/sections/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `sectionRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Insert an import line and a registration line into a registry file.\n *\n * Strategy:\n * 1. Check that the import and registration don't already exist.\n * 2. Find the \"Custom Blocks/Sections\" comment block at the end of the file.\n * 3. Insert the import at the end of the existing import section (before the\n * first blank line after imports or before \"// Create instance\").\n * 4. Insert the registration line just before the closing comment block,\n * or at the very end if no comment block is found.\n */\nfunction updateRegistryFile(\n filePath: string,\n importLine: string,\n registerLine: string,\n): void {\n let content = fs.readFileSync(filePath, \"utf-8\");\n\n // Bail if already registered\n if (content.includes(registerLine)) {\n return;\n }\n\n // --- Insert the import ---\n // Find the last import statement and insert after it\n const importRegex = /^import .+$/gm;\n let lastImportMatch: RegExpExecArray | null = null;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n lastImportMatch = match;\n }\n\n if (lastImportMatch) {\n const insertPos = lastImportMatch.index + lastImportMatch[0].length;\n content =\n content.slice(0, insertPos) +\n \"\\n\" +\n importLine +\n content.slice(insertPos);\n } else {\n // No imports found; prepend\n content = importLine + \"\\n\" + content;\n }\n\n // --- Insert the registration ---\n // Look for the \"Custom Blocks\" or \"Custom Sections\" comment block\n const customCommentIndex = content.indexOf(\"/**\\n * Custom \");\n if (customCommentIndex !== -1) {\n // Insert just before the comment block, with a blank line\n content =\n content.slice(0, customCommentIndex) +\n registerLine +\n \"\\n\\n\" +\n content.slice(customCommentIndex);\n } else {\n // Append at end\n content = content.trimEnd() + \"\\n\" + registerLine + \"\\n\";\n }\n\n fs.writeFileSync(filePath, content, \"utf-8\");\n}\n","/**\n * Environment utilities for reading CLI configuration from .env.local or process.env.\n */\n\nimport * as dotenv from \"dotenv\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { CliConfig } from \"../types\";\n\n/**\n * Load CLI configuration from .env.local (in the current directory) and\n * process.env. The .env.local file takes precedence for values it defines;\n * process.env acts as a fallback.\n *\n * Returns the resolved config, or throws an error with a user-friendly\n * message when required values are missing.\n */\nexport function loadConfig(): CliConfig {\n // Try to load .env.local from cwd\n const envLocalPath = path.resolve(process.cwd(), \".env.local\");\n let fileEnv: Record<string, string> = {};\n\n if (fs.existsSync(envLocalPath)) {\n const parsed = dotenv.parse(fs.readFileSync(envLocalPath, \"utf-8\"));\n fileEnv = parsed;\n }\n\n const siteId = fileEnv[\"SITE_ID\"] || process.env[\"SITE_ID\"] || \"\";\n const accessToken =\n fileEnv[\"SITE_ACCESS_TOKEN\"] || process.env[\"SITE_ACCESS_TOKEN\"] || \"\";\n const apiUrl =\n fileEnv[\"API_URL\"] || process.env[\"API_URL\"] || \"http://localhost:8080\";\n\n if (!siteId || !accessToken) {\n console.error(\"Error: Missing SITE_ID and/or SITE_ACCESS_TOKEN.\");\n console.error(\n \"Run 'npx @otl-core/cli init' to configure your environment.\",\n );\n process.exit(1);\n }\n\n return { siteId, accessToken, apiUrl };\n}\n","/**\n * Engine project detection and path resolution.\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { EnginePaths } from \"../types\";\n\n/** OTL package names that indicate an engine project. */\nconst ENGINE_MARKERS = [\n \"@otl-core/block-registry\",\n \"@otl-core/section-registry\",\n];\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\n/**\n * Read and parse a package.json file. Returns null if it cannot be read.\n */\nfunction readPackageJson(dir: string): PackageJson | null {\n const filePath = path.join(dir, \"package.json\");\n if (!fs.existsSync(filePath)) {\n return null;\n }\n try {\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/**\n * Check whether a directory looks like a OTL engine project.\n */\nfunction isEngineProject(dir: string): boolean {\n const pkg = readPackageJson(dir);\n if (!pkg) {\n return false;\n }\n\n const allDeps: Record<string, string> = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n\n return ENGINE_MARKERS.some((marker) => marker in allDeps);\n}\n\n/**\n * Detect the engine project root starting from the current working directory.\n * Walks up the directory tree until it finds a matching package.json or hits\n * the filesystem root.\n *\n * Returns the resolved EnginePaths, or prints an error and exits.\n */\nexport function requireEngineProject(): EnginePaths {\n let current = process.cwd();\n\n // Walk up at most 10 levels\n for (let i = 0; i < 10; i++) {\n if (isEngineProject(current)) {\n return {\n root: current,\n blocksDir: path.join(current, \"src\", \"components\", \"blocks\"),\n sectionsDir: path.join(current, \"src\", \"components\", \"sections\"),\n blockRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"block-registry.ts\",\n ),\n sectionRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"section-registry.ts\",\n ),\n };\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n console.error(\"Error: Not in a OTL engine project.\");\n console.error(\"Could not find a package.json with @otl-core/ dependencies.\");\n console.error(\"Run this command from your engine project root.\");\n process.exit(1);\n}\n","/**\n * `otl-cli customize` command.\n *\n * Vendor any @otl-core/* package locally for customization.\n * Derives the GitHub repo URL from the package name by convention:\n * @otl-core/<name> → github.com/otl-core/<name>\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst GITHUB_ORG = \"otl-core\";\n\ninterface PkgJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nfunction readPkgJson(): { pkgJson: PkgJson; pkgPath: string } {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n if (!fs.existsSync(pkgPath)) {\n console.error(\"Error: No package.json found in current directory.\");\n process.exit(1);\n }\n const pkgJson = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as PkgJson;\n return { pkgJson, pkgPath };\n}\n\nfunction getOtlDeps(pkgJson: PkgJson): Map<string, string> {\n const deps = new Map<string, string>();\n for (const [name, version] of Object.entries(pkgJson.dependencies || {})) {\n if (name.startsWith(\"@otl-core/\")) {\n deps.set(name, version);\n }\n }\n return deps;\n}\n\nfunction packageNameToShort(fullName: string): string {\n return fullName.replace(\"@otl-core/\", \"\");\n}\n\nexport function registerCustomizeCommands(program: Command): void {\n const cmd = program\n .command(\"customize [packages...]\")\n .description(\"Vendor @otl-core/* packages locally for customization\")\n .option(\"--force\", \"Overwrite existing local packages\", false)\n .option(\"--list\", \"List all customizable @otl-core/* dependencies\")\n .option(\"--restore <packages...>\", \"Restore packages to their npm versions\")\n .action(\n async (\n packages: string[],\n options: { force: boolean; list: boolean; restore?: string[] },\n ) => {\n try {\n const { pkgJson, pkgPath } = readPkgJson();\n const otlDeps = getOtlDeps(pkgJson);\n\n if (options.list) {\n listPackages(otlDeps);\n return;\n }\n\n if (options.restore) {\n restorePackages(options.restore, pkgJson, pkgPath, otlDeps);\n return;\n }\n\n if (packages.length === 0) {\n console.error(\n \"Error: Specify packages to customize, or use --list to see available packages.\",\n );\n cmd.help();\n return;\n }\n\n customizePackages(packages, pkgJson, pkgPath, otlDeps, options.force);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n },\n );\n}\n\nfunction listPackages(otlDeps: Map<string, string>): void {\n if (otlDeps.size === 0) {\n console.log(\"No @otl-core/* dependencies found in package.json.\");\n return;\n }\n\n console.log(\"Customizable @otl-core/* packages:\\n\");\n for (const [name, version] of otlDeps) {\n const isLocal = version.startsWith(\"file:\");\n const status = isLocal ? \" (customized)\" : \"\";\n console.log(` ${packageNameToShort(name)}${status}`);\n }\n console.log(\"\\nUsage: otl-cli customize <package-name> [<package-name> ...]\");\n}\n\nfunction customizePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n force: boolean,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (currentVersion.startsWith(\"file:\") && !force) {\n console.log(\n `Skipping ${shortName} — already customized (${currentVersion}). Use --force to re-clone.`,\n );\n continue;\n }\n\n const targetDir = path.resolve(process.cwd(), \"packages\", shortName);\n\n if (fs.existsSync(targetDir)) {\n if (!force) {\n console.error(\n `Error: ./packages/${shortName}/ already exists. Use --force to overwrite.`,\n );\n process.exit(1);\n }\n fs.rmSync(targetDir, { recursive: true, force: true });\n }\n\n // Ensure packages/ directory exists\n const packagesDir = path.resolve(process.cwd(), \"packages\");\n if (!fs.existsSync(packagesDir)) {\n fs.mkdirSync(packagesDir, { recursive: true });\n }\n\n const repoUrl = `https://github.com/${GITHUB_ORG}/${shortName}.git`;\n console.log(`Cloning ${repoUrl} into ./packages/${shortName}/...`);\n execSync(`git clone --depth 1 ${repoUrl} ${targetDir}`, {\n stdio: \"inherit\",\n });\n\n // Remove .git directory\n const gitDir = path.join(targetDir, \".git\");\n if (fs.existsSync(gitDir)) {\n fs.rmSync(gitDir, { recursive: true, force: true });\n }\n\n // Update package.json dependency to point to local copy\n pkgJson.dependencies![fullName] = `file:./packages/${shortName}`;\n console.log(`Customized ${shortName} → ./packages/${shortName}/`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n\n console.log(\"\");\n console.log(\"Next steps:\");\n console.log(\" 1. Run `npm install` to link the local packages\");\n console.log(\" 2. Customize the source in ./packages/\");\n console.log(\" 3. Rebuild with `npm run build` inside the package directory\");\n}\n\nfunction restorePackages(\n packages: string[],\n pkgJson: PkgJson,\n pkgPath: string,\n otlDeps: Map<string, string>,\n): void {\n for (const pkg of packages) {\n const fullName = pkg.startsWith(\"@otl-core/\") ? pkg : `@otl-core/${pkg}`;\n const shortName = packageNameToShort(fullName);\n\n if (!otlDeps.has(fullName)) {\n console.error(\n `Error: \"${fullName}\" is not a dependency. Run --list to see available packages.`,\n );\n process.exit(1);\n }\n\n const currentVersion = otlDeps.get(fullName)!;\n if (!currentVersion.startsWith(\"file:\")) {\n console.log(\n `${shortName} is already using npm version (${currentVersion}).`,\n );\n continue;\n }\n\n // Restore to latest\n pkgJson.dependencies![fullName] = \"*\";\n console.log(`Restored ${shortName} to npm registry version.`);\n }\n\n fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n console.log(\"\\nRun `npm install` to fetch the packages from npm.\");\n}\n","/**\n * `otl-cli init` command.\n *\n * Interactive setup that writes SITE_ID, SITE_ACCESS_TOKEN,\n * and API_URL into .env.local.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as readline from \"readline\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Configure site credentials in .env.local\")\n .action(async () => {\n try {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n\n console.log(\"OTL CMS -- Engine Configuration\");\n console.log(\"\");\n\n const siteId = await ask(\"Site ID: \");\n if (!siteId) {\n console.error(\"Error: Site ID is required.\");\n rl.close();\n process.exit(1);\n }\n\n const accessToken = await ask(\"Site Access Token: \");\n if (!accessToken) {\n console.error(\"Error: Access token is required.\");\n rl.close();\n process.exit(1);\n }\n\n const apiUrlInput = await ask(\"API URL [http://localhost:8080]: \");\n const apiUrl = apiUrlInput || \"http://localhost:8080\";\n\n rl.close();\n\n // Write or update .env.local\n const envPath = path.resolve(process.cwd(), \".env.local\");\n let content = \"\";\n\n if (fs.existsSync(envPath)) {\n content = fs.readFileSync(envPath, \"utf-8\");\n content = upsertEnvVar(content, \"SITE_ID\", siteId);\n content = upsertEnvVar(content, \"SITE_ACCESS_TOKEN\", accessToken);\n content = upsertEnvVar(content, \"API_URL\", apiUrl);\n } else {\n content = [\n \"# OTL CMS Engine Configuration\",\n `SITE_ID=${siteId}`,\n `SITE_ACCESS_TOKEN=${accessToken}`,\n `API_URL=${apiUrl}`,\n \"\",\n ].join(\"\\n\");\n }\n\n fs.writeFileSync(envPath, content, \"utf-8\");\n console.log(\"\");\n console.log(\"Written to .env.local\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/**\n * Update or insert an environment variable in a .env file string.\n * If the variable already exists, its value is replaced.\n * If it doesn't exist, it's appended at the end.\n */\nfunction upsertEnvVar(content: string, key: string, value: string): string {\n const regex = new RegExp(`^${key}=.*$`, \"m\");\n if (regex.test(content)) {\n return content.replace(regex, `${key}=${value}`);\n }\n // Ensure trailing newline before appending\n const base = content.endsWith(\"\\n\") ? content : content + \"\\n\";\n return base + `${key}=${value}\\n`;\n}\n","/**\n * `otl-cli list` command group.\n *\n * Lists available block or section schemas for the configured site.\n */\n\nimport type { Command } from \"commander\";\nimport { fetchBlockSchemas, fetchSectionSchemas } from \"../api/client\";\nimport { loadConfig } from \"../utils/env\";\n\nexport function registerListCommands(program: Command): void {\n const list = program\n .command(\"list\")\n .description(\"List available schemas for the site\");\n\n list\n .command(\"blocks\")\n .description(\"List all block schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchBlockSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No block schemas found for this site.\");\n return;\n }\n\n // Print header\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n list\n .command(\"sections\")\n .description(\"List all section schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchSectionSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No section schemas found for this site.\");\n return;\n }\n\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol),\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount),\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/** Pad a string to a minimum width with trailing spaces. */\nfunction padRight(str: string, width: number): string {\n if (str.length >= width) {\n return str + \" \";\n }\n return str + \" \".repeat(width - str.length);\n}\n","/**\n * `otl-cli upgrade` command.\n *\n * Fetches the diff between the current engine version and the latest\n * stable release, applies source patches, and updates package.json\n * dependencies programmatically.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execSync } from \"child_process\";\n\nconst VERSION_FILE = \".otl-engine-version\";\nconst REPO = \"otl-core/engine-next\";\n\nfunction getCurrentVersion(): string | null {\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n if (!fs.existsSync(versionPath)) return null;\n return fs.readFileSync(versionPath, \"utf-8\").trim();\n}\n\nasync function getLatestRelease(): Promise<string | null> {\n const res = await fetch(\n `https://api.github.com/repos/${REPO}/releases/latest`,\n { headers: { Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { tag_name: string };\n return data.tag_name;\n}\n\nasync function fetchDiff(from: string, to: string): Promise<string | null> {\n const url = `https://github.com/${REPO}/compare/${from}...${to}.diff`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.text();\n}\n\nasync function fetchPackageJson(\n tag: string,\n): Promise<Record<string, unknown> | null> {\n const url = `https://raw.githubusercontent.com/${REPO}/${tag}/package.json`;\n const res = await fetch(url);\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n}\n\nfunction filterDiff(diff: string, excludeFiles: string[]): string {\n const lines = diff.split(\"\\n\");\n const result: string[] = [];\n let skip = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n const match = line.match(/b\\/(.+)$/);\n skip = match ? excludeFiles.includes(match[1]) : false;\n }\n if (!skip) {\n result.push(line);\n }\n }\n return result.join(\"\\n\");\n}\n\nfunction updatePackageJson(\n localPkg: Record<string, unknown>,\n sourcePkg: Record<string, unknown>,\n targetPkg: Record<string, unknown>,\n): void {\n const localDeps = (localPkg.dependencies ?? {}) as Record<string, string>;\n const targetDeps = (targetPkg.dependencies ?? {}) as Record<string, string>;\n\n // Update @otl-core/* dependency versions\n for (const [key, value] of Object.entries(targetDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDeps) {\n localDeps[key] = value;\n }\n }\n\n // Add new dependencies from target\n for (const [key, value] of Object.entries(targetDeps)) {\n if (!(key in localDeps)) {\n localDeps[key] = value;\n console.log(` Added dependency: ${key}@${value}`);\n }\n }\n\n // Remove deps that upstream removed (existed in source but not in target)\n const sourceDeps = (sourcePkg.dependencies ?? {}) as Record<string, string>;\n for (const key of Object.keys(localDeps)) {\n if (key in sourceDeps && !(key in targetDeps)) {\n delete localDeps[key];\n console.log(` Removed dependency: ${key}`);\n }\n }\n\n localPkg.dependencies = localDeps;\n\n // Handle devDependencies the same way\n const localDevDeps = (localPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const sourceDevDeps = (sourcePkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n const targetDevDeps = (targetPkg.devDependencies ?? {}) as Record<\n string,\n string\n >;\n\n // Add new devDependencies from target\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (!(key in localDevDeps)) {\n localDevDeps[key] = value;\n console.log(` Added devDependency: ${key}@${value}`);\n }\n }\n\n // Remove devDependencies that upstream removed\n for (const key of Object.keys(localDevDeps)) {\n if (key in sourceDevDeps && !(key in targetDevDeps)) {\n delete localDevDeps[key];\n console.log(` Removed devDependency: ${key}`);\n }\n }\n\n // Update @otl-core/* devDependency versions\n for (const [key, value] of Object.entries(targetDevDeps)) {\n if (key.startsWith(\"@otl-core/\") && key in localDevDeps) {\n localDevDeps[key] = value;\n }\n }\n\n localPkg.devDependencies = localDevDeps;\n\n // Update version\n if (targetPkg.version) {\n localPkg.version = targetPkg.version;\n }\n}\n\nexport function registerUpgradeCommand(program: Command): void {\n program\n .command(\"upgrade\")\n .description(\"Update the engine to the latest stable version\")\n .option(\"--dry-run\", \"Show what would change without applying\")\n .action(async (opts: { dryRun?: boolean }) => {\n try {\n const currentVersion = getCurrentVersion();\n if (!currentVersion) {\n console.error(\n `Error: ${VERSION_FILE} not found. Are you in an OTL Engine project?`,\n );\n process.exit(1);\n }\n\n console.log(`Current version: ${currentVersion}`);\n console.log(\"Checking for updates...\");\n\n const latest = await getLatestRelease();\n if (!latest) {\n console.error(\"Error: Could not fetch latest release.\");\n process.exit(1);\n }\n\n if (latest === currentVersion) {\n console.log(`Already up to date (${currentVersion}).`);\n return;\n }\n\n console.log(`New version available: ${latest}`);\n console.log(`Fetching changes ${currentVersion} -> ${latest}...`);\n\n // Fetch diff, source and target package.json in parallel\n const [diff, sourcePkg, targetPkg] = await Promise.all([\n fetchDiff(currentVersion, latest),\n fetchPackageJson(currentVersion),\n fetchPackageJson(latest),\n ]);\n\n if (!diff) {\n console.error(\"Error: Could not fetch diff between versions.\");\n process.exit(1);\n }\n\n if (opts.dryRun) {\n console.log(\"\\n--- Dry run (changes not applied) ---\\n\");\n console.log(diff);\n return;\n }\n\n // 1. Apply source code patches (exclude package.json and .otl-engine-version)\n const sourceDiff = filterDiff(diff, [\n \"package.json\",\n \".otl-engine-version\",\n ]);\n if (sourceDiff.trim()) {\n const tmpDiff = path.resolve(process.cwd(), \".otl-upgrade.patch\");\n fs.writeFileSync(tmpDiff, sourceDiff, \"utf-8\");\n\n try {\n execSync(`git apply --reject \"${tmpDiff}\" 2>&1 || true`, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n shell: true,\n });\n // Clean up .rej files and report\n const rejFiles: string[] = [];\n const findRej = (dir: string) => {\n for (const entry of fs.readdirSync(dir, {\n withFileTypes: true,\n })) {\n const full = path.join(dir, entry.name);\n if (\n entry.isDirectory() &&\n entry.name !== \"node_modules\" &&\n entry.name !== \".git\"\n ) {\n findRej(full);\n } else if (entry.name.endsWith(\".rej\")) {\n rejFiles.push(full);\n fs.unlinkSync(full);\n }\n }\n };\n findRej(process.cwd());\n if (rejFiles.length > 0) {\n console.log(\n `${rejFiles.length} file(s) had conflicts (skipped). Review manually if needed.`,\n );\n } else {\n console.log(\"Source patches applied successfully.\");\n }\n } finally {\n fs.unlinkSync(tmpDiff);\n }\n }\n\n // 2. Update package.json programmatically\n if (targetPkg && sourcePkg) {\n const pkgPath = path.resolve(process.cwd(), \"package.json\");\n const localPkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n\n console.log(\"\\nUpdating package.json...\");\n updatePackageJson(localPkg, sourcePkg, targetPkg);\n fs.writeFileSync(\n pkgPath,\n JSON.stringify(localPkg, null, 2) + \"\\n\",\n \"utf-8\",\n );\n console.log(\"package.json updated.\");\n }\n\n // 3. Update version file\n const versionPath = path.resolve(process.cwd(), VERSION_FILE);\n fs.writeFileSync(versionPath, latest + \"\\n\", \"utf-8\");\n\n console.log(`\\nUpgraded to ${latest}.`);\n console.log(\"Run 'npm install' then review and commit the changes.\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":["fs","path","path","fs","fs","path","program","fs","path","program","fs","path","program","resolve","program","fs","path","execSync","program"]}
|