@hstm-labs/forge-architect 0.1.2
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 +42 -0
- package/dist/api-style-resolver.d.ts +21 -0
- package/dist/api-style-resolver.d.ts.map +1 -0
- package/dist/api-style-resolver.js +28 -0
- package/dist/api-style-resolver.js.map +1 -0
- package/dist/architect-stage.d.ts +48 -0
- package/dist/architect-stage.d.ts.map +1 -0
- package/dist/architect-stage.js +133 -0
- package/dist/architect-stage.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +41 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +191 -0
- package/dist/validator.js.map +1 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @hstm-labs/forge-architect
|
|
2
|
+
|
|
3
|
+
Architecture generation stage for Forge — produces component design, module breakdown, data model entities, and technology decisions from a validated specification.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hstm-labs/forge-architect
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Public API
|
|
12
|
+
|
|
13
|
+
### Types
|
|
14
|
+
|
|
15
|
+
- `ArchitectureArtifact` — complete architecture output
|
|
16
|
+
- `ArchitectureComponent`, `ArchitectureModule` — component/module definitions
|
|
17
|
+
- `DataModelEntity`, `DataModelField`, `DataModelRelationship` — data modeling
|
|
18
|
+
- `TechnologyDecision` — technology choice with rationale
|
|
19
|
+
- `ApiStyle` — resolved API style (REST, GraphQL, etc.)
|
|
20
|
+
|
|
21
|
+
### Classes
|
|
22
|
+
|
|
23
|
+
- `ArchitectStage` — pipeline stage implementing `PipelineStage` interface
|
|
24
|
+
- `ArchitectureOutputValidator` — validates LLM-produced architecture output
|
|
25
|
+
|
|
26
|
+
### Functions
|
|
27
|
+
|
|
28
|
+
- `resolveApiStyle(spec, profile)` — determine API style from spec and profile
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { ArchitectStage } from '@hstm-labs/forge-architect';
|
|
34
|
+
|
|
35
|
+
const stage = new ArchitectStage();
|
|
36
|
+
const result = await stage.execute(input);
|
|
37
|
+
// result.data contains ArchitectureArtifact
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
[MIT](../../LICENSE)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the API style for architecture generation.
|
|
3
|
+
*
|
|
4
|
+
* Precedence chain:
|
|
5
|
+
* 1. Specification declares API style → use it
|
|
6
|
+
* 2. Profile suggests default API style → use it
|
|
7
|
+
* 3. Both silent → default to GraphQL
|
|
8
|
+
*/
|
|
9
|
+
import type { ParsedSpecification } from '@hstm-labs/forge-spec-parser';
|
|
10
|
+
import type { TechnologyProfile } from '@hstm-labs/forge-profiles';
|
|
11
|
+
/** Supported API styles. */
|
|
12
|
+
export type ApiStyle = 'rest' | 'graphql' | 'grpc';
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the API style from specification and profile.
|
|
15
|
+
*
|
|
16
|
+
* @param spec - Parsed specification (may declare apiStyle)
|
|
17
|
+
* @param profile - Technology profile (may suggest defaultApiStyle)
|
|
18
|
+
* @returns Resolved API style
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveApiStyle(spec: ParsedSpecification, profile: TechnologyProfile): ApiStyle;
|
|
21
|
+
//# sourceMappingURL=api-style-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-style-resolver.d.ts","sourceRoot":"","sources":["../src/api-style-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,4BAA4B;AAC5B,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,iBAAiB,GACzB,QAAQ,CAaV"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the API style for architecture generation.
|
|
3
|
+
*
|
|
4
|
+
* Precedence chain:
|
|
5
|
+
* 1. Specification declares API style → use it
|
|
6
|
+
* 2. Profile suggests default API style → use it
|
|
7
|
+
* 3. Both silent → default to GraphQL
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the API style from specification and profile.
|
|
11
|
+
*
|
|
12
|
+
* @param spec - Parsed specification (may declare apiStyle)
|
|
13
|
+
* @param profile - Technology profile (may suggest defaultApiStyle)
|
|
14
|
+
* @returns Resolved API style
|
|
15
|
+
*/
|
|
16
|
+
export function resolveApiStyle(spec, profile) {
|
|
17
|
+
// 1. Spec declares → use it
|
|
18
|
+
if (spec.apiStyle !== undefined) {
|
|
19
|
+
return spec.apiStyle;
|
|
20
|
+
}
|
|
21
|
+
// 2. Profile suggests → use it
|
|
22
|
+
if (profile.defaultApiStyle !== undefined) {
|
|
23
|
+
return profile.defaultApiStyle;
|
|
24
|
+
}
|
|
25
|
+
// 3. Both silent → default GraphQL
|
|
26
|
+
return 'graphql';
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=api-style-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-style-resolver.js","sourceRoot":"","sources":["../src/api-style-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAyB,EACzB,OAA0B;IAE1B,4BAA4B;IAC5B,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,+BAA+B;IAC/B,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,OAAO,CAAC,eAAe,CAAC;IACjC,CAAC;IAED,mCAAmC;IACnC,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture generation pipeline stage.
|
|
3
|
+
*
|
|
4
|
+
* Produces component boundaries, module structure, and data model from
|
|
5
|
+
* a parsed specification and technology profile. This is the first
|
|
6
|
+
* LLM-driven generation stage and establishes the pattern for all
|
|
7
|
+
* subsequent generation stages.
|
|
8
|
+
*
|
|
9
|
+
* In API mode, renders prompt templates, calls the LLM via
|
|
10
|
+
* {@link ApiStageExecutor}, validates the output, and returns the
|
|
11
|
+
* parsed {@link ArchitectureArtifact} in the stage output data.
|
|
12
|
+
*
|
|
13
|
+
* In agent mode, the pipeline runner intercepts before calling
|
|
14
|
+
* `execute()` and exports a prompt via {@link AgentStageExecutor}.
|
|
15
|
+
*/
|
|
16
|
+
import type { StageName } from '@hstm-labs/forge-common';
|
|
17
|
+
import type { PipelineStage, PipelineStageInput, PipelineStageOutput, PipelineContext } from '@hstm-labs/forge-core';
|
|
18
|
+
/**
|
|
19
|
+
* Pipeline stage that generates the application architecture.
|
|
20
|
+
*
|
|
21
|
+
* Produces an {@link ArchitectureArtifact} containing component boundaries,
|
|
22
|
+
* module structure, data model, technology decisions, and a dependency graph.
|
|
23
|
+
* The output is consumed by ALL subsequent generation stages as the shared
|
|
24
|
+
* architecture model.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const stage = new ArchitectStage();
|
|
29
|
+
* const output = await stage.execute(input, context);
|
|
30
|
+
* const architecture = output.data?.architecture as ArchitectureArtifact;
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare class ArchitectStage implements PipelineStage {
|
|
34
|
+
readonly name: StageName;
|
|
35
|
+
readonly dependsOn: StageName[];
|
|
36
|
+
readonly requiresLLM = true;
|
|
37
|
+
/**
|
|
38
|
+
* Execute the architecture generation stage.
|
|
39
|
+
*
|
|
40
|
+
* @param input - Input from prior stages (expects validate stage output)
|
|
41
|
+
* @param context - Pipeline context with config, workspace, and adapter
|
|
42
|
+
* @returns Stage output with architecture artifact and file artifacts
|
|
43
|
+
* @throws {ForgeError} FORGE-PIPE-001 if validate stage output is missing
|
|
44
|
+
* @throws {ForgeError} FORGE-GEN-003 if max retries exhausted
|
|
45
|
+
*/
|
|
46
|
+
execute(input: PipelineStageInput, context: PipelineContext): Promise<PipelineStageOutput>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=architect-stage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architect-stage.d.ts","sourceRoot":"","sources":["../src/architect-stage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAU/B;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAe,YAAW,aAAa;IAClD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAe;IACvC,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,CAAgB;IAC/C,QAAQ,CAAC,WAAW,QAAQ;IAE5B;;;;;;;;OAQG;IACG,OAAO,CACX,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,mBAAmB,CAAC;CAyHhC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture generation pipeline stage.
|
|
3
|
+
*
|
|
4
|
+
* Produces component boundaries, module structure, and data model from
|
|
5
|
+
* a parsed specification and technology profile. This is the first
|
|
6
|
+
* LLM-driven generation stage and establishes the pattern for all
|
|
7
|
+
* subsequent generation stages.
|
|
8
|
+
*
|
|
9
|
+
* In API mode, renders prompt templates, calls the LLM via
|
|
10
|
+
* {@link ApiStageExecutor}, validates the output, and returns the
|
|
11
|
+
* parsed {@link ArchitectureArtifact} in the stage output data.
|
|
12
|
+
*
|
|
13
|
+
* In agent mode, the pipeline runner intercepts before calling
|
|
14
|
+
* `execute()` and exports a prompt via {@link AgentStageExecutor}.
|
|
15
|
+
*/
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
18
|
+
import { ForgeError, ErrorCodes, hashContent } from '@hstm-labs/forge-common';
|
|
19
|
+
import { ApiStageExecutor } from '@hstm-labs/forge-core';
|
|
20
|
+
import { loadProfile } from '@hstm-labs/forge-profiles';
|
|
21
|
+
import { loadTemplate, renderTemplate } from '@hstm-labs/forge-templates';
|
|
22
|
+
import { ArchitectureOutputValidator } from './validator.js';
|
|
23
|
+
import { resolveApiStyle } from './api-style-resolver.js';
|
|
24
|
+
/**
|
|
25
|
+
* Pipeline stage that generates the application architecture.
|
|
26
|
+
*
|
|
27
|
+
* Produces an {@link ArchitectureArtifact} containing component boundaries,
|
|
28
|
+
* module structure, data model, technology decisions, and a dependency graph.
|
|
29
|
+
* The output is consumed by ALL subsequent generation stages as the shared
|
|
30
|
+
* architecture model.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const stage = new ArchitectStage();
|
|
35
|
+
* const output = await stage.execute(input, context);
|
|
36
|
+
* const architecture = output.data?.architecture as ArchitectureArtifact;
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class ArchitectStage {
|
|
40
|
+
name = 'architect';
|
|
41
|
+
dependsOn = ['validate'];
|
|
42
|
+
requiresLLM = true;
|
|
43
|
+
/**
|
|
44
|
+
* Execute the architecture generation stage.
|
|
45
|
+
*
|
|
46
|
+
* @param input - Input from prior stages (expects validate stage output)
|
|
47
|
+
* @param context - Pipeline context with config, workspace, and adapter
|
|
48
|
+
* @returns Stage output with architecture artifact and file artifacts
|
|
49
|
+
* @throws {ForgeError} FORGE-PIPE-001 if validate stage output is missing
|
|
50
|
+
* @throws {ForgeError} FORGE-GEN-003 if max retries exhausted
|
|
51
|
+
*/
|
|
52
|
+
async execute(input, context) {
|
|
53
|
+
// 1. Get parsed spec from validate stage output
|
|
54
|
+
const validateOutput = input['validate'];
|
|
55
|
+
if (validateOutput === undefined) {
|
|
56
|
+
throw new ForgeError(ErrorCodes.PIPE.DEPENDENCY_UNMET, "Architect stage requires 'validate' stage output, but it was not found. " +
|
|
57
|
+
'Ensure the validate stage runs before the architect stage.');
|
|
58
|
+
}
|
|
59
|
+
const parsedSpec = validateOutput.data?.['parsedSpec'];
|
|
60
|
+
if (parsedSpec === undefined) {
|
|
61
|
+
throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Validate stage did not produce a parsed specification in its output data. ' +
|
|
62
|
+
'Ensure the validate stage includes parsedSpec in its data output.');
|
|
63
|
+
}
|
|
64
|
+
// 2. Load profile
|
|
65
|
+
const profile = loadProfile(context.config.profileName, context.workspace.rootDir);
|
|
66
|
+
// 3. Resolve API style (spec → profile → default GraphQL)
|
|
67
|
+
const resolvedApiStyle = resolveApiStyle(parsedSpec, profile);
|
|
68
|
+
// 4. Compute output directory
|
|
69
|
+
const outputDir = join(context.workspace.forgeDir, 'runs', context.runId, 'stages', 'architect', 'artifacts');
|
|
70
|
+
// 5. Load and render templates
|
|
71
|
+
const systemTemplate = loadTemplate('architect-system', context.workspace.rootDir);
|
|
72
|
+
const userTemplate = loadTemplate('architect-user', context.workspace.rootDir);
|
|
73
|
+
const templateContext = {
|
|
74
|
+
spec: parsedSpec,
|
|
75
|
+
profile: profile,
|
|
76
|
+
stage: {
|
|
77
|
+
resolvedApiStyle,
|
|
78
|
+
outputDir,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
const systemPrompt = renderTemplate(systemTemplate, templateContext);
|
|
82
|
+
const userPrompt = renderTemplate(userTemplate, templateContext);
|
|
83
|
+
// 6. Execute via API mode StageExecutor
|
|
84
|
+
if (context.adapter === undefined) {
|
|
85
|
+
throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Architect stage requires an LLM adapter in API mode, but none was provided. ' +
|
|
86
|
+
'Configure an LLM provider in forge.config.json or use agent mode.');
|
|
87
|
+
}
|
|
88
|
+
const validator = new ArchitectureOutputValidator(parsedSpec.entities);
|
|
89
|
+
const executor = new ApiStageExecutor({
|
|
90
|
+
adapter: context.adapter,
|
|
91
|
+
validator,
|
|
92
|
+
retryPolicy: {
|
|
93
|
+
maxRetries: 3,
|
|
94
|
+
backoffMs: 1000,
|
|
95
|
+
includeErrorInRetry: true,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
const result = await executor.execute({
|
|
99
|
+
prompt: userPrompt.content,
|
|
100
|
+
systemPrompt: systemPrompt.content,
|
|
101
|
+
stageName: 'architect',
|
|
102
|
+
outputDir,
|
|
103
|
+
runId: context.runId,
|
|
104
|
+
mode: 'api',
|
|
105
|
+
outputSchema: { format: 'json' },
|
|
106
|
+
});
|
|
107
|
+
// 7. Parse architecture artifact from LLM output
|
|
108
|
+
const rawContent = result.artifacts[0]?.content ?? '';
|
|
109
|
+
const architecture = JSON.parse(rawContent);
|
|
110
|
+
// 8. Write architecture.json to artifacts directory
|
|
111
|
+
mkdirSync(outputDir, { recursive: true });
|
|
112
|
+
const artifactPath = join(outputDir, 'architecture.json');
|
|
113
|
+
const artifactContent = JSON.stringify(architecture, null, 2);
|
|
114
|
+
writeFileSync(artifactPath, artifactContent, 'utf-8');
|
|
115
|
+
const contentHash = hashContent(artifactContent);
|
|
116
|
+
const sizeBytes = Buffer.byteLength(artifactContent, 'utf-8');
|
|
117
|
+
// 9. Return PipelineStageOutput with artifacts and data
|
|
118
|
+
return {
|
|
119
|
+
artifacts: [
|
|
120
|
+
{
|
|
121
|
+
filePath: 'architecture.json',
|
|
122
|
+
content: artifactContent,
|
|
123
|
+
contentHash,
|
|
124
|
+
sizeBytes,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
data: {
|
|
128
|
+
architecture,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=architect-stage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architect-stage.js","sourceRoot":"","sources":["../src/architect-stage.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { ArchitectureArtifact, ArchitectureComponent, ArchitectureModule, DataModelEntity, DataModelField, DataModelRelationship, TechnologyDecision, } from './types.js';
|
|
2
|
+
export { ArchitectStage } from './architect-stage.js';
|
|
3
|
+
export { ArchitectureOutputValidator } from './validator.js';
|
|
4
|
+
export { resolveApiStyle } from './api-style-resolver.js';
|
|
5
|
+
export type { ApiStyle } from './api-style-resolver.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAYxC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture artifact type definitions for the Forge architect stage.
|
|
3
|
+
*
|
|
4
|
+
* Defines the output schema produced by the architecture generation stage,
|
|
5
|
+
* including component boundaries, module structure, data model, and
|
|
6
|
+
* technology decisions.
|
|
7
|
+
*/
|
|
8
|
+
/** Complete architecture output produced by the architect stage. */
|
|
9
|
+
export interface ArchitectureArtifact {
|
|
10
|
+
/** Application components with boundaries. */
|
|
11
|
+
components: ArchitectureComponent[];
|
|
12
|
+
/** Module/layer structure. */
|
|
13
|
+
modules: ArchitectureModule[];
|
|
14
|
+
/** Data model derived from spec entities. */
|
|
15
|
+
dataModel: DataModelEntity[];
|
|
16
|
+
/** Technology mapping decisions. */
|
|
17
|
+
technologyDecisions: TechnologyDecision[];
|
|
18
|
+
/** Component dependency graph (adjacency list). */
|
|
19
|
+
dependencyGraph: Record<string, string[]>;
|
|
20
|
+
}
|
|
21
|
+
/** An application component with defined boundaries and responsibilities. */
|
|
22
|
+
export interface ArchitectureComponent {
|
|
23
|
+
/** Unique component name. */
|
|
24
|
+
name: string;
|
|
25
|
+
/** Component type category. */
|
|
26
|
+
type: 'service' | 'library' | 'ui' | 'database' | 'infrastructure' | 'gateway';
|
|
27
|
+
/** Brief description of the component's purpose. */
|
|
28
|
+
description: string;
|
|
29
|
+
/** List of responsibilities this component owns. */
|
|
30
|
+
responsibilities: string[];
|
|
31
|
+
/** Names of other components this component depends on. */
|
|
32
|
+
dependencies: string[];
|
|
33
|
+
}
|
|
34
|
+
/** A module grouping components by architectural layer. */
|
|
35
|
+
export interface ArchitectureModule {
|
|
36
|
+
/** Unique module name. */
|
|
37
|
+
name: string;
|
|
38
|
+
/** Architectural layer this module belongs to. */
|
|
39
|
+
layer: 'presentation' | 'application' | 'domain' | 'infrastructure';
|
|
40
|
+
/** Component names assigned to this module. */
|
|
41
|
+
components: string[];
|
|
42
|
+
/** Brief description of the module's purpose. */
|
|
43
|
+
description: string;
|
|
44
|
+
}
|
|
45
|
+
/** A data model entity derived from a specification entity. */
|
|
46
|
+
export interface DataModelEntity {
|
|
47
|
+
/** Entity name (matches spec entity). */
|
|
48
|
+
name: string;
|
|
49
|
+
/** Database table name. */
|
|
50
|
+
table: string;
|
|
51
|
+
/** Fields on this entity. */
|
|
52
|
+
fields: DataModelField[];
|
|
53
|
+
/** Relationships to other entities. */
|
|
54
|
+
relationships: DataModelRelationship[];
|
|
55
|
+
}
|
|
56
|
+
/** A field within a data model entity. */
|
|
57
|
+
export interface DataModelField {
|
|
58
|
+
/** Field name. */
|
|
59
|
+
name: string;
|
|
60
|
+
/** Database column type (engine-specific, e.g. PostgreSQL types). */
|
|
61
|
+
type: string;
|
|
62
|
+
/** Database column name. */
|
|
63
|
+
column: string;
|
|
64
|
+
/** Whether the field allows NULL values. */
|
|
65
|
+
nullable: boolean;
|
|
66
|
+
/** Whether this field is a primary key. */
|
|
67
|
+
primaryKey: boolean;
|
|
68
|
+
/** Optional description of the field. */
|
|
69
|
+
description?: string | undefined;
|
|
70
|
+
}
|
|
71
|
+
/** A relationship between two data model entities. */
|
|
72
|
+
export interface DataModelRelationship {
|
|
73
|
+
/** Name of the target entity. */
|
|
74
|
+
target: string;
|
|
75
|
+
/** Relationship cardinality. */
|
|
76
|
+
type: 'one-to-one' | 'one-to-many' | 'many-to-many';
|
|
77
|
+
/** Foreign key column name (for one-to-one / one-to-many). */
|
|
78
|
+
foreignKey?: string | undefined;
|
|
79
|
+
/** Join table name (for many-to-many). */
|
|
80
|
+
joinTable?: string | undefined;
|
|
81
|
+
}
|
|
82
|
+
/** A technology decision with rationale. */
|
|
83
|
+
export interface TechnologyDecision {
|
|
84
|
+
/** Area of the decision (e.g. "API Layer", "Authentication"). */
|
|
85
|
+
area: string;
|
|
86
|
+
/** The technology choice made. */
|
|
87
|
+
decision: string;
|
|
88
|
+
/** Rationale for the decision. */
|
|
89
|
+
rationale: string;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,oEAAoE;AACpE,MAAM,WAAW,oBAAoB;IACnC,8CAA8C;IAC9C,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,8BAA8B;IAC9B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,6CAA6C;IAC7C,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,oCAAoC;IACpC,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IAC1C,mDAAmD;IACnD,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC3C;AAMD,6EAA6E;AAC7E,MAAM,WAAW,qBAAqB;IACpC,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,UAAU,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAC/E,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,2DAA2D;IAC3D,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAMD,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,KAAK,EAAE,cAAc,GAAG,aAAa,GAAG,QAAQ,GAAG,gBAAgB,CAAC;IACpE,+CAA+C;IAC/C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,uCAAuC;IACvC,aAAa,EAAE,qBAAqB,EAAE,CAAC;CACxC;AAED,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,sDAAsD;AACtD,MAAM,WAAW,qBAAqB;IACpC,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,IAAI,EAAE,YAAY,GAAG,aAAa,GAAG,cAAc,CAAC;IACpD,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAMD,4CAA4C;AAC5C,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture artifact type definitions for the Forge architect stage.
|
|
3
|
+
*
|
|
4
|
+
* Defines the output schema produced by the architecture generation stage,
|
|
5
|
+
* including component boundaries, module structure, data model, and
|
|
6
|
+
* technology decisions.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture output validator for the Forge architect stage.
|
|
3
|
+
*
|
|
4
|
+
* Validates LLM-generated architecture output against the
|
|
5
|
+
* {@link ArchitectureArtifact} schema with structural and semantic checks.
|
|
6
|
+
*/
|
|
7
|
+
import type { OutputValidator, OutputSchema, ValidationResult } from '@hstm-labs/forge-core';
|
|
8
|
+
import type { SpecEntity } from '@hstm-labs/forge-spec-parser';
|
|
9
|
+
/**
|
|
10
|
+
* Validator for architecture stage output.
|
|
11
|
+
*
|
|
12
|
+
* Performs the following checks:
|
|
13
|
+
* 1. JSON parse validation
|
|
14
|
+
* 2. Required top-level keys
|
|
15
|
+
* 3. Components array structure
|
|
16
|
+
* 4. Non-empty dataModel
|
|
17
|
+
* 5. Entity coverage (every spec entity in dataModel)
|
|
18
|
+
* 6. Dependency graph key validation
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const validator = new ArchitectureOutputValidator(specEntities);
|
|
23
|
+
* const result = validator.validate(llmOutput, { format: 'json' });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class ArchitectureOutputValidator implements OutputValidator {
|
|
27
|
+
private readonly specEntities;
|
|
28
|
+
/**
|
|
29
|
+
* @param specEntities - Spec entities to verify coverage against dataModel
|
|
30
|
+
*/
|
|
31
|
+
constructor(specEntities: SpecEntity[]);
|
|
32
|
+
/**
|
|
33
|
+
* Validate architecture output against the ArchitectureArtifact 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;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AA2B/D;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,2BAA4B,YAAW,eAAe;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAE5C;;OAEG;gBACS,YAAY,EAAE,UAAU,EAAE;IAItC;;;;;;OAMG;IAEH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,gBAAgB;CA8JlE"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture output validator for the Forge architect stage.
|
|
3
|
+
*
|
|
4
|
+
* Validates LLM-generated architecture output against the
|
|
5
|
+
* {@link ArchitectureArtifact} schema with structural and semantic checks.
|
|
6
|
+
*/
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Valid component types (for type-narrowing checks)
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const VALID_COMPONENT_TYPES = new Set([
|
|
11
|
+
'service',
|
|
12
|
+
'library',
|
|
13
|
+
'ui',
|
|
14
|
+
'database',
|
|
15
|
+
'infrastructure',
|
|
16
|
+
'gateway',
|
|
17
|
+
]);
|
|
18
|
+
const REQUIRED_TOP_LEVEL_KEYS = [
|
|
19
|
+
'components',
|
|
20
|
+
'modules',
|
|
21
|
+
'dataModel',
|
|
22
|
+
'technologyDecisions',
|
|
23
|
+
'dependencyGraph',
|
|
24
|
+
];
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Implementation
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Validator for architecture stage output.
|
|
30
|
+
*
|
|
31
|
+
* Performs the following checks:
|
|
32
|
+
* 1. JSON parse validation
|
|
33
|
+
* 2. Required top-level keys
|
|
34
|
+
* 3. Components array structure
|
|
35
|
+
* 4. Non-empty dataModel
|
|
36
|
+
* 5. Entity coverage (every spec entity in dataModel)
|
|
37
|
+
* 6. Dependency graph key validation
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const validator = new ArchitectureOutputValidator(specEntities);
|
|
42
|
+
* const result = validator.validate(llmOutput, { format: 'json' });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class ArchitectureOutputValidator {
|
|
46
|
+
specEntities;
|
|
47
|
+
/**
|
|
48
|
+
* @param specEntities - Spec entities to verify coverage against dataModel
|
|
49
|
+
*/
|
|
50
|
+
constructor(specEntities) {
|
|
51
|
+
this.specEntities = specEntities;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate architecture output against the ArchitectureArtifact schema.
|
|
55
|
+
*
|
|
56
|
+
* @param output - Raw LLM output text
|
|
57
|
+
* @param _schema - Output schema (format expected to be 'json')
|
|
58
|
+
* @returns Validation result with descriptive errors
|
|
59
|
+
*/
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
61
|
+
validate(output, _schema) {
|
|
62
|
+
const errors = [];
|
|
63
|
+
// 1. Parse as JSON
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(output);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
errors.push({
|
|
70
|
+
message: 'Architecture output is not valid JSON. Ensure the LLM produces only raw JSON without markdown fences or explanatory text.',
|
|
71
|
+
severity: 'error',
|
|
72
|
+
});
|
|
73
|
+
return { valid: false, errors };
|
|
74
|
+
}
|
|
75
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
76
|
+
errors.push({
|
|
77
|
+
message: 'Architecture output must be a JSON object, not an array or primitive.',
|
|
78
|
+
severity: 'error',
|
|
79
|
+
});
|
|
80
|
+
return { valid: false, errors };
|
|
81
|
+
}
|
|
82
|
+
const obj = parsed;
|
|
83
|
+
// 2. Verify required top-level keys
|
|
84
|
+
for (const key of REQUIRED_TOP_LEVEL_KEYS) {
|
|
85
|
+
if (!(key in obj)) {
|
|
86
|
+
errors.push({
|
|
87
|
+
message: `Missing required top-level key: '${key}'.`,
|
|
88
|
+
path: key,
|
|
89
|
+
severity: 'error',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (errors.length > 0) {
|
|
94
|
+
return { valid: false, errors };
|
|
95
|
+
}
|
|
96
|
+
// 3. Verify components is a non-empty array with required fields
|
|
97
|
+
const components = obj['components'];
|
|
98
|
+
if (!Array.isArray(components) || components.length === 0) {
|
|
99
|
+
errors.push({
|
|
100
|
+
message: "Key 'components' must be a non-empty array of architecture components.",
|
|
101
|
+
path: 'components',
|
|
102
|
+
severity: 'error',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
for (let i = 0; i < components.length; i++) {
|
|
107
|
+
const comp = components[i];
|
|
108
|
+
if (comp === undefined || typeof comp !== 'object' || comp === null) {
|
|
109
|
+
errors.push({
|
|
110
|
+
message: `components[${String(i)}] is not a valid object.`,
|
|
111
|
+
path: `components[${String(i)}]`,
|
|
112
|
+
severity: 'error',
|
|
113
|
+
});
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (typeof comp['name'] !== 'string' || comp['name'].length === 0) {
|
|
117
|
+
errors.push({
|
|
118
|
+
message: `components[${String(i)}] is missing required field 'name'.`,
|
|
119
|
+
path: `components[${String(i)}].name`,
|
|
120
|
+
severity: 'error',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (typeof comp['type'] !== 'string' ||
|
|
124
|
+
!VALID_COMPONENT_TYPES.has(comp['type'])) {
|
|
125
|
+
errors.push({
|
|
126
|
+
message: `components[${String(i)}] has invalid or missing 'type'. Expected one of: ${[...VALID_COMPONENT_TYPES].join(', ')}.`,
|
|
127
|
+
path: `components[${String(i)}].type`,
|
|
128
|
+
severity: 'error',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (typeof comp['description'] !== 'string' ||
|
|
132
|
+
comp['description'].length === 0) {
|
|
133
|
+
errors.push({
|
|
134
|
+
message: `components[${String(i)}] is missing required field 'description'.`,
|
|
135
|
+
path: `components[${String(i)}].description`,
|
|
136
|
+
severity: 'error',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// 4. Verify dataModel is a non-empty array
|
|
142
|
+
const dataModel = obj['dataModel'];
|
|
143
|
+
if (!Array.isArray(dataModel) || dataModel.length === 0) {
|
|
144
|
+
errors.push({
|
|
145
|
+
message: "Key 'dataModel' must be a non-empty array of data model entities.",
|
|
146
|
+
path: 'dataModel',
|
|
147
|
+
severity: 'error',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
// 5. Entity coverage check — every spec entity in dataModel
|
|
151
|
+
if (Array.isArray(dataModel) && dataModel.length > 0) {
|
|
152
|
+
const dataModelNames = new Set(dataModel
|
|
153
|
+
.filter((e) => typeof e === 'object' && e !== null)
|
|
154
|
+
.map((e) => {
|
|
155
|
+
const name = e['name'];
|
|
156
|
+
return typeof name === 'string' ? name.toLowerCase() : '';
|
|
157
|
+
}));
|
|
158
|
+
for (const entity of this.specEntities) {
|
|
159
|
+
if (!dataModelNames.has(entity.name.toLowerCase())) {
|
|
160
|
+
errors.push({
|
|
161
|
+
message: `Spec entity '${entity.name}' is not represented in the dataModel. Every spec entity must appear in the architecture data model.`,
|
|
162
|
+
path: 'dataModel',
|
|
163
|
+
severity: 'error',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// 6. Verify dependencyGraph keys reference valid component names
|
|
169
|
+
const dependencyGraph = obj['dependencyGraph'];
|
|
170
|
+
if (typeof dependencyGraph === 'object' &&
|
|
171
|
+
dependencyGraph !== null &&
|
|
172
|
+
!Array.isArray(dependencyGraph)) {
|
|
173
|
+
const componentNames = new Set(Array.isArray(components)
|
|
174
|
+
? components
|
|
175
|
+
.filter((c) => typeof c['name'] === 'string')
|
|
176
|
+
.map((c) => c['name'])
|
|
177
|
+
: []);
|
|
178
|
+
for (const key of Object.keys(dependencyGraph)) {
|
|
179
|
+
if (!componentNames.has(key)) {
|
|
180
|
+
errors.push({
|
|
181
|
+
message: `Dependency graph key '${key}' does not reference a valid component name.`,
|
|
182
|
+
path: `dependencyGraph.${key}`,
|
|
183
|
+
severity: 'error',
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return { valid: errors.length === 0, errors };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# 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,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hstm-labs/forge-architect",
|
|
3
|
+
"version": "0.1.2",
|
|
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.2",
|
|
20
|
+
"@hstm-labs/forge-core": "0.1.2",
|
|
21
|
+
"@hstm-labs/forge-spec-parser": "0.1.2",
|
|
22
|
+
"@hstm-labs/forge-profiles": "0.1.2",
|
|
23
|
+
"@hstm-labs/forge-templates": "0.1.2"
|
|
24
|
+
}
|
|
25
|
+
}
|