@claudetools/tools 0.7.0 → 0.7.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/dist/codedna/generators/base.d.ts +11 -2
- package/dist/codedna/generators/base.js +91 -8
- package/dist/codedna/generators/react-frontend.js +2 -1
- package/dist/codedna/parser.d.ts +6 -0
- package/dist/codedna/parser.js +7 -0
- package/dist/codedna/registry.d.ts +23 -17
- package/dist/codedna/registry.js +103 -263
- package/dist/codedna/template-engine.js +23 -0
- package/dist/codedna/types.d.ts +22 -0
- package/dist/handlers/codedna-handlers.d.ts +219 -6
- package/dist/handlers/codedna-handlers.js +379 -11
- package/dist/handlers/tool-handlers.js +45 -2
- package/dist/helpers/workers.js +60 -7
- package/dist/templates/orchestrator-prompt.js +15 -7
- package/dist/templates/worker-prompt.js +24 -31
- package/dist/tools.js +101 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EntitySpec } from '../parser.js';
|
|
2
2
|
import { TemplateEngine } from '../template-engine.js';
|
|
3
3
|
import { TemplateRegistry } from '../registry.js';
|
|
4
|
-
import { GenerationResult, GenerationMetadata } from '../types.js';
|
|
4
|
+
import { GenerationResult, GenerationMetadata, PatternContext } from '../types.js';
|
|
5
5
|
export declare abstract class BaseGenerator {
|
|
6
6
|
protected engine: TemplateEngine;
|
|
7
7
|
protected registry: TemplateRegistry;
|
|
@@ -10,6 +10,15 @@ export declare abstract class BaseGenerator {
|
|
|
10
10
|
* Generate code from entity specification
|
|
11
11
|
*/
|
|
12
12
|
generate(entity: EntitySpec, options?: any): Promise<GenerationResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve template variants based on detected patterns
|
|
15
|
+
* For each base template, check if a pattern-specific variant exists
|
|
16
|
+
*/
|
|
17
|
+
protected resolveTemplateVariants(generatorId: string, baseTemplates: string[], patterns?: PatternContext): Promise<string[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Build a map from base template names to resolved variants
|
|
20
|
+
*/
|
|
21
|
+
private buildTemplateMap;
|
|
13
22
|
/**
|
|
14
23
|
* Get the generator ID (e.g., "express-api")
|
|
15
24
|
*/
|
|
@@ -25,7 +34,7 @@ export declare abstract class BaseGenerator {
|
|
|
25
34
|
/**
|
|
26
35
|
* Calculate generation metadata
|
|
27
36
|
*/
|
|
28
|
-
protected calculateMetadata(generatorId: string, framework: string, entity: EntitySpec, files: Record<string, string
|
|
37
|
+
protected calculateMetadata(generatorId: string, framework: string, entity: EntitySpec, files: Record<string, string>, patterns?: PatternContext): GenerationMetadata;
|
|
29
38
|
/**
|
|
30
39
|
* Validate options against generator capabilities
|
|
31
40
|
*/
|
|
@@ -5,7 +5,34 @@
|
|
|
5
5
|
// Abstract base class for all code generators with common file generation
|
|
6
6
|
// pipeline, metadata tracking, and utilities.
|
|
7
7
|
//
|
|
8
|
+
// Pattern-Aware Template Selection:
|
|
9
|
+
// Templates can have variants based on detected patterns. For example:
|
|
10
|
+
// - validator.ts.j2 (default)
|
|
11
|
+
// - validator.zod.ts.j2 (if Zod is detected)
|
|
12
|
+
// - validator.yup.ts.j2 (if Yup is detected)
|
|
13
|
+
//
|
|
14
|
+
// The generator automatically selects the best variant based on detected patterns.
|
|
15
|
+
//
|
|
8
16
|
import { TemplateEngine, buildContext } from '../template-engine.js';
|
|
17
|
+
/**
|
|
18
|
+
* Template variant mapping: pattern_id -> template suffix
|
|
19
|
+
*/
|
|
20
|
+
const PATTERN_TEMPLATE_VARIANTS = {
|
|
21
|
+
'zod-validation': '.zod',
|
|
22
|
+
'yup-validation': '.yup',
|
|
23
|
+
'react-hook-form': '.rhf',
|
|
24
|
+
'formik': '.formik',
|
|
25
|
+
'tanstack-query': '.tanstack',
|
|
26
|
+
'swr-pattern': '.swr',
|
|
27
|
+
'zustand': '.zustand',
|
|
28
|
+
'redux-toolkit': '.redux',
|
|
29
|
+
'tailwind': '.tailwind',
|
|
30
|
+
'shadcn-ui': '.shadcn',
|
|
31
|
+
'mui-patterns': '.mui',
|
|
32
|
+
'chakra-patterns': '.chakra',
|
|
33
|
+
'compound-components': '.compound',
|
|
34
|
+
'headless-components': '.headless',
|
|
35
|
+
};
|
|
9
36
|
export class BaseGenerator {
|
|
10
37
|
engine;
|
|
11
38
|
registry;
|
|
@@ -20,33 +47,84 @@ export class BaseGenerator {
|
|
|
20
47
|
// Get generator metadata
|
|
21
48
|
const generatorId = this.getGeneratorId();
|
|
22
49
|
const metadata = await this.registry.getGeneratorMetadata(generatorId);
|
|
23
|
-
// Get required templates
|
|
24
|
-
const
|
|
50
|
+
// Get required templates (with pattern-aware variant selection)
|
|
51
|
+
const baseTemplates = this.getRequiredTemplates(options);
|
|
52
|
+
const templateFiles = await this.resolveTemplateVariants(generatorId, baseTemplates, options.patterns);
|
|
25
53
|
const templates = await this.registry.getTemplates(generatorId, templateFiles);
|
|
26
54
|
// Build template context
|
|
27
55
|
const context = buildContext(entity, options);
|
|
28
56
|
// Generate files
|
|
29
57
|
const files = {};
|
|
30
58
|
const fileMapping = this.getFileMapping(entity, options);
|
|
31
|
-
|
|
32
|
-
|
|
59
|
+
// Map base template names to resolved variants
|
|
60
|
+
const templateMap = this.buildTemplateMap(baseTemplates, templateFiles);
|
|
61
|
+
for (const [outputPath, baseTemplate] of Object.entries(fileMapping)) {
|
|
62
|
+
const resolvedTemplate = templateMap[baseTemplate] || baseTemplate;
|
|
63
|
+
const template = templates[resolvedTemplate];
|
|
33
64
|
if (!template) {
|
|
34
|
-
throw new Error(`Template not found: ${
|
|
65
|
+
throw new Error(`Template not found: ${resolvedTemplate}`);
|
|
35
66
|
}
|
|
36
67
|
const content = this.engine.render(template, context);
|
|
37
68
|
files[outputPath] = content;
|
|
38
69
|
}
|
|
39
70
|
// Calculate metadata
|
|
40
|
-
const generationMetadata = this.calculateMetadata(generatorId, metadata.framework, entity, files);
|
|
71
|
+
const generationMetadata = this.calculateMetadata(generatorId, metadata.framework, entity, files, options.patterns);
|
|
41
72
|
return {
|
|
42
73
|
files,
|
|
43
74
|
metadata: generationMetadata,
|
|
44
75
|
};
|
|
45
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve template variants based on detected patterns
|
|
79
|
+
* For each base template, check if a pattern-specific variant exists
|
|
80
|
+
*/
|
|
81
|
+
async resolveTemplateVariants(generatorId, baseTemplates, patterns) {
|
|
82
|
+
if (!patterns?.detected?.length) {
|
|
83
|
+
return baseTemplates; // No patterns detected, use defaults
|
|
84
|
+
}
|
|
85
|
+
const resolvedTemplates = [];
|
|
86
|
+
for (const baseTemplate of baseTemplates) {
|
|
87
|
+
// Try to find a matching variant for each detected pattern
|
|
88
|
+
let resolved = baseTemplate;
|
|
89
|
+
// Sort patterns by confidence (highest first)
|
|
90
|
+
const sortedPatterns = [...patterns.detected].sort((a, b) => b.confidence - a.confidence);
|
|
91
|
+
for (const pattern of sortedPatterns) {
|
|
92
|
+
const suffix = PATTERN_TEMPLATE_VARIANTS[pattern.pattern_id];
|
|
93
|
+
if (!suffix)
|
|
94
|
+
continue;
|
|
95
|
+
// Build variant name: validator.ts.j2 -> validator.zod.ts.j2
|
|
96
|
+
const parts = baseTemplate.split('.');
|
|
97
|
+
if (parts.length >= 2) {
|
|
98
|
+
const variantName = `${parts[0]}${suffix}.${parts.slice(1).join('.')}`;
|
|
99
|
+
// Check if variant exists (try to fetch, cache result)
|
|
100
|
+
try {
|
|
101
|
+
await this.registry.getTemplate(generatorId, variantName);
|
|
102
|
+
resolved = variantName;
|
|
103
|
+
break; // Use first matching variant
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Variant doesn't exist, continue checking
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
resolvedTemplates.push(resolved);
|
|
111
|
+
}
|
|
112
|
+
return resolvedTemplates;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Build a map from base template names to resolved variants
|
|
116
|
+
*/
|
|
117
|
+
buildTemplateMap(baseTemplates, resolvedTemplates) {
|
|
118
|
+
const map = {};
|
|
119
|
+
for (let i = 0; i < baseTemplates.length; i++) {
|
|
120
|
+
map[baseTemplates[i]] = resolvedTemplates[i];
|
|
121
|
+
}
|
|
122
|
+
return map;
|
|
123
|
+
}
|
|
46
124
|
/**
|
|
47
125
|
* Calculate generation metadata
|
|
48
126
|
*/
|
|
49
|
-
calculateMetadata(generatorId, framework, entity, files) {
|
|
127
|
+
calculateMetadata(generatorId, framework, entity, files, patterns) {
|
|
50
128
|
const filesGenerated = Object.keys(files).length;
|
|
51
129
|
const linesOfCode = Object.values(files).reduce((sum, content) => sum + content.split('\n').length, 0);
|
|
52
130
|
// Estimate token savings
|
|
@@ -54,7 +132,7 @@ export class BaseGenerator {
|
|
|
54
132
|
// AI would generate all lines from scratch
|
|
55
133
|
// With CodeDNA: ~150 tokens for the API call
|
|
56
134
|
const estimatedTokensSaved = Math.max(0, linesOfCode * 25 - 150);
|
|
57
|
-
|
|
135
|
+
const metadata = {
|
|
58
136
|
generator: generatorId,
|
|
59
137
|
framework,
|
|
60
138
|
entities: [entity.name],
|
|
@@ -62,6 +140,11 @@ export class BaseGenerator {
|
|
|
62
140
|
linesOfCode,
|
|
63
141
|
estimatedTokensSaved,
|
|
64
142
|
};
|
|
143
|
+
// Add pattern information to metadata if patterns were used
|
|
144
|
+
if (patterns?.detected?.length) {
|
|
145
|
+
metadata.patternsApplied = patterns.detected.map(p => p.pattern_id);
|
|
146
|
+
}
|
|
147
|
+
return metadata;
|
|
65
148
|
}
|
|
66
149
|
/**
|
|
67
150
|
* Validate options against generator capabilities
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// React Frontend Generator
|
|
3
3
|
// =============================================================================
|
|
4
4
|
//
|
|
5
|
-
// Generate React components
|
|
5
|
+
// Generate React components for forms, tables, and CRUD views.
|
|
6
|
+
// Supports multiple UI libraries: shadcn, mui, chakra (default: shadcn)
|
|
6
7
|
//
|
|
7
8
|
import { BaseGenerator } from './base.js';
|
|
8
9
|
export class ReactFrontendGenerator extends BaseGenerator {
|
package/dist/codedna/parser.d.ts
CHANGED
package/dist/codedna/parser.js
CHANGED
|
@@ -151,6 +151,13 @@ export class EntityParser {
|
|
|
151
151
|
return { kind: 'nullable' };
|
|
152
152
|
if (constraintStr === 'immutable')
|
|
153
153
|
return { kind: 'immutable' };
|
|
154
|
+
// UI hints
|
|
155
|
+
if (constraintStr === 'textarea')
|
|
156
|
+
return { kind: 'textarea' };
|
|
157
|
+
if (constraintStr === 'switch')
|
|
158
|
+
return { kind: 'switch' };
|
|
159
|
+
if (constraintStr === 'radio')
|
|
160
|
+
return { kind: 'radio' };
|
|
154
161
|
// Parameterized constraints: min(18), max(100), default(true), length(10,100), pattern(/regex/)
|
|
155
162
|
const paramMatch = constraintStr.match(/^([a-z]+)\((.+)\)$/);
|
|
156
163
|
if (paramMatch) {
|
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
import { GeneratorMetadata } from './types.js';
|
|
2
2
|
export interface RegistryResponse {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
success: boolean;
|
|
4
|
+
data: {
|
|
5
|
+
generators: GeneratorMetadata[];
|
|
6
|
+
byDomain: Record<string, GeneratorMetadata[]>;
|
|
7
|
+
summary: {
|
|
8
|
+
total: number;
|
|
9
|
+
api: number;
|
|
10
|
+
frontend: number;
|
|
11
|
+
component: number;
|
|
12
|
+
};
|
|
13
|
+
version: string;
|
|
14
|
+
};
|
|
6
15
|
}
|
|
7
16
|
export declare class TemplateRegistry {
|
|
8
17
|
private baseUrl;
|
|
9
18
|
private cacheDir;
|
|
10
19
|
private useCache;
|
|
20
|
+
private registryCache;
|
|
11
21
|
constructor(baseUrl?: string, useCache?: boolean);
|
|
12
22
|
/**
|
|
13
23
|
* List all available generators
|
|
24
|
+
* Fetches from Cloudflare D1 (single source of truth)
|
|
25
|
+
* @param domain Optional domain filter: 'api' | 'frontend' | 'component'
|
|
14
26
|
*/
|
|
15
|
-
listGenerators(): Promise<GeneratorMetadata[]>;
|
|
27
|
+
listGenerators(domain?: 'api' | 'frontend' | 'component'): Promise<GeneratorMetadata[]>;
|
|
16
28
|
/**
|
|
17
29
|
* Get metadata for specific generator
|
|
18
30
|
*/
|
|
@@ -22,37 +34,31 @@ export declare class TemplateRegistry {
|
|
|
22
34
|
*/
|
|
23
35
|
getTemplate(generatorId: string, templateFile: string): Promise<string>;
|
|
24
36
|
/**
|
|
25
|
-
* Get multiple templates at once
|
|
37
|
+
* Get multiple templates at once (parallel fetch)
|
|
26
38
|
*/
|
|
27
39
|
getTemplates(generatorId: string, templateFiles: string[]): Promise<Record<string, string>>;
|
|
28
40
|
/**
|
|
29
|
-
*
|
|
41
|
+
* Get cached template from file system
|
|
30
42
|
*/
|
|
31
43
|
private getCachedTemplate;
|
|
32
44
|
/**
|
|
33
|
-
* Cache template
|
|
45
|
+
* Cache template to file system
|
|
34
46
|
*/
|
|
35
47
|
private cacheTemplate;
|
|
36
48
|
/**
|
|
37
|
-
* Get local
|
|
38
|
-
*/
|
|
39
|
-
private getLocalGenerators;
|
|
40
|
-
/**
|
|
41
|
-
* Get local metadata (fallback)
|
|
42
|
-
*/
|
|
43
|
-
private getLocalMetadata;
|
|
44
|
-
/**
|
|
45
|
-
* Get local template (fallback)
|
|
49
|
+
* Get template from bundled local files (fallback)
|
|
46
50
|
*/
|
|
47
51
|
private getLocalTemplate;
|
|
48
52
|
/**
|
|
49
|
-
* Clear local cache
|
|
53
|
+
* Clear local template cache
|
|
50
54
|
*/
|
|
51
55
|
clearCache(): Promise<void>;
|
|
52
56
|
/**
|
|
53
57
|
* Get cache statistics
|
|
54
58
|
*/
|
|
55
59
|
getCacheStats(): Promise<{
|
|
60
|
+
registryCached: boolean;
|
|
61
|
+
registryAge: number | null;
|
|
56
62
|
cachedGenerators: string[];
|
|
57
63
|
totalFiles: number;
|
|
58
64
|
totalSize: number;
|