@polymorphism-tech/morph-spec 2.2.0 → 2.4.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 +314 -1673
- package/LICENSE +72 -72
- package/README.md +515 -516
- package/bin/detect-agents.js +225 -225
- package/bin/morph-spec.js +358 -173
- package/bin/render-template.js +302 -302
- package/bin/semantic-detect-agents.js +246 -246
- package/bin/task-manager.js +429 -0
- package/bin/validate-agents-skills.js +251 -251
- package/bin/validate-agents.js +69 -69
- package/bin/validate-phase.js +263 -263
- package/bin/validate.js +369 -0
- package/content/.azure/README.md +293 -293
- package/content/.azure/docs/azure-devops-setup.md +454 -454
- package/content/.azure/docs/branch-strategy.md +398 -398
- package/content/.azure/docs/local-development.md +515 -515
- package/content/.azure/pipelines/pipeline-variables.yml +34 -34
- package/content/.azure/pipelines/prod-pipeline.yml +319 -319
- package/content/.azure/pipelines/staging-pipeline.yml +234 -234
- package/content/.azure/pipelines/templates/build-dotnet.yml +75 -75
- package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -94
- package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -120
- package/content/.azure/pipelines/templates/infra-deploy.yml +90 -90
- package/content/.claude/commands/morph-apply.md +221 -158
- package/content/.claude/commands/morph-archive.md +79 -79
- package/content/.claude/commands/morph-infra.md +209 -209
- package/content/.claude/commands/morph-preflight.md +227 -0
- package/content/.claude/commands/morph-proposal.md +122 -101
- package/content/.claude/commands/morph-status.md +86 -86
- package/content/.claude/commands/morph-troubleshoot.md +122 -0
- package/content/.claude/settings.local.json +15 -15
- package/content/.claude/skills/checklists/code-review.md +226 -0
- package/content/.claude/skills/checklists/morph-checklist.md +117 -0
- package/content/.claude/skills/checklists/simulation-checklist.md +77 -0
- package/content/.claude/skills/infra/bicep-architect.md +126 -419
- package/content/.claude/skills/infra/container-specialist.md +131 -437
- package/content/.claude/skills/infra/devops-engineer.md +119 -405
- package/content/.claude/skills/integrations/asaas-financial.md +130 -333
- package/content/.claude/skills/integrations/azure-identity.md +142 -309
- package/content/.claude/skills/integrations/clerk-auth.md +108 -290
- package/content/.claude/skills/integrations/resend-email.md +119 -0
- package/content/.claude/skills/specialists/ai-system-architect.md +192 -604
- package/content/.claude/skills/specialists/azure-architect.md +142 -142
- package/content/.claude/skills/specialists/code-analyzer.md +235 -0
- package/content/.claude/skills/specialists/dotnet-senior.md +287 -0
- package/content/.claude/skills/specialists/ef-modeler.md +113 -200
- package/content/.claude/skills/specialists/hangfire-orchestrator.md +126 -245
- package/content/.claude/skills/specialists/ms-agent-expert.md +109 -263
- package/content/.claude/skills/specialists/po-pm-advisor.md +197 -197
- package/content/.claude/skills/specialists/standards-architect.md +156 -78
- package/content/.claude/skills/specialists/testing-specialist.md +126 -0
- package/content/.claude/skills/specialists/ui-ux-designer.md +191 -1060
- package/content/.claude/skills/stacks/dotnet-blazor.md +210 -588
- package/content/.claude/skills/stacks/dotnet-nextjs.md +154 -402
- package/content/.claude/skills/workflows/morph-replicate.md +213 -0
- package/content/.claude/{commands/morph-clarify.md → skills/workflows/phase-clarify.md} +5 -58
- package/content/.claude/{commands/morph-design.md → skills/workflows/phase-design.md} +16 -86
- package/content/.claude/{commands/morph-setup.md → skills/workflows/phase-setup.md} +9 -17
- package/content/.claude/skills/workflows/phase-tasks.md +164 -0
- package/content/.claude/{commands/morph-uiux.md → skills/workflows/phase-uiux.md} +15 -88
- package/content/.morph/.morphversion +5 -5
- package/content/.morph/archive/.gitkeep +25 -25
- package/content/.morph/config/agents.json +378 -242
- package/content/.morph/config/config.template.json +89 -108
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
- package/content/.morph/docs/workflows/design-impl.md +37 -0
- package/content/.morph/docs/workflows/fast-track.md +29 -0
- package/content/.morph/docs/workflows/full-morph.md +76 -0
- package/content/.morph/docs/workflows/standard.md +44 -0
- package/content/.morph/docs/workflows/ui-refresh.md +39 -0
- package/content/.morph/examples/api-nextjs/README.md +241 -241
- package/content/.morph/examples/api-nextjs/contracts.ts +307 -307
- package/content/.morph/examples/api-nextjs/spec.md +399 -399
- package/content/.morph/examples/api-nextjs/tasks.md +168 -168
- package/content/.morph/examples/micro-saas/README.md +125 -125
- package/content/.morph/examples/micro-saas/contracts.cs +358 -358
- package/content/.morph/examples/micro-saas/decisions.md +246 -246
- package/content/.morph/examples/micro-saas/spec.md +236 -236
- package/content/.morph/examples/micro-saas/tasks.md +150 -150
- package/content/.morph/examples/multi-agent/README.md +309 -309
- package/content/.morph/examples/multi-agent/contracts.cs +433 -433
- package/content/.morph/examples/multi-agent/spec.md +479 -479
- package/content/.morph/examples/multi-agent/tasks.md +185 -185
- package/content/.morph/examples/scheduled-reports/decisions.md +158 -0
- package/content/.morph/examples/scheduled-reports/proposal.md +95 -0
- package/content/.morph/examples/scheduled-reports/spec.md +267 -0
- package/content/.morph/examples/state-v3.json +188 -0
- package/content/.morph/features/.gitkeep +25 -25
- package/content/.morph/hooks/README.md +190 -239
- package/content/.morph/hooks/pre-commit-agents.sh +24 -24
- package/content/.morph/hooks/pre-commit-all.sh +48 -48
- package/content/.morph/hooks/pre-commit-specs.sh +49 -49
- package/content/.morph/hooks/pre-commit-tests.sh +60 -60
- package/content/.morph/project.md +160 -160
- package/content/.morph/schemas/agent.schema.json +296 -296
- package/content/.morph/schemas/tasks.schema.json +220 -0
- package/content/.morph/specs/.gitkeep +20 -20
- package/content/.morph/standards/agent-framework-blazor-ui.md +359 -0
- package/content/.morph/standards/agent-framework-production.md +410 -0
- package/content/.morph/standards/agent-framework-setup.md +413 -453
- package/content/.morph/standards/agent-framework-workflows.md +349 -0
- package/content/.morph/standards/architecture.md +325 -325
- package/content/.morph/standards/azure.md +605 -379
- package/content/.morph/standards/coding.md +377 -377
- package/content/.morph/standards/dotnet10-migration.md +520 -494
- package/content/.morph/standards/fluent-ui-setup.md +590 -590
- package/content/.morph/standards/migration-guide.md +514 -514
- package/content/.morph/standards/passkeys-auth.md +423 -423
- package/content/.morph/standards/vector-search-rag.md +536 -536
- package/content/.morph/state.json +17 -17
- package/content/.morph/templates/FluentDesignTheme.cs +149 -149
- package/content/.morph/templates/MudTheme.cs +281 -281
- package/content/.morph/templates/agent.cs +163 -172
- package/content/.morph/templates/clarify-questions.md +159 -0
- package/content/.morph/templates/component.razor +239 -239
- package/content/.morph/templates/contracts/Commands.cs +74 -0
- package/content/.morph/templates/contracts/Entities.cs +25 -0
- package/content/.morph/templates/contracts/Queries.cs +74 -0
- package/content/.morph/templates/contracts/README.md +74 -0
- package/content/.morph/templates/contracts.cs +217 -217
- package/content/.morph/templates/decisions.md +123 -106
- package/content/.morph/templates/design-system.css +226 -226
- package/content/.morph/templates/infra/.dockerignore.example +89 -89
- package/content/.morph/templates/infra/Dockerfile.example +82 -82
- package/content/.morph/templates/infra/README.md +286 -286
- package/content/.morph/templates/infra/app-insights.bicep +63 -63
- package/content/.morph/templates/infra/app-service.bicep +164 -164
- package/content/.morph/templates/infra/container-app-env.bicep +49 -49
- package/content/.morph/templates/infra/container-app.bicep +156 -156
- package/content/.morph/templates/infra/deploy-checklist.md +426 -0
- package/content/.morph/templates/infra/deploy.ps1 +229 -229
- package/content/.morph/templates/infra/deploy.sh +208 -208
- package/content/.morph/templates/infra/key-vault.bicep +91 -91
- package/content/.morph/templates/infra/main.bicep +189 -189
- package/content/.morph/templates/infra/parameters.dev.json +29 -29
- package/content/.morph/templates/infra/parameters.prod.json +29 -29
- package/content/.morph/templates/infra/parameters.staging.json +29 -29
- package/content/.morph/templates/infra/sql-database.bicep +103 -103
- package/content/.morph/templates/infra/storage.bicep +106 -106
- package/content/.morph/templates/integrations/asaas-client.cs +387 -387
- package/content/.morph/templates/integrations/asaas-webhook.cs +351 -351
- package/content/.morph/templates/integrations/azure-identity-config.cs +288 -288
- package/content/.morph/templates/integrations/clerk-config.cs +258 -258
- package/content/.morph/templates/job.cs +171 -171
- package/content/.morph/templates/migration.cs +83 -83
- package/content/.morph/templates/proposal.md +141 -155
- package/content/.morph/templates/recap.md +94 -105
- package/content/.morph/templates/repository.cs +141 -141
- package/content/.morph/templates/saas/subscription.cs +347 -347
- package/content/.morph/templates/saas/tenant.cs +338 -338
- package/content/.morph/templates/service.cs +139 -139
- package/content/.morph/templates/simulation.md +353 -0
- package/content/.morph/templates/spec.md +149 -148
- package/content/.morph/templates/sprint-status.yaml +68 -68
- package/content/.morph/templates/state.template.json +222 -222
- package/content/.morph/templates/story.md +143 -143
- package/content/.morph/templates/tasks.md +257 -235
- package/content/.morph/templates/test.cs +239 -239
- package/content/.morph/templates/ui-components.md +362 -276
- package/content/.morph/templates/ui-design-system.md +286 -286
- package/content/.morph/templates/ui-flows.md +336 -336
- package/content/.morph/templates/ui-mockups.md +133 -133
- package/content/.morph/test-infra/example.bicep +59 -59
- package/content/CLAUDE.md +150 -442
- package/content/README.md +79 -79
- package/detectors/config-detector.js +223 -223
- package/detectors/conversation-analyzer.js +163 -163
- package/detectors/index.js +84 -84
- package/detectors/standards-generator.js +275 -275
- package/detectors/structure-detector.js +245 -250
- package/docs/README.md +144 -149
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
- package/docs/api/scripts/collapse.js +38 -38
- package/docs/api/scripts/commonNav.js +28 -28
- package/docs/api/scripts/linenumber.js +25 -25
- package/docs/api/scripts/nav.js +12 -12
- package/docs/api/scripts/polyfill.js +3 -3
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
- package/docs/api/scripts/prettify/lang-css.js +2 -2
- package/docs/api/scripts/prettify/prettify.js +28 -28
- package/docs/api/scripts/search.js +98 -98
- package/docs/api/styles/jsdoc.css +776 -776
- package/docs/api/styles/prettify.css +80 -80
- package/docs/examples.md +328 -328
- package/docs/getting-started.md +301 -302
- package/docs/installation.md +361 -361
- package/docs/templates.md +418 -418
- package/docs/validation-checklist.md +265 -266
- package/package.json +80 -80
- package/scripts/postinstall.js +132 -132
- package/src/commands/advance-phase.js +183 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -0
- package/src/commands/create-story.js +351 -351
- package/src/commands/detect-agents.js +139 -0
- package/src/commands/detect.js +104 -104
- package/src/commands/doctor.js +356 -280
- package/src/commands/generate.js +149 -149
- package/src/commands/init.js +258 -245
- package/src/commands/lint-fluent.js +352 -0
- package/src/commands/rollback-phase.js +185 -0
- package/src/commands/session-summary.js +291 -0
- package/src/commands/shard-spec.js +224 -224
- package/src/commands/sprint-status.js +250 -250
- package/src/commands/state.js +333 -333
- package/src/commands/sync.js +167 -167
- package/src/commands/task.js +78 -0
- package/src/commands/troubleshoot.js +222 -0
- package/src/commands/update.js +192 -159
- package/src/commands/validate-blazor-state.js +210 -0
- package/src/commands/validate-blazor.js +156 -0
- package/src/commands/validate-css.js +84 -0
- package/src/commands/validate-phase.js +221 -0
- package/src/lib/blazor-concurrency-analyzer.js +288 -0
- package/src/lib/blazor-state-validator.js +291 -0
- package/src/lib/blazor-validator.js +374 -0
- package/src/lib/complexity-analyzer.js +441 -292
- package/src/lib/continuous-validator.js +421 -0
- package/src/lib/css-validator.js +352 -0
- package/src/lib/decision-constraint-loader.js +109 -0
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/learning-system.js +520 -0
- package/src/lib/mockup-generator.js +366 -0
- package/src/lib/recap-generator.js +205 -0
- package/src/lib/state-manager.js +397 -340
- package/src/lib/troubleshoot-grep.js +194 -0
- package/src/lib/troubleshoot-index.js +144 -0
- package/src/lib/ui-detector.js +350 -0
- package/src/lib/validation-runner.js +231 -0
- package/src/lib/validators/architecture-validator.js +387 -0
- package/src/lib/validators/contract-compliance-validator.js +273 -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 +179 -139
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- package/content/.claude/commands/morph-costs.md +0 -206
- package/content/.claude/commands/morph-tasks.md +0 -319
- package/content/.claude/skills/specialists/cost-guardian.md +0 -110
- package/content/.claude/skills/stacks/shopify.md +0 -445
- package/content/.morph/config/azure-pricing.json +0 -70
- package/content/.morph/config/azure-pricing.schema.json +0 -50
- package/content/.morph/hooks/pre-commit-costs.sh +0 -91
- package/docs/api/cost-calculator.js.html +0 -513
- package/docs/api/design-system-generator.js.html +0 -382
- package/docs/api/global.html +0 -5263
- package/docs/api/index.html +0 -96
- package/docs/api/state-manager.js.html +0 -423
- package/src/commands/cost.js +0 -181
- package/src/commands/update-pricing.js +0 -206
- package/src/lib/cost-calculator.js +0 -429
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validate-blazor command
|
|
3
|
+
*
|
|
4
|
+
* Validates Fluent UI Blazor patterns and icons in Razor files.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* morph-spec validate-blazor [path]
|
|
8
|
+
* morph-spec validate-blazor src/Components --verbose
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { glob } from 'glob';
|
|
12
|
+
import { readFileSync, existsSync, statSync } from 'fs';
|
|
13
|
+
import { join, resolve } from 'path';
|
|
14
|
+
import chalk from 'chalk';
|
|
15
|
+
import ora from 'ora';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
validateBlazorFile,
|
|
19
|
+
formatIssues,
|
|
20
|
+
countIssues,
|
|
21
|
+
} from '../lib/blazor-validator.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Main command handler for validate-blazor.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} [targetPath] - Path to validate (file or directory)
|
|
27
|
+
* @param {Object} options - Command options
|
|
28
|
+
* @param {boolean} [options.verbose] - Show detailed output
|
|
29
|
+
* @param {boolean} [options.fix] - Auto-fix issues where possible
|
|
30
|
+
*/
|
|
31
|
+
export async function validateBlazorCommand(targetPath, options = {}) {
|
|
32
|
+
const { verbose = false } = options;
|
|
33
|
+
|
|
34
|
+
console.log('');
|
|
35
|
+
console.log(
|
|
36
|
+
chalk.cyan('\uD83D\uDD0D Validating Fluent UI Blazor patterns...')
|
|
37
|
+
);
|
|
38
|
+
console.log('');
|
|
39
|
+
|
|
40
|
+
// Determine target path
|
|
41
|
+
const basePath = targetPath ? resolve(targetPath) : process.cwd();
|
|
42
|
+
|
|
43
|
+
if (!existsSync(basePath)) {
|
|
44
|
+
console.log(chalk.red(`\u274C Path not found: ${basePath}`));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const spinner = ora('Scanning for Razor files...').start();
|
|
49
|
+
|
|
50
|
+
let files = [];
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const stats = statSync(basePath);
|
|
54
|
+
|
|
55
|
+
if (stats.isFile()) {
|
|
56
|
+
// Single file
|
|
57
|
+
if (
|
|
58
|
+
basePath.endsWith('.razor') ||
|
|
59
|
+
basePath.endsWith('.razor.cs') ||
|
|
60
|
+
basePath.endsWith('.cs')
|
|
61
|
+
) {
|
|
62
|
+
files = [basePath];
|
|
63
|
+
} else {
|
|
64
|
+
spinner.fail('File must be .razor or .cs');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
// Directory - find all Razor files
|
|
69
|
+
const pattern = join(basePath, '**/*.{razor,razor.cs}');
|
|
70
|
+
files = await glob(pattern, {
|
|
71
|
+
ignore: ['**/node_modules/**', '**/bin/**', '**/obj/**'],
|
|
72
|
+
windowsPathsNoEscape: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
spinner.succeed(`Found ${files.length} Razor file(s)`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
spinner.fail(`Error scanning files: ${error.message}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (files.length === 0) {
|
|
83
|
+
console.log(chalk.yellow('\n\u26A0\uFE0F No Razor files found to validate'));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Validate each file
|
|
88
|
+
const allIssues = [];
|
|
89
|
+
const fileResults = [];
|
|
90
|
+
|
|
91
|
+
for (const file of files) {
|
|
92
|
+
try {
|
|
93
|
+
const content = readFileSync(file, 'utf-8');
|
|
94
|
+
const issues = validateBlazorFile(content, file);
|
|
95
|
+
|
|
96
|
+
if (issues.length > 0) {
|
|
97
|
+
allIssues.push(...issues);
|
|
98
|
+
fileResults.push({ file, issues });
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.log(chalk.red(`\u274C Error reading ${file}: ${error.message}`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Output results
|
|
106
|
+
console.log('');
|
|
107
|
+
|
|
108
|
+
if (allIssues.length === 0) {
|
|
109
|
+
console.log(
|
|
110
|
+
chalk.green('\u2705 No issues found! All patterns look correct.')
|
|
111
|
+
);
|
|
112
|
+
console.log('');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Group and display issues
|
|
117
|
+
if (verbose) {
|
|
118
|
+
// Verbose: show all issues with details
|
|
119
|
+
fileResults.forEach(({ file, issues }) => {
|
|
120
|
+
console.log(chalk.white.bold(`\n${file}`));
|
|
121
|
+
console.log(chalk.gray('-'.repeat(60)));
|
|
122
|
+
console.log(formatIssues(issues));
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
// Compact: just list issues
|
|
126
|
+
allIssues.forEach((issue) => {
|
|
127
|
+
const icon = issue.type === 'error' ? '\u274C' : '\u26A0\uFE0F';
|
|
128
|
+
const location = issue.line ? `${issue.file}:${issue.line}` : issue.file;
|
|
129
|
+
|
|
130
|
+
console.log(`${icon} ${issue.message}`);
|
|
131
|
+
if (issue.suggestion) {
|
|
132
|
+
console.log(chalk.gray(` \u2192 ${issue.suggestion}`));
|
|
133
|
+
}
|
|
134
|
+
console.log(chalk.dim(` ${location}`));
|
|
135
|
+
console.log('');
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Summary
|
|
140
|
+
const { errors, warnings } = countIssues(allIssues);
|
|
141
|
+
const summaryColor = errors > 0 ? chalk.red : chalk.yellow;
|
|
142
|
+
|
|
143
|
+
console.log(chalk.gray('-'.repeat(60)));
|
|
144
|
+
console.log(
|
|
145
|
+
summaryColor(
|
|
146
|
+
`\n${files.length} arquivo(s) validado(s) | ${errors} erro(s) | ${warnings} warning(s)\n`
|
|
147
|
+
)
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// Exit with error code if there are errors
|
|
151
|
+
if (errors > 0) {
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export default validateBlazorCommand;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MORPH-SPEC validate-css Command
|
|
3
|
+
*
|
|
4
|
+
* Validates that all CSS classes used in Razor files are defined in CSS files.
|
|
5
|
+
* Helps catch missing CSS definitions before runtime.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* morph-spec validate-css [path]
|
|
9
|
+
* morph-spec validate-css src/MyApp.Web
|
|
10
|
+
* morph-spec validate-css --verbose
|
|
11
|
+
* morph-spec validate-css --generate-stub
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import chalk from 'chalk';
|
|
15
|
+
import { existsSync, writeFileSync } from 'fs';
|
|
16
|
+
import { resolve, join } from 'path';
|
|
17
|
+
import {
|
|
18
|
+
validateCssClasses,
|
|
19
|
+
formatValidationResults,
|
|
20
|
+
generateCssStub
|
|
21
|
+
} from '../lib/css-validator.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Execute the validate-css command
|
|
25
|
+
* @param {string} path - Project path to validate
|
|
26
|
+
* @param {Object} options - Command options
|
|
27
|
+
*/
|
|
28
|
+
export async function validateCssCommand(path, options = {}) {
|
|
29
|
+
const projectPath = resolve(path || '.');
|
|
30
|
+
const { verbose, generateStub, includeUtilities } = options;
|
|
31
|
+
|
|
32
|
+
// Validate path exists
|
|
33
|
+
if (!existsSync(projectPath)) {
|
|
34
|
+
console.error(chalk.red(`\n Error: Path does not exist: ${projectPath}\n`));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(chalk.cyan('\n Validating CSS classes...\n'));
|
|
39
|
+
console.log(chalk.gray(` Path: ${projectPath}`));
|
|
40
|
+
console.log('');
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
// Run validation
|
|
44
|
+
const results = await validateCssClasses(projectPath, {
|
|
45
|
+
verbose,
|
|
46
|
+
includeUtilities
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Output results
|
|
50
|
+
const formatted = formatValidationResults(results, verbose);
|
|
51
|
+
console.log(formatted);
|
|
52
|
+
|
|
53
|
+
// Generate stub if requested
|
|
54
|
+
if (generateStub && !results.valid) {
|
|
55
|
+
const stubContent = generateCssStub(results);
|
|
56
|
+
const stubPath = join(projectPath, 'missing-classes.css');
|
|
57
|
+
|
|
58
|
+
writeFileSync(stubPath, stubContent, 'utf8');
|
|
59
|
+
console.log(chalk.green(`\n Generated stub file: ${stubPath}\n`));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Summary with colors
|
|
63
|
+
if (results.valid) {
|
|
64
|
+
console.log(chalk.green('\n All CSS classes are properly defined!\n'));
|
|
65
|
+
process.exit(0);
|
|
66
|
+
} else {
|
|
67
|
+
console.log(chalk.yellow(`\n Found ${results.missingClasses.length} missing CSS class(es)\n`));
|
|
68
|
+
|
|
69
|
+
// Suggestions
|
|
70
|
+
console.log(chalk.cyan('Suggestions:'));
|
|
71
|
+
console.log(chalk.gray(' 1. Add the missing classes to your design-system.css'));
|
|
72
|
+
console.log(chalk.gray(' 2. Run with --generate-stub to create a template file'));
|
|
73
|
+
console.log(chalk.gray(' 3. If using utility frameworks (Tailwind), add --include-utilities\n'));
|
|
74
|
+
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error(chalk.red(`\n Error: ${error.message}\n`));
|
|
79
|
+
if (verbose) {
|
|
80
|
+
console.error(error.stack);
|
|
81
|
+
}
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MORPH-SPEC Phase Validator Command
|
|
3
|
+
*
|
|
4
|
+
* Validates that required previous phases have been completed before advancing.
|
|
5
|
+
* Prevents skipping phases accidentally.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* morph-spec validate-phase <feature-name> <target-phase>
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
* morph-spec validate-phase scheduled-reports implement
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'fs';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import chalk from 'chalk';
|
|
17
|
+
import { loadState, getFeature } from '../lib/state-manager.js';
|
|
18
|
+
|
|
19
|
+
// Phase definitions with requirements
|
|
20
|
+
const PHASES = {
|
|
21
|
+
'proposal': {
|
|
22
|
+
order: 0,
|
|
23
|
+
name: 'FASE 0: PROPOSAL',
|
|
24
|
+
requiredOutputs: [],
|
|
25
|
+
description: 'Initial proposal and agent detection'
|
|
26
|
+
},
|
|
27
|
+
'setup': {
|
|
28
|
+
order: 1,
|
|
29
|
+
name: 'FASE 1: SETUP',
|
|
30
|
+
requiredOutputs: ['proposal.md'],
|
|
31
|
+
description: 'Load context and standards'
|
|
32
|
+
},
|
|
33
|
+
'uiux': {
|
|
34
|
+
order: 2,
|
|
35
|
+
name: 'FASE 1.5: UI/UX DESIGN',
|
|
36
|
+
requiredOutputs: ['proposal.md'],
|
|
37
|
+
optionalOutputs: ['ui-design-system.md', 'ui-mockups.md', 'ui-components.md', 'ui-flows.md'],
|
|
38
|
+
description: 'UI/UX design (conditional - only if frontend)',
|
|
39
|
+
optional: true
|
|
40
|
+
},
|
|
41
|
+
'design': {
|
|
42
|
+
order: 3,
|
|
43
|
+
name: 'FASE 2: DESIGN',
|
|
44
|
+
requiredOutputs: ['proposal.md'],
|
|
45
|
+
description: 'Technical specification and contracts'
|
|
46
|
+
},
|
|
47
|
+
'clarify': {
|
|
48
|
+
order: 4,
|
|
49
|
+
name: 'FASE 3: CLARIFY',
|
|
50
|
+
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
51
|
+
description: 'Clarify ambiguities and edge cases'
|
|
52
|
+
},
|
|
53
|
+
'tasks': {
|
|
54
|
+
order: 5,
|
|
55
|
+
name: 'FASE 4: TASKS',
|
|
56
|
+
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
57
|
+
description: 'Break down into executable tasks'
|
|
58
|
+
},
|
|
59
|
+
'implement': {
|
|
60
|
+
order: 6,
|
|
61
|
+
name: 'FASE 5: IMPLEMENT',
|
|
62
|
+
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
63
|
+
description: 'Execute tasks and implement code'
|
|
64
|
+
},
|
|
65
|
+
'sync': {
|
|
66
|
+
order: 7,
|
|
67
|
+
name: 'FASE 6: SYNC',
|
|
68
|
+
requiredOutputs: ['proposal.md', 'spec.md', 'decisions.md'],
|
|
69
|
+
description: 'Sync decisions to project standards',
|
|
70
|
+
optional: true
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if output file exists
|
|
76
|
+
*/
|
|
77
|
+
function checkOutput(featurePath, outputFile) {
|
|
78
|
+
const filePath = path.join(featurePath, outputFile);
|
|
79
|
+
return fs.existsSync(filePath);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Validate phase requirements
|
|
84
|
+
*/
|
|
85
|
+
function validatePhase(featureName, targetPhase) {
|
|
86
|
+
const featurePath = path.join(process.cwd(), '.morph/project/outputs', featureName);
|
|
87
|
+
|
|
88
|
+
// Check if feature directory exists
|
|
89
|
+
if (!fs.existsSync(featurePath)) {
|
|
90
|
+
return {
|
|
91
|
+
valid: false,
|
|
92
|
+
error: `Feature directory not found: ${featurePath}`,
|
|
93
|
+
suggestion: `Run 'morph-spec state set ${featureName} phase proposal' to start`,
|
|
94
|
+
missingOutputs: [],
|
|
95
|
+
phase: null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Get target phase definition
|
|
100
|
+
const phaseDefinition = PHASES[targetPhase];
|
|
101
|
+
if (!phaseDefinition) {
|
|
102
|
+
return {
|
|
103
|
+
valid: false,
|
|
104
|
+
error: `Unknown phase: ${targetPhase}`,
|
|
105
|
+
validPhases: Object.keys(PHASES),
|
|
106
|
+
missingOutputs: [],
|
|
107
|
+
phase: null
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Check required outputs
|
|
112
|
+
const missingOutputs = [];
|
|
113
|
+
for (const output of phaseDefinition.requiredOutputs) {
|
|
114
|
+
if (!checkOutput(featurePath, output)) {
|
|
115
|
+
missingOutputs.push(output);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check state.json for current phase
|
|
120
|
+
let stateWarning = null;
|
|
121
|
+
try {
|
|
122
|
+
const feature = getFeature(featureName);
|
|
123
|
+
if (feature) {
|
|
124
|
+
const currentPhaseOrder = PHASES[feature.phase]?.order ?? -1;
|
|
125
|
+
const targetPhaseOrder = phaseDefinition.order;
|
|
126
|
+
|
|
127
|
+
if (targetPhaseOrder > currentPhaseOrder + 1) {
|
|
128
|
+
stateWarning = `Skipping phases: current is '${feature.phase}' (order ${currentPhaseOrder}), target is '${targetPhase}' (order ${targetPhaseOrder})`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
// State file may not exist, that's OK
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Special validation: if target is 'implement', check tasks exist in state
|
|
136
|
+
if (targetPhase === 'implement') {
|
|
137
|
+
try {
|
|
138
|
+
const feature = getFeature(featureName);
|
|
139
|
+
if (feature && (!feature.tasks || feature.tasks.total === 0)) {
|
|
140
|
+
missingOutputs.push('tasks in state.json (run morph-spec task to add tasks)');
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
// State file may not exist
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
valid: missingOutputs.length === 0,
|
|
149
|
+
error: null,
|
|
150
|
+
missingOutputs,
|
|
151
|
+
phase: phaseDefinition,
|
|
152
|
+
featurePath,
|
|
153
|
+
stateWarning
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Main command handler
|
|
159
|
+
*/
|
|
160
|
+
export async function validatePhaseCommand(feature, phase, options = {}) {
|
|
161
|
+
console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
162
|
+
console.log(chalk.cyan('║ MORPH-SPEC PHASE VALIDATOR ║'));
|
|
163
|
+
console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
164
|
+
|
|
165
|
+
const result = validatePhase(feature, phase);
|
|
166
|
+
|
|
167
|
+
console.log(chalk.gray('Feature:'), feature);
|
|
168
|
+
console.log(chalk.gray('Target Phase:'), result.phase ? result.phase.name : phase);
|
|
169
|
+
|
|
170
|
+
if (result.phase) {
|
|
171
|
+
console.log(chalk.gray('Description:'), result.phase.description);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (result.stateWarning) {
|
|
175
|
+
console.log(chalk.yellow(`\n⚠️ Warning: ${result.stateWarning}`));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (result.valid) {
|
|
179
|
+
console.log(chalk.green('\n✓ VALIDATION PASSED'));
|
|
180
|
+
console.log(chalk.green(' All required outputs are present.'));
|
|
181
|
+
console.log(chalk.green(` Safe to proceed to ${result.phase.name}\n`));
|
|
182
|
+
|
|
183
|
+
if (options.verbose) {
|
|
184
|
+
console.log(chalk.gray('Required outputs found:'));
|
|
185
|
+
result.phase.requiredOutputs.forEach(output => {
|
|
186
|
+
console.log(chalk.gray(` ✓ ${output}`));
|
|
187
|
+
});
|
|
188
|
+
console.log('');
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
console.log(chalk.red('\n✗ VALIDATION FAILED'));
|
|
192
|
+
|
|
193
|
+
if (result.error) {
|
|
194
|
+
console.log(chalk.red(` Error: ${result.error}\n`));
|
|
195
|
+
|
|
196
|
+
if (result.suggestion) {
|
|
197
|
+
console.log(chalk.yellow(` Suggestion: ${result.suggestion}\n`));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (result.validPhases) {
|
|
201
|
+
console.log(chalk.yellow('Valid phases:'));
|
|
202
|
+
result.validPhases.forEach(p => {
|
|
203
|
+
const def = PHASES[p];
|
|
204
|
+
console.log(chalk.gray(` - ${p}: ${def.name}${def.optional ? ' (optional)' : ''}`));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
console.log(chalk.red(' Missing required outputs:'));
|
|
209
|
+
result.missingOutputs.forEach(output => {
|
|
210
|
+
console.log(chalk.gray(` - ${output}`));
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
console.log(chalk.yellow(`\n Action required:`));
|
|
214
|
+
console.log(chalk.yellow(` Complete the missing outputs before advancing to ${result.phase.name}`));
|
|
215
|
+
}
|
|
216
|
+
console.log('');
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export { PHASES, validatePhase };
|