@polymorphism-tech/morph-spec 2.1.2 ā 2.3.0
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/CLAUDE.md +389 -40
- package/bin/morph-spec.js +121 -0
- package/bin/task-manager.js +368 -0
- package/bin/validate-agents-skills.js +17 -5
- package/bin/validate.js +268 -0
- package/content/.claude/skills/specialists/ef-modeler.md +11 -0
- package/content/.claude/skills/specialists/hangfire-orchestrator.md +10 -0
- package/content/.claude/skills/specialists/ui-ux-designer.md +40 -0
- package/content/.claude/skills/stacks/dotnet-blazor.md +18 -0
- package/content/.morph/examples/state-v3.json +188 -0
- package/detectors/structure-detector.js +32 -3
- package/package.json +1 -1
- package/src/commands/create-story.js +68 -0
- package/src/commands/init.js +59 -5
- package/src/commands/state.js +1 -1
- package/src/commands/task.js +75 -0
- package/src/lib/continuous-validator.js +440 -0
- package/src/lib/learning-system.js +520 -0
- package/src/lib/mockup-generator.js +366 -0
- package/src/lib/ui-detector.js +350 -0
- package/src/lib/validators/architecture-validator.js +387 -0
- package/src/lib/validators/package-validator.js +360 -0
- package/src/lib/validators/ui-contrast-validator.js +422 -0
- package/src/utils/file-copier.js +26 -0
package/bin/validate.js
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validation CLI
|
|
5
|
+
*
|
|
6
|
+
* Runs all validators (package, architecture, contrast) on the project.
|
|
7
|
+
* Part of Sprint 4: Continuous Validation + Learning System
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* morph-spec validate [options]
|
|
11
|
+
* morph-spec validate packages
|
|
12
|
+
* morph-spec validate architecture
|
|
13
|
+
* morph-spec validate contrast
|
|
14
|
+
* morph-spec validate all
|
|
15
|
+
*
|
|
16
|
+
* MORPH-SPEC 3.0
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import chalk from 'chalk';
|
|
20
|
+
import { validatePackages } from '../src/lib/validators/package-validator.js';
|
|
21
|
+
import { validateArchitecture } from '../src/lib/validators/architecture-validator.js';
|
|
22
|
+
import { validateContrast } from '../src/lib/validators/ui-contrast-validator.js';
|
|
23
|
+
import { LearningSystem } from '../src/lib/learning-system.js';
|
|
24
|
+
|
|
25
|
+
const VALIDATORS = {
|
|
26
|
+
packages: {
|
|
27
|
+
name: 'Package Compatibility',
|
|
28
|
+
description: 'Validates NuGet package versions against .NET compatibility matrix',
|
|
29
|
+
run: validatePackages
|
|
30
|
+
},
|
|
31
|
+
architecture: {
|
|
32
|
+
name: 'Architecture Patterns',
|
|
33
|
+
description: 'Detects DI anti-patterns and lifecycle issues in Blazor',
|
|
34
|
+
run: validateArchitecture
|
|
35
|
+
},
|
|
36
|
+
contrast: {
|
|
37
|
+
name: 'UI Contrast (WCAG)',
|
|
38
|
+
description: 'Validates color contrast ratios for accessibility',
|
|
39
|
+
run: validateContrast
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Main validation command
|
|
45
|
+
*/
|
|
46
|
+
export async function validateCommand(args = []) {
|
|
47
|
+
const validatorName = args[0] || 'all';
|
|
48
|
+
const options = parseOptions(args);
|
|
49
|
+
|
|
50
|
+
console.log(chalk.bold.cyan('\nš MORPH-SPEC Validator\n'));
|
|
51
|
+
|
|
52
|
+
if (validatorName === 'all') {
|
|
53
|
+
await runAllValidators(options);
|
|
54
|
+
} else if (VALIDATORS[validatorName]) {
|
|
55
|
+
await runValidator(validatorName, options);
|
|
56
|
+
} else {
|
|
57
|
+
console.error(chalk.red(`ā Unknown validator: ${validatorName}`));
|
|
58
|
+
console.log(chalk.gray('\nAvailable validators:'));
|
|
59
|
+
for (const [name, validator] of Object.entries(VALIDATORS)) {
|
|
60
|
+
console.log(chalk.gray(` - ${name}: ${validator.description}`));
|
|
61
|
+
}
|
|
62
|
+
console.log(chalk.gray(' - all: Run all validators'));
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Show learning insights if --insights flag
|
|
67
|
+
if (options.insights) {
|
|
68
|
+
await showLearningInsights(options);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Run all validators
|
|
74
|
+
*/
|
|
75
|
+
async function runAllValidators(options) {
|
|
76
|
+
const results = {};
|
|
77
|
+
let totalErrors = 0;
|
|
78
|
+
let totalWarnings = 0;
|
|
79
|
+
|
|
80
|
+
console.log(chalk.gray('Running all validators...\n'));
|
|
81
|
+
|
|
82
|
+
for (const [name, validator] of Object.entries(VALIDATORS)) {
|
|
83
|
+
console.log(chalk.cyan(`\nāø ${validator.name}`));
|
|
84
|
+
console.log(chalk.gray(` ${validator.description}\n`));
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const result = await validator.run('.', {
|
|
88
|
+
verbose: options.verbose,
|
|
89
|
+
autoFix: options.autoFix
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
results[name] = result;
|
|
93
|
+
|
|
94
|
+
// Count errors/warnings
|
|
95
|
+
if (result.errors !== undefined) {
|
|
96
|
+
totalErrors += result.errors;
|
|
97
|
+
totalWarnings += result.warnings || 0;
|
|
98
|
+
} else if (result.results) {
|
|
99
|
+
// Count issues in results array
|
|
100
|
+
const issues = result.results.flatMap(r => r.issues || []);
|
|
101
|
+
totalErrors += issues.filter(i => i.level === 'error').length;
|
|
102
|
+
totalWarnings += issues.filter(i => i.level === 'warning').length;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(chalk.red(` ā Failed: ${error.message}`));
|
|
107
|
+
results[name] = { status: 'error', error: error.message };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Summary
|
|
112
|
+
console.log(chalk.bold.cyan('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
113
|
+
console.log(chalk.bold('š Validation Summary\n'));
|
|
114
|
+
|
|
115
|
+
if (totalErrors === 0 && totalWarnings === 0) {
|
|
116
|
+
console.log(chalk.green('ā
All validations passed!'));
|
|
117
|
+
} else {
|
|
118
|
+
if (totalErrors > 0) {
|
|
119
|
+
console.log(chalk.red(`ā ${totalErrors} error(s) found`));
|
|
120
|
+
}
|
|
121
|
+
if (totalWarnings > 0) {
|
|
122
|
+
console.log(chalk.yellow(`ā ļø ${totalWarnings} warning(s) found`));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log('');
|
|
127
|
+
|
|
128
|
+
// Exit with error code if errors found
|
|
129
|
+
if (totalErrors > 0 && !options.noFail) {
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Run single validator
|
|
136
|
+
*/
|
|
137
|
+
async function runValidator(name, options) {
|
|
138
|
+
const validator = VALIDATORS[name];
|
|
139
|
+
|
|
140
|
+
console.log(chalk.cyan(`āø ${validator.name}`));
|
|
141
|
+
console.log(chalk.gray(` ${validator.description}\n`));
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const result = await validator.run('.', {
|
|
145
|
+
verbose: true, // Always verbose for single validator
|
|
146
|
+
autoFix: options.autoFix,
|
|
147
|
+
wcagLevel: options.wcagLevel
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (result.status === 'ok') {
|
|
151
|
+
console.log(chalk.green('\nā
Validation passed!\n'));
|
|
152
|
+
} else {
|
|
153
|
+
console.log(chalk.yellow('\nā ļø Validation completed with issues\n'));
|
|
154
|
+
|
|
155
|
+
if (result.errors > 0 && !options.noFail) {
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error(chalk.red(`\nā Validation failed: ${error.message}\n`));
|
|
162
|
+
if (!options.noFail) {
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Show learning insights
|
|
170
|
+
*/
|
|
171
|
+
async function showLearningInsights(options) {
|
|
172
|
+
console.log(chalk.bold.cyan('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
173
|
+
|
|
174
|
+
const learner = new LearningSystem('.');
|
|
175
|
+
learner.formatInsights();
|
|
176
|
+
|
|
177
|
+
if (options.verbose) {
|
|
178
|
+
const suggestions = learner.getAllSuggestions();
|
|
179
|
+
learner.formatSuggestions(suggestions);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Parse command-line options
|
|
185
|
+
*/
|
|
186
|
+
function parseOptions(args) {
|
|
187
|
+
const options = {
|
|
188
|
+
verbose: false,
|
|
189
|
+
autoFix: false,
|
|
190
|
+
noFail: false,
|
|
191
|
+
insights: false,
|
|
192
|
+
wcagLevel: 'AA'
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
for (const arg of args) {
|
|
196
|
+
if (arg === '--verbose' || arg === '-v') {
|
|
197
|
+
options.verbose = true;
|
|
198
|
+
} else if (arg === '--auto-fix' || arg === '--fix') {
|
|
199
|
+
options.autoFix = true;
|
|
200
|
+
} else if (arg === '--no-fail') {
|
|
201
|
+
options.noFail = true;
|
|
202
|
+
} else if (arg === '--insights' || arg === '-i') {
|
|
203
|
+
options.insights = true;
|
|
204
|
+
} else if (arg === '--wcag-aaa') {
|
|
205
|
+
options.wcagLevel = 'AAA';
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return options;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Show help
|
|
214
|
+
*/
|
|
215
|
+
export function showValidateHelp() {
|
|
216
|
+
console.log(`
|
|
217
|
+
${chalk.bold.cyan('morph-spec validate')} - Run project validations
|
|
218
|
+
|
|
219
|
+
${chalk.bold('USAGE')}
|
|
220
|
+
morph-spec validate [validator] [options]
|
|
221
|
+
|
|
222
|
+
${chalk.bold('VALIDATORS')}
|
|
223
|
+
all Run all validators (default)
|
|
224
|
+
packages Validate NuGet package compatibility (.NET 10)
|
|
225
|
+
architecture Validate architecture patterns (DI, lifecycle)
|
|
226
|
+
contrast Validate UI contrast ratios (WCAG 2.1)
|
|
227
|
+
|
|
228
|
+
${chalk.bold('OPTIONS')}
|
|
229
|
+
--verbose, -v Show detailed output
|
|
230
|
+
--auto-fix, --fix Auto-fix issues where possible
|
|
231
|
+
--no-fail Don't exit with error code
|
|
232
|
+
--insights, -i Show learning insights
|
|
233
|
+
--wcag-aaa Use WCAG AAA standard (stricter)
|
|
234
|
+
|
|
235
|
+
${chalk.bold('EXAMPLES')}
|
|
236
|
+
morph-spec validate # Run all validators
|
|
237
|
+
morph-spec validate packages --fix # Validate packages and auto-fix
|
|
238
|
+
morph-spec validate architecture -v # Verbose architecture validation
|
|
239
|
+
morph-spec validate contrast --wcag-aaa # Stricter contrast validation
|
|
240
|
+
morph-spec validate all --insights # All validators + AI insights
|
|
241
|
+
|
|
242
|
+
${chalk.bold('EXIT CODES')}
|
|
243
|
+
0 All validations passed
|
|
244
|
+
1 Validation errors found (unless --no-fail)
|
|
245
|
+
|
|
246
|
+
${chalk.bold('INTEGRATION')}
|
|
247
|
+
Add to pre-commit hook:
|
|
248
|
+
morph-spec validate --no-fail
|
|
249
|
+
|
|
250
|
+
CI/CD pipeline:
|
|
251
|
+
morph-spec validate || exit 1
|
|
252
|
+
`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Run if called directly
|
|
256
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
257
|
+
const args = process.argv.slice(2);
|
|
258
|
+
|
|
259
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
260
|
+
showValidateHelp();
|
|
261
|
+
process.exit(0);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
validateCommand(args).catch(error => {
|
|
265
|
+
console.error(chalk.red(`\nā Error: ${error.message}\n`));
|
|
266
|
+
process.exit(1);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
@@ -13,6 +13,17 @@ Especialista em Entity Framework Core para modelagem de dados e banco de dados.
|
|
|
13
13
|
|
|
14
14
|
Keywords: `entity`, `database`, `migration`, `ef core`, `dbcontext`, `table`, `column`, `relationship`, `query`
|
|
15
15
|
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## ā ļø .NET 10 Compatibility
|
|
19
|
+
|
|
20
|
+
**ALWAYS check package version:**
|
|
21
|
+
- Entity Framework Core: **ā„ 10.0.0** (required for .NET 10)
|
|
22
|
+
- New features: Vector search, primitive collections
|
|
23
|
+
- Breaking changes: Required navigation properties, query splitting
|
|
24
|
+
|
|
25
|
+
**Consult:** `framework/standards/dotnet10-compatibility.md`
|
|
26
|
+
|
|
16
27
|
## Estrutura de Entidades
|
|
17
28
|
|
|
18
29
|
```csharp
|
|
@@ -13,6 +13,16 @@ Especialista em background jobs, tarefas agendadas e processamento assĆncrono c
|
|
|
13
13
|
|
|
14
14
|
Keywords: `scheduled`, `job`, `background`, `cron`, `recurring`, `batch`, `queue`, `hangfire`, `task`
|
|
15
15
|
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## ā ļø .NET 10 Compatibility
|
|
19
|
+
|
|
20
|
+
**ALWAYS check package version:**
|
|
21
|
+
- Hangfire.AspNetCore: **ā„ 1.8.22** (required for .NET 10)
|
|
22
|
+
- No breaking changes from .NET 9
|
|
23
|
+
|
|
24
|
+
**Consult:** `framework/standards/dotnet10-compatibility.md`
|
|
25
|
+
|
|
16
26
|
## Por que Hangfire (não Azure Functions)
|
|
17
27
|
|
|
18
28
|
| Aspecto | Hangfire | Azure Functions |
|
|
@@ -19,6 +19,46 @@ Especialista em design de interfaces, experiência do usuÔrio e componentes Bla
|
|
|
19
19
|
- `blazor`, `component`, `page`, `razor`, `ui`, `ux`, `design`, `layout`
|
|
20
20
|
- `wizard`, `dashboard`, `form`, `chart`, `table`, `dialog`, `modal`
|
|
21
21
|
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## šØ Design Moderno (2025+)
|
|
25
|
+
|
|
26
|
+
**SEMPRE aim for modern, beautiful UI:**
|
|
27
|
+
|
|
28
|
+
### Visual Trends
|
|
29
|
+
- **Glassmorphism**: `backdrop-filter: blur(10px)`, semi-transparent backgrounds
|
|
30
|
+
- **Gradients**: Purple (#667eea ā #764ba2), Blue-Purple (#4facfe ā #00f2fe)
|
|
31
|
+
- **Soft Shadows**: `box-shadow: 0 4px 6px rgba(0,0,0,0.1)`
|
|
32
|
+
- **Rounded Corners**: `border-radius: 12px-16px` (não 4px!)
|
|
33
|
+
- **Micro-interactions**: Hover effects, transitions (transform, scale, opacity)
|
|
34
|
+
|
|
35
|
+
### Component Patterns
|
|
36
|
+
- **Cards with elevation**: Subtle shadow + hover lift effect
|
|
37
|
+
- **Skeleton loaders**: Durante loading, não apenas spinner
|
|
38
|
+
- **Toast notifications**: Bottom-right, auto-dismiss
|
|
39
|
+
- **Empty states**: Ilustração + CTA, nunca apenas texto
|
|
40
|
+
- **Dark mode support**: ALWAYS design for both light/dark
|
|
41
|
+
|
|
42
|
+
### Layout Principles
|
|
43
|
+
- **Whitespace**: Generous padding (32px-48px containers, não 16px)
|
|
44
|
+
- **Grid systems**: 12-column grid, gap 24px-32px
|
|
45
|
+
- **Typography hierarchy**: Clear sizes (xs: 12px, sm: 14px, base: 16px, lg: 18px, xl: 20px, 2xl: 24px)
|
|
46
|
+
- **Contrast**: WCAG AA minimum (4.5:1 text, 3:1 UI components)
|
|
47
|
+
|
|
48
|
+
### ReferĆŖncias Modernas
|
|
49
|
+
- **Linear** (linear.app): Clean, purple gradients, minimal
|
|
50
|
+
- **Vercel** (vercel.com): Black & white, subtle animations
|
|
51
|
+
- **Stripe** (stripe.com): Professional, blue accent, great forms
|
|
52
|
+
- **Dribbble** (dribbble.com/tags/dashboard): Modern dashboard designs
|
|
53
|
+
- **Awwwards** (awwwards.com): Award-winning UI patterns
|
|
54
|
+
|
|
55
|
+
**Framework integration:**
|
|
56
|
+
- Use `src/lib/mockup-generator.js` for wireframes
|
|
57
|
+
- Use `framework/templates/ui-components/` for component scaffolding
|
|
58
|
+
- Consult `framework/standards/blazor-pitfalls.md` for Blazor-specific patterns
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
22
62
|
## Deliverables da FASE 1.5
|
|
23
63
|
|
|
24
64
|
| Arquivo | ConteĆŗdo |
|
|
@@ -17,6 +17,24 @@ Stack principal para desenvolvimento de aplicaƧƵes web com .NET e Blazor Serve
|
|
|
17
17
|
|
|
18
18
|
Keywords: `blazor`, `razor`, `server-side`, `.net`, `csharp`, `dotnet`
|
|
19
19
|
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ā ļø CRITICAL PITFALLS (Read FIRST!)
|
|
23
|
+
|
|
24
|
+
**ALWAYS consult framework standards before implementing:**
|
|
25
|
+
- `framework/standards/blazor-pitfalls.md` - Common issues & solutions
|
|
26
|
+
- `framework/standards/blazor-lifecycle.md` - Lifecycle patterns
|
|
27
|
+
- `framework/standards/program-cs-checklist.md` - Required Program.cs setup
|
|
28
|
+
- `framework/standards/dotnet10-compatibility.md` - Package compatibility
|
|
29
|
+
|
|
30
|
+
**Quick Checklist:**
|
|
31
|
+
- [ ] DI Pattern: Use HttpClient, NOT direct Application layer injection
|
|
32
|
+
- [ ] Lifecycle: JSRuntime ONLY in OnAfterRenderAsync(firstRender)
|
|
33
|
+
- [ ] Program.cs: app.UseStaticFiles() BEFORE app.UseAntiforgery()
|
|
34
|
+
- [ ] File Upload: Specify maxAllowedSize in OpenReadStream()
|
|
35
|
+
- [ ] RenderMode: NO @rendermode on MainLayout
|
|
36
|
+
- [ ] Package Versions: MudBlazor ā„ 8.15.0 for .NET 10
|
|
37
|
+
|
|
20
38
|
## Estrutura de Projeto
|
|
21
39
|
|
|
22
40
|
```
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "3.0.0",
|
|
3
|
+
"project": {
|
|
4
|
+
"name": "FishArt",
|
|
5
|
+
"type": "blazor-server",
|
|
6
|
+
"createdAt": "2024-01-15T10:00:00Z",
|
|
7
|
+
"updatedAt": "2024-01-15T14:30:00Z"
|
|
8
|
+
},
|
|
9
|
+
"features": {
|
|
10
|
+
"scheduled-reports": {
|
|
11
|
+
"status": "in_progress",
|
|
12
|
+
"phase": "implement",
|
|
13
|
+
"activeAgents": [
|
|
14
|
+
"standards-architect",
|
|
15
|
+
"blazor-builder",
|
|
16
|
+
"ef-modeler",
|
|
17
|
+
"hangfire-orchestrator"
|
|
18
|
+
],
|
|
19
|
+
"tasks": [
|
|
20
|
+
{
|
|
21
|
+
"id": "T001",
|
|
22
|
+
"title": "Create ScheduledReport entity",
|
|
23
|
+
"status": "completed",
|
|
24
|
+
"completedAt": "2024-01-15T10:30:00Z",
|
|
25
|
+
"completedBy": "claude",
|
|
26
|
+
"dependencies": [],
|
|
27
|
+
"files": [
|
|
28
|
+
"Domain/Entities/ScheduledReport.cs",
|
|
29
|
+
"Infrastructure/Persistence/Config/ScheduledReportConfig.cs"
|
|
30
|
+
],
|
|
31
|
+
"checkpoint": "CHECKPOINT_001"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "T002",
|
|
35
|
+
"title": "Create CreateReportCommand + Handler",
|
|
36
|
+
"status": "completed",
|
|
37
|
+
"completedAt": "2024-01-15T11:15:00Z",
|
|
38
|
+
"completedBy": "claude",
|
|
39
|
+
"dependencies": ["T001"],
|
|
40
|
+
"files": [
|
|
41
|
+
"Application/Commands/CreateReport/CreateReportCommand.cs",
|
|
42
|
+
"Application/Commands/CreateReport/CreateReportHandler.cs"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "T003",
|
|
47
|
+
"title": "Create Hangfire job for report generation",
|
|
48
|
+
"status": "completed",
|
|
49
|
+
"completedAt": "2024-01-15T12:00:00Z",
|
|
50
|
+
"completedBy": "claude",
|
|
51
|
+
"dependencies": ["T002"],
|
|
52
|
+
"files": [
|
|
53
|
+
"Infrastructure/Jobs/GenerateReportJob.cs"
|
|
54
|
+
],
|
|
55
|
+
"checkpoint": "CHECKPOINT_002"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "T004",
|
|
59
|
+
"title": "Create ReportList component (Blazor)",
|
|
60
|
+
"status": "in_progress",
|
|
61
|
+
"startedAt": "2024-01-15T13:00:00Z",
|
|
62
|
+
"dependencies": ["T001"],
|
|
63
|
+
"files": [
|
|
64
|
+
"Components/Reports/ReportList.razor",
|
|
65
|
+
"Components/Reports/ReportList.razor.cs",
|
|
66
|
+
"Components/Reports/ReportList.razor.css"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "T005",
|
|
71
|
+
"title": "Create CreateReportForm component (Blazor)",
|
|
72
|
+
"status": "pending",
|
|
73
|
+
"dependencies": ["T002"],
|
|
74
|
+
"files": [
|
|
75
|
+
"Components/Reports/CreateReportForm.razor",
|
|
76
|
+
"Components/Reports/CreateReportForm.razor.cs",
|
|
77
|
+
"Components/Reports/CreateReportForm.razor.css"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "T006",
|
|
82
|
+
"title": "Create API controller for reports",
|
|
83
|
+
"status": "pending",
|
|
84
|
+
"dependencies": ["T002"],
|
|
85
|
+
"files": [
|
|
86
|
+
"API/Controllers/ReportsController.cs"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "T007",
|
|
91
|
+
"title": "Add Hangfire dashboard configuration",
|
|
92
|
+
"status": "pending",
|
|
93
|
+
"dependencies": ["T003"],
|
|
94
|
+
"files": [
|
|
95
|
+
"Program.cs"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": "T008",
|
|
100
|
+
"title": "Create unit tests for CreateReportCommand",
|
|
101
|
+
"status": "pending",
|
|
102
|
+
"dependencies": ["T002"],
|
|
103
|
+
"files": [
|
|
104
|
+
"Tests/Application/Commands/CreateReportCommandTests.cs"
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "T009",
|
|
109
|
+
"title": "Create integration tests for report generation",
|
|
110
|
+
"status": "pending",
|
|
111
|
+
"dependencies": ["T003", "T006"],
|
|
112
|
+
"files": [
|
|
113
|
+
"Tests/Integration/ReportGenerationTests.cs"
|
|
114
|
+
],
|
|
115
|
+
"checkpoint": "CHECKPOINT_003"
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"progress": {
|
|
119
|
+
"total": 9,
|
|
120
|
+
"completed": 3,
|
|
121
|
+
"inProgress": 1,
|
|
122
|
+
"pending": 5,
|
|
123
|
+
"percentage": 33
|
|
124
|
+
},
|
|
125
|
+
"checkpoints": [
|
|
126
|
+
{
|
|
127
|
+
"id": "CHECKPOINT_001",
|
|
128
|
+
"timestamp": "2024-01-15T10:30:00Z",
|
|
129
|
+
"tasksCompleted": ["T001"],
|
|
130
|
+
"note": "Checkpoint: Create ScheduledReport entity"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"id": "CHECKPOINT_002",
|
|
134
|
+
"timestamp": "2024-01-15T12:00:00Z",
|
|
135
|
+
"tasksCompleted": ["T003"],
|
|
136
|
+
"note": "Checkpoint: Create Hangfire job for report generation"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": "CHECKPOINT_AUTO_1705326000000",
|
|
140
|
+
"timestamp": "2024-01-15T12:00:00Z",
|
|
141
|
+
"tasksCompleted": ["T001", "T002", "T003"],
|
|
142
|
+
"note": "Auto-checkpoint: 3 tasks completed"
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"outputs": {
|
|
146
|
+
"proposal": {
|
|
147
|
+
"created": true,
|
|
148
|
+
"path": ".morph/project/outputs/scheduled-reports/proposal.md"
|
|
149
|
+
},
|
|
150
|
+
"spec": {
|
|
151
|
+
"created": true,
|
|
152
|
+
"path": ".morph/project/outputs/scheduled-reports/spec.md"
|
|
153
|
+
},
|
|
154
|
+
"contracts": {
|
|
155
|
+
"created": true,
|
|
156
|
+
"path": ".morph/project/outputs/scheduled-reports/contracts.cs"
|
|
157
|
+
},
|
|
158
|
+
"ui-spec": {
|
|
159
|
+
"created": true,
|
|
160
|
+
"path": ".morph/project/outputs/scheduled-reports/ui-spec.md"
|
|
161
|
+
},
|
|
162
|
+
"tasks": {
|
|
163
|
+
"created": true,
|
|
164
|
+
"note": "Tasks are now inline in state.json (schema 3.0.0)"
|
|
165
|
+
},
|
|
166
|
+
"decisions": {
|
|
167
|
+
"created": true,
|
|
168
|
+
"path": ".morph/project/outputs/scheduled-reports/decisions.md"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"costs": {
|
|
172
|
+
"estimated": 5.50,
|
|
173
|
+
"approved": true,
|
|
174
|
+
"breakdown": {
|
|
175
|
+
"hangfire": 0,
|
|
176
|
+
"storage": 0.02,
|
|
177
|
+
"sql": 4.99,
|
|
178
|
+
"containerApp": 0.49
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"metadata": {
|
|
184
|
+
"totalFeatures": 1,
|
|
185
|
+
"completedFeatures": 0,
|
|
186
|
+
"totalCostEstimated": 5.50
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -50,6 +50,7 @@ export async function detectStructure(projectPath) {
|
|
|
50
50
|
* Detect stack type
|
|
51
51
|
*/
|
|
52
52
|
async function detectStack(projectPath) {
|
|
53
|
+
// Order matters: more specific patterns first
|
|
53
54
|
const patterns = {
|
|
54
55
|
blazor: [
|
|
55
56
|
'**/*.razor',
|
|
@@ -57,19 +58,47 @@ async function detectStack(projectPath) {
|
|
|
57
58
|
'**/Components/**/*.razor'
|
|
58
59
|
],
|
|
59
60
|
nextjs: [
|
|
60
|
-
'pages/**/*.tsx',
|
|
61
|
-
'app/**/*.tsx',
|
|
62
61
|
'next.config.js',
|
|
63
|
-
'next.config.mjs'
|
|
62
|
+
'next.config.mjs',
|
|
63
|
+
'next.config.ts',
|
|
64
|
+
'pages/**/*.tsx',
|
|
65
|
+
'app/**/*.tsx'
|
|
64
66
|
],
|
|
65
67
|
shopify: [
|
|
66
68
|
'**/*.liquid',
|
|
67
69
|
'sections/**/*.liquid',
|
|
68
70
|
'templates/**/*.liquid'
|
|
69
71
|
],
|
|
72
|
+
react: [
|
|
73
|
+
'src/App.jsx',
|
|
74
|
+
'src/App.tsx',
|
|
75
|
+
'vite.config.js',
|
|
76
|
+
'craco.config.js'
|
|
77
|
+
],
|
|
78
|
+
vue: [
|
|
79
|
+
'vite.config.js', // Vue 3 + Vite
|
|
80
|
+
'vue.config.js', // Vue 2
|
|
81
|
+
'src/App.vue'
|
|
82
|
+
],
|
|
70
83
|
dotnet: [
|
|
71
84
|
'**/*.csproj',
|
|
72
85
|
'**/Program.cs'
|
|
86
|
+
],
|
|
87
|
+
typescript: [
|
|
88
|
+
'tsconfig.json',
|
|
89
|
+
'src/**/*.ts'
|
|
90
|
+
],
|
|
91
|
+
nodejs: [
|
|
92
|
+
'package.json' // Fallback: generic Node.js
|
|
93
|
+
],
|
|
94
|
+
python: [
|
|
95
|
+
'requirements.txt',
|
|
96
|
+
'pyproject.toml',
|
|
97
|
+
'setup.py'
|
|
98
|
+
],
|
|
99
|
+
go: [
|
|
100
|
+
'go.mod',
|
|
101
|
+
'main.go'
|
|
73
102
|
]
|
|
74
103
|
};
|
|
75
104
|
|
package/package.json
CHANGED