@compilr-dev/factory 0.1.1
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 +131 -0
- package/dist/factory/file-writer.d.ts +11 -0
- package/dist/factory/file-writer.js +21 -0
- package/dist/factory/list-toolkits-tool.d.ts +12 -0
- package/dist/factory/list-toolkits-tool.js +35 -0
- package/dist/factory/registry.d.ts +15 -0
- package/dist/factory/registry.js +28 -0
- package/dist/factory/scaffold-tool.d.ts +21 -0
- package/dist/factory/scaffold-tool.js +95 -0
- package/dist/factory/skill.d.ts +14 -0
- package/dist/factory/skill.js +146 -0
- package/dist/factory/tools.d.ts +14 -0
- package/dist/factory/tools.js +17 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +25 -0
- package/dist/model/defaults.d.ts +10 -0
- package/dist/model/defaults.js +68 -0
- package/dist/model/naming.d.ts +12 -0
- package/dist/model/naming.js +80 -0
- package/dist/model/operations-entity.d.ts +35 -0
- package/dist/model/operations-entity.js +110 -0
- package/dist/model/operations-field.d.ts +33 -0
- package/dist/model/operations-field.js +104 -0
- package/dist/model/operations-relationship.d.ts +19 -0
- package/dist/model/operations-relationship.js +90 -0
- package/dist/model/operations-section.d.ts +32 -0
- package/dist/model/operations-section.js +35 -0
- package/dist/model/operations.d.ts +12 -0
- package/dist/model/operations.js +63 -0
- package/dist/model/persistence.d.ts +19 -0
- package/dist/model/persistence.js +40 -0
- package/dist/model/schema.d.ts +15 -0
- package/dist/model/schema.js +269 -0
- package/dist/model/tools.d.ts +14 -0
- package/dist/model/tools.js +380 -0
- package/dist/model/types.d.ts +70 -0
- package/dist/model/types.js +8 -0
- package/dist/toolkits/react-node/api.d.ts +8 -0
- package/dist/toolkits/react-node/api.js +198 -0
- package/dist/toolkits/react-node/config.d.ts +9 -0
- package/dist/toolkits/react-node/config.js +120 -0
- package/dist/toolkits/react-node/dashboard.d.ts +8 -0
- package/dist/toolkits/react-node/dashboard.js +60 -0
- package/dist/toolkits/react-node/entity.d.ts +8 -0
- package/dist/toolkits/react-node/entity.js +469 -0
- package/dist/toolkits/react-node/helpers.d.ts +27 -0
- package/dist/toolkits/react-node/helpers.js +71 -0
- package/dist/toolkits/react-node/index.d.ts +8 -0
- package/dist/toolkits/react-node/index.js +52 -0
- package/dist/toolkits/react-node/router.d.ts +8 -0
- package/dist/toolkits/react-node/router.js +49 -0
- package/dist/toolkits/react-node/seed.d.ts +11 -0
- package/dist/toolkits/react-node/seed.js +144 -0
- package/dist/toolkits/react-node/shared.d.ts +7 -0
- package/dist/toolkits/react-node/shared.js +119 -0
- package/dist/toolkits/react-node/shell.d.ts +8 -0
- package/dist/toolkits/react-node/shell.js +152 -0
- package/dist/toolkits/react-node/static.d.ts +8 -0
- package/dist/toolkits/react-node/static.js +105 -0
- package/dist/toolkits/react-node/types-gen.d.ts +8 -0
- package/dist/toolkits/react-node/types-gen.js +31 -0
- package/dist/toolkits/types.d.ts +22 -0
- package/dist/toolkits/types.js +6 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @compilr-dev/factory
|
|
2
|
+
|
|
3
|
+
AI-driven application scaffolder for the compilr-dev ecosystem. Generates working full-stack MVPs from an Application Model — a declarative description of what an app is (entities, fields, relationships, layout, features).
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
@compilr-dev/agents → @compilr-dev/sdk → @compilr-dev/factory → @compilr-dev/cli
|
|
9
|
+
↑ peer dep on SDK
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The factory provides **5 tools** (via MetaToolsRegistry) and **1 skill**:
|
|
13
|
+
|
|
14
|
+
| Tool | Purpose |
|
|
15
|
+
|------|---------|
|
|
16
|
+
| `app_model_get` | Scoped reads of the Application Model |
|
|
17
|
+
| `app_model_update` | Semantic operations (addEntity, updateField, etc.) |
|
|
18
|
+
| `app_model_validate` | Check model health |
|
|
19
|
+
| `factory_scaffold` | Generate files from model + toolkit |
|
|
20
|
+
| `factory_list_toolkits` | List available toolkits |
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @compilr-dev/factory
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Peer dependency: `@compilr-dev/sdk ^0.1.11`
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { createModelTools } from '@compilr-dev/factory';
|
|
34
|
+
import type { PlatformContext } from '@compilr-dev/sdk';
|
|
35
|
+
|
|
36
|
+
// Create the 3 model tools (get, update, validate)
|
|
37
|
+
const tools = createModelTools({
|
|
38
|
+
context: platformContext, // PlatformContext with documents repo
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Or use individual utilities
|
|
42
|
+
import {
|
|
43
|
+
createDefaultModel,
|
|
44
|
+
createDefaultEntity,
|
|
45
|
+
applyOperation,
|
|
46
|
+
validateModel,
|
|
47
|
+
} from '@compilr-dev/factory';
|
|
48
|
+
|
|
49
|
+
const model = createDefaultModel({
|
|
50
|
+
identity: { name: 'Restaurant Manager', description: 'Manage reservations', version: '1.0.0' },
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const updated = applyOperation(model, {
|
|
54
|
+
op: 'addEntity',
|
|
55
|
+
entity: {
|
|
56
|
+
name: 'Reservation',
|
|
57
|
+
pluralName: 'Reservations',
|
|
58
|
+
icon: '📅',
|
|
59
|
+
fields: [
|
|
60
|
+
{ name: 'date', label: 'Date', type: 'date', required: true },
|
|
61
|
+
{ name: 'partySize', label: 'Party Size', type: 'number', required: true },
|
|
62
|
+
{ name: 'status', label: 'Status', type: 'enum', required: true, enumValues: ['pending', 'confirmed', 'cancelled'] },
|
|
63
|
+
],
|
|
64
|
+
views: ['card', 'list', 'detail'],
|
|
65
|
+
relationships: [],
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const result = validateModel(updated);
|
|
70
|
+
// { valid: true, errors: [] }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Application Model
|
|
74
|
+
|
|
75
|
+
The model describes **what** an application is, independently of how it's built:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
ApplicationModel
|
|
79
|
+
├── identity — name, description, version
|
|
80
|
+
├── entities[] — domain objects with fields, views, relationships
|
|
81
|
+
├── layout — shell type (sidebar-header | header-only)
|
|
82
|
+
├── features — boolean toggles (dashboard, auth, darkMode, etc.)
|
|
83
|
+
├── theme — primaryColor (#RRGGBB)
|
|
84
|
+
├── techStack — toolkit ID (e.g. 'react-node')
|
|
85
|
+
└── meta — revision, timestamps, factoryVersion
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Semantic Operations
|
|
89
|
+
|
|
90
|
+
The model is never edited as raw JSON. All changes go through typed operations:
|
|
91
|
+
|
|
92
|
+
**Entity:** addEntity, updateEntity, removeEntity, renameEntity, reorderEntities
|
|
93
|
+
**Field:** addField, updateField, removeField, renameField
|
|
94
|
+
**Relationship:** addRelationship, removeRelationship (with auto-inverse management)
|
|
95
|
+
**Section:** updateIdentity, updateLayout, updateFeatures, updateTheme, updateTechStack
|
|
96
|
+
|
|
97
|
+
Every operation follows: **READ → CHECK → APPLY → VALIDATE → WRITE**.
|
|
98
|
+
|
|
99
|
+
### Key Features
|
|
100
|
+
|
|
101
|
+
- **Name-based addressing** — `entity: "Reservation"`, not `entities[2]`
|
|
102
|
+
- **Optimistic locking** — revision counter prevents lost updates
|
|
103
|
+
- **Auto-inverse relationships** — adding `belongsTo` auto-adds `hasMany` on target
|
|
104
|
+
- **Cascading operations** — renaming an entity updates all relationship targets
|
|
105
|
+
- **Scoped reads** — `app_model_get({ scope: "summary" })` for lightweight overview
|
|
106
|
+
|
|
107
|
+
## Development
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm run build # Compile TypeScript
|
|
111
|
+
npm run lint # ESLint (strict, 0 errors required)
|
|
112
|
+
npm run format:check # Prettier check
|
|
113
|
+
npm test -- --run # Run 143 tests
|
|
114
|
+
npm run typecheck # Type-check without emitting
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Implementation Status
|
|
118
|
+
|
|
119
|
+
| Phase | Status | Description |
|
|
120
|
+
|-------|--------|-------------|
|
|
121
|
+
| 1 | ✅ | Types, validation, naming, defaults |
|
|
122
|
+
| 2 | ✅ | Model operations, persistence, 3 tools |
|
|
123
|
+
| 3 | 🔲 | Factory infrastructure (toolkit registry, scaffold tool) |
|
|
124
|
+
| 4 | 🔲 | React+Node toolkit (~37 file generators) |
|
|
125
|
+
| 5 | 🔲 | Skill prompt (factory-scaffold) |
|
|
126
|
+
| 6 | 🔲 | SDK integration (DocumentType extension) |
|
|
127
|
+
| 7 | 🔲 | CLI integration |
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Writer
|
|
3
|
+
*
|
|
4
|
+
* Writes generated FactoryFile[] to disk, creating directories as needed.
|
|
5
|
+
*/
|
|
6
|
+
import type { FactoryFile } from '../toolkits/types.js';
|
|
7
|
+
export interface WriteResult {
|
|
8
|
+
readonly written: number;
|
|
9
|
+
readonly paths: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function writeFactoryFiles(files: readonly FactoryFile[], targetDir: string): Promise<WriteResult>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Writer
|
|
3
|
+
*
|
|
4
|
+
* Writes generated FactoryFile[] to disk, creating directories as needed.
|
|
5
|
+
*/
|
|
6
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
7
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
|
+
export async function writeFactoryFiles(files, targetDir) {
|
|
9
|
+
const absDir = resolve(targetDir);
|
|
10
|
+
const writtenPaths = [];
|
|
11
|
+
for (const file of files) {
|
|
12
|
+
const absPath = join(absDir, file.path);
|
|
13
|
+
await mkdir(dirname(absPath), { recursive: true });
|
|
14
|
+
await writeFile(absPath, file.content, 'utf-8');
|
|
15
|
+
writtenPaths.push(file.path);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
written: writtenPaths.length,
|
|
19
|
+
paths: writtenPaths,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* factory_list_toolkits Tool
|
|
3
|
+
*
|
|
4
|
+
* Lists all registered toolkits with their descriptions.
|
|
5
|
+
*/
|
|
6
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
7
|
+
import type { ToolkitRegistry } from './registry.js';
|
|
8
|
+
interface ListToolkitsInput {
|
|
9
|
+
_unused?: never;
|
|
10
|
+
}
|
|
11
|
+
export declare function createListToolkitsTool(registry: ToolkitRegistry): Tool<ListToolkitsInput>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* factory_list_toolkits Tool
|
|
3
|
+
*
|
|
4
|
+
* Lists all registered toolkits with their descriptions.
|
|
5
|
+
*/
|
|
6
|
+
import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
|
|
7
|
+
export function createListToolkitsTool(registry) {
|
|
8
|
+
return defineTool({
|
|
9
|
+
name: 'factory_list_toolkits',
|
|
10
|
+
description: 'List all available factory toolkits. Each toolkit generates a different type of application (e.g. React+Node, Next.js, etc.).',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {},
|
|
14
|
+
required: [],
|
|
15
|
+
},
|
|
16
|
+
execute: () => {
|
|
17
|
+
try {
|
|
18
|
+
const toolkits = registry.list();
|
|
19
|
+
return Promise.resolve(createSuccessResult({
|
|
20
|
+
count: toolkits.length,
|
|
21
|
+
toolkits: toolkits.map((t) => ({
|
|
22
|
+
id: t.id,
|
|
23
|
+
name: t.name,
|
|
24
|
+
description: t.description,
|
|
25
|
+
requiredSections: t.requiredSections,
|
|
26
|
+
})),
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return Promise.resolve(createErrorResult(error instanceof Error ? error.message : String(error)));
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
readonly: true,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toolkit Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages registered FactoryToolkit implementations.
|
|
5
|
+
* Toolkits register themselves by ID and are looked up during scaffold.
|
|
6
|
+
*/
|
|
7
|
+
import type { FactoryToolkit } from '../toolkits/types.js';
|
|
8
|
+
export declare class ToolkitRegistry {
|
|
9
|
+
private readonly toolkits;
|
|
10
|
+
register(toolkit: FactoryToolkit): void;
|
|
11
|
+
get(id: string): FactoryToolkit | undefined;
|
|
12
|
+
list(): FactoryToolkit[];
|
|
13
|
+
has(id: string): boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const defaultRegistry: ToolkitRegistry;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toolkit Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages registered FactoryToolkit implementations.
|
|
5
|
+
* Toolkits register themselves by ID and are looked up during scaffold.
|
|
6
|
+
*/
|
|
7
|
+
export class ToolkitRegistry {
|
|
8
|
+
toolkits = new Map();
|
|
9
|
+
register(toolkit) {
|
|
10
|
+
if (this.toolkits.has(toolkit.id)) {
|
|
11
|
+
throw new Error(`Toolkit "${toolkit.id}" is already registered`);
|
|
12
|
+
}
|
|
13
|
+
this.toolkits.set(toolkit.id, toolkit);
|
|
14
|
+
}
|
|
15
|
+
get(id) {
|
|
16
|
+
return this.toolkits.get(id);
|
|
17
|
+
}
|
|
18
|
+
list() {
|
|
19
|
+
return [...this.toolkits.values()];
|
|
20
|
+
}
|
|
21
|
+
has(id) {
|
|
22
|
+
return this.toolkits.has(id);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export const defaultRegistry = new ToolkitRegistry();
|
|
26
|
+
// Register built-in toolkits
|
|
27
|
+
import { reactNodeToolkit } from '../toolkits/react-node/index.js';
|
|
28
|
+
defaultRegistry.register(reactNodeToolkit);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* factory_scaffold Tool
|
|
3
|
+
*
|
|
4
|
+
* Reads the Application Model, validates it, generates files via the toolkit,
|
|
5
|
+
* and writes them to disk.
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
8
|
+
import type { PlatformContext } from '@compilr-dev/sdk';
|
|
9
|
+
import type { ToolkitRegistry } from './registry.js';
|
|
10
|
+
export interface ScaffoldToolConfig {
|
|
11
|
+
readonly context: PlatformContext;
|
|
12
|
+
readonly cwd?: string;
|
|
13
|
+
readonly registry: ToolkitRegistry;
|
|
14
|
+
}
|
|
15
|
+
interface ScaffoldInput {
|
|
16
|
+
dry_run?: boolean;
|
|
17
|
+
output_dir?: string;
|
|
18
|
+
project_id?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function createScaffoldTool(config: ScaffoldToolConfig): Tool<ScaffoldInput>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* factory_scaffold Tool
|
|
3
|
+
*
|
|
4
|
+
* Reads the Application Model, validates it, generates files via the toolkit,
|
|
5
|
+
* and writes them to disk.
|
|
6
|
+
*/
|
|
7
|
+
import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
|
|
8
|
+
import { ModelStore } from '../model/persistence.js';
|
|
9
|
+
import { validateModel } from '../model/schema.js';
|
|
10
|
+
import { writeFactoryFiles } from './file-writer.js';
|
|
11
|
+
export function createScaffoldTool(config) {
|
|
12
|
+
return defineTool({
|
|
13
|
+
name: 'factory_scaffold',
|
|
14
|
+
description: 'Generate a full application from the Application Model. Reads the model, validates it, runs the toolkit generators, and writes files to disk. Use dry_run: true to preview without writing.',
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
dry_run: {
|
|
19
|
+
type: 'boolean',
|
|
20
|
+
description: 'Preview generated files without writing to disk. Default: false.',
|
|
21
|
+
},
|
|
22
|
+
output_dir: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Directory to write generated files. Defaults to current working directory.',
|
|
25
|
+
},
|
|
26
|
+
project_id: {
|
|
27
|
+
type: 'number',
|
|
28
|
+
description: 'Project ID. Uses active project if omitted.',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: [],
|
|
32
|
+
},
|
|
33
|
+
execute: async (input) => {
|
|
34
|
+
try {
|
|
35
|
+
const projectId = input.project_id ?? config.context.currentProjectId;
|
|
36
|
+
if (!projectId) {
|
|
37
|
+
return createErrorResult('No active project. Use project_create or project_get first.');
|
|
38
|
+
}
|
|
39
|
+
// 1. Read model
|
|
40
|
+
const store = new ModelStore({
|
|
41
|
+
documents: config.context.documents,
|
|
42
|
+
projectId,
|
|
43
|
+
});
|
|
44
|
+
const model = await store.get();
|
|
45
|
+
if (!model) {
|
|
46
|
+
return createErrorResult('No Application Model found. Use app_model_update to build one first.');
|
|
47
|
+
}
|
|
48
|
+
// 2. Validate
|
|
49
|
+
const validation = validateModel(model);
|
|
50
|
+
if (!validation.valid) {
|
|
51
|
+
const msgs = validation.errors.map((e) => `${e.path}: ${e.message}`).join('; ');
|
|
52
|
+
return createErrorResult(`Model validation failed: ${msgs}`);
|
|
53
|
+
}
|
|
54
|
+
// 3. Look up toolkit
|
|
55
|
+
const toolkit = config.registry.get(model.techStack.toolkit);
|
|
56
|
+
if (!toolkit) {
|
|
57
|
+
const available = config.registry
|
|
58
|
+
.list()
|
|
59
|
+
.map((t) => t.id)
|
|
60
|
+
.join(', ');
|
|
61
|
+
return createErrorResult(`Toolkit "${model.techStack.toolkit}" not found. Available: ${available || 'none'}`);
|
|
62
|
+
}
|
|
63
|
+
// 4. Generate
|
|
64
|
+
const result = toolkit.generate(model);
|
|
65
|
+
// 5. Write (unless dry_run)
|
|
66
|
+
if (!input.dry_run) {
|
|
67
|
+
const targetDir = input.output_dir ?? config.cwd ?? process.cwd();
|
|
68
|
+
await writeFactoryFiles(result.files, targetDir);
|
|
69
|
+
// 6. Update generatedAt
|
|
70
|
+
const updatedModel = {
|
|
71
|
+
...model,
|
|
72
|
+
meta: {
|
|
73
|
+
...model.meta,
|
|
74
|
+
generatedAt: new Date().toISOString(),
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
await store.save(updatedModel);
|
|
78
|
+
}
|
|
79
|
+
return createSuccessResult({
|
|
80
|
+
toolkit: result.toolkit,
|
|
81
|
+
fileCount: result.files.length,
|
|
82
|
+
files: result.files.map((f) => f.path),
|
|
83
|
+
warnings: result.warnings,
|
|
84
|
+
dryRun: input.dry_run ?? false,
|
|
85
|
+
message: input.dry_run
|
|
86
|
+
? `Dry run: ${String(result.files.length)} files would be generated.`
|
|
87
|
+
: `Generated ${String(result.files.length)} files using "${result.toolkit}" toolkit.`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory Skill — Guided Model-First Scaffold
|
|
3
|
+
*
|
|
4
|
+
* The factory-scaffold skill guides the agent through:
|
|
5
|
+
* 1. Reading project context (PRD, architecture, existing docs)
|
|
6
|
+
* 2. Checking toolkit availability
|
|
7
|
+
* 3. Building the Application Model incrementally
|
|
8
|
+
* 4. Scaffolding the application
|
|
9
|
+
* 5. Post-generation verification
|
|
10
|
+
*/
|
|
11
|
+
import { type Skill } from '@compilr-dev/agents';
|
|
12
|
+
export declare const factoryScaffoldSkill: Skill;
|
|
13
|
+
/** All factory skills. */
|
|
14
|
+
export declare const factorySkills: readonly Skill[];
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory Skill — Guided Model-First Scaffold
|
|
3
|
+
*
|
|
4
|
+
* The factory-scaffold skill guides the agent through:
|
|
5
|
+
* 1. Reading project context (PRD, architecture, existing docs)
|
|
6
|
+
* 2. Checking toolkit availability
|
|
7
|
+
* 3. Building the Application Model incrementally
|
|
8
|
+
* 4. Scaffolding the application
|
|
9
|
+
* 5. Post-generation verification
|
|
10
|
+
*/
|
|
11
|
+
import { defineSkill } from '@compilr-dev/agents';
|
|
12
|
+
export const factoryScaffoldSkill = defineSkill({
|
|
13
|
+
name: 'factory-scaffold',
|
|
14
|
+
description: 'Guide the user through building an Application Model and scaffolding a full-stack app',
|
|
15
|
+
tags: ['factory', 'scaffold', 'model'],
|
|
16
|
+
prompt: `You are in FACTORY SCAFFOLD MODE. Your goal is to build an Application Model from the user's project description and generate a working full-stack application.
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
The factory system works in two phases:
|
|
21
|
+
1. **Model Building** — You build an Application Model that describes WHAT the app is
|
|
22
|
+
2. **Code Generation** — The factory toolkit deterministically generates code from the model
|
|
23
|
+
|
|
24
|
+
You have access to these tools:
|
|
25
|
+
- \`app_model_get\` — Read the current Application Model (or sections of it)
|
|
26
|
+
- \`app_model_update\` — Apply semantic operations to the model (addEntity, updateField, etc.)
|
|
27
|
+
- \`app_model_validate\` — Check model health and get error details
|
|
28
|
+
- \`factory_scaffold\` — Generate code from the model using a toolkit
|
|
29
|
+
- \`factory_list_toolkits\` — List available code generation toolkits
|
|
30
|
+
|
|
31
|
+
## PHASE 1: Context Gathering
|
|
32
|
+
|
|
33
|
+
Before building the model, understand the project:
|
|
34
|
+
|
|
35
|
+
1. Check for existing context:
|
|
36
|
+
- Use \`project_document_get_by_type\` to look for PRD, architecture, and design docs
|
|
37
|
+
- Read any existing Application Model with \`app_model_get\`
|
|
38
|
+
|
|
39
|
+
2. If NO model exists, gather requirements from the user:
|
|
40
|
+
- What is the app? (name, one-sentence description)
|
|
41
|
+
- Who uses it? What are the main things they manage? (→ entities)
|
|
42
|
+
- What information does each thing have? (→ fields)
|
|
43
|
+
- How do things relate to each other? (→ relationships)
|
|
44
|
+
- Any special features? (dashboard, dark mode, settings)
|
|
45
|
+
|
|
46
|
+
3. If a model EXISTS, show a summary and ask what to change.
|
|
47
|
+
|
|
48
|
+
## PHASE 2: Check Toolkit Availability
|
|
49
|
+
|
|
50
|
+
Call \`factory_list_toolkits\` to see what's available.
|
|
51
|
+
- If a suitable toolkit exists → proceed with automated generation
|
|
52
|
+
- If no toolkit matches → inform the user and offer to build the model anyway (useful as a spec for manual implementation)
|
|
53
|
+
|
|
54
|
+
## PHASE 3: Build the Application Model
|
|
55
|
+
|
|
56
|
+
Build the model incrementally using \`app_model_update\`:
|
|
57
|
+
|
|
58
|
+
### Step 1: Set Identity
|
|
59
|
+
\`\`\`json
|
|
60
|
+
{ "op": "updateIdentity", "updates": { "name": "App Name", "description": "..." } }
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
### Step 2: Set Tech Stack
|
|
64
|
+
\`\`\`json
|
|
65
|
+
{ "op": "updateTechStack", "updates": { "toolkit": "react-node" } }
|
|
66
|
+
\`\`\`
|
|
67
|
+
|
|
68
|
+
### Step 3: Add Entities (one at a time)
|
|
69
|
+
\`\`\`json
|
|
70
|
+
{
|
|
71
|
+
"op": "addEntity",
|
|
72
|
+
"entity": {
|
|
73
|
+
"name": "Customer",
|
|
74
|
+
"pluralName": "Customers",
|
|
75
|
+
"icon": "👤",
|
|
76
|
+
"fields": [
|
|
77
|
+
{ "name": "name", "label": "Name", "type": "string", "required": true },
|
|
78
|
+
{ "name": "email", "label": "Email", "type": "string", "required": true }
|
|
79
|
+
],
|
|
80
|
+
"views": ["list", "detail", "card"],
|
|
81
|
+
"relationships": []
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
### Step 4: Add Relationships (after all entities exist)
|
|
87
|
+
\`\`\`json
|
|
88
|
+
{ "op": "addRelationship", "entity": "Reservation", "relationship": { "type": "belongsTo", "target": "Customer" } }
|
|
89
|
+
\`\`\`
|
|
90
|
+
Note: The inverse hasMany is added automatically.
|
|
91
|
+
|
|
92
|
+
### Step 5: Configure Features
|
|
93
|
+
\`\`\`json
|
|
94
|
+
{ "op": "updateFeatures", "updates": { "dashboard": true, "darkMode": true } }
|
|
95
|
+
\`\`\`
|
|
96
|
+
|
|
97
|
+
### Step 6: Set Theme
|
|
98
|
+
\`\`\`json
|
|
99
|
+
{ "op": "updateTheme", "updates": { "primaryColor": "#1976D2" } }
|
|
100
|
+
\`\`\`
|
|
101
|
+
|
|
102
|
+
### Step 7: Set Layout
|
|
103
|
+
\`\`\`json
|
|
104
|
+
{ "op": "updateLayout", "updates": { "shell": "sidebar-header" } }
|
|
105
|
+
\`\`\`
|
|
106
|
+
|
|
107
|
+
### Step 8: Validate
|
|
108
|
+
Call \`app_model_validate\` and fix any errors.
|
|
109
|
+
|
|
110
|
+
## PHASE 4: Generate Code
|
|
111
|
+
|
|
112
|
+
Once the model is valid:
|
|
113
|
+
|
|
114
|
+
1. **Dry run first:**
|
|
115
|
+
Call \`factory_scaffold\` with \`{ "dry_run": true }\` to preview files.
|
|
116
|
+
|
|
117
|
+
2. **Show the user** the file list and confirm they want to proceed.
|
|
118
|
+
|
|
119
|
+
3. **Generate:**
|
|
120
|
+
Call \`factory_scaffold\` without dry_run to write files.
|
|
121
|
+
|
|
122
|
+
## PHASE 5: Post-Generation
|
|
123
|
+
|
|
124
|
+
After code generation:
|
|
125
|
+
|
|
126
|
+
1. Tell the user what was generated (file count, structure)
|
|
127
|
+
2. Suggest next steps:
|
|
128
|
+
- \`cd <project-dir> && npm install && npm run dev\`
|
|
129
|
+
- The app will be at http://localhost:5173
|
|
130
|
+
- API at http://localhost:3001
|
|
131
|
+
3. Mention what can be customized (theme, features, adding entities)
|
|
132
|
+
4. If backlog tools are available, offer to seed backlog with enhancement items
|
|
133
|
+
|
|
134
|
+
## IMPORTANT RULES
|
|
135
|
+
|
|
136
|
+
- **Never guess field types** — ask if unclear (e.g., is "status" a string or enum?)
|
|
137
|
+
- **Entities use PascalCase** names (Customer, not customer)
|
|
138
|
+
- **Fields use camelCase** names (firstName, not first_name)
|
|
139
|
+
- **Always validate** before scaffolding
|
|
140
|
+
- **Show progress** — after adding each entity, show a brief summary
|
|
141
|
+
- **Relationships come last** — all entities must exist before adding relationships
|
|
142
|
+
- **Use \`belongsTo\`** for the FK side — the inverse \`hasMany\` is automatic
|
|
143
|
+
`,
|
|
144
|
+
});
|
|
145
|
+
/** All factory skills. */
|
|
146
|
+
export const factorySkills = [factoryScaffoldSkill];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory Tools — Public API
|
|
3
|
+
*
|
|
4
|
+
* createFactoryTools() returns all 5 tools (3 model + 2 factory).
|
|
5
|
+
*/
|
|
6
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
7
|
+
import type { PlatformContext } from '@compilr-dev/sdk';
|
|
8
|
+
import { ToolkitRegistry } from './registry.js';
|
|
9
|
+
export interface FactoryConfig {
|
|
10
|
+
readonly context: PlatformContext;
|
|
11
|
+
readonly cwd?: string;
|
|
12
|
+
readonly registry?: ToolkitRegistry;
|
|
13
|
+
}
|
|
14
|
+
export declare function createFactoryTools(config: FactoryConfig): Tool<never>[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory Tools — Public API
|
|
3
|
+
*
|
|
4
|
+
* createFactoryTools() returns all 5 tools (3 model + 2 factory).
|
|
5
|
+
*/
|
|
6
|
+
import { createModelTools } from '../model/tools.js';
|
|
7
|
+
import { createScaffoldTool } from './scaffold-tool.js';
|
|
8
|
+
import { createListToolkitsTool } from './list-toolkits-tool.js';
|
|
9
|
+
import { defaultRegistry } from './registry.js';
|
|
10
|
+
export function createFactoryTools(config) {
|
|
11
|
+
const registry = config.registry ?? defaultRegistry;
|
|
12
|
+
return [
|
|
13
|
+
...createModelTools(config),
|
|
14
|
+
createScaffoldTool({ ...config, registry }),
|
|
15
|
+
createListToolkitsTool(registry),
|
|
16
|
+
];
|
|
17
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @compilr-dev/factory
|
|
3
|
+
*
|
|
4
|
+
* AI-driven application scaffolder for the compilr-dev ecosystem.
|
|
5
|
+
*/
|
|
6
|
+
export type { ApplicationModel, Entity, Field, FieldType, View, Relationship, RelationshipType, Identity, Layout, ShellType, Features, Theme, TechStack, Meta, } from './model/types.js';
|
|
7
|
+
export { validateModel } from './model/schema.js';
|
|
8
|
+
export type { ValidationError, ValidationResult } from './model/schema.js';
|
|
9
|
+
export { createDefaultModel, createDefaultEntity, createDefaultField } from './model/defaults.js';
|
|
10
|
+
export { toPascalCase, toCamelCase, toKebabCase, toPlural, isPascalCase, isCamelCase, isValidHexColor, } from './model/naming.js';
|
|
11
|
+
export type { FactoryFile, FactoryResult, FactoryToolkit } from './toolkits/types.js';
|
|
12
|
+
export { ModelStore } from './model/persistence.js';
|
|
13
|
+
export { applyOperation } from './model/operations.js';
|
|
14
|
+
export type { ModelOperation } from './model/operations.js';
|
|
15
|
+
export { createModelTools } from './model/tools.js';
|
|
16
|
+
export { createFactoryTools } from './factory/tools.js';
|
|
17
|
+
export type { FactoryConfig } from './factory/tools.js';
|
|
18
|
+
export { ToolkitRegistry, defaultRegistry } from './factory/registry.js';
|
|
19
|
+
export { writeFactoryFiles } from './factory/file-writer.js';
|
|
20
|
+
export type { WriteResult } from './factory/file-writer.js';
|
|
21
|
+
export { reactNodeToolkit } from './toolkits/react-node/index.js';
|
|
22
|
+
export { factoryScaffoldSkill, factorySkills } from './factory/skill.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @compilr-dev/factory
|
|
3
|
+
*
|
|
4
|
+
* AI-driven application scaffolder for the compilr-dev ecosystem.
|
|
5
|
+
*/
|
|
6
|
+
// Validation
|
|
7
|
+
export { validateModel } from './model/schema.js';
|
|
8
|
+
// Defaults
|
|
9
|
+
export { createDefaultModel, createDefaultEntity, createDefaultField } from './model/defaults.js';
|
|
10
|
+
// Naming utilities
|
|
11
|
+
export { toPascalCase, toCamelCase, toKebabCase, toPlural, isPascalCase, isCamelCase, isValidHexColor, } from './model/naming.js';
|
|
12
|
+
// Model persistence (Phase 2)
|
|
13
|
+
export { ModelStore } from './model/persistence.js';
|
|
14
|
+
// Model operations (Phase 2)
|
|
15
|
+
export { applyOperation } from './model/operations.js';
|
|
16
|
+
// Model tools (Phase 2)
|
|
17
|
+
export { createModelTools } from './model/tools.js';
|
|
18
|
+
// Factory tools (Phase 3)
|
|
19
|
+
export { createFactoryTools } from './factory/tools.js';
|
|
20
|
+
export { ToolkitRegistry, defaultRegistry } from './factory/registry.js';
|
|
21
|
+
export { writeFactoryFiles } from './factory/file-writer.js';
|
|
22
|
+
// React+Node Toolkit (Phase 4)
|
|
23
|
+
export { reactNodeToolkit } from './toolkits/react-node/index.js';
|
|
24
|
+
// Factory skill (Phase 5)
|
|
25
|
+
export { factoryScaffoldSkill, factorySkills } from './factory/skill.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Model Creators
|
|
3
|
+
*
|
|
4
|
+
* Factory functions for creating ApplicationModel and Entity instances
|
|
5
|
+
* with sensible defaults.
|
|
6
|
+
*/
|
|
7
|
+
import type { ApplicationModel, Entity, Field } from './types.js';
|
|
8
|
+
export declare function createDefaultModel(overrides?: Partial<ApplicationModel>): ApplicationModel;
|
|
9
|
+
export declare function createDefaultEntity(name: string, overrides?: Partial<Entity>): Entity;
|
|
10
|
+
export declare function createDefaultField(name: string, label: string, overrides?: Partial<Field>): Field;
|