@polymorphism-tech/morph-spec 2.4.0 → 3.0.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 +158 -26
- package/LICENSE +72 -72
- package/bin/detect-agents.js +225 -225
- package/bin/morph-spec.js +8 -0
- package/bin/render-template.js +302 -302
- package/bin/semantic-detect-agents.js +246 -246
- package/bin/validate-agents-skills.js +251 -251
- package/bin/validate-agents.js +69 -69
- package/bin/validate-phase.js +263 -263
- 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-archive.md +79 -79
- package/content/.claude/commands/morph-deploy.md +529 -0
- package/content/.claude/commands/morph-infra.md +209 -209
- package/content/.claude/commands/morph-preflight.md +227 -227
- package/content/.claude/commands/morph-troubleshoot.md +122 -122
- package/content/.claude/settings.local.json +15 -15
- package/content/.claude/skills/infra/azure-deploy-specialist.md +699 -0
- package/content/.claude/skills/level-0-meta/README.md +7 -0
- package/content/.claude/skills/{checklists → level-0-meta}/morph-checklist.md +117 -117
- package/content/.claude/skills/level-1-workflows/README.md +7 -0
- package/content/.claude/skills/{workflows → level-1-workflows}/morph-replicate.md +213 -213
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-clarify.md +131 -131
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-design.md +213 -205
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-setup.md +106 -92
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-tasks.md +164 -164
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-uiux.md +169 -138
- package/content/.claude/skills/level-2-domains/README.md +14 -0
- package/content/.claude/skills/{specialists → level-2-domains/quality}/testing-specialist.md +126 -126
- package/content/.claude/skills/level-3-technologies/README.md +7 -0
- package/content/.claude/skills/level-4-patterns/README.md +7 -0
- package/content/.claude/skills/specialists/prompt-engineer.md +189 -0
- package/content/.claude/skills/specialists/seo-growth-hacker.md +320 -0
- package/content/.morph/.morphversion +5 -5
- package/content/.morph/archive/.gitkeep +25 -25
- package/content/.morph/config/agents.json +742 -358
- package/content/.morph/config/config.template.json +33 -0
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
- package/content/.morph/docs/workflows/enforcement-pipeline.md +668 -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 -158
- package/content/.morph/examples/scheduled-reports/proposal.md +95 -95
- package/content/.morph/examples/scheduled-reports/spec.md +267 -267
- package/content/.morph/examples/state-v3.json +188 -188
- package/content/.morph/features/.gitkeep +25 -25
- package/content/.morph/hooks/README.md +158 -0
- 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/hooks/task-completed.js +73 -0
- package/content/.morph/hooks/teammate-idle.js +68 -0
- package/content/.morph/project.md +160 -160
- package/content/.morph/schemas/agent.schema.json +296 -296
- package/content/.morph/schemas/tasks.schema.json +220 -220
- package/content/.morph/specs/.gitkeep +20 -20
- package/content/.morph/standards/agent-teams-workflow.md +474 -0
- package/content/.morph/standards/coding.md +377 -377
- 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/CONTEXT-FEATURE.md +276 -0
- package/content/.morph/templates/CONTEXT.md +170 -0
- package/content/.morph/templates/FluentDesignTheme.cs +149 -149
- package/content/.morph/templates/MudTheme.cs +281 -281
- package/content/.morph/templates/clarify-questions.md +159 -159
- package/content/.morph/templates/component.razor +239 -239
- package/content/.morph/templates/contracts/Commands.cs +74 -74
- package/content/.morph/templates/contracts/Entities.cs +25 -25
- package/content/.morph/templates/contracts/Queries.cs +74 -74
- package/content/.morph/templates/contracts/README.md +74 -74
- package/content/.morph/templates/contracts.cs +217 -217
- 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/azure-pipelines-deploy.yml +480 -0
- 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 -426
- 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/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/sprint-status.yaml +68 -68
- package/content/.morph/templates/story.md +143 -143
- package/content/.morph/templates/test.cs +239 -239
- 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/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/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/templates.md +418 -418
- package/package.json +1 -1
- package/scripts/postinstall.js +132 -132
- package/src/commands/advance-phase.js +83 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -193
- package/src/commands/create-story.js +351 -351
- package/src/commands/deploy.js +780 -0
- package/src/commands/detect-agents.js +34 -6
- package/src/commands/detect.js +104 -104
- package/src/commands/generate-context.js +40 -0
- package/src/commands/generate.js +149 -149
- package/src/commands/lint-fluent.js +352 -352
- package/src/commands/rollback-phase.js +185 -185
- package/src/commands/session-summary.js +291 -291
- 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/troubleshoot.js +222 -222
- package/src/commands/validate-blazor-state.js +210 -210
- package/src/commands/validate-blazor.js +156 -156
- package/src/commands/validate-css.js +84 -84
- package/src/commands/validate-phase.js +221 -221
- package/src/lib/blazor-concurrency-analyzer.js +288 -288
- package/src/lib/blazor-state-validator.js +291 -291
- package/src/lib/blazor-validator.js +374 -374
- package/src/lib/context-generator.js +513 -0
- package/src/lib/css-validator.js +352 -352
- package/src/lib/design-system-detector.js +187 -0
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/design-system-scaffolder.js +299 -0
- package/src/lib/hook-executor.js +256 -0
- package/src/lib/learning-system.js +520 -520
- package/src/lib/mockup-generator.js +366 -366
- package/src/lib/spec-validator.js +258 -0
- package/src/lib/standards-context-injector.js +287 -0
- package/src/lib/team-orchestrator.js +322 -0
- package/src/lib/troubleshoot-grep.js +194 -194
- package/src/lib/troubleshoot-index.js +144 -144
- package/src/lib/ui-detector.js +350 -350
- package/src/lib/validation-runner.js +65 -13
- package/src/lib/validators/architecture-validator.js +387 -387
- package/src/lib/validators/design-system-validator.js +231 -0
- package/src/lib/validators/package-validator.js +360 -360
- package/src/lib/validators/ui-contrast-validator.js +422 -422
- package/src/utils/file-copier.js +9 -1
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- /package/content/.claude/skills/{checklists → level-0-meta}/code-review.md +0 -0
- /package/content/.claude/skills/{checklists → level-0-meta}/simulation-checklist.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/ai-agents}/ai-system-architect.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/architecture}/po-pm-advisor.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/architecture}/standards-architect.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/dotnet-senior.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/ef-modeler.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/hangfire-orchestrator.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/ms-agent-expert.md +0 -0
- /package/content/.claude/skills/{stacks/dotnet-blazor.md → level-2-domains/frontend/blazor-builder.md} +0 -0
- /package/content/.claude/skills/{stacks/dotnet-nextjs.md → level-2-domains/frontend/nextjs-expert.md} +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/frontend}/ui-ux-designer.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/infrastructure}/azure-architect.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/bicep-architect.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/container-specialist.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/devops-engineer.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/asaas-financial.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/azure-identity.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/clerk-auth.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/resend-email.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/quality}/code-analyzer.md +0 -0
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Conversation Analyzer - Analyzes Claude Code conversation history for user preferences
|
|
3
|
-
*
|
|
4
|
-
* Note: This is a basic implementation. Full conversation analysis would require
|
|
5
|
-
* access to Claude Code's message history API or local cache.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { existsSync, readFileSync } from 'fs';
|
|
9
|
-
import { join } from 'path';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Analyze conversation history
|
|
13
|
-
* @param {string} projectPath - Project root path
|
|
14
|
-
* @returns {Promise<Object>} Conversation analysis results
|
|
15
|
-
*/
|
|
16
|
-
export async function analyzeConversation(projectPath) {
|
|
17
|
-
const result = {
|
|
18
|
-
preferences: {},
|
|
19
|
-
decisions: [],
|
|
20
|
-
patterns: [],
|
|
21
|
-
available: false
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// Check if .morph/project/context exists (past decisions)
|
|
25
|
-
const contextPath = join(projectPath, '.morph', 'project', 'context');
|
|
26
|
-
if (existsSync(contextPath)) {
|
|
27
|
-
result.available = true;
|
|
28
|
-
|
|
29
|
-
// Read decisions-history.md if exists
|
|
30
|
-
const decisionsFile = join(contextPath, 'decisions-history.md');
|
|
31
|
-
if (existsSync(decisionsFile)) {
|
|
32
|
-
const content = readFileSync(decisionsFile, 'utf8');
|
|
33
|
-
result.decisions = extractDecisions(content);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Check .morph/project/outputs/*/decisions.md
|
|
38
|
-
const outputsPath = join(projectPath, '.morph', 'project', 'outputs');
|
|
39
|
-
if (existsSync(outputsPath)) {
|
|
40
|
-
const { readdirSync } = await import('fs');
|
|
41
|
-
const features = readdirSync(outputsPath, { withFileTypes: true })
|
|
42
|
-
.filter(dirent => dirent.isDirectory())
|
|
43
|
-
.map(dirent => dirent.name);
|
|
44
|
-
|
|
45
|
-
for (const feature of features) {
|
|
46
|
-
const decisionsFile = join(outputsPath, feature, 'decisions.md');
|
|
47
|
-
if (existsSync(decisionsFile)) {
|
|
48
|
-
const content = readFileSync(decisionsFile, 'utf8');
|
|
49
|
-
result.decisions.push(...extractDecisions(content));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Extract patterns from decisions
|
|
55
|
-
result.patterns = inferPatternsFromDecisions(result.decisions);
|
|
56
|
-
|
|
57
|
-
// Extract preferences
|
|
58
|
-
result.preferences = extractPreferences(result.decisions);
|
|
59
|
-
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Extract decisions from markdown
|
|
65
|
-
*/
|
|
66
|
-
function extractDecisions(markdown) {
|
|
67
|
-
const decisions = [];
|
|
68
|
-
const lines = markdown.split('\n');
|
|
69
|
-
|
|
70
|
-
let currentDecision = null;
|
|
71
|
-
|
|
72
|
-
for (const line of lines) {
|
|
73
|
-
// Look for decision headings
|
|
74
|
-
if (line.match(/^##\s+Decision/i) || line.match(/^###\s+ADR/i)) {
|
|
75
|
-
if (currentDecision) {
|
|
76
|
-
decisions.push(currentDecision);
|
|
77
|
-
}
|
|
78
|
-
currentDecision = { text: '', category: 'unknown', confidence: 0.5 };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (currentDecision) {
|
|
82
|
-
currentDecision.text += line + '\n';
|
|
83
|
-
|
|
84
|
-
// Categorize
|
|
85
|
-
if (line.includes('UI') || line.includes('component') || line.includes('Fluent') || line.includes('Mud')) {
|
|
86
|
-
currentDecision.category = 'ui-ux';
|
|
87
|
-
currentDecision.confidence = 0.8;
|
|
88
|
-
} else if (line.includes('pattern') || line.includes('architecture') || line.includes('CQRS')) {
|
|
89
|
-
currentDecision.category = 'architecture';
|
|
90
|
-
currentDecision.confidence = 0.8;
|
|
91
|
-
} else if (line.includes('Azure') || line.includes('Container') || line.includes('deployment')) {
|
|
92
|
-
currentDecision.category = 'azure';
|
|
93
|
-
currentDecision.confidence = 0.8;
|
|
94
|
-
} else if (line.includes('class') || line.includes('method') || line.includes('naming')) {
|
|
95
|
-
currentDecision.category = 'coding';
|
|
96
|
-
currentDecision.confidence = 0.8;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (currentDecision) {
|
|
102
|
-
decisions.push(currentDecision);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return decisions;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Infer patterns from decisions
|
|
110
|
-
*/
|
|
111
|
-
function inferPatternsFromDecisions(decisions) {
|
|
112
|
-
const patterns = [];
|
|
113
|
-
|
|
114
|
-
for (const decision of decisions) {
|
|
115
|
-
const text = decision.text.toLowerCase();
|
|
116
|
-
|
|
117
|
-
if (text.includes('always use') || text.includes('sempre usar')) {
|
|
118
|
-
patterns.push(`Pattern: ${decision.text.split('\n')[0].substring(0, 60)}...`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (text.includes('never') || text.includes('nunca')) {
|
|
122
|
-
patterns.push(`Anti-pattern: ${decision.text.split('\n')[0].substring(0, 60)}...`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return patterns;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Extract user preferences
|
|
131
|
-
*/
|
|
132
|
-
function extractPreferences(decisions) {
|
|
133
|
-
const preferences = {
|
|
134
|
-
uiLibrary: null,
|
|
135
|
-
architecture: null,
|
|
136
|
-
testing: null,
|
|
137
|
-
deployment: null
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
for (const decision of decisions) {
|
|
141
|
-
const text = decision.text.toLowerCase();
|
|
142
|
-
|
|
143
|
-
if (text.includes('fluent ui') && !text.includes('not')) {
|
|
144
|
-
preferences.uiLibrary = 'Fluent UI';
|
|
145
|
-
} else if (text.includes('mudblazor') && !text.includes('not')) {
|
|
146
|
-
preferences.uiLibrary = 'MudBlazor';
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (text.includes('clean architecture')) {
|
|
150
|
-
preferences.architecture = 'Clean Architecture';
|
|
151
|
-
} else if (text.includes('cqrs')) {
|
|
152
|
-
preferences.architecture = 'CQRS';
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (text.includes('container apps')) {
|
|
156
|
-
preferences.deployment = 'Azure Container Apps';
|
|
157
|
-
} else if (text.includes('app service')) {
|
|
158
|
-
preferences.deployment = 'Azure App Service';
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return preferences;
|
|
163
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Conversation Analyzer - Analyzes Claude Code conversation history for user preferences
|
|
3
|
+
*
|
|
4
|
+
* Note: This is a basic implementation. Full conversation analysis would require
|
|
5
|
+
* access to Claude Code's message history API or local cache.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, readFileSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Analyze conversation history
|
|
13
|
+
* @param {string} projectPath - Project root path
|
|
14
|
+
* @returns {Promise<Object>} Conversation analysis results
|
|
15
|
+
*/
|
|
16
|
+
export async function analyzeConversation(projectPath) {
|
|
17
|
+
const result = {
|
|
18
|
+
preferences: {},
|
|
19
|
+
decisions: [],
|
|
20
|
+
patterns: [],
|
|
21
|
+
available: false
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Check if .morph/project/context exists (past decisions)
|
|
25
|
+
const contextPath = join(projectPath, '.morph', 'project', 'context');
|
|
26
|
+
if (existsSync(contextPath)) {
|
|
27
|
+
result.available = true;
|
|
28
|
+
|
|
29
|
+
// Read decisions-history.md if exists
|
|
30
|
+
const decisionsFile = join(contextPath, 'decisions-history.md');
|
|
31
|
+
if (existsSync(decisionsFile)) {
|
|
32
|
+
const content = readFileSync(decisionsFile, 'utf8');
|
|
33
|
+
result.decisions = extractDecisions(content);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check .morph/project/outputs/*/decisions.md
|
|
38
|
+
const outputsPath = join(projectPath, '.morph', 'project', 'outputs');
|
|
39
|
+
if (existsSync(outputsPath)) {
|
|
40
|
+
const { readdirSync } = await import('fs');
|
|
41
|
+
const features = readdirSync(outputsPath, { withFileTypes: true })
|
|
42
|
+
.filter(dirent => dirent.isDirectory())
|
|
43
|
+
.map(dirent => dirent.name);
|
|
44
|
+
|
|
45
|
+
for (const feature of features) {
|
|
46
|
+
const decisionsFile = join(outputsPath, feature, 'decisions.md');
|
|
47
|
+
if (existsSync(decisionsFile)) {
|
|
48
|
+
const content = readFileSync(decisionsFile, 'utf8');
|
|
49
|
+
result.decisions.push(...extractDecisions(content));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Extract patterns from decisions
|
|
55
|
+
result.patterns = inferPatternsFromDecisions(result.decisions);
|
|
56
|
+
|
|
57
|
+
// Extract preferences
|
|
58
|
+
result.preferences = extractPreferences(result.decisions);
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Extract decisions from markdown
|
|
65
|
+
*/
|
|
66
|
+
function extractDecisions(markdown) {
|
|
67
|
+
const decisions = [];
|
|
68
|
+
const lines = markdown.split('\n');
|
|
69
|
+
|
|
70
|
+
let currentDecision = null;
|
|
71
|
+
|
|
72
|
+
for (const line of lines) {
|
|
73
|
+
// Look for decision headings
|
|
74
|
+
if (line.match(/^##\s+Decision/i) || line.match(/^###\s+ADR/i)) {
|
|
75
|
+
if (currentDecision) {
|
|
76
|
+
decisions.push(currentDecision);
|
|
77
|
+
}
|
|
78
|
+
currentDecision = { text: '', category: 'unknown', confidence: 0.5 };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (currentDecision) {
|
|
82
|
+
currentDecision.text += line + '\n';
|
|
83
|
+
|
|
84
|
+
// Categorize
|
|
85
|
+
if (line.includes('UI') || line.includes('component') || line.includes('Fluent') || line.includes('Mud')) {
|
|
86
|
+
currentDecision.category = 'ui-ux';
|
|
87
|
+
currentDecision.confidence = 0.8;
|
|
88
|
+
} else if (line.includes('pattern') || line.includes('architecture') || line.includes('CQRS')) {
|
|
89
|
+
currentDecision.category = 'architecture';
|
|
90
|
+
currentDecision.confidence = 0.8;
|
|
91
|
+
} else if (line.includes('Azure') || line.includes('Container') || line.includes('deployment')) {
|
|
92
|
+
currentDecision.category = 'azure';
|
|
93
|
+
currentDecision.confidence = 0.8;
|
|
94
|
+
} else if (line.includes('class') || line.includes('method') || line.includes('naming')) {
|
|
95
|
+
currentDecision.category = 'coding';
|
|
96
|
+
currentDecision.confidence = 0.8;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (currentDecision) {
|
|
102
|
+
decisions.push(currentDecision);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return decisions;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Infer patterns from decisions
|
|
110
|
+
*/
|
|
111
|
+
function inferPatternsFromDecisions(decisions) {
|
|
112
|
+
const patterns = [];
|
|
113
|
+
|
|
114
|
+
for (const decision of decisions) {
|
|
115
|
+
const text = decision.text.toLowerCase();
|
|
116
|
+
|
|
117
|
+
if (text.includes('always use') || text.includes('sempre usar')) {
|
|
118
|
+
patterns.push(`Pattern: ${decision.text.split('\n')[0].substring(0, 60)}...`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (text.includes('never') || text.includes('nunca')) {
|
|
122
|
+
patterns.push(`Anti-pattern: ${decision.text.split('\n')[0].substring(0, 60)}...`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return patterns;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Extract user preferences
|
|
131
|
+
*/
|
|
132
|
+
function extractPreferences(decisions) {
|
|
133
|
+
const preferences = {
|
|
134
|
+
uiLibrary: null,
|
|
135
|
+
architecture: null,
|
|
136
|
+
testing: null,
|
|
137
|
+
deployment: null
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
for (const decision of decisions) {
|
|
141
|
+
const text = decision.text.toLowerCase();
|
|
142
|
+
|
|
143
|
+
if (text.includes('fluent ui') && !text.includes('not')) {
|
|
144
|
+
preferences.uiLibrary = 'Fluent UI';
|
|
145
|
+
} else if (text.includes('mudblazor') && !text.includes('not')) {
|
|
146
|
+
preferences.uiLibrary = 'MudBlazor';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (text.includes('clean architecture')) {
|
|
150
|
+
preferences.architecture = 'Clean Architecture';
|
|
151
|
+
} else if (text.includes('cqrs')) {
|
|
152
|
+
preferences.architecture = 'CQRS';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (text.includes('container apps')) {
|
|
156
|
+
preferences.deployment = 'Azure Container Apps';
|
|
157
|
+
} else if (text.includes('app service')) {
|
|
158
|
+
preferences.deployment = 'Azure App Service';
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return preferences;
|
|
163
|
+
}
|
package/detectors/index.js
CHANGED
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MORPH-SPEC Detectors - Main Orchestrator
|
|
3
|
-
*
|
|
4
|
-
* Coordinates all detection modules to build a complete picture of the project.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { detectStructure } from './structure-detector.js';
|
|
8
|
-
import { detectConfig } from './config-detector.js';
|
|
9
|
-
import { analyzeConversation } from './conversation-analyzer.js';
|
|
10
|
-
import { generateStandards } from './standards-generator.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Main detection orchestrator
|
|
14
|
-
* @param {string} projectPath - Path to project root
|
|
15
|
-
* @param {Object} options - Detection options
|
|
16
|
-
* @returns {Promise<Object>} Detection results
|
|
17
|
-
*/
|
|
18
|
-
export async function detectProject(projectPath, options = {}) {
|
|
19
|
-
const results = {
|
|
20
|
-
path: projectPath,
|
|
21
|
-
timestamp: new Date().toISOString(),
|
|
22
|
-
structure: null,
|
|
23
|
-
config: null,
|
|
24
|
-
conversation: null,
|
|
25
|
-
inferred: null
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
// 1. Detect structure (stack, architecture, patterns)
|
|
30
|
-
if (options.structure !== false) {
|
|
31
|
-
results.structure = await detectStructure(projectPath);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 2. Detect config (technologies, dependencies, versions)
|
|
35
|
-
if (options.config !== false) {
|
|
36
|
-
results.config = await detectConfig(projectPath);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// 3. Analyze conversation history (if available)
|
|
40
|
-
if (options.conversation !== false) {
|
|
41
|
-
results.conversation = await analyzeConversation(projectPath);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 4. Generate inferred standards
|
|
45
|
-
if (options.generateStandards !== false) {
|
|
46
|
-
results.inferred = await generateStandards(results);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return results;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
throw new Error(`Detection failed: ${error.message}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get detection summary
|
|
57
|
-
* @param {Object} results - Detection results
|
|
58
|
-
* @returns {string} Human-readable summary
|
|
59
|
-
*/
|
|
60
|
-
export function getDetectionSummary(results) {
|
|
61
|
-
const { structure, config } = results;
|
|
62
|
-
|
|
63
|
-
const lines = [
|
|
64
|
-
'## Detection Summary',
|
|
65
|
-
'',
|
|
66
|
-
'### Stack',
|
|
67
|
-
`- **Type**: ${structure?.stack || 'unknown'}`,
|
|
68
|
-
`- **Architecture**: ${structure?.architecture || 'unknown'}`,
|
|
69
|
-
`- **UI Library**: ${structure?.uiLibrary || 'none'}`,
|
|
70
|
-
'',
|
|
71
|
-
'### Technologies',
|
|
72
|
-
`- **Language**: ${config?.language || 'unknown'}`,
|
|
73
|
-
`- **Version**: ${config?.version || 'unknown'}`,
|
|
74
|
-
`- **Package Manager**: ${config?.packageManager || 'unknown'}`,
|
|
75
|
-
'',
|
|
76
|
-
'### Patterns Detected',
|
|
77
|
-
...(structure?.patterns || []).map(p => `- ${p}`),
|
|
78
|
-
'',
|
|
79
|
-
'### Recommendations',
|
|
80
|
-
...(results.inferred?.recommendations || []).map(r => `- ${r}`)
|
|
81
|
-
];
|
|
82
|
-
|
|
83
|
-
return lines.join('\n');
|
|
84
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* MORPH-SPEC Detectors - Main Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Coordinates all detection modules to build a complete picture of the project.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { detectStructure } from './structure-detector.js';
|
|
8
|
+
import { detectConfig } from './config-detector.js';
|
|
9
|
+
import { analyzeConversation } from './conversation-analyzer.js';
|
|
10
|
+
import { generateStandards } from './standards-generator.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Main detection orchestrator
|
|
14
|
+
* @param {string} projectPath - Path to project root
|
|
15
|
+
* @param {Object} options - Detection options
|
|
16
|
+
* @returns {Promise<Object>} Detection results
|
|
17
|
+
*/
|
|
18
|
+
export async function detectProject(projectPath, options = {}) {
|
|
19
|
+
const results = {
|
|
20
|
+
path: projectPath,
|
|
21
|
+
timestamp: new Date().toISOString(),
|
|
22
|
+
structure: null,
|
|
23
|
+
config: null,
|
|
24
|
+
conversation: null,
|
|
25
|
+
inferred: null
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// 1. Detect structure (stack, architecture, patterns)
|
|
30
|
+
if (options.structure !== false) {
|
|
31
|
+
results.structure = await detectStructure(projectPath);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 2. Detect config (technologies, dependencies, versions)
|
|
35
|
+
if (options.config !== false) {
|
|
36
|
+
results.config = await detectConfig(projectPath);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 3. Analyze conversation history (if available)
|
|
40
|
+
if (options.conversation !== false) {
|
|
41
|
+
results.conversation = await analyzeConversation(projectPath);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 4. Generate inferred standards
|
|
45
|
+
if (options.generateStandards !== false) {
|
|
46
|
+
results.inferred = await generateStandards(results);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return results;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new Error(`Detection failed: ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get detection summary
|
|
57
|
+
* @param {Object} results - Detection results
|
|
58
|
+
* @returns {string} Human-readable summary
|
|
59
|
+
*/
|
|
60
|
+
export function getDetectionSummary(results) {
|
|
61
|
+
const { structure, config } = results;
|
|
62
|
+
|
|
63
|
+
const lines = [
|
|
64
|
+
'## Detection Summary',
|
|
65
|
+
'',
|
|
66
|
+
'### Stack',
|
|
67
|
+
`- **Type**: ${structure?.stack || 'unknown'}`,
|
|
68
|
+
`- **Architecture**: ${structure?.architecture || 'unknown'}`,
|
|
69
|
+
`- **UI Library**: ${structure?.uiLibrary || 'none'}`,
|
|
70
|
+
'',
|
|
71
|
+
'### Technologies',
|
|
72
|
+
`- **Language**: ${config?.language || 'unknown'}`,
|
|
73
|
+
`- **Version**: ${config?.version || 'unknown'}`,
|
|
74
|
+
`- **Package Manager**: ${config?.packageManager || 'unknown'}`,
|
|
75
|
+
'',
|
|
76
|
+
'### Patterns Detected',
|
|
77
|
+
...(structure?.patterns || []).map(p => `- ${p}`),
|
|
78
|
+
'',
|
|
79
|
+
'### Recommendations',
|
|
80
|
+
...(results.inferred?.recommendations || []).map(r => `- ${r}`)
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
return lines.join('\n');
|
|
84
|
+
}
|