@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
package/bin/detect-agents.js
CHANGED
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MORPH-SPEC Agent Detection CLI
|
|
5
|
-
*
|
|
6
|
-
* Detecta automaticamente quais agentes devem ser ativados baseado
|
|
7
|
-
* em keywords no input do usuário.
|
|
8
|
-
*
|
|
9
|
-
* Uso:
|
|
10
|
-
* node bin/detect-agents.js "implementar jobs agendados"
|
|
11
|
-
* node bin/detect-agents.js --verbose "criar dashboard com charts"
|
|
12
|
-
* node bin/detect-agents.js --json "adicionar background tasks"
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { readFileSync } from 'fs';
|
|
16
|
-
import { join, dirname } from 'path';
|
|
17
|
-
import { fileURLToPath } from 'url';
|
|
18
|
-
|
|
19
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
-
const AGENTS_CONFIG_PATH = join(__dirname, '../content/.morph/config/agents.json');
|
|
21
|
-
|
|
22
|
-
// Cores para output no terminal
|
|
23
|
-
const colors = {
|
|
24
|
-
reset: '\x1b[0m',
|
|
25
|
-
bright: '\x1b[1m',
|
|
26
|
-
green: '\x1b[32m',
|
|
27
|
-
yellow: '\x1b[33m',
|
|
28
|
-
blue: '\x1b[34m',
|
|
29
|
-
cyan: '\x1b[36m',
|
|
30
|
-
gray: '\x1b[90m'
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
function log(message, color = 'reset') {
|
|
34
|
-
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Carrega configuração de agentes
|
|
39
|
-
* @returns {Object} Configuração de agentes
|
|
40
|
-
*/
|
|
41
|
-
function loadAgentsConfig() {
|
|
42
|
-
try {
|
|
43
|
-
const content = readFileSync(AGENTS_CONFIG_PATH, 'utf8');
|
|
44
|
-
return JSON.parse(content);
|
|
45
|
-
} catch (err) {
|
|
46
|
-
console.error(`ERROR: Failed to load agents config: ${err.message}`);
|
|
47
|
-
process.exit(1);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Detecta agentes baseado em user input
|
|
53
|
-
* @param {string} userInput - Input do usuário
|
|
54
|
-
* @param {Object} config - Configuração de agentes
|
|
55
|
-
* @returns {Object} Resultado da detecção { core, specialists, all, matches }
|
|
56
|
-
*/
|
|
57
|
-
function detectAgents(userInput, config) {
|
|
58
|
-
const input = userInput.toLowerCase();
|
|
59
|
-
const coreAgents = config.agents.core || [];
|
|
60
|
-
const specialists = config.agents.specialists || [];
|
|
61
|
-
|
|
62
|
-
// Core agents sempre ativos
|
|
63
|
-
const coreIds = coreAgents.map(a => a.id);
|
|
64
|
-
|
|
65
|
-
// Detectar specialists por keyword matching
|
|
66
|
-
const specialistMatches = [];
|
|
67
|
-
|
|
68
|
-
for (const agent of specialists) {
|
|
69
|
-
const keywords = agent.autoActivation?.keywords || [];
|
|
70
|
-
const matchedKeywords = [];
|
|
71
|
-
|
|
72
|
-
for (const keyword of keywords) {
|
|
73
|
-
if (input.includes(keyword.toLowerCase())) {
|
|
74
|
-
matchedKeywords.push(keyword);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (matchedKeywords.length > 0) {
|
|
79
|
-
specialistMatches.push({
|
|
80
|
-
id: agent.id,
|
|
81
|
-
name: agent.name,
|
|
82
|
-
emoji: agent.emoji,
|
|
83
|
-
matchedKeywords: matchedKeywords,
|
|
84
|
-
matchCount: matchedKeywords.length
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Ordenar por número de matches (mais relevante primeiro)
|
|
90
|
-
specialistMatches.sort((a, b) => b.matchCount - a.matchCount);
|
|
91
|
-
|
|
92
|
-
const specialistIds = specialistMatches.map(m => m.id);
|
|
93
|
-
const allIds = [...new Set([...coreIds, ...specialistIds])];
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
core: coreIds,
|
|
97
|
-
specialists: specialistIds,
|
|
98
|
-
all: allIds,
|
|
99
|
-
matches: specialistMatches,
|
|
100
|
-
input: userInput
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Formata output em modo verbose
|
|
106
|
-
* @param {Object} result - Resultado da detecção
|
|
107
|
-
*/
|
|
108
|
-
function formatVerbose(result) {
|
|
109
|
-
log('\n╔════════════════════════════════════════════════════════════════╗', 'cyan');
|
|
110
|
-
log('║ AGENT DETECTION RESULT ║', 'cyan');
|
|
111
|
-
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
112
|
-
log(`║ Input: ${result.input.substring(0, 54).padEnd(54)} ║`, 'bright');
|
|
113
|
-
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
114
|
-
log('║ CORE AGENTS (always active) ║', 'cyan');
|
|
115
|
-
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
116
|
-
|
|
117
|
-
result.core.forEach(id => {
|
|
118
|
-
log(`║ ✓ ${id.padEnd(58)}║`, 'green');
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (result.specialists.length > 0) {
|
|
122
|
-
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
123
|
-
log('║ SPECIALIST AGENTS (keyword matched) ║', 'cyan');
|
|
124
|
-
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
125
|
-
|
|
126
|
-
result.matches.forEach(match => {
|
|
127
|
-
const line = `${match.emoji} ${match.name} (${match.matchCount} matches)`;
|
|
128
|
-
log(`║ ${line.padEnd(61)}║`, 'yellow');
|
|
129
|
-
const keywords = match.matchedKeywords.join(', ');
|
|
130
|
-
const keywordLine = `Keywords: ${keywords}`;
|
|
131
|
-
// Quebrar em múltiplas linhas se necessário
|
|
132
|
-
if (keywordLine.length > 58) {
|
|
133
|
-
const chunks = keywordLine.match(/.{1,58}/g) || [];
|
|
134
|
-
chunks.forEach((chunk, i) => {
|
|
135
|
-
log(`║ ${chunk.padEnd(59)}║`, 'gray');
|
|
136
|
-
});
|
|
137
|
-
} else {
|
|
138
|
-
log(`║ ${keywordLine.padEnd(59)}║`, 'gray');
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
} else {
|
|
142
|
-
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
143
|
-
log('║ No specialist agents matched ║', 'gray');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
147
|
-
log(`║ TOTAL: ${result.all.length} agents activated ║`, 'bright');
|
|
148
|
-
log('╚════════════════════════════════════════════════════════════════╝\n', 'cyan');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Formata output em modo simples (apenas IDs)
|
|
153
|
-
* @param {Object} result - Resultado da detecção
|
|
154
|
-
*/
|
|
155
|
-
function formatSimple(result) {
|
|
156
|
-
result.all.forEach(id => console.log(id));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Formata output em modo JSON
|
|
161
|
-
* @param {Object} result - Resultado da detecção
|
|
162
|
-
*/
|
|
163
|
-
function formatJSON(result) {
|
|
164
|
-
console.log(JSON.stringify(result, null, 2));
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// ============================================================================
|
|
168
|
-
// MAIN
|
|
169
|
-
// ============================================================================
|
|
170
|
-
|
|
171
|
-
function main() {
|
|
172
|
-
const args = process.argv.slice(2);
|
|
173
|
-
|
|
174
|
-
// Parse flags
|
|
175
|
-
const hasVerbose = args.includes('--verbose') || args.includes('-v');
|
|
176
|
-
const hasJSON = args.includes('--json') || args.includes('-j');
|
|
177
|
-
const hasHelp = args.includes('--help') || args.includes('-h');
|
|
178
|
-
const hasIdsOnly = args.includes('--ids-only') || args.includes('-i');
|
|
179
|
-
|
|
180
|
-
// Remove flags para pegar user input
|
|
181
|
-
const userInput = args
|
|
182
|
-
.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'))
|
|
183
|
-
.join(' ');
|
|
184
|
-
|
|
185
|
-
if (hasHelp || args.length === 0) {
|
|
186
|
-
log('\nMORPH-SPEC Agent Detection CLI', 'bright');
|
|
187
|
-
log('\nUsage:', 'cyan');
|
|
188
|
-
log(' node bin/detect-agents.js [options] "<user input>"', 'gray');
|
|
189
|
-
log('\nOptions:', 'cyan');
|
|
190
|
-
log(' -v, --verbose Show detailed detection results', 'gray');
|
|
191
|
-
log(' -j, --json Output full result as JSON', 'gray');
|
|
192
|
-
log(' -i, --ids-only Output only agent IDs (one per line)', 'gray');
|
|
193
|
-
log(' -h, --help Show this help', 'gray');
|
|
194
|
-
log('\nExamples:', 'cyan');
|
|
195
|
-
log(' node bin/detect-agents.js "criar dashboard com charts"', 'gray');
|
|
196
|
-
log(' node bin/detect-agents.js --verbose "implementar jobs agendados"', 'gray');
|
|
197
|
-
log(' node bin/detect-agents.js --json "adicionar RAG pipeline"', 'gray');
|
|
198
|
-
log(' node bin/detect-agents.js --ids-only "background tasks"\n', 'gray');
|
|
199
|
-
process.exit(0);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (!userInput) {
|
|
203
|
-
console.error('ERROR: User input is required');
|
|
204
|
-
console.error('Run with --help for usage information');
|
|
205
|
-
process.exit(1);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Carregar config e detectar agentes
|
|
209
|
-
const config = loadAgentsConfig();
|
|
210
|
-
const result = detectAgents(userInput, config);
|
|
211
|
-
|
|
212
|
-
// Formatar output
|
|
213
|
-
if (hasJSON) {
|
|
214
|
-
formatJSON(result);
|
|
215
|
-
} else if (hasVerbose) {
|
|
216
|
-
formatVerbose(result);
|
|
217
|
-
} else if (hasIdsOnly) {
|
|
218
|
-
formatSimple(result);
|
|
219
|
-
} else {
|
|
220
|
-
// Default: JSON compact (só all array)
|
|
221
|
-
console.log(JSON.stringify(result.all));
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MORPH-SPEC Agent Detection CLI
|
|
5
|
+
*
|
|
6
|
+
* Detecta automaticamente quais agentes devem ser ativados baseado
|
|
7
|
+
* em keywords no input do usuário.
|
|
8
|
+
*
|
|
9
|
+
* Uso:
|
|
10
|
+
* node bin/detect-agents.js "implementar jobs agendados"
|
|
11
|
+
* node bin/detect-agents.js --verbose "criar dashboard com charts"
|
|
12
|
+
* node bin/detect-agents.js --json "adicionar background tasks"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFileSync } from 'fs';
|
|
16
|
+
import { join, dirname } from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const AGENTS_CONFIG_PATH = join(__dirname, '../content/.morph/config/agents.json');
|
|
21
|
+
|
|
22
|
+
// Cores para output no terminal
|
|
23
|
+
const colors = {
|
|
24
|
+
reset: '\x1b[0m',
|
|
25
|
+
bright: '\x1b[1m',
|
|
26
|
+
green: '\x1b[32m',
|
|
27
|
+
yellow: '\x1b[33m',
|
|
28
|
+
blue: '\x1b[34m',
|
|
29
|
+
cyan: '\x1b[36m',
|
|
30
|
+
gray: '\x1b[90m'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function log(message, color = 'reset') {
|
|
34
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Carrega configuração de agentes
|
|
39
|
+
* @returns {Object} Configuração de agentes
|
|
40
|
+
*/
|
|
41
|
+
function loadAgentsConfig() {
|
|
42
|
+
try {
|
|
43
|
+
const content = readFileSync(AGENTS_CONFIG_PATH, 'utf8');
|
|
44
|
+
return JSON.parse(content);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error(`ERROR: Failed to load agents config: ${err.message}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Detecta agentes baseado em user input
|
|
53
|
+
* @param {string} userInput - Input do usuário
|
|
54
|
+
* @param {Object} config - Configuração de agentes
|
|
55
|
+
* @returns {Object} Resultado da detecção { core, specialists, all, matches }
|
|
56
|
+
*/
|
|
57
|
+
function detectAgents(userInput, config) {
|
|
58
|
+
const input = userInput.toLowerCase();
|
|
59
|
+
const coreAgents = config.agents.core || [];
|
|
60
|
+
const specialists = config.agents.specialists || [];
|
|
61
|
+
|
|
62
|
+
// Core agents sempre ativos
|
|
63
|
+
const coreIds = coreAgents.map(a => a.id);
|
|
64
|
+
|
|
65
|
+
// Detectar specialists por keyword matching
|
|
66
|
+
const specialistMatches = [];
|
|
67
|
+
|
|
68
|
+
for (const agent of specialists) {
|
|
69
|
+
const keywords = agent.autoActivation?.keywords || [];
|
|
70
|
+
const matchedKeywords = [];
|
|
71
|
+
|
|
72
|
+
for (const keyword of keywords) {
|
|
73
|
+
if (input.includes(keyword.toLowerCase())) {
|
|
74
|
+
matchedKeywords.push(keyword);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (matchedKeywords.length > 0) {
|
|
79
|
+
specialistMatches.push({
|
|
80
|
+
id: agent.id,
|
|
81
|
+
name: agent.name,
|
|
82
|
+
emoji: agent.emoji,
|
|
83
|
+
matchedKeywords: matchedKeywords,
|
|
84
|
+
matchCount: matchedKeywords.length
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Ordenar por número de matches (mais relevante primeiro)
|
|
90
|
+
specialistMatches.sort((a, b) => b.matchCount - a.matchCount);
|
|
91
|
+
|
|
92
|
+
const specialistIds = specialistMatches.map(m => m.id);
|
|
93
|
+
const allIds = [...new Set([...coreIds, ...specialistIds])];
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
core: coreIds,
|
|
97
|
+
specialists: specialistIds,
|
|
98
|
+
all: allIds,
|
|
99
|
+
matches: specialistMatches,
|
|
100
|
+
input: userInput
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Formata output em modo verbose
|
|
106
|
+
* @param {Object} result - Resultado da detecção
|
|
107
|
+
*/
|
|
108
|
+
function formatVerbose(result) {
|
|
109
|
+
log('\n╔════════════════════════════════════════════════════════════════╗', 'cyan');
|
|
110
|
+
log('║ AGENT DETECTION RESULT ║', 'cyan');
|
|
111
|
+
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
112
|
+
log(`║ Input: ${result.input.substring(0, 54).padEnd(54)} ║`, 'bright');
|
|
113
|
+
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
114
|
+
log('║ CORE AGENTS (always active) ║', 'cyan');
|
|
115
|
+
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
116
|
+
|
|
117
|
+
result.core.forEach(id => {
|
|
118
|
+
log(`║ ✓ ${id.padEnd(58)}║`, 'green');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (result.specialists.length > 0) {
|
|
122
|
+
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
123
|
+
log('║ SPECIALIST AGENTS (keyword matched) ║', 'cyan');
|
|
124
|
+
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
125
|
+
|
|
126
|
+
result.matches.forEach(match => {
|
|
127
|
+
const line = `${match.emoji} ${match.name} (${match.matchCount} matches)`;
|
|
128
|
+
log(`║ ${line.padEnd(61)}║`, 'yellow');
|
|
129
|
+
const keywords = match.matchedKeywords.join(', ');
|
|
130
|
+
const keywordLine = `Keywords: ${keywords}`;
|
|
131
|
+
// Quebrar em múltiplas linhas se necessário
|
|
132
|
+
if (keywordLine.length > 58) {
|
|
133
|
+
const chunks = keywordLine.match(/.{1,58}/g) || [];
|
|
134
|
+
chunks.forEach((chunk, i) => {
|
|
135
|
+
log(`║ ${chunk.padEnd(59)}║`, 'gray');
|
|
136
|
+
});
|
|
137
|
+
} else {
|
|
138
|
+
log(`║ ${keywordLine.padEnd(59)}║`, 'gray');
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
} else {
|
|
142
|
+
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
143
|
+
log('║ No specialist agents matched ║', 'gray');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
|
|
147
|
+
log(`║ TOTAL: ${result.all.length} agents activated ║`, 'bright');
|
|
148
|
+
log('╚════════════════════════════════════════════════════════════════╝\n', 'cyan');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Formata output em modo simples (apenas IDs)
|
|
153
|
+
* @param {Object} result - Resultado da detecção
|
|
154
|
+
*/
|
|
155
|
+
function formatSimple(result) {
|
|
156
|
+
result.all.forEach(id => console.log(id));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Formata output em modo JSON
|
|
161
|
+
* @param {Object} result - Resultado da detecção
|
|
162
|
+
*/
|
|
163
|
+
function formatJSON(result) {
|
|
164
|
+
console.log(JSON.stringify(result, null, 2));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ============================================================================
|
|
168
|
+
// MAIN
|
|
169
|
+
// ============================================================================
|
|
170
|
+
|
|
171
|
+
function main() {
|
|
172
|
+
const args = process.argv.slice(2);
|
|
173
|
+
|
|
174
|
+
// Parse flags
|
|
175
|
+
const hasVerbose = args.includes('--verbose') || args.includes('-v');
|
|
176
|
+
const hasJSON = args.includes('--json') || args.includes('-j');
|
|
177
|
+
const hasHelp = args.includes('--help') || args.includes('-h');
|
|
178
|
+
const hasIdsOnly = args.includes('--ids-only') || args.includes('-i');
|
|
179
|
+
|
|
180
|
+
// Remove flags para pegar user input
|
|
181
|
+
const userInput = args
|
|
182
|
+
.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'))
|
|
183
|
+
.join(' ');
|
|
184
|
+
|
|
185
|
+
if (hasHelp || args.length === 0) {
|
|
186
|
+
log('\nMORPH-SPEC Agent Detection CLI', 'bright');
|
|
187
|
+
log('\nUsage:', 'cyan');
|
|
188
|
+
log(' node bin/detect-agents.js [options] "<user input>"', 'gray');
|
|
189
|
+
log('\nOptions:', 'cyan');
|
|
190
|
+
log(' -v, --verbose Show detailed detection results', 'gray');
|
|
191
|
+
log(' -j, --json Output full result as JSON', 'gray');
|
|
192
|
+
log(' -i, --ids-only Output only agent IDs (one per line)', 'gray');
|
|
193
|
+
log(' -h, --help Show this help', 'gray');
|
|
194
|
+
log('\nExamples:', 'cyan');
|
|
195
|
+
log(' node bin/detect-agents.js "criar dashboard com charts"', 'gray');
|
|
196
|
+
log(' node bin/detect-agents.js --verbose "implementar jobs agendados"', 'gray');
|
|
197
|
+
log(' node bin/detect-agents.js --json "adicionar RAG pipeline"', 'gray');
|
|
198
|
+
log(' node bin/detect-agents.js --ids-only "background tasks"\n', 'gray');
|
|
199
|
+
process.exit(0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!userInput) {
|
|
203
|
+
console.error('ERROR: User input is required');
|
|
204
|
+
console.error('Run with --help for usage information');
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Carregar config e detectar agentes
|
|
209
|
+
const config = loadAgentsConfig();
|
|
210
|
+
const result = detectAgents(userInput, config);
|
|
211
|
+
|
|
212
|
+
// Formatar output
|
|
213
|
+
if (hasJSON) {
|
|
214
|
+
formatJSON(result);
|
|
215
|
+
} else if (hasVerbose) {
|
|
216
|
+
formatVerbose(result);
|
|
217
|
+
} else if (hasIdsOnly) {
|
|
218
|
+
formatSimple(result);
|
|
219
|
+
} else {
|
|
220
|
+
// Default: JSON compact (só all array)
|
|
221
|
+
console.log(JSON.stringify(result.all));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
main();
|
package/bin/morph-spec.js
CHANGED
|
@@ -18,6 +18,7 @@ import { sprintStatusCommand } from '../src/commands/sprint-status.js';
|
|
|
18
18
|
import { stateCommand } from '../src/commands/state.js';
|
|
19
19
|
import { taskDoneCommand, taskStartCommand, taskNextCommand } from '../src/commands/task.js';
|
|
20
20
|
import { generateDesignSystemCommand } from '../src/commands/generate.js';
|
|
21
|
+
import { generateContextCommand } from '../src/commands/generate-context.js';
|
|
21
22
|
import { validateCommand } from './validate.js';
|
|
22
23
|
import { validateBlazorCommand } from '../src/commands/validate-blazor.js';
|
|
23
24
|
import { lintFluentCommand } from '../src/commands/lint-fluent.js';
|
|
@@ -179,6 +180,13 @@ generateCommand
|
|
|
179
180
|
await generateRecap('.', feature, options);
|
|
180
181
|
});
|
|
181
182
|
|
|
183
|
+
generateCommand
|
|
184
|
+
.command('context [feature]')
|
|
185
|
+
.description('Generate CONTEXT.md with full project data for Claude Code')
|
|
186
|
+
.action(async (feature) => {
|
|
187
|
+
await generateContextCommand('.', feature);
|
|
188
|
+
});
|
|
189
|
+
|
|
182
190
|
// Validation commands (Sprint 4: Continuous Validation)
|
|
183
191
|
program
|
|
184
192
|
.command('validate [validator]')
|