@polymorphism-tech/morph-spec 3.0.0 → 3.1.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.
Files changed (240) hide show
  1. package/CLAUDE.md +68 -400
  2. package/README.md +198 -76
  3. package/bin/detect-agents.js +227 -225
  4. package/bin/morph-spec.js +10 -0
  5. package/bin/render-template.js +303 -302
  6. package/bin/semantic-detect-agents.js +247 -246
  7. package/bin/{task-manager.js → task-manager.cjs} +12 -1
  8. package/bin/validate-agents-skills.js +257 -251
  9. package/bin/validate-agents.js +70 -69
  10. package/bin/validate-phase.js +263 -263
  11. package/docs/getting-started.md +3 -3
  12. package/package.json +3 -4
  13. package/scripts/reorganize-skills.cjs +175 -0
  14. package/scripts/validate-agents-structure.cjs +52 -0
  15. package/scripts/validate-skills.cjs +180 -0
  16. package/src/commands/create-story.js +354 -351
  17. package/src/commands/detect-agents.js +13 -2
  18. package/src/commands/detect.js +104 -104
  19. package/src/commands/state.js +334 -333
  20. package/src/commands/sync.js +167 -167
  21. package/src/commands/task.js +1 -1
  22. package/src/commands/update.js +13 -1
  23. package/src/lib/context-generator.js +7 -4
  24. package/{detectors → src/lib/detectors}/config-detector.js +223 -223
  25. package/{detectors → src/lib/detectors}/conversation-analyzer.js +163 -163
  26. package/{detectors → src/lib/detectors}/index.js +84 -84
  27. package/{detectors → src/lib/detectors}/standards-generator.js +275 -275
  28. package/src/lib/hook-executor.js +2 -1
  29. package/src/lib/stack-resolver.js +148 -0
  30. package/src/lib/standards-context-injector.js +4 -3
  31. package/src/lib/state-manager.js +21 -4
  32. package/src/lib/team-orchestrator.js +2 -1
  33. package/src/lib/troubleshoot-grep.js +13 -3
  34. package/src/lib/validation-runner.js +2 -1
  35. package/src/utils/file-copier.js +3 -1
  36. package/{content → stacks/blazor-azure}/.azure/README.md +293 -293
  37. package/{content → stacks/blazor-azure}/.azure/docs/azure-devops-setup.md +454 -454
  38. package/{content → stacks/blazor-azure}/.azure/docs/branch-strategy.md +398 -398
  39. package/{content → stacks/blazor-azure}/.azure/docs/local-development.md +515 -515
  40. package/{content → stacks/blazor-azure}/.azure/pipelines/pipeline-variables.yml +34 -34
  41. package/{content → stacks/blazor-azure}/.azure/pipelines/prod-pipeline.yml +319 -319
  42. package/{content → stacks/blazor-azure}/.azure/pipelines/staging-pipeline.yml +234 -234
  43. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/build-dotnet.yml +75 -75
  44. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-app-service.yml +94 -94
  45. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-container-app.yml +120 -120
  46. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/infra-deploy.yml +90 -90
  47. package/{content → stacks/blazor-azure}/.claude/commands/morph-archive.md +79 -79
  48. package/{content → stacks/blazor-azure}/.claude/commands/morph-deploy.md +529 -529
  49. package/{content → stacks/blazor-azure}/.claude/commands/morph-infra.md +209 -209
  50. package/{content → stacks/blazor-azure}/.claude/commands/morph-troubleshoot.md +1 -1
  51. package/{content → stacks/blazor-azure}/.claude/settings.local.json +15 -15
  52. package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-setup.md +1 -1
  53. package/{content/.claude/skills/specialists → stacks/blazor-azure/.claude/skills/level-2-domains/architecture}/prompt-engineer.md +189 -189
  54. package/{content/.claude/skills/specialists → stacks/blazor-azure/.claude/skills/level-2-domains/architecture}/seo-growth-hacker.md +320 -320
  55. package/{content/.claude/skills/infra → stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure}/azure-deploy-specialist.md +699 -699
  56. package/{content → stacks/blazor-azure}/.morph/.morphversion +5 -5
  57. package/{content → stacks/blazor-azure}/.morph/archive/.gitkeep +25 -25
  58. package/{content → stacks/blazor-azure}/.morph/config/agents.json +7 -5
  59. package/{content → stacks/blazor-azure}/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
  60. package/{content → stacks/blazor-azure}/.morph/docs/workflows/enforcement-pipeline.md +3 -3
  61. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/README.md +241 -241
  62. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/contracts.ts +307 -307
  63. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/spec.md +399 -399
  64. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/tasks.md +168 -168
  65. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/README.md +125 -125
  66. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/contracts.cs +358 -358
  67. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/decisions.md +246 -246
  68. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/spec.md +236 -236
  69. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/tasks.md +150 -150
  70. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/README.md +309 -309
  71. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/contracts.cs +433 -433
  72. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/spec.md +479 -479
  73. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/tasks.md +185 -185
  74. package/{content → stacks/blazor-azure}/.morph/examples/state-v3.json +188 -188
  75. package/{content → stacks/blazor-azure}/.morph/features/.gitkeep +25 -25
  76. package/{content → stacks/blazor-azure}/.morph/hooks/README.md +12 -12
  77. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-all.sh +48 -48
  78. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-specs.sh +49 -49
  79. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-tests.sh +60 -60
  80. package/{content → stacks/blazor-azure}/.morph/project.md +160 -160
  81. package/{content → stacks/blazor-azure}/.morph/schemas/agent.schema.json +296 -296
  82. package/{content → stacks/blazor-azure}/.morph/specs/.gitkeep +20 -20
  83. package/{content → stacks/blazor-azure}/.morph/standards/agent-teams-workflow.md +2 -2
  84. package/{content → stacks/blazor-azure}/.morph/standards/coding.md +377 -377
  85. package/{content → stacks/blazor-azure}/.morph/standards/fluent-ui-setup.md +590 -590
  86. package/{content → stacks/blazor-azure}/.morph/standards/migration-guide.md +514 -514
  87. package/{content → stacks/blazor-azure}/.morph/standards/passkeys-auth.md +423 -423
  88. package/{content → stacks/blazor-azure}/.morph/standards/vector-search-rag.md +536 -536
  89. package/{content → stacks/blazor-azure}/.morph/state.json +17 -17
  90. package/{content → stacks/blazor-azure}/.morph/templates/FluentDesignTheme.cs +149 -149
  91. package/{content → stacks/blazor-azure}/.morph/templates/MudTheme.cs +281 -281
  92. package/{content → stacks/blazor-azure}/.morph/templates/component.razor +239 -239
  93. package/{content → stacks/blazor-azure}/.morph/templates/contracts.cs +217 -217
  94. package/{content → stacks/blazor-azure}/.morph/templates/design-system.css +226 -226
  95. package/{content → stacks/blazor-azure}/.morph/templates/infra/.dockerignore.example +89 -89
  96. package/{content → stacks/blazor-azure}/.morph/templates/infra/Dockerfile.example +82 -82
  97. package/{content → stacks/blazor-azure}/.morph/templates/infra/README.md +286 -286
  98. package/{content → stacks/blazor-azure}/.morph/templates/infra/app-insights.bicep +63 -63
  99. package/{content → stacks/blazor-azure}/.morph/templates/infra/app-service.bicep +164 -164
  100. package/{content → stacks/blazor-azure}/.morph/templates/infra/azure-pipelines-deploy.yml +480 -480
  101. package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app-env.bicep +49 -49
  102. package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app.bicep +156 -156
  103. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.ps1 +229 -229
  104. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.sh +208 -208
  105. package/{content → stacks/blazor-azure}/.morph/templates/infra/key-vault.bicep +91 -91
  106. package/{content → stacks/blazor-azure}/.morph/templates/infra/main.bicep +189 -189
  107. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.dev.json +29 -29
  108. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.prod.json +29 -29
  109. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.staging.json +29 -29
  110. package/{content → stacks/blazor-azure}/.morph/templates/infra/sql-database.bicep +103 -103
  111. package/{content → stacks/blazor-azure}/.morph/templates/infra/storage.bicep +106 -106
  112. package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-client.cs +387 -387
  113. package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-webhook.cs +351 -351
  114. package/{content → stacks/blazor-azure}/.morph/templates/integrations/azure-identity-config.cs +288 -288
  115. package/{content → stacks/blazor-azure}/.morph/templates/integrations/clerk-config.cs +258 -258
  116. package/{content → stacks/blazor-azure}/.morph/templates/job.cs +171 -171
  117. package/{content → stacks/blazor-azure}/.morph/templates/migration.cs +83 -83
  118. package/{content → stacks/blazor-azure}/.morph/templates/repository.cs +141 -141
  119. package/{content → stacks/blazor-azure}/.morph/templates/saas/subscription.cs +347 -347
  120. package/{content → stacks/blazor-azure}/.morph/templates/saas/tenant.cs +338 -338
  121. package/{content → stacks/blazor-azure}/.morph/templates/service.cs +139 -139
  122. package/{content → stacks/blazor-azure}/.morph/templates/sprint-status.yaml +68 -68
  123. package/{content → stacks/blazor-azure}/.morph/templates/story.md +143 -143
  124. package/{content → stacks/blazor-azure}/.morph/templates/test.cs +239 -239
  125. package/{content → stacks/blazor-azure}/.morph/templates/ui-design-system.md +286 -286
  126. package/{content → stacks/blazor-azure}/.morph/templates/ui-flows.md +336 -336
  127. package/{content → stacks/blazor-azure}/.morph/templates/ui-mockups.md +133 -133
  128. package/{content → stacks/blazor-azure}/.morph/test-infra/example.bicep +59 -59
  129. package/{content → stacks/blazor-azure}/README.md +79 -79
  130. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +244 -0
  131. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +335 -0
  132. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +189 -0
  133. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +170 -0
  134. package/stacks/nextjs-supabase/.morph/config/agents.json +345 -0
  135. package/stacks/nextjs-supabase/.morph/config/config.template.json +92 -0
  136. package/stacks/nextjs-supabase/.morph/docs/easypanel-setup.md +169 -0
  137. package/stacks/nextjs-supabase/.morph/docs/supabase-mcp-setup.md +247 -0
  138. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/README.md +697 -0
  139. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/spec.md +85 -0
  140. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/tasks.md +86 -0
  141. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/README.md +498 -0
  142. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/decisions.md +121 -0
  143. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/spec.md +138 -0
  144. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/tasks.md +162 -0
  145. package/stacks/nextjs-supabase/.morph/project.md +168 -0
  146. package/stacks/nextjs-supabase/.morph/standards/easypanel-deploy.md +191 -0
  147. package/stacks/nextjs-supabase/.morph/standards/nextjs-patterns.md +193 -0
  148. package/stacks/nextjs-supabase/.morph/standards/supabase-auth.md +171 -0
  149. package/stacks/nextjs-supabase/.morph/standards/supabase-pgvector.md +164 -0
  150. package/stacks/nextjs-supabase/.morph/standards/supabase-rls.md +179 -0
  151. package/stacks/nextjs-supabase/.morph/standards/supabase-storage.md +148 -0
  152. package/stacks/nextjs-supabase/.morph/templates/contracts.cs +173 -0
  153. package/stacks/nextjs-supabase/.morph/templates/contracts.ts +168 -0
  154. package/stacks/nextjs-supabase/.morph/templates/decisions.md +115 -0
  155. package/stacks/nextjs-supabase/.morph/templates/dockerfile-api.dockerfile +38 -0
  156. package/stacks/nextjs-supabase/.morph/templates/dockerfile-web.dockerfile +48 -0
  157. package/stacks/nextjs-supabase/.morph/templates/proposal.md +145 -0
  158. package/stacks/nextjs-supabase/.morph/templates/recap.md +134 -0
  159. package/stacks/nextjs-supabase/.morph/templates/rls-policy.sql +57 -0
  160. package/stacks/nextjs-supabase/.morph/templates/spec.md +231 -0
  161. package/stacks/nextjs-supabase/.morph/templates/supabase-migration.sql +100 -0
  162. package/stacks/nextjs-supabase/.morph/templates/tasks.md +257 -0
  163. package/stacks/nextjs-supabase/CLAUDE.md +149 -0
  164. package/stacks/nextjs-supabase/README.md +112 -0
  165. /package/{detectors → src/lib/detectors}/structure-detector.js +0 -0
  166. /package/{content → stacks/blazor-azure}/.claude/commands/morph-apply.md +0 -0
  167. /package/{content → stacks/blazor-azure}/.claude/commands/morph-preflight.md +0 -0
  168. /package/{content → stacks/blazor-azure}/.claude/commands/morph-proposal.md +0 -0
  169. /package/{content → stacks/blazor-azure}/.claude/commands/morph-status.md +0 -0
  170. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/README.md +0 -0
  171. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/code-review.md +0 -0
  172. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/morph-checklist.md +0 -0
  173. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/simulation-checklist.md +0 -0
  174. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/README.md +0 -0
  175. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/morph-replicate.md +0 -0
  176. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-clarify.md +0 -0
  177. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-design.md +0 -0
  178. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-tasks.md +0 -0
  179. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-uiux.md +0 -0
  180. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/README.md +0 -0
  181. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -0
  182. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -0
  183. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -0
  184. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -0
  185. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -0
  186. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -0
  187. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -0
  188. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -0
  189. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -0
  190. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -0
  191. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -0
  192. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -0
  193. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -0
  194. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -0
  195. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -0
  196. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -0
  197. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -0
  198. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/resend-email.md +0 -0
  199. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -0
  200. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -0
  201. /package/{content → stacks/blazor-azure}/.claude/skills/level-3-technologies/README.md +0 -0
  202. /package/{content → stacks/blazor-azure}/.claude/skills/level-4-patterns/README.md +0 -0
  203. /package/{content → stacks/blazor-azure}/.morph/config/config.template.json +0 -0
  204. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/design-impl.md +0 -0
  205. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/fast-track.md +0 -0
  206. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/full-morph.md +0 -0
  207. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/standard.md +0 -0
  208. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/ui-refresh.md +0 -0
  209. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/decisions.md +0 -0
  210. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/proposal.md +0 -0
  211. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/spec.md +0 -0
  212. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-agents.sh +0 -0
  213. /package/{content → stacks/blazor-azure}/.morph/hooks/task-completed.js +0 -0
  214. /package/{content → stacks/blazor-azure}/.morph/hooks/teammate-idle.js +0 -0
  215. /package/{content → stacks/blazor-azure}/.morph/schemas/tasks.schema.json +0 -0
  216. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-blazor-ui.md +0 -0
  217. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-production.md +0 -0
  218. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-setup.md +0 -0
  219. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-workflows.md +0 -0
  220. /package/{content → stacks/blazor-azure}/.morph/standards/architecture.md +0 -0
  221. /package/{content → stacks/blazor-azure}/.morph/standards/azure.md +0 -0
  222. /package/{content → stacks/blazor-azure}/.morph/standards/dotnet10-migration.md +0 -0
  223. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT-FEATURE.md +0 -0
  224. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT.md +0 -0
  225. /package/{content → stacks/blazor-azure}/.morph/templates/agent.cs +0 -0
  226. /package/{content → stacks/blazor-azure}/.morph/templates/clarify-questions.md +0 -0
  227. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Commands.cs +0 -0
  228. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Entities.cs +0 -0
  229. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Queries.cs +0 -0
  230. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/README.md +0 -0
  231. /package/{content → stacks/blazor-azure}/.morph/templates/decisions.md +0 -0
  232. /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy-checklist.md +0 -0
  233. /package/{content → stacks/blazor-azure}/.morph/templates/proposal.md +0 -0
  234. /package/{content → stacks/blazor-azure}/.morph/templates/recap.md +0 -0
  235. /package/{content → stacks/blazor-azure}/.morph/templates/simulation.md +0 -0
  236. /package/{content → stacks/blazor-azure}/.morph/templates/spec.md +0 -0
  237. /package/{content → stacks/blazor-azure}/.morph/templates/state.template.json +0 -0
  238. /package/{content → stacks/blazor-azure}/.morph/templates/tasks.md +0 -0
  239. /package/{content → stacks/blazor-azure}/.morph/templates/ui-components.md +0 -0
  240. /package/{content → stacks/blazor-azure}/CLAUDE.md +0 -0
@@ -1,251 +1,257 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * MORPH-SPEC Agent-Skill Validator
5
- *
6
- * Valida a consistência entre agents.json e arquivos de skills.
7
- * Garante que não há agentes sem skills ou skills sem agentes (orphans).
8
- *
9
- * Uso:
10
- * node bin/validate-agents-skills.js
11
- * node bin/validate-agents-skills.js --verbose
12
- */
13
-
14
- import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
15
- import { join, dirname } from 'path';
16
- import { fileURLToPath } from 'url';
17
-
18
- const __dirname = dirname(fileURLToPath(import.meta.url));
19
- const AGENTS_CONFIG_PATH = join(__dirname, '../content/.morph/config/agents.json');
20
- const SKILLS_BASE_PATH = join(__dirname, '../content/.claude/skills');
21
-
22
- // Cores para output
23
- const colors = {
24
- reset: '\x1b[0m',
25
- bright: '\x1b[1m',
26
- green: '\x1b[32m',
27
- yellow: '\x1b[33m',
28
- red: '\x1b[31m',
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 agents.json
39
- */
40
- function loadAgentsConfig() {
41
- try {
42
- const content = readFileSync(AGENTS_CONFIG_PATH, 'utf8');
43
- return JSON.parse(content);
44
- } catch (err) {
45
- log(`ERROR: Failed to load agents.json: ${err.message}`, 'red');
46
- process.exit(1);
47
- }
48
- }
49
-
50
- /**
51
- * Recursivamente lista todos os arquivos .md no diretório de skills
52
- */
53
- function getAllSkillFiles(dir, fileList = []) {
54
- const files = readdirSync(dir);
55
-
56
- files.forEach(file => {
57
- const filePath = join(dir, file);
58
- const stat = statSync(filePath);
59
-
60
- if (stat.isDirectory()) {
61
- getAllSkillFiles(filePath, fileList);
62
- } else if (file.endsWith('.md')) {
63
- // Converter para path relativo ao content/
64
- const relativePath = filePath.replace(/\\/g, '/').split('/content/')[1];
65
- fileList.push(relativePath);
66
- }
67
- });
68
-
69
- return fileList;
70
- }
71
-
72
- /**
73
- * Valida agents vs skills
74
- */
75
- function validateAgentsSkills(config, verbose = false) {
76
- const errors = [];
77
- const warnings = [];
78
- const info = [];
79
-
80
- // 1. Coletar todos os agentes e seus skillPaths
81
- const allAgents = [...config.agents.core, ...config.agents.specialists];
82
- const agentSkillPaths = new Set();
83
-
84
- for (const agent of allAgents) {
85
- if (agent.skillPath) {
86
- agentSkillPaths.add(agent.skillPath);
87
-
88
- // Verificar se skill file existe
89
- const skillFilePath = join(__dirname, '../content', agent.skillPath);
90
- if (!existsSync(skillFilePath)) {
91
- errors.push({
92
- type: 'missing-skill',
93
- agent: agent.id,
94
- skillPath: agent.skillPath,
95
- message: `Agent '${agent.id}' references non-existent skill: ${agent.skillPath}`
96
- });
97
- } else if (verbose) {
98
- info.push({
99
- type: 'valid-mapping',
100
- agent: agent.id,
101
- skillPath: agent.skillPath,
102
- message: `✓ ${agent.id} → ${agent.skillPath}`
103
- });
104
- }
105
- } else if (verbose) {
106
- warnings.push({
107
- type: 'no-skill',
108
- agent: agent.id,
109
- message: `Agent '${agent.id}' has no skillPath defined (metadata-only agent)`
110
- });
111
- }
112
- }
113
-
114
- // 2. Verificar skills órfãs (sem agente correspondente)
115
- const allSkillFiles = getAllSkillFiles(SKILLS_BASE_PATH);
116
-
117
- for (const skillFile of allSkillFiles) {
118
- const skillPath = `.claude/skills/${skillFile.replace('.claude/skills/', '')}`;
119
-
120
- if (!agentSkillPaths.has(skillPath)) {
121
- // Orphan skills são OK - podem ser usados manualmente
122
- // Apenas reportar em verbose mode
123
- if (verbose) {
124
- info.push({
125
- type: 'manual-skill',
126
- skillPath: skillPath,
127
- message: `ℹ️ Manual skill: ${skillPath} (no auto-activation)`
128
- });
129
- }
130
- }
131
- }
132
-
133
- return { errors, warnings, info };
134
- }
135
-
136
- /**
137
- * Formata e exibe resultados
138
- */
139
- function displayResults(results, verbose) {
140
- const { errors, warnings, info } = results;
141
-
142
- log('\n╔════════════════════════════════════════════════════════════════╗', 'cyan');
143
- log('║ MORPH-SPEC AGENT-SKILL VALIDATION REPORT ║', 'cyan');
144
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
145
-
146
- // Erros
147
- if (errors.length > 0) {
148
- log('║ ERRORS ║', 'red');
149
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
150
-
151
- errors.forEach(err => {
152
- log(`║ ❌ ${err.message.substring(0, 61).padEnd(61)}║`, 'red');
153
- });
154
-
155
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
156
- }
157
-
158
- // Warnings
159
- if (warnings.length > 0) {
160
- log('║ WARNINGS ║', 'yellow');
161
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
162
-
163
- warnings.forEach(warn => {
164
- // Quebrar mensagens longas
165
- const lines = warn.message.match(/.{1,60}/g) || [warn.message];
166
- lines.forEach((line, idx) => {
167
- if (idx === 0) {
168
- log(`║ ⚠️ ${line.padEnd(61)}║`, 'yellow');
169
- } else {
170
- log(`║ ${line.padEnd(61)}║`, 'yellow');
171
- }
172
- });
173
- });
174
-
175
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
176
- }
177
-
178
- // Info (verbose mode)
179
- if (verbose && info.length > 0) {
180
- log('║ VALID MAPPINGS ║', 'green');
181
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
182
-
183
- info.forEach(item => {
184
- log(`║ ${item.message.substring(0, 62).padEnd(62)}║`, 'gray');
185
- });
186
-
187
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
188
- }
189
-
190
- // Summary
191
- log('║ SUMMARY ║', 'cyan');
192
- log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
193
- log(`║ Errors: ${errors.length.toString().padEnd(56)}║`, errors.length > 0 ? 'red' : 'green');
194
- log(`║ Warnings: ${warnings.length.toString().padEnd(54)}║`, warnings.length > 0 ? 'yellow' : 'green');
195
-
196
- if (errors.length === 0 && warnings.length === 0) {
197
- log('║ ║', 'cyan');
198
- log('║ ✅ All agents and skills are properly mapped! ║', 'green');
199
- }
200
-
201
- // Nota sobre manual skills
202
- const manualSkills = info.filter(i => i.type === 'manual-skill').length;
203
- if (manualSkills > 0 && verbose) {
204
- log('║ ║', 'cyan');
205
- log(`║ ℹ️ ${manualSkills} manual-only skills found (use --verbose to see) ║`, 'gray');
206
- log('║ These are extra skills without auto-activation. ║', 'gray');
207
- }
208
-
209
- log('╚════════════════════════════════════════════════════════════════╝\n', 'cyan');
210
- }
211
-
212
- // ============================================================================
213
- // MAIN
214
- // ============================================================================
215
-
216
- function main() {
217
- const args = process.argv.slice(2);
218
- const verbose = args.includes('--verbose') || args.includes('-v');
219
- const hasHelp = args.includes('--help') || args.includes('-h');
220
-
221
- if (hasHelp) {
222
- log('\nMORPH-SPEC Agent-Skill Validator', 'bright');
223
- log('\nUsage:', 'cyan');
224
- log(' node bin/validate-agents-skills.js [options]', 'gray');
225
- log('\nOptions:', 'cyan');
226
- log(' -v, --verbose Show all valid mappings', 'gray');
227
- log(' -h, --help Show this help', 'gray');
228
- log('\nDescription:', 'cyan');
229
- log(' Validates consistency between agents.json and skill files.', 'gray');
230
- log(' - Checks if all skillPaths exist', 'gray');
231
- log(' - Detects orphan skills (no corresponding agent)', 'gray');
232
- log(' - Exit code 0 if valid, 1 if errors found\n', 'gray');
233
- process.exit(0);
234
- }
235
-
236
- // Load config and validate
237
- const config = loadAgentsConfig();
238
- const results = validateAgentsSkills(config, verbose);
239
-
240
- // Display results
241
- displayResults(results, verbose);
242
-
243
- // Exit with appropriate code
244
- if (results.errors.length > 0) {
245
- process.exit(1);
246
- }
247
-
248
- process.exit(0);
249
- }
250
-
251
- main();
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MORPH-SPEC Agent-Skill Validator
5
+ *
6
+ * Valida a consistência entre agents.json e arquivos de skills.
7
+ * Garante que não há agentes sem skills ou skills sem agentes (orphans).
8
+ *
9
+ * Uso:
10
+ * node bin/validate-agents-skills.js
11
+ * node bin/validate-agents-skills.js --verbose
12
+ */
13
+
14
+ import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
15
+ import { join, dirname } from 'path';
16
+ import { fileURLToPath } from 'url';
17
+ import { resolveAgentsConfigPath, resolveStackPath } from '../src/lib/stack-resolver.js';
18
+
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const frameworkRoot = join(__dirname, '..');
21
+ const AGENTS_CONFIG_PATH = resolveAgentsConfigPath(frameworkRoot);
22
+ const SKILLS_BASE_PATH = join(resolveStackPath(frameworkRoot), '.claude/skills');
23
+
24
+ // Cores para output
25
+ const colors = {
26
+ reset: '\x1b[0m',
27
+ bright: '\x1b[1m',
28
+ green: '\x1b[32m',
29
+ yellow: '\x1b[33m',
30
+ red: '\x1b[31m',
31
+ cyan: '\x1b[36m',
32
+ gray: '\x1b[90m'
33
+ };
34
+
35
+ function log(message, color = 'reset') {
36
+ console.log(`${colors[color]}${message}${colors.reset}`);
37
+ }
38
+
39
+ /**
40
+ * Carrega agents.json
41
+ */
42
+ function loadAgentsConfig() {
43
+ try {
44
+ const content = readFileSync(AGENTS_CONFIG_PATH, 'utf8');
45
+ return JSON.parse(content);
46
+ } catch (err) {
47
+ log(`ERROR: Failed to load agents.json: ${err.message}`, 'red');
48
+ process.exit(1);
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Recursivamente lista todos os arquivos .md no diretório de skills
54
+ */
55
+ function getAllSkillFiles(dir, fileList = []) {
56
+ const files = readdirSync(dir);
57
+
58
+ files.forEach(file => {
59
+ const filePath = join(dir, file);
60
+ const stat = statSync(filePath);
61
+
62
+ if (stat.isDirectory()) {
63
+ getAllSkillFiles(filePath, fileList);
64
+ } else if (file.endsWith('.md')) {
65
+ // Converter para path relativo ao stacks/blazor-azure/
66
+ const stackPath = resolveStackPath(frameworkRoot).replace(/\\/g, '/');
67
+ const normalizedFile = filePath.replace(/\\/g, '/');
68
+ const relativePath = normalizedFile.startsWith(stackPath)
69
+ ? normalizedFile.slice(stackPath.length + 1)
70
+ : normalizedFile;
71
+ fileList.push(relativePath);
72
+ }
73
+ });
74
+
75
+ return fileList;
76
+ }
77
+
78
+ /**
79
+ * Valida agents vs skills
80
+ */
81
+ function validateAgentsSkills(config, verbose = false) {
82
+ const errors = [];
83
+ const warnings = [];
84
+ const info = [];
85
+
86
+ // 1. Coletar todos os agentes e seus skillPaths
87
+ const allAgents = [...config.agents.core, ...config.agents.specialists];
88
+ const agentSkillPaths = new Set();
89
+
90
+ for (const agent of allAgents) {
91
+ if (agent.skillPath) {
92
+ agentSkillPaths.add(agent.skillPath);
93
+
94
+ // Verificar se skill file existe
95
+ const skillFilePath = join(__dirname, '../content', agent.skillPath);
96
+ if (!existsSync(skillFilePath)) {
97
+ errors.push({
98
+ type: 'missing-skill',
99
+ agent: agent.id,
100
+ skillPath: agent.skillPath,
101
+ message: `Agent '${agent.id}' references non-existent skill: ${agent.skillPath}`
102
+ });
103
+ } else if (verbose) {
104
+ info.push({
105
+ type: 'valid-mapping',
106
+ agent: agent.id,
107
+ skillPath: agent.skillPath,
108
+ message: `✓ ${agent.id} → ${agent.skillPath}`
109
+ });
110
+ }
111
+ } else if (verbose) {
112
+ warnings.push({
113
+ type: 'no-skill',
114
+ agent: agent.id,
115
+ message: `Agent '${agent.id}' has no skillPath defined (metadata-only agent)`
116
+ });
117
+ }
118
+ }
119
+
120
+ // 2. Verificar skills órfãs (sem agente correspondente)
121
+ const allSkillFiles = getAllSkillFiles(SKILLS_BASE_PATH);
122
+
123
+ for (const skillFile of allSkillFiles) {
124
+ const skillPath = `.claude/skills/${skillFile.replace('.claude/skills/', '')}`;
125
+
126
+ if (!agentSkillPaths.has(skillPath)) {
127
+ // Orphan skills são OK - podem ser usados manualmente
128
+ // Apenas reportar em verbose mode
129
+ if (verbose) {
130
+ info.push({
131
+ type: 'manual-skill',
132
+ skillPath: skillPath,
133
+ message: `ℹ️ Manual skill: ${skillPath} (no auto-activation)`
134
+ });
135
+ }
136
+ }
137
+ }
138
+
139
+ return { errors, warnings, info };
140
+ }
141
+
142
+ /**
143
+ * Formata e exibe resultados
144
+ */
145
+ function displayResults(results, verbose) {
146
+ const { errors, warnings, info } = results;
147
+
148
+ log('\n╔════════════════════════════════════════════════════════════════╗', 'cyan');
149
+ log('║ MORPH-SPEC AGENT-SKILL VALIDATION REPORT ║', 'cyan');
150
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
151
+
152
+ // Erros
153
+ if (errors.length > 0) {
154
+ log('║ ERRORS ║', 'red');
155
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
156
+
157
+ errors.forEach(err => {
158
+ log(`║ ❌ ${err.message.substring(0, 61).padEnd(61)}║`, 'red');
159
+ });
160
+
161
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
162
+ }
163
+
164
+ // Warnings
165
+ if (warnings.length > 0) {
166
+ log('║ WARNINGS ║', 'yellow');
167
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
168
+
169
+ warnings.forEach(warn => {
170
+ // Quebrar mensagens longas
171
+ const lines = warn.message.match(/.{1,60}/g) || [warn.message];
172
+ lines.forEach((line, idx) => {
173
+ if (idx === 0) {
174
+ log(`║ ⚠️ ${line.padEnd(61)}║`, 'yellow');
175
+ } else {
176
+ log(`║ ${line.padEnd(61)}║`, 'yellow');
177
+ }
178
+ });
179
+ });
180
+
181
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
182
+ }
183
+
184
+ // Info (verbose mode)
185
+ if (verbose && info.length > 0) {
186
+ log('║ VALID MAPPINGS ║', 'green');
187
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
188
+
189
+ info.forEach(item => {
190
+ log(`║ ${item.message.substring(0, 62).padEnd(62)}║`, 'gray');
191
+ });
192
+
193
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
194
+ }
195
+
196
+ // Summary
197
+ log('║ SUMMARY ║', 'cyan');
198
+ log('╠════════════════════════════════════════════════════════════════╣', 'cyan');
199
+ log(`║ Errors: ${errors.length.toString().padEnd(56)}║`, errors.length > 0 ? 'red' : 'green');
200
+ log(`║ Warnings: ${warnings.length.toString().padEnd(54)}║`, warnings.length > 0 ? 'yellow' : 'green');
201
+
202
+ if (errors.length === 0 && warnings.length === 0) {
203
+ log('║ ║', 'cyan');
204
+ log('║ ✅ All agents and skills are properly mapped! ║', 'green');
205
+ }
206
+
207
+ // Nota sobre manual skills
208
+ const manualSkills = info.filter(i => i.type === 'manual-skill').length;
209
+ if (manualSkills > 0 && verbose) {
210
+ log('║ ║', 'cyan');
211
+ log(`║ ℹ️ ${manualSkills} manual-only skills found (use --verbose to see) ║`, 'gray');
212
+ log('║ These are extra skills without auto-activation. ║', 'gray');
213
+ }
214
+
215
+ log('╚════════════════════════════════════════════════════════════════╝\n', 'cyan');
216
+ }
217
+
218
+ // ============================================================================
219
+ // MAIN
220
+ // ============================================================================
221
+
222
+ function main() {
223
+ const args = process.argv.slice(2);
224
+ const verbose = args.includes('--verbose') || args.includes('-v');
225
+ const hasHelp = args.includes('--help') || args.includes('-h');
226
+
227
+ if (hasHelp) {
228
+ log('\nMORPH-SPEC Agent-Skill Validator', 'bright');
229
+ log('\nUsage:', 'cyan');
230
+ log(' node bin/validate-agents-skills.js [options]', 'gray');
231
+ log('\nOptions:', 'cyan');
232
+ log(' -v, --verbose Show all valid mappings', 'gray');
233
+ log(' -h, --help Show this help', 'gray');
234
+ log('\nDescription:', 'cyan');
235
+ log(' Validates consistency between agents.json and skill files.', 'gray');
236
+ log(' - Checks if all skillPaths exist', 'gray');
237
+ log(' - Detects orphan skills (no corresponding agent)', 'gray');
238
+ log(' - Exit code 0 if valid, 1 if errors found\n', 'gray');
239
+ process.exit(0);
240
+ }
241
+
242
+ // Load config and validate
243
+ const config = loadAgentsConfig();
244
+ const results = validateAgentsSkills(config, verbose);
245
+
246
+ // Display results
247
+ displayResults(results, verbose);
248
+
249
+ // Exit with appropriate code
250
+ if (results.errors.length > 0) {
251
+ process.exit(1);
252
+ }
253
+
254
+ process.exit(0);
255
+ }
256
+
257
+ main();