44b5d814d4
- Updated cursor_templates_version in project-brief.yaml to 1.0.4 for reproducibility. - Enhanced CHANGELOG with fixes and features for version 1.0.4, including improved template resolution for global installs. - Updated pubspec.yaml and VERSION file to reflect the new version. - Added new templates for AGENTS.md and lefthook.yaml to the generator. - Adjusted tests to include new root-level files in the output. This release addresses template resolution issues and introduces new repo-level configuration files.
136 lines
6.5 KiB
Dart
136 lines
6.5 KiB
Dart
// resolver.dart — Maps brief values → template file paths (Pillar 3, 4 improvements)
|
|
|
|
import 'models.dart';
|
|
|
|
class Resolver {
|
|
/// Returns an ordered list of template file keys to render.
|
|
/// Each key maps to: templates/<key>.mdc.tmpl (or SKILL.md.tmpl for skills)
|
|
static List<String> resolve(ProjectBrief brief) {
|
|
final files = <String>[];
|
|
|
|
// ── Universal (every project) ──────────────────────────────────────
|
|
files.addAll([
|
|
'rules/universal/flutter-core',
|
|
'rules/universal/ui-ux-standards',
|
|
'rules/universal/project-context',
|
|
]);
|
|
|
|
// ── Security (Pillar 5: always-on, not just for large/auth projects) ──
|
|
files.add('rules/security/security-standards');
|
|
|
|
// ── Error handling (always-on) ────────────────────────────────────
|
|
files.add('rules/error-handling/error-handling');
|
|
|
|
// ── State management — exactly one ───────────────────────────────
|
|
files.add('rules/state-management/${brief.stateManagement}');
|
|
|
|
// ── Architecture — exactly one ────────────────────────────────────
|
|
files.add('rules/architecture/${brief.architecture}');
|
|
|
|
// ── Backend — one or more ─────────────────────────────────────────
|
|
for (final b in brief.backends) files.add('rules/backend/$b');
|
|
if (brief.specialFeatures.contains('realtime')) {
|
|
files.add('rules/backend/realtime');
|
|
}
|
|
|
|
// ── Routing — exactly one ─────────────────────────────────────────
|
|
files.add('rules/routing/${brief.routing}');
|
|
|
|
// ── Testing — SM-matched ──────────────────────────────────────────
|
|
files.add('rules/testing/testing-${brief.stateManagement}');
|
|
if (brief.testingDepth == 'full' || brief.testingDepth == 'e2e') {
|
|
files.add('rules/testing/testing-e2e-${brief.e2eTool}');
|
|
}
|
|
|
|
// ── Platform targets (Pillar 4) ───────────────────────────────────
|
|
for (final platform in brief.platforms) {
|
|
files.add('rules/platform/platform-$platform');
|
|
}
|
|
|
|
// ── Code generation tools (Pillar 4) ─────────────────────────────
|
|
for (final tool in brief.codegenTools) {
|
|
files.add('rules/codegen/codegen-$tool');
|
|
}
|
|
|
|
// ── Hooks (Pillar 4) — tied to codegen, not state_management ─────
|
|
if (brief.codegenTools.isNotEmpty) {
|
|
files.addAll([
|
|
'hooks/hooks-json',
|
|
'hooks/flutter-analyze',
|
|
'hooks/grind-tests',
|
|
'hooks/arch-guard',
|
|
]);
|
|
}
|
|
|
|
// ── Localization ──────────────────────────────────────────────────
|
|
if (brief.i18nEnabled) {
|
|
files.add('rules/i18n/localization');
|
|
}
|
|
|
|
// ── Skills ────────────────────────────────────────────────────────
|
|
files.addAll([
|
|
'skills/scaffold-feature',
|
|
'skills/scaffold-screen',
|
|
'skills/generate-tests',
|
|
'skills/build',
|
|
]);
|
|
if (brief.apiDocsFormat != 'none') files.add('skills/generate-api-client');
|
|
if (brief.flavors.length > 1) files.add('skills/create-flavor');
|
|
if (brief.cicd.isNotEmpty) files.add('skills/deploy');
|
|
|
|
// ── Agents ────────────────────────────────────────────────────────
|
|
files.addAll([
|
|
'agents/code-reviewer',
|
|
'agents/test-writer',
|
|
'agents/ui-validator',
|
|
]);
|
|
if (brief.backends.contains('rest')) files.add('agents/api-client-gen');
|
|
|
|
// Pillar 5: Security agent as ADDITIONAL layer (rules are primary)
|
|
if (brief.scale == 'large' || brief.auth != 'none') {
|
|
files.add('agents/security-agent');
|
|
}
|
|
if (brief.stateManagement == 'getx') {
|
|
files.add('agents/migration-agent');
|
|
}
|
|
|
|
files.addAll(['root/AGENTS.md', 'root/lefthook.yaml']);
|
|
|
|
return files;
|
|
}
|
|
|
|
/// Returns human-readable description of why each file was included
|
|
static Map<String, String> resolveWithReasons(ProjectBrief brief) {
|
|
final resolved = resolve(brief);
|
|
final reasons = <String, String>{};
|
|
for (final f in resolved) {
|
|
reasons[f] = _reason(f, brief);
|
|
}
|
|
return reasons;
|
|
}
|
|
|
|
static String _reason(String key, ProjectBrief brief) {
|
|
if (key.contains('universal')) return 'Always included';
|
|
if (key.contains('security')) return 'Always included — Pillar 5';
|
|
if (key.contains('error-handling')) return 'Always included';
|
|
if (key.contains('state-management')) return 'Matches stack.state_management: ${brief.stateManagement}';
|
|
if (key.contains('architecture')) return 'Matches stack.architecture: ${brief.architecture}';
|
|
if (key.contains('routing')) return 'Matches stack.routing: ${brief.routing}';
|
|
if (key.contains('testing-e2e')) return 'testing.depth includes e2e';
|
|
if (key.contains('testing')) return 'Matches state_management testing patterns';
|
|
if (key.contains('platform')) return 'Matches stack.platforms';
|
|
if (key.startsWith('hooks/')) {
|
|
return 'stack.codegen non-empty — Cursor hooks for analyze, boundaries, and tests';
|
|
}
|
|
if (key.contains('codegen')) return 'Matches stack.codegen';
|
|
if (key.contains('i18n')) return 'localization.enabled: true';
|
|
if (key.contains('migration')) return 'state_management is GetX — migration guidance included';
|
|
if (key.contains('security-agent')) return 'scale: ${brief.scale} or auth is configured';
|
|
if (key == 'skills/build') return 'Always included — universal TDD-first feature implementation command';
|
|
if (key.contains('api-client')) return 'api_docs.format is set';
|
|
if (key.contains('realtime')) return 'features.special contains realtime';
|
|
if (key.startsWith('root/')) return 'Repo-level companion files';
|
|
return 'Included';
|
|
}
|
|
}
|