@hstm-labs/forge-apps-generator 0.1.11

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/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @hstm-labs/forge-apps-generator
2
+
3
+ Apps (UI) layer generation stage for Forge — produces pages, components, layouts, forms, and navigation for web/ and mobile-web/ from specification workflows, architecture, and services (API) output.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @hstm-labs/forge-apps-generator
9
+ ```
10
+
11
+ ## Public API
12
+
13
+ ### Types
14
+
15
+ - `UiArtifact` — complete UI layer output
16
+ - `UiPage`, `UiComponent`, `UiLayout`, `UiForm`, `UiNavigation`, `UiRoute`
17
+
18
+ ### Classes
19
+
20
+ - `AppsGenerateStage` — pipeline stage implementing `PipelineStage` interface
21
+ - `UiOutputValidator` — validates LLM-produced UI output
22
+
23
+ ## Usage
24
+
25
+ ```typescript
26
+ import { AppsGenerateStage } from '@hstm-labs/forge-apps-generator';
27
+
28
+ const stage = new AppsGenerateStage();
29
+ const result = await stage.execute(input);
30
+ // result.data contains UiArtifact
31
+ ```
32
+
33
+ ## License
34
+
35
+ [MIT](../../LICENSE)
@@ -0,0 +1,57 @@
1
+ /**
2
+ * UI generation pipeline stage.
3
+ *
4
+ * Produces pages, components, layouts, forms, and navigation from
5
+ * specification workflows, architecture, API endpoints, and technology
6
+ * profile. Follows the same stage implementation pattern established by
7
+ * {@link ArchitectStage} and {@link ServicesGenerateStage}.
8
+ *
9
+ * In API mode, renders prompt templates, calls the LLM via
10
+ * {@link ApiStageExecutor}, validates the output, unpacks individual
11
+ * files into subdirectories, and returns the parsed {@link UiArtifact}
12
+ * in the stage output data.
13
+ *
14
+ * In agent mode, the pipeline runner intercepts before calling
15
+ * `execute()` and exports a prompt via {@link AgentStageExecutor}.
16
+ */
17
+ import type { StageName } from '@hstm-labs/forge-common';
18
+ import type { PipelineStage, PipelineStageInput, PipelineStageOutput, PipelineContext, AgentPromptContext } from '@hstm-labs/forge-core';
19
+ /**
20
+ * Pipeline stage that generates the UI layer.
21
+ *
22
+ * Produces a {@link UiArtifact} containing pages, components, layouts,
23
+ * forms, and navigation configuration. Each element is written as a
24
+ * separate file artifact grouped into subdirectories.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const stage = new AppsGenerateStage();
29
+ * const output = await stage.execute(input, context);
30
+ * const ui = output.data?.ui as UiArtifact;
31
+ * ```
32
+ */
33
+ export declare class AppsGenerateStage implements PipelineStage {
34
+ readonly name: StageName;
35
+ readonly dependsOn: StageName[];
36
+ readonly requiresLLM = true;
37
+ /**
38
+ * Return rendered agent-mode prompt context using `apps-generate-agent.hbs`.
39
+ *
40
+ * @param input - Input from prior stages
41
+ * @param context - Pipeline context with config, workspace, and runId
42
+ * @returns Agent prompt context with rendered template and output schema
43
+ */
44
+ getAgentContext(input: PipelineStageInput, context: PipelineContext): AgentPromptContext;
45
+ /**
46
+ * Execute the UI generation stage.
47
+ *
48
+ * @param input - Input from prior stages (expects validate + architect + services-generate output)
49
+ * @param context - Pipeline context with config, workspace, and adapter
50
+ * @returns Stage output with UI artifacts and parsed UiArtifact in data
51
+ * @throws {ForgeError} FORGE-PIPE-003 if dependency stage output is missing
52
+ * @throws {ForgeError} FORGE-PIPE-001 if adapter is missing
53
+ * @throws {ForgeError} FORGE-GEN-003 if max retries exhausted
54
+ */
55
+ execute(input: PipelineStageInput, context: PipelineContext): Promise<PipelineStageOutput>;
56
+ }
57
+ //# sourceMappingURL=apps-generate-stage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-generate-stage.d.ts","sourceRoot":"","sources":["../src/apps-generate-stage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EAEf,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAY/B;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAkB,YAAW,aAAa;IACrD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAmB;IAC3C,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,CAAsC;IACrE,QAAQ,CAAC,WAAW,QAAQ;IAE5B;;;;;;OAMG;IACH,eAAe,CACb,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,eAAe,GACvB,kBAAkB;IA+CrB;;;;;;;;;OASG;IACG,OAAO,CACX,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,mBAAmB,CAAC;CAqNhC"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * UI generation pipeline stage.
3
+ *
4
+ * Produces pages, components, layouts, forms, and navigation from
5
+ * specification workflows, architecture, API endpoints, and technology
6
+ * profile. Follows the same stage implementation pattern established by
7
+ * {@link ArchitectStage} and {@link ServicesGenerateStage}.
8
+ *
9
+ * In API mode, renders prompt templates, calls the LLM via
10
+ * {@link ApiStageExecutor}, validates the output, unpacks individual
11
+ * files into subdirectories, and returns the parsed {@link UiArtifact}
12
+ * in the stage output data.
13
+ *
14
+ * In agent mode, the pipeline runner intercepts before calling
15
+ * `execute()` and exports a prompt via {@link AgentStageExecutor}.
16
+ */
17
+ import { join } from 'node:path';
18
+ import { writeFileSync, mkdirSync } from 'node:fs';
19
+ import { ForgeError, ErrorCodes, hashContent } from '@hstm-labs/forge-common';
20
+ import { ApiStageExecutor } from '@hstm-labs/forge-core';
21
+ import { resolveApiStyle } from '@hstm-labs/forge-architect';
22
+ import { loadProfile } from '@hstm-labs/forge-profiles';
23
+ import { loadTemplate, renderTemplate } from '@hstm-labs/forge-templates';
24
+ import { UiOutputValidator } from './validator.js';
25
+ /**
26
+ * Pipeline stage that generates the UI layer.
27
+ *
28
+ * Produces a {@link UiArtifact} containing pages, components, layouts,
29
+ * forms, and navigation configuration. Each element is written as a
30
+ * separate file artifact grouped into subdirectories.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const stage = new AppsGenerateStage();
35
+ * const output = await stage.execute(input, context);
36
+ * const ui = output.data?.ui as UiArtifact;
37
+ * ```
38
+ */
39
+ export class AppsGenerateStage {
40
+ name = 'apps-generate';
41
+ dependsOn = ['architect', 'services-generate'];
42
+ requiresLLM = true;
43
+ /**
44
+ * Return rendered agent-mode prompt context using `apps-generate-agent.hbs`.
45
+ *
46
+ * @param input - Input from prior stages
47
+ * @param context - Pipeline context with config, workspace, and runId
48
+ * @returns Agent prompt context with rendered template and output schema
49
+ */
50
+ getAgentContext(input, context) {
51
+ const parsedSpec = input['validate']?.data?.['parsedSpec'];
52
+ const architecture = input['architect']?.data?.['architecture'];
53
+ const api = input['services-generate']?.data?.['api'];
54
+ const profile = loadProfile(context.config.profileName, context.workspace.rootDir);
55
+ const resolvedApiStyle = parsedSpec
56
+ ? resolveApiStyle(parsedSpec, profile)
57
+ : 'graphql';
58
+ const outputDir = join(context.workspace.forgeDir, 'runs', context.runId, 'stages', 'apps-generate', 'artifacts');
59
+ const agentTemplate = loadTemplate('apps-generate-agent', context.workspace.rootDir);
60
+ const rendered = renderTemplate(agentTemplate, {
61
+ spec: (parsedSpec ?? {}),
62
+ profile: profile,
63
+ architecture: (architecture ?? {}),
64
+ api: (api ?? {}),
65
+ stage: { resolvedApiStyle, outputDir },
66
+ });
67
+ return {
68
+ prompt: rendered.content,
69
+ outputSchema: { format: 'json' },
70
+ };
71
+ }
72
+ /**
73
+ * Execute the UI generation stage.
74
+ *
75
+ * @param input - Input from prior stages (expects validate + architect + services-generate output)
76
+ * @param context - Pipeline context with config, workspace, and adapter
77
+ * @returns Stage output with UI artifacts and parsed UiArtifact in data
78
+ * @throws {ForgeError} FORGE-PIPE-003 if dependency stage output is missing
79
+ * @throws {ForgeError} FORGE-PIPE-001 if adapter is missing
80
+ * @throws {ForgeError} FORGE-GEN-003 if max retries exhausted
81
+ */
82
+ async execute(input, context) {
83
+ // 1. Get parsed spec from validate stage output
84
+ const validateOutput = input['validate'];
85
+ if (validateOutput === undefined) {
86
+ throw new ForgeError(ErrorCodes.PIPE.DEPENDENCY_UNMET, "Apps generate stage requires 'validate' stage output, but it was not found. " +
87
+ 'Ensure the validate stage runs before the apps-generate stage.');
88
+ }
89
+ const parsedSpec = validateOutput.data?.['parsedSpec'];
90
+ if (parsedSpec === undefined) {
91
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Validate stage did not produce a parsed specification in its output data. ' +
92
+ 'Ensure the validate stage includes parsedSpec in its data output.');
93
+ }
94
+ // 2. Get architecture from architect stage output
95
+ const architectOutput = input['architect'];
96
+ if (architectOutput === undefined) {
97
+ throw new ForgeError(ErrorCodes.PIPE.DEPENDENCY_UNMET, "Apps generate stage requires 'architect' stage output, but it was not found. " +
98
+ 'Ensure the architect stage runs before the apps-generate stage.');
99
+ }
100
+ const architecture = architectOutput.data?.['architecture'];
101
+ if (architecture === undefined) {
102
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Architect stage did not produce an architecture in its output data. ' +
103
+ 'Ensure the architect stage includes architecture in its data output.');
104
+ }
105
+ // 3. Get API artifact from services-generate stage output
106
+ const servicesGenerateOutput = input['services-generate'];
107
+ if (servicesGenerateOutput === undefined) {
108
+ throw new ForgeError(ErrorCodes.PIPE.DEPENDENCY_UNMET, "Apps generate stage requires 'services-generate' stage output, but it was not found. " +
109
+ 'Ensure the services-generate stage runs before the apps-generate stage.');
110
+ }
111
+ const api = servicesGenerateOutput.data?.['api'];
112
+ if (api === undefined) {
113
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Services generate stage did not produce an API artifact in its output data. ' +
114
+ 'Ensure the services-generate stage includes api in its data output.');
115
+ }
116
+ // 4. Load profile, resolve API style
117
+ const profile = loadProfile(context.config.profileName, context.workspace.rootDir);
118
+ const resolvedApiStyle = resolveApiStyle(parsedSpec, profile);
119
+ // 5. Compute output directory
120
+ const outputDir = join(context.workspace.forgeDir, 'runs', context.runId, 'stages', 'apps-generate', 'artifacts');
121
+ // 6. Load and render templates
122
+ const systemTemplate = loadTemplate('apps-generate-system', context.workspace.rootDir);
123
+ const userTemplate = loadTemplate('apps-generate-user', context.workspace.rootDir);
124
+ const templateContext = {
125
+ spec: parsedSpec,
126
+ profile: profile,
127
+ architecture: architecture,
128
+ api: api,
129
+ stage: {
130
+ resolvedApiStyle,
131
+ outputDir,
132
+ },
133
+ };
134
+ const systemPrompt = renderTemplate(systemTemplate, templateContext);
135
+ const userPrompt = renderTemplate(userTemplate, templateContext);
136
+ // 7. Execute via API mode StageExecutor
137
+ if (context.adapter === undefined) {
138
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Apps generate stage requires an LLM adapter in API mode, but none was provided. ' +
139
+ 'Configure an LLM provider in forge.config.json or use agent mode.');
140
+ }
141
+ const entityNames = architecture.dataModel.map((e) => e.name);
142
+ const validator = new UiOutputValidator(entityNames);
143
+ const executor = new ApiStageExecutor({
144
+ adapter: context.adapter,
145
+ validator,
146
+ retryPolicy: {
147
+ maxRetries: 3,
148
+ backoffMs: 1000,
149
+ includeErrorInRetry: true,
150
+ },
151
+ });
152
+ const result = await executor.execute({
153
+ prompt: userPrompt.content,
154
+ systemPrompt: systemPrompt.content,
155
+ stageName: 'apps-generate',
156
+ outputDir,
157
+ runId: context.runId,
158
+ mode: 'api',
159
+ outputSchema: { format: 'json' },
160
+ });
161
+ // 8. Parse UiArtifact from LLM output
162
+ const rawContent = result.artifacts[0]?.content ?? '';
163
+ const uiArtifact = JSON.parse(rawContent);
164
+ // 9. Write individual files to artifacts directory in subdirectories
165
+ const artifacts = [];
166
+ // Pages
167
+ const pagesDir = join(outputDir, 'pages');
168
+ mkdirSync(pagesDir, { recursive: true });
169
+ for (const page of uiArtifact.pages) {
170
+ writeFileSync(join(pagesDir, page.fileName), page.content, 'utf-8');
171
+ artifacts.push({
172
+ filePath: join('pages', page.fileName),
173
+ content: page.content,
174
+ contentHash: hashContent(page.content),
175
+ sizeBytes: Buffer.byteLength(page.content, 'utf-8'),
176
+ });
177
+ }
178
+ // Components
179
+ const componentsDir = join(outputDir, 'components');
180
+ mkdirSync(componentsDir, { recursive: true });
181
+ for (const component of uiArtifact.components) {
182
+ writeFileSync(join(componentsDir, component.fileName), component.content, 'utf-8');
183
+ artifacts.push({
184
+ filePath: join('components', component.fileName),
185
+ content: component.content,
186
+ contentHash: hashContent(component.content),
187
+ sizeBytes: Buffer.byteLength(component.content, 'utf-8'),
188
+ });
189
+ }
190
+ // Layouts
191
+ const layoutsDir = join(outputDir, 'layouts');
192
+ mkdirSync(layoutsDir, { recursive: true });
193
+ for (const layout of uiArtifact.layouts) {
194
+ writeFileSync(join(layoutsDir, layout.fileName), layout.content, 'utf-8');
195
+ artifacts.push({
196
+ filePath: join('layouts', layout.fileName),
197
+ content: layout.content,
198
+ contentHash: hashContent(layout.content),
199
+ sizeBytes: Buffer.byteLength(layout.content, 'utf-8'),
200
+ });
201
+ }
202
+ // Forms
203
+ const formsDir = join(outputDir, 'forms');
204
+ mkdirSync(formsDir, { recursive: true });
205
+ for (const form of uiArtifact.forms) {
206
+ writeFileSync(join(formsDir, form.fileName), form.content, 'utf-8');
207
+ artifacts.push({
208
+ filePath: join('forms', form.fileName),
209
+ content: form.content,
210
+ contentHash: hashContent(form.content),
211
+ sizeBytes: Buffer.byteLength(form.content, 'utf-8'),
212
+ });
213
+ }
214
+ // Navigation
215
+ mkdirSync(outputDir, { recursive: true });
216
+ writeFileSync(join(outputDir, uiArtifact.navigation.fileName), uiArtifact.navigation.content, 'utf-8');
217
+ artifacts.push({
218
+ filePath: uiArtifact.navigation.fileName,
219
+ content: uiArtifact.navigation.content,
220
+ contentHash: hashContent(uiArtifact.navigation.content),
221
+ sizeBytes: Buffer.byteLength(uiArtifact.navigation.content, 'utf-8'),
222
+ });
223
+ // 10. Return PipelineStageOutput with all artifacts and data
224
+ return {
225
+ artifacts,
226
+ data: {
227
+ ui: uiArtifact,
228
+ },
229
+ };
230
+ }
231
+ }
232
+ //# sourceMappingURL=apps-generate-stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-generate-stage.js","sourceRoot":"","sources":["../src/apps-generate-stage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type { UiArtifact, UiPage, UiComponent, UiLayout, UiForm, UiNavigation, UiRoute, } from './types.js';
2
+ export { AppsGenerateStage } from './apps-generate-stage.js';
3
+ export { UiOutputValidator } from './validator.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,UAAU,EACV,MAAM,EACN,WAAW,EACX,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { AppsGenerateStage } from './apps-generate-stage.js';
2
+ export { UiOutputValidator } from './validator.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * UI artifact type definitions for the Forge UI generation stage.
3
+ *
4
+ * Defines the output schema produced by the UI generation stage,
5
+ * including pages, components, layouts, forms, and navigation.
6
+ */
7
+ /** Complete UI layer output produced by the apps-generate stage. */
8
+ export interface UiArtifact {
9
+ /** Frontend framework used. */
10
+ framework: string;
11
+ /** Generated pages (route-level components). */
12
+ pages: UiPage[];
13
+ /** Shared/reusable components. */
14
+ components: UiComponent[];
15
+ /** Layout components (shells, navigation). */
16
+ layouts: UiLayout[];
17
+ /** Form definitions for entity CRUD. */
18
+ forms: UiForm[];
19
+ /** Navigation/routing configuration. */
20
+ navigation: UiNavigation;
21
+ }
22
+ /** A route-level page component. */
23
+ export interface UiPage {
24
+ /** Page name (e.g., "PetListPage"). */
25
+ name: string;
26
+ /** Route path (e.g., "/pets"). */
27
+ route: string;
28
+ /** File name (e.g., "PetListPage.tsx"). */
29
+ fileName: string;
30
+ /** File content (source code). */
31
+ content: string;
32
+ /** Entity this page relates to (if any). */
33
+ entity?: string | undefined;
34
+ /** Description. */
35
+ description: string;
36
+ }
37
+ /** A reusable UI component. */
38
+ export interface UiComponent {
39
+ /** Component name (e.g., "PetCard"). */
40
+ name: string;
41
+ /** File name. */
42
+ fileName: string;
43
+ /** File content. */
44
+ content: string;
45
+ /** Reusability scope: page-specific or shared. */
46
+ scope: 'shared' | 'page';
47
+ /** Description. */
48
+ description: string;
49
+ }
50
+ /** A layout/shell component. */
51
+ export interface UiLayout {
52
+ /** Layout name (e.g., "AppShell", "DashboardLayout"). */
53
+ name: string;
54
+ /** File name. */
55
+ fileName: string;
56
+ /** File content. */
57
+ content: string;
58
+ /** Description. */
59
+ description: string;
60
+ }
61
+ /** A form component for entity CRUD operations. */
62
+ export interface UiForm {
63
+ /** Form name (e.g., "CreatePetForm"). */
64
+ name: string;
65
+ /** Entity this form operates on. */
66
+ entity: string;
67
+ /** Operation: create, edit, or search. */
68
+ operation: 'create' | 'edit' | 'search';
69
+ /** File name. */
70
+ fileName: string;
71
+ /** File content. */
72
+ content: string;
73
+ }
74
+ /** Navigation/routing configuration. */
75
+ export interface UiNavigation {
76
+ /** Route definitions. */
77
+ routes: UiRoute[];
78
+ /** Navigation file name. */
79
+ fileName: string;
80
+ /** File content (router config). */
81
+ content: string;
82
+ }
83
+ /** A single route definition. */
84
+ export interface UiRoute {
85
+ /** Route path. */
86
+ path: string;
87
+ /** Page component name. */
88
+ page: string;
89
+ /** Display label in navigation. */
90
+ label: string;
91
+ }
92
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kCAAkC;IAClC,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,8CAA8C;IAC9C,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,wCAAwC;IACxC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,wCAAwC;IACxC,UAAU,EAAE,YAAY,CAAC;CAC1B;AAMD,oCAAoC;AACpC,MAAM,WAAW,MAAM;IACrB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,+BAA+B;AAC/B,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,gCAAgC;AAChC,MAAM,WAAW,QAAQ;IACvB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,mDAAmD;AACnD,MAAM,WAAW,MAAM;IACrB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,SAAS,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACxC,iBAAiB;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,iCAAiC;AACjC,MAAM,WAAW,OAAO;IACtB,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf"}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * UI artifact type definitions for the Forge UI generation stage.
3
+ *
4
+ * Defines the output schema produced by the UI generation stage,
5
+ * including pages, components, layouts, forms, and navigation.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * UI generation pipeline stage.
3
+ *
4
+ * Produces pages, components, layouts, forms, and navigation from
5
+ * specification workflows, architecture, API endpoints, and technology
6
+ * profile. Follows the same stage implementation pattern established by
7
+ * {@link ArchitectStage} in Task 5.1 and {@link ApiGenerateStage} in Task 5.2.
8
+ *
9
+ * In API mode, renders prompt templates, calls the LLM via
10
+ * {@link ApiStageExecutor}, validates the output, unpacks individual
11
+ * files into subdirectories, and returns the parsed {@link UiArtifact}
12
+ * in the stage output data.
13
+ *
14
+ * In agent mode, the pipeline runner intercepts before calling
15
+ * `execute()` and exports a prompt via {@link AgentStageExecutor}.
16
+ */
17
+ import type { StageName } from '@hstm-labs/forge-common';
18
+ import type { PipelineStage, PipelineStageInput, PipelineStageOutput, PipelineContext, AgentPromptContext } from '@hstm-labs/forge-core';
19
+ /**
20
+ * Pipeline stage that generates the UI layer.
21
+ *
22
+ * Produces a {@link UiArtifact} containing pages, components, layouts,
23
+ * forms, and navigation configuration. Each element is written as a
24
+ * separate file artifact grouped into subdirectories.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const stage = new UiGenerateStage();
29
+ * const output = await stage.execute(input, context);
30
+ * const ui = output.data?.ui as UiArtifact;
31
+ * ```
32
+ */
33
+ export declare class UiGenerateStage implements PipelineStage {
34
+ readonly name: StageName;
35
+ readonly dependsOn: StageName[];
36
+ readonly requiresLLM = true;
37
+ /**
38
+ * Return rendered agent-mode prompt context using `ui-generate-agent.hbs`.
39
+ *
40
+ * @param input - Input from prior stages
41
+ * @param context - Pipeline context with config, workspace, and runId
42
+ * @returns Agent prompt context with rendered template and output schema
43
+ */
44
+ getAgentContext(input: PipelineStageInput, context: PipelineContext): AgentPromptContext;
45
+ /**
46
+ * Execute the UI generation stage.
47
+ *
48
+ * @param input - Input from prior stages (expects validate + architect + api-generate output)
49
+ * @param context - Pipeline context with config, workspace, and adapter
50
+ * @returns Stage output with UI artifacts and parsed UiArtifact in data
51
+ * @throws {ForgeError} FORGE-PIPE-003 if dependency stage output is missing
52
+ * @throws {ForgeError} FORGE-PIPE-001 if adapter is missing
53
+ * @throws {ForgeError} FORGE-GEN-003 if max retries exhausted
54
+ */
55
+ execute(input: PipelineStageInput, context: PipelineContext): Promise<PipelineStageOutput>;
56
+ }
57
+ //# sourceMappingURL=ui-generate-stage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-generate-stage.d.ts","sourceRoot":"","sources":["../src/ui-generate-stage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EAEf,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAY/B;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAiB;IACzC,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,CAAiC;IAChE,QAAQ,CAAC,WAAW,QAAQ;IAE5B;;;;;;OAMG;IACH,eAAe,CACb,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,eAAe,GACvB,kBAAkB;IA+CrB;;;;;;;;;OASG;IACG,OAAO,CACX,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,mBAAmB,CAAC;CAqNhC"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * UI generation pipeline stage.
3
+ *
4
+ * Produces pages, components, layouts, forms, and navigation from
5
+ * specification workflows, architecture, API endpoints, and technology
6
+ * profile. Follows the same stage implementation pattern established by
7
+ * {@link ArchitectStage} in Task 5.1 and {@link ApiGenerateStage} in Task 5.2.
8
+ *
9
+ * In API mode, renders prompt templates, calls the LLM via
10
+ * {@link ApiStageExecutor}, validates the output, unpacks individual
11
+ * files into subdirectories, and returns the parsed {@link UiArtifact}
12
+ * in the stage output data.
13
+ *
14
+ * In agent mode, the pipeline runner intercepts before calling
15
+ * `execute()` and exports a prompt via {@link AgentStageExecutor}.
16
+ */
17
+ import { join } from 'node:path';
18
+ import { writeFileSync, mkdirSync } from 'node:fs';
19
+ import { ForgeError, ErrorCodes, hashContent } from '@hstm-labs/forge-common';
20
+ import { ApiStageExecutor } from '@hstm-labs/forge-core';
21
+ import { resolveApiStyle } from '@hstm-labs/forge-architect';
22
+ import { loadProfile } from '@hstm-labs/forge-profiles';
23
+ import { loadTemplate, renderTemplate } from '@hstm-labs/forge-templates';
24
+ import { UiOutputValidator } from './validator.js';
25
+ /**
26
+ * Pipeline stage that generates the UI layer.
27
+ *
28
+ * Produces a {@link UiArtifact} containing pages, components, layouts,
29
+ * forms, and navigation configuration. Each element is written as a
30
+ * separate file artifact grouped into subdirectories.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const stage = new UiGenerateStage();
35
+ * const output = await stage.execute(input, context);
36
+ * const ui = output.data?.ui as UiArtifact;
37
+ * ```
38
+ */
39
+ export class UiGenerateStage {
40
+ name = 'ui-generate';
41
+ dependsOn = ['architect', 'api-generate'];
42
+ requiresLLM = true;
43
+ /**
44
+ * Return rendered agent-mode prompt context using `ui-generate-agent.hbs`.
45
+ *
46
+ * @param input - Input from prior stages
47
+ * @param context - Pipeline context with config, workspace, and runId
48
+ * @returns Agent prompt context with rendered template and output schema
49
+ */
50
+ getAgentContext(input, context) {
51
+ const parsedSpec = input['validate']?.data?.['parsedSpec'];
52
+ const architecture = input['architect']?.data?.['architecture'];
53
+ const api = input['api-generate']?.data?.['api'];
54
+ const profile = loadProfile(context.config.profileName, context.workspace.rootDir);
55
+ const resolvedApiStyle = parsedSpec
56
+ ? resolveApiStyle(parsedSpec, profile)
57
+ : 'graphql';
58
+ const outputDir = join(context.workspace.forgeDir, 'runs', context.runId, 'stages', 'ui-generate', 'artifacts');
59
+ const agentTemplate = loadTemplate('ui-generate-agent', context.workspace.rootDir);
60
+ const rendered = renderTemplate(agentTemplate, {
61
+ spec: (parsedSpec ?? {}),
62
+ profile: profile,
63
+ architecture: (architecture ?? {}),
64
+ api: (api ?? {}),
65
+ stage: { resolvedApiStyle, outputDir },
66
+ });
67
+ return {
68
+ prompt: rendered.content,
69
+ outputSchema: { format: 'json' },
70
+ };
71
+ }
72
+ /**
73
+ * Execute the UI generation stage.
74
+ *
75
+ * @param input - Input from prior stages (expects validate + architect + api-generate output)
76
+ * @param context - Pipeline context with config, workspace, and adapter
77
+ * @returns Stage output with UI artifacts and parsed UiArtifact in data
78
+ * @throws {ForgeError} FORGE-PIPE-003 if dependency stage output is missing
79
+ * @throws {ForgeError} FORGE-PIPE-001 if adapter is missing
80
+ * @throws {ForgeError} FORGE-GEN-003 if max retries exhausted
81
+ */
82
+ async execute(input, context) {
83
+ // 1. Get parsed spec from validate stage output
84
+ const validateOutput = input['validate'];
85
+ if (validateOutput === undefined) {
86
+ throw new ForgeError(ErrorCodes.PIPE.DEPENDENCY_UNMET, "UI generate stage requires 'validate' stage output, but it was not found. " +
87
+ 'Ensure the validate stage runs before the ui-generate stage.');
88
+ }
89
+ const parsedSpec = validateOutput.data?.['parsedSpec'];
90
+ if (parsedSpec === undefined) {
91
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Validate stage did not produce a parsed specification in its output data. ' +
92
+ 'Ensure the validate stage includes parsedSpec in its data output.');
93
+ }
94
+ // 2. Get architecture from architect stage output
95
+ const architectOutput = input['architect'];
96
+ if (architectOutput === undefined) {
97
+ throw new ForgeError(ErrorCodes.PIPE.DEPENDENCY_UNMET, "UI generate stage requires 'architect' stage output, but it was not found. " +
98
+ 'Ensure the architect stage runs before the ui-generate stage.');
99
+ }
100
+ const architecture = architectOutput.data?.['architecture'];
101
+ if (architecture === undefined) {
102
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Architect stage did not produce an architecture in its output data. ' +
103
+ 'Ensure the architect stage includes architecture in its data output.');
104
+ }
105
+ // 3. Get API artifact from api-generate stage output
106
+ const apiGenerateOutput = input['api-generate'];
107
+ if (apiGenerateOutput === undefined) {
108
+ throw new ForgeError(ErrorCodes.PIPE.DEPENDENCY_UNMET, "UI generate stage requires 'api-generate' stage output, but it was not found. " +
109
+ 'Ensure the api-generate stage runs before the ui-generate stage.');
110
+ }
111
+ const api = apiGenerateOutput.data?.['api'];
112
+ if (api === undefined) {
113
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'API generate stage did not produce an API artifact in its output data. ' +
114
+ 'Ensure the api-generate stage includes api in its data output.');
115
+ }
116
+ // 4. Load profile, resolve API style
117
+ const profile = loadProfile(context.config.profileName, context.workspace.rootDir);
118
+ const resolvedApiStyle = resolveApiStyle(parsedSpec, profile);
119
+ // 5. Compute output directory
120
+ const outputDir = join(context.workspace.forgeDir, 'runs', context.runId, 'stages', 'ui-generate', 'artifacts');
121
+ // 6. Load and render templates
122
+ const systemTemplate = loadTemplate('ui-generate-system', context.workspace.rootDir);
123
+ const userTemplate = loadTemplate('ui-generate-user', context.workspace.rootDir);
124
+ const templateContext = {
125
+ spec: parsedSpec,
126
+ profile: profile,
127
+ architecture: architecture,
128
+ api: api,
129
+ stage: {
130
+ resolvedApiStyle,
131
+ outputDir,
132
+ },
133
+ };
134
+ const systemPrompt = renderTemplate(systemTemplate, templateContext);
135
+ const userPrompt = renderTemplate(userTemplate, templateContext);
136
+ // 7. Execute via API mode StageExecutor
137
+ if (context.adapter === undefined) {
138
+ throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'UI generate stage requires an LLM adapter in API mode, but none was provided. ' +
139
+ 'Configure an LLM provider in forge.config.json or use agent mode.');
140
+ }
141
+ const entityNames = architecture.dataModel.map((e) => e.name);
142
+ const validator = new UiOutputValidator(entityNames);
143
+ const executor = new ApiStageExecutor({
144
+ adapter: context.adapter,
145
+ validator,
146
+ retryPolicy: {
147
+ maxRetries: 3,
148
+ backoffMs: 1000,
149
+ includeErrorInRetry: true,
150
+ },
151
+ });
152
+ const result = await executor.execute({
153
+ prompt: userPrompt.content,
154
+ systemPrompt: systemPrompt.content,
155
+ stageName: 'ui-generate',
156
+ outputDir,
157
+ runId: context.runId,
158
+ mode: 'api',
159
+ outputSchema: { format: 'json' },
160
+ });
161
+ // 8. Parse UiArtifact from LLM output
162
+ const rawContent = result.artifacts[0]?.content ?? '';
163
+ const uiArtifact = JSON.parse(rawContent);
164
+ // 9. Write individual files to artifacts directory in subdirectories
165
+ const artifacts = [];
166
+ // Pages
167
+ const pagesDir = join(outputDir, 'pages');
168
+ mkdirSync(pagesDir, { recursive: true });
169
+ for (const page of uiArtifact.pages) {
170
+ writeFileSync(join(pagesDir, page.fileName), page.content, 'utf-8');
171
+ artifacts.push({
172
+ filePath: join('pages', page.fileName),
173
+ content: page.content,
174
+ contentHash: hashContent(page.content),
175
+ sizeBytes: Buffer.byteLength(page.content, 'utf-8'),
176
+ });
177
+ }
178
+ // Components
179
+ const componentsDir = join(outputDir, 'components');
180
+ mkdirSync(componentsDir, { recursive: true });
181
+ for (const component of uiArtifact.components) {
182
+ writeFileSync(join(componentsDir, component.fileName), component.content, 'utf-8');
183
+ artifacts.push({
184
+ filePath: join('components', component.fileName),
185
+ content: component.content,
186
+ contentHash: hashContent(component.content),
187
+ sizeBytes: Buffer.byteLength(component.content, 'utf-8'),
188
+ });
189
+ }
190
+ // Layouts
191
+ const layoutsDir = join(outputDir, 'layouts');
192
+ mkdirSync(layoutsDir, { recursive: true });
193
+ for (const layout of uiArtifact.layouts) {
194
+ writeFileSync(join(layoutsDir, layout.fileName), layout.content, 'utf-8');
195
+ artifacts.push({
196
+ filePath: join('layouts', layout.fileName),
197
+ content: layout.content,
198
+ contentHash: hashContent(layout.content),
199
+ sizeBytes: Buffer.byteLength(layout.content, 'utf-8'),
200
+ });
201
+ }
202
+ // Forms
203
+ const formsDir = join(outputDir, 'forms');
204
+ mkdirSync(formsDir, { recursive: true });
205
+ for (const form of uiArtifact.forms) {
206
+ writeFileSync(join(formsDir, form.fileName), form.content, 'utf-8');
207
+ artifacts.push({
208
+ filePath: join('forms', form.fileName),
209
+ content: form.content,
210
+ contentHash: hashContent(form.content),
211
+ sizeBytes: Buffer.byteLength(form.content, 'utf-8'),
212
+ });
213
+ }
214
+ // Navigation
215
+ mkdirSync(outputDir, { recursive: true });
216
+ writeFileSync(join(outputDir, uiArtifact.navigation.fileName), uiArtifact.navigation.content, 'utf-8');
217
+ artifacts.push({
218
+ filePath: uiArtifact.navigation.fileName,
219
+ content: uiArtifact.navigation.content,
220
+ contentHash: hashContent(uiArtifact.navigation.content),
221
+ sizeBytes: Buffer.byteLength(uiArtifact.navigation.content, 'utf-8'),
222
+ });
223
+ // 10. Return PipelineStageOutput with all artifacts and data
224
+ return {
225
+ artifacts,
226
+ data: {
227
+ ui: uiArtifact,
228
+ },
229
+ };
230
+ }
231
+ }
232
+ //# sourceMappingURL=ui-generate-stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-generate-stage.js","sourceRoot":"","sources":["../src/ui-generate-stage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * UI output validator for the Forge UI generation stage.
3
+ *
4
+ * Validates LLM-generated UI output against the
5
+ * {@link UiArtifact} schema with structural and semantic checks.
6
+ */
7
+ import type { OutputValidator, OutputSchema, ValidationResult } from '@hstm-labs/forge-core';
8
+ /**
9
+ * Validator for UI generation stage output.
10
+ *
11
+ * Performs the following checks:
12
+ * 1. JSON parse validation
13
+ * 2. Required top-level keys
14
+ * 3. Non-empty pages with required fields
15
+ * 4. Entity coverage (every entity has at least one page)
16
+ * 5. Form coverage (every entity has create and edit forms)
17
+ * 6. Navigation routes non-empty and cover all pages
18
+ * 7. Non-empty layouts (at least one)
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const validator = new UiOutputValidator(['User', 'Post']);
23
+ * const result = validator.validate(llmOutput, { format: 'json' });
24
+ * ```
25
+ */
26
+ export declare class UiOutputValidator implements OutputValidator {
27
+ private readonly entityNames;
28
+ /**
29
+ * @param entityNames - Entity names from architecture data model for coverage checks
30
+ */
31
+ constructor(entityNames: string[]);
32
+ /**
33
+ * Validate UI output against the UiArtifact schema.
34
+ *
35
+ * @param output - Raw LLM output text
36
+ * @param _schema - Output schema (format expected to be 'json')
37
+ * @returns Validation result with descriptive errors
38
+ */
39
+ validate(output: string, _schema: OutputSchema): ValidationResult;
40
+ }
41
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,gBAAgB,EAEjB,MAAM,uBAAuB,CAAC;AAmB/B;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAkB,YAAW,eAAe;IACvD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAW;IAEvC;;OAEG;gBACS,WAAW,EAAE,MAAM,EAAE;IAIjC;;;;;;OAMG;IAEH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,gBAAgB;CAkLlE"}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * UI output validator for the Forge UI generation stage.
3
+ *
4
+ * Validates LLM-generated UI output against the
5
+ * {@link UiArtifact} schema with structural and semantic checks.
6
+ */
7
+ // ---------------------------------------------------------------------------
8
+ // Constants
9
+ // ---------------------------------------------------------------------------
10
+ const REQUIRED_TOP_LEVEL_KEYS = [
11
+ 'framework',
12
+ 'pages',
13
+ 'components',
14
+ 'layouts',
15
+ 'forms',
16
+ 'navigation',
17
+ ];
18
+ // ---------------------------------------------------------------------------
19
+ // Implementation
20
+ // ---------------------------------------------------------------------------
21
+ /**
22
+ * Validator for UI generation stage output.
23
+ *
24
+ * Performs the following checks:
25
+ * 1. JSON parse validation
26
+ * 2. Required top-level keys
27
+ * 3. Non-empty pages with required fields
28
+ * 4. Entity coverage (every entity has at least one page)
29
+ * 5. Form coverage (every entity has create and edit forms)
30
+ * 6. Navigation routes non-empty and cover all pages
31
+ * 7. Non-empty layouts (at least one)
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const validator = new UiOutputValidator(['User', 'Post']);
36
+ * const result = validator.validate(llmOutput, { format: 'json' });
37
+ * ```
38
+ */
39
+ export class UiOutputValidator {
40
+ entityNames;
41
+ /**
42
+ * @param entityNames - Entity names from architecture data model for coverage checks
43
+ */
44
+ constructor(entityNames) {
45
+ this.entityNames = entityNames;
46
+ }
47
+ /**
48
+ * Validate UI output against the UiArtifact schema.
49
+ *
50
+ * @param output - Raw LLM output text
51
+ * @param _schema - Output schema (format expected to be 'json')
52
+ * @returns Validation result with descriptive errors
53
+ */
54
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
55
+ validate(output, _schema) {
56
+ const errors = [];
57
+ // 1. Parse as JSON
58
+ let parsed;
59
+ try {
60
+ parsed = JSON.parse(output);
61
+ }
62
+ catch {
63
+ errors.push({
64
+ message: 'UI output is not valid JSON. Ensure the LLM produces only raw JSON without markdown fences or explanatory text.',
65
+ severity: 'error',
66
+ });
67
+ return { valid: false, errors };
68
+ }
69
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
70
+ errors.push({
71
+ message: 'UI output must be a JSON object, not an array or primitive.',
72
+ severity: 'error',
73
+ });
74
+ return { valid: false, errors };
75
+ }
76
+ const obj = parsed;
77
+ // 2. Verify required top-level keys
78
+ for (const key of REQUIRED_TOP_LEVEL_KEYS) {
79
+ if (!(key in obj)) {
80
+ errors.push({
81
+ message: `Missing required top-level key: '${key}'.`,
82
+ path: key,
83
+ severity: 'error',
84
+ });
85
+ }
86
+ }
87
+ if (errors.length > 0) {
88
+ return { valid: false, errors };
89
+ }
90
+ // 3. Verify pages is non-empty array with required fields
91
+ const pages = obj['pages'];
92
+ if (!Array.isArray(pages) || pages.length === 0) {
93
+ errors.push({
94
+ message: "Key 'pages' must be a non-empty array of page definitions.",
95
+ path: 'pages',
96
+ severity: 'error',
97
+ });
98
+ }
99
+ else {
100
+ for (let i = 0; i < pages.length; i++) {
101
+ const page = pages[i];
102
+ if (page === undefined || typeof page !== 'object' || page === null) {
103
+ errors.push({
104
+ message: `pages[${String(i)}] is not a valid object.`,
105
+ path: `pages[${String(i)}]`,
106
+ severity: 'error',
107
+ });
108
+ continue;
109
+ }
110
+ for (const field of ['name', 'route', 'fileName', 'content']) {
111
+ if (typeof page[field] !== 'string' || page[field].length === 0) {
112
+ errors.push({
113
+ message: `pages[${String(i)}] is missing required field '${field}'.`,
114
+ path: `pages[${String(i)}].${field}`,
115
+ severity: 'error',
116
+ });
117
+ }
118
+ }
119
+ }
120
+ }
121
+ // 4. Entity coverage — every entity has at least one page
122
+ if (Array.isArray(pages) && pages.length > 0) {
123
+ const pageEntities = new Set();
124
+ for (const page of pages) {
125
+ // Check page.entity field
126
+ if (typeof page['entity'] === 'string' && page['entity'].length > 0) {
127
+ pageEntities.add(page['entity'].toLowerCase());
128
+ }
129
+ // Also check page name containing entity name
130
+ if (typeof page['name'] === 'string') {
131
+ const pageName = page['name'].toLowerCase();
132
+ for (const entityName of this.entityNames) {
133
+ if (pageName.includes(entityName.toLowerCase())) {
134
+ pageEntities.add(entityName.toLowerCase());
135
+ }
136
+ }
137
+ }
138
+ }
139
+ for (const entityName of this.entityNames) {
140
+ if (!pageEntities.has(entityName.toLowerCase())) {
141
+ errors.push({
142
+ message: `Entity '${entityName}' has no corresponding page. Every entity must have at least one page.`,
143
+ path: 'pages',
144
+ severity: 'error',
145
+ });
146
+ }
147
+ }
148
+ }
149
+ // 5. Form coverage — every entity has create and edit forms
150
+ const forms = obj['forms'];
151
+ if (!Array.isArray(forms) || forms.length === 0) {
152
+ errors.push({
153
+ message: "Key 'forms' must be a non-empty array of form definitions.",
154
+ path: 'forms',
155
+ severity: 'error',
156
+ });
157
+ }
158
+ else {
159
+ const entityFormOps = new Map();
160
+ for (const form of forms) {
161
+ const entity = typeof form['entity'] === 'string' ? form['entity'].toLowerCase() : '';
162
+ const operation = typeof form['operation'] === 'string' ? form['operation'] : '';
163
+ if (entity.length > 0 && operation.length > 0) {
164
+ if (!entityFormOps.has(entity)) {
165
+ entityFormOps.set(entity, new Set());
166
+ }
167
+ entityFormOps.get(entity).add(operation);
168
+ }
169
+ }
170
+ for (const entityName of this.entityNames) {
171
+ const ops = entityFormOps.get(entityName.toLowerCase());
172
+ if (ops === undefined || !ops.has('create')) {
173
+ errors.push({
174
+ message: `Entity '${entityName}' is missing a 'create' form.`,
175
+ path: 'forms',
176
+ severity: 'error',
177
+ });
178
+ }
179
+ if (ops === undefined || !ops.has('edit')) {
180
+ errors.push({
181
+ message: `Entity '${entityName}' is missing an 'edit' form.`,
182
+ path: 'forms',
183
+ severity: 'error',
184
+ });
185
+ }
186
+ }
187
+ }
188
+ // 6. Navigation routes non-empty and cover all pages
189
+ const navigation = obj['navigation'];
190
+ if (typeof navigation !== 'object' || navigation === null || Array.isArray(navigation)) {
191
+ errors.push({
192
+ message: "Key 'navigation' must be an object with routes and content.",
193
+ path: 'navigation',
194
+ severity: 'error',
195
+ });
196
+ }
197
+ else {
198
+ const nav = navigation;
199
+ const routes = nav['routes'];
200
+ if (!Array.isArray(routes) || routes.length === 0) {
201
+ errors.push({
202
+ message: "Navigation 'routes' must be a non-empty array.",
203
+ path: 'navigation.routes',
204
+ severity: 'error',
205
+ });
206
+ }
207
+ }
208
+ // 7. Verify layouts is non-empty
209
+ const layouts = obj['layouts'];
210
+ if (!Array.isArray(layouts) || layouts.length === 0) {
211
+ errors.push({
212
+ message: "Key 'layouts' must be a non-empty array — at least one layout is required.",
213
+ path: 'layouts',
214
+ severity: 'error',
215
+ });
216
+ }
217
+ return { valid: errors.length === 0, errors };
218
+ }
219
+ }
220
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@hstm-labs/forge-apps-generator",
3
+ "version": "0.1.11",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "test": "vitest run",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "dependencies": {
19
+ "@hstm-labs/forge-common": "0.1.11",
20
+ "@hstm-labs/forge-core": "0.1.11",
21
+ "@hstm-labs/forge-architect": "0.1.11",
22
+ "@hstm-labs/forge-services-generator": "0.1.11",
23
+ "@hstm-labs/forge-spec-parser": "0.1.11",
24
+ "@hstm-labs/forge-profiles": "0.1.11",
25
+ "@hstm-labs/forge-templates": "0.1.11"
26
+ }
27
+ }