@polymorphism-tech/morph-spec 9.0.0 โ†’ 9.2.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 (345) hide show
  1. package/CLAUDE.md +8 -9
  2. package/README.md +38 -36
  3. package/bin/morph-spec.js +11 -63
  4. package/bin/validate.js +1 -39
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +1 -1
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/CLAUDE.md +2 -1
  9. package/framework/MORPH.md +3 -3
  10. package/framework/agents.json +19 -11
  11. package/framework/commands/morph-apply.md +1 -1
  12. package/framework/commands/morph-status.md +1 -1
  13. package/framework/docs/CLI.md +22 -31
  14. package/framework/evals/review-checklist.md +12 -2
  15. package/framework/hooks/README.md +8 -44
  16. package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
  17. package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
  18. package/framework/hooks/claude-code/core/chain.js +4 -65
  19. package/framework/hooks/claude-code/core/comment-guard.js +2 -16
  20. package/framework/hooks/claude-code/core/enforce-phase-writes.js +6 -50
  21. package/framework/hooks/claude-code/core/gate-guard.js +7 -67
  22. package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
  23. package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
  24. package/framework/hooks/claude-code/core/heavy-release.js +2 -13
  25. package/framework/hooks/claude-code/core/loop-detect.js +2 -31
  26. package/framework/hooks/claude-code/core/pre-bash-denylist.js +0 -4
  27. package/framework/hooks/claude-code/core/protect-spec-files.js +7 -67
  28. package/framework/hooks/claude-code/core/state-sync.js +12 -68
  29. package/framework/hooks/claude-code/core/telemetry-log.js +12 -93
  30. package/framework/hooks/claude-code/core/validate-completion.js +11 -57
  31. package/framework/hooks/claude-code/core/warn-bash-source-write.js +1 -9
  32. package/framework/hooks/claude-code/core/worktree-context.js +10 -110
  33. package/framework/hooks/claude-code/core/worktree-create.js +6 -70
  34. package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
  35. package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
  36. package/framework/hooks/claude-code/statusline.sh +11 -11
  37. package/framework/hooks/shared/activity-logger.js +9 -89
  38. package/framework/hooks/shared/agent-reap.js +2 -17
  39. package/framework/hooks/shared/build-check.js +6 -75
  40. package/framework/hooks/shared/claim-registry.js +9 -119
  41. package/framework/hooks/shared/command-tokens.js +6 -51
  42. package/framework/hooks/shared/comment-rules.js +5 -20
  43. package/framework/hooks/shared/comment-scanner.js +6 -25
  44. package/framework/hooks/shared/comment-stripper.js +11 -85
  45. package/framework/hooks/shared/e2e-check.js +0 -0
  46. package/framework/hooks/shared/errata.js +2 -15
  47. package/framework/hooks/shared/feature-locator.js +11 -95
  48. package/framework/hooks/shared/frontend-locations.js +1 -3
  49. package/framework/hooks/shared/gate-question.js +1 -7
  50. package/framework/hooks/shared/git-exclude.js +3 -20
  51. package/framework/hooks/shared/git-paths.js +8 -104
  52. package/framework/hooks/shared/graph-freshness.js +22 -166
  53. package/framework/hooks/shared/graph-refresh.js +21 -149
  54. package/framework/hooks/shared/heavy-command.js +4 -12
  55. package/framework/hooks/shared/hook-response.js +8 -83
  56. package/framework/hooks/shared/morph-cli.js +8 -52
  57. package/framework/hooks/shared/payload-utils.js +10 -132
  58. package/framework/hooks/shared/phase-utils.js +1 -42
  59. package/framework/hooks/shared/redact-secrets.js +4 -15
  60. package/framework/hooks/shared/reparse-scan.js +6 -66
  61. package/framework/hooks/shared/slice-progress.js +4 -23
  62. package/framework/hooks/shared/source-files.js +4 -17
  63. package/framework/hooks/shared/state-reader.js +13 -183
  64. package/framework/hooks/shared/state-writer.js +8 -52
  65. package/framework/hooks/shared/stdin-reader.js +1 -11
  66. package/framework/hooks/shared/telemetry-logger.js +7 -67
  67. package/framework/hooks/shared/transcript-usage.js +7 -29
  68. package/framework/hooks/shared/worktree-root.js +7 -29
  69. package/framework/rules/csharp-standards.md +1 -1
  70. package/framework/rules/frontend-standards.md +1 -0
  71. package/framework/rules/hangfire-standards.md +1 -1
  72. package/framework/rules/neon-standards.md +1 -1
  73. package/framework/rules/nextjs-standards.md +1 -1
  74. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  75. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  76. package/framework/skills/core/morph-apply/SKILL.md +4 -4
  77. package/framework/skills/core/morph-hotfix/SKILL.md +3 -3
  78. package/framework/skills/core/morph-machine/SKILL.md +1 -1
  79. package/framework/skills/core/morph-media/SKILL.md +1 -1
  80. package/framework/skills/core/morph-plan/SKILL.md +9 -7
  81. package/framework/skills/core/morph-review/SKILL.md +9 -6
  82. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  83. package/framework/skills/core/morph-uiux/SKILL.md +29 -12
  84. package/framework/standards/STANDARDS.json +36 -14
  85. package/framework/standards/STANDARDS.meta.json +16 -2
  86. package/framework/standards/ai-agents/agent-archetypes.md +2 -2
  87. package/framework/standards/ai-agents/agent-session.md +1 -1
  88. package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
  89. package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
  90. package/framework/standards/ai-agents/guardrails.md +1 -1
  91. package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
  92. package/framework/standards/ai-agents/observability-patterns.md +1 -1
  93. package/framework/standards/ai-agents/production.md +1 -1
  94. package/framework/standards/ai-agents/prompt-sources.md +2 -2
  95. package/framework/standards/ai-agents/providers/model-registry.md +1 -1
  96. package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
  97. package/framework/standards/ai-agents/setup.md +2 -2
  98. package/framework/standards/ai-agents/sweet-spot.md +2 -2
  99. package/framework/standards/ai-agents/tool-adapters.md +0 -2
  100. package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
  101. package/framework/standards/ai-agents/workflows.md +1 -1
  102. package/framework/standards/architecture/code-comments.md +1 -1
  103. package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
  104. package/framework/standards/backend/api/validation.md +1 -1
  105. package/framework/standards/backend/dotnet/testing.md +10 -4
  106. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
  107. package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
  108. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
  109. package/framework/standards/data/nosql/cache/redis.md +1 -1
  110. package/framework/standards/data/nosql/cosmos-db.md +3 -3
  111. package/framework/standards/frontend/admin-app/forms.md +1 -1
  112. package/framework/standards/frontend/design-system/art-direction.md +88 -0
  113. package/framework/standards/frontend/design-system/premium-finish.md +77 -2
  114. package/framework/standards/frontend/nextjs/testing.md +10 -6
  115. package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
  116. package/framework/templates/.idea/morph-templates.xml +92 -0
  117. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  118. package/framework/templates/CLAUDE.md.core.template +3 -3
  119. package/framework/templates/IDE-SNIPPETS.md +262 -262
  120. package/framework/templates/REGISTRY.json +9 -9
  121. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  122. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  123. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  124. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  125. package/framework/templates/docs/plan.md +3 -1
  126. package/framework/templates/docs/ui-mockups.md +4 -0
  127. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  128. package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
  129. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  130. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  131. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  132. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  133. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  134. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  135. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  136. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  137. package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
  138. package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
  139. package/framework/templates/state.template.json +17 -17
  140. package/framework/templates/ui/design-system.css +226 -226
  141. package/package.json +1 -1
  142. package/src/commands/context/context-refresh.js +0 -16
  143. package/src/commands/dashboard/dashboard.js +2 -8
  144. package/src/commands/e2e/e2e.js +17 -104
  145. package/src/commands/graph/affected.js +0 -14
  146. package/src/commands/graph/build.js +11 -50
  147. package/src/commands/graph/explain.js +0 -16
  148. package/src/commands/graph/status.js +1 -12
  149. package/src/commands/mcp/mcp-setup.js +4 -62
  150. package/src/commands/observability/cost.js +5 -57
  151. package/src/commands/observability/telemetry.js +1 -14
  152. package/src/commands/project/branch.js +4 -45
  153. package/src/commands/project/claim.js +4 -48
  154. package/src/commands/project/doctor.js +48 -302
  155. package/src/commands/project/env.js +1 -27
  156. package/src/commands/project/fleet.js +3 -32
  157. package/src/commands/project/init.js +4 -68
  158. package/src/commands/project/install-plugin-cmd.js +0 -1
  159. package/src/commands/project/standards.js +1 -62
  160. package/src/commands/project/status.js +0 -53
  161. package/src/commands/project/update.js +31 -239
  162. package/src/commands/project/worktree.js +108 -882
  163. package/src/commands/scaffold/scaffold.js +0 -25
  164. package/src/commands/state/advance.js +14 -85
  165. package/src/commands/state/approve.js +15 -97
  166. package/src/commands/state/archive.js +12 -64
  167. package/src/commands/state/auto-approval.js +2 -5
  168. package/src/commands/state/create.js +22 -109
  169. package/src/commands/state/delete.js +11 -63
  170. package/src/commands/state/finish.js +98 -475
  171. package/src/commands/state/gate-check.js +22 -132
  172. package/src/commands/state/gate-decision.js +3 -39
  173. package/src/commands/state/handoff.js +3 -30
  174. package/src/commands/state/list.js +14 -84
  175. package/src/commands/state/report-check.js +8 -58
  176. package/src/commands/state/retype.js +4 -26
  177. package/src/commands/validation/index.js +0 -3
  178. package/src/commands/validation/mutate.js +11 -11
  179. package/src/commands/validation/plan-check.js +4 -2
  180. package/src/commands/validation/tests-audit.js +7 -0
  181. package/src/commands/validation/validate-feature.js +10 -97
  182. package/src/commands/validation/verify.js +30 -113
  183. package/src/core/paths/output-schema.js +2 -101
  184. package/src/core/state/feature-identity.js +1 -25
  185. package/src/core/state/gate-order.js +0 -27
  186. package/src/core/state/lifecycle-audit.js +8 -100
  187. package/src/core/state/state-manager.js +22 -304
  188. package/src/core/templates/template-registry.js +2 -97
  189. package/src/core/templates/template-renderer.js +13 -93
  190. package/src/core/templates/template-seed.js +0 -1
  191. package/src/core/work-types.js +1 -36
  192. package/src/dashboard/app/App.jsx +1 -8
  193. package/src/dashboard/app/components/ActivityFeed.jsx +0 -5
  194. package/src/dashboard/app/components/CommandPalette.jsx +0 -7
  195. package/src/dashboard/app/components/DetailPanel.jsx +1 -5
  196. package/src/dashboard/app/components/EntityLink.jsx +0 -12
  197. package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
  198. package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
  199. package/src/dashboard/app/components/Markdown.jsx +0 -9
  200. package/src/dashboard/app/components/PhaseRail.jsx +0 -11
  201. package/src/dashboard/app/components/SearchFilter.jsx +0 -4
  202. package/src/dashboard/app/components/Sidebar.jsx +0 -5
  203. package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
  204. package/src/dashboard/app/hooks/usePref.js +1 -5
  205. package/src/dashboard/app/lib/format.js +0 -2
  206. package/src/dashboard/app/lib/phases.js +1 -5
  207. package/src/dashboard/app/lib/project.js +0 -12
  208. package/src/dashboard/app/main.jsx +13 -13
  209. package/src/dashboard/app/pages/AgentMap.jsx +1 -8
  210. package/src/dashboard/app/pages/FeatureDetail.jsx +1 -5
  211. package/src/dashboard/app/pages/Features.jsx +1 -8
  212. package/src/dashboard/app/pages/Guide.jsx +0 -1
  213. package/src/dashboard/app/pages/HookInspector.jsx +2 -23
  214. package/src/dashboard/app/pages/PhasePipeline.jsx +0 -3
  215. package/src/dashboard/app/pages/Portfolio.jsx +0 -1
  216. package/src/dashboard/app/pages/RulesMap.jsx +1 -16
  217. package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
  218. package/src/dashboard/app/pages/Standards.jsx +2 -17
  219. package/src/dashboard/scanner/activity-scanner.js +10 -69
  220. package/src/dashboard/scanner/agents-scanner.js +1 -23
  221. package/src/dashboard/scanner/docs-scanner.js +0 -6
  222. package/src/dashboard/scanner/feature-status.js +2 -5
  223. package/src/dashboard/scanner/features-scanner.js +10 -66
  224. package/src/dashboard/scanner/hooks-scanner.js +5 -28
  225. package/src/dashboard/scanner/index.js +0 -4
  226. package/src/dashboard/scanner/portfolio.js +5 -29
  227. package/src/dashboard/scanner/project-api.js +8 -54
  228. package/src/dashboard/scanner/rules-scanner.js +1 -2
  229. package/src/dashboard/scanner/skills-scanner.js +2 -12
  230. package/src/dashboard/scanner/standards-scanner.js +2 -6
  231. package/src/dashboard/vite-plugin-morph-data.js +5 -19
  232. package/src/dashboard/vite.config.js +24 -24
  233. package/src/lib/ai/ai-checks.js +7 -52
  234. package/src/lib/ai/ai-project-scan.js +14 -108
  235. package/src/lib/ai/code-audit.js +7 -63
  236. package/src/lib/ai/pin-drift.js +8 -51
  237. package/src/lib/ai/registry-audit.js +11 -90
  238. package/src/lib/ci/ci-verify.js +4 -19
  239. package/src/lib/ci/github-ci.js +9 -37
  240. package/src/lib/ci/workflow-scaffold.js +14 -10
  241. package/src/lib/detectors/claude-config-detector.js +13 -74
  242. package/src/lib/detectors/index.js +4 -50
  243. package/src/lib/e2e/applicability.js +37 -0
  244. package/src/lib/e2e/compose-env.js +5 -66
  245. package/src/lib/e2e/stack-teardown.js +6 -40
  246. package/src/lib/generators/architecture-scanner.js +18 -156
  247. package/src/lib/generators/handoff-generator.js +9 -53
  248. package/src/lib/generators/scaffold-generator.js +5 -101
  249. package/src/lib/generators/settings-generator.js +4 -37
  250. package/src/lib/git/branch-classifier.js +11 -84
  251. package/src/lib/git/default-branch.js +14 -169
  252. package/src/lib/git/evidence-staleness.js +1 -0
  253. package/src/lib/git/gh.js +2 -17
  254. package/src/lib/git/pending-prs.js +6 -37
  255. package/src/lib/git/pr-files.js +3 -28
  256. package/src/lib/git/pr-index.js +3 -34
  257. package/src/lib/git/tree-fingerprint.js +3 -15
  258. package/src/lib/git/tree-state.js +6 -33
  259. package/src/lib/graph/god-nodes.js +2 -22
  260. package/src/lib/graph/graph-health.js +3 -24
  261. package/src/lib/graph/graph-loader.js +5 -56
  262. package/src/lib/graph/graphify-runtime.js +7 -37
  263. package/src/lib/graph/graphifyignore.js +8 -74
  264. package/src/lib/graph/sanitize.js +16 -136
  265. package/src/lib/heavy/cleanup.js +1 -1
  266. package/src/lib/installers/effects.js +8 -93
  267. package/src/lib/installers/mcp-installer.js +9 -169
  268. package/src/lib/installers/memory-installer.js +4 -27
  269. package/src/lib/installers/templates-reconcile.js +5 -60
  270. package/src/lib/mutation/adapters.js +6 -17
  271. package/src/lib/mutation/dotnet-introspection.js +20 -106
  272. package/src/lib/mutation/runner.js +23 -75
  273. package/src/lib/mutation/subset.js +1 -4
  274. package/src/lib/mutation/trx.js +0 -1
  275. package/src/lib/plan/artifact-vocabulary.js +5 -25
  276. package/src/lib/plan/checks.js +34 -33
  277. package/src/lib/plan/plan-parser.js +7 -8
  278. package/src/lib/projects/registry.js +7 -44
  279. package/src/lib/review-reports.js +11 -26
  280. package/src/lib/risk-detector.js +41 -173
  281. package/src/lib/specs/adr-index.js +6 -34
  282. package/src/lib/specs/frontmatter.js +2 -15
  283. package/src/lib/specs/gfm-table.js +1 -7
  284. package/src/lib/specs/revocations.js +1 -14
  285. package/src/lib/specs/screen-checklist.js +47 -124
  286. package/src/lib/stack/dotnet-build-ignores.js +2 -6
  287. package/src/lib/stack/stack-profile.js +1 -28
  288. package/src/lib/stack/stack-scan.js +1 -8
  289. package/src/lib/stack-filter.js +4 -27
  290. package/src/lib/standards/registry.js +1 -7
  291. package/src/lib/standards/sections.js +2 -13
  292. package/src/lib/standards/verified-against.js +19 -191
  293. package/src/lib/tasks/eval-node.js +21 -169
  294. package/src/lib/tasks/linux-runner.js +18 -142
  295. package/src/lib/tasks/test-nodes.js +43 -240
  296. package/src/lib/tasks/test-runner.js +43 -341
  297. package/src/lib/telemetry/metrics.js +7 -36
  298. package/src/lib/telemetry/telemetry-reader.js +13 -125
  299. package/src/lib/telemetry/verify-event.js +2 -30
  300. package/src/lib/tests-audit/audit.js +96 -0
  301. package/src/lib/validators/code-budget/code-budget-validator.js +4 -44
  302. package/src/lib/validators/code-budget/index.js +0 -7
  303. package/src/lib/validators/contracts/contract-compliance-validator.js +2 -24
  304. package/src/lib/validators/contracts/index.js +0 -6
  305. package/src/lib/validators/nextjs/index.js +0 -5
  306. package/src/lib/validators/nextjs/next-component-validator.js +4 -81
  307. package/src/lib/validators/packages/index.js +0 -6
  308. package/src/lib/validators/packages/package-validator.js +6 -56
  309. package/src/lib/validators/reuse/index.js +0 -8
  310. package/src/lib/validators/reuse/reuse-validator.js +11 -101
  311. package/src/lib/validators/reuse/symbol-scanner.js +6 -62
  312. package/src/lib/validators/traceability-check.js +5 -63
  313. package/src/lib/validators/validation-runner.js +21 -158
  314. package/src/lib/validators/verify-runner.js +85 -376
  315. package/src/lib/work-type-detector.js +5 -67
  316. package/src/lib/worktree/docker-audit.js +17 -136
  317. package/src/lib/worktree/env-allocator.js +10 -98
  318. package/src/lib/worktree/feature-truth.js +12 -115
  319. package/src/lib/worktree/finish-backup.js +32 -242
  320. package/src/lib/worktree/fleet-scanner.js +13 -95
  321. package/src/lib/worktree/ignored-triage.js +15 -91
  322. package/src/lib/worktree/vscode-settings.js +2 -3
  323. package/src/lib/worktree/worktree-audit.js +21 -213
  324. package/src/lib/worktree/worktree-include.js +3 -5
  325. package/src/scripts/global-install.js +3 -9
  326. package/src/scripts/install-plugin.js +1 -13
  327. package/src/scripts/setup-infra.js +17 -147
  328. package/src/utils/agents-installer.js +29 -276
  329. package/src/utils/banner.js +4 -25
  330. package/src/utils/claude-md-injector.js +1 -37
  331. package/src/utils/claude-settings-manager.js +1 -52
  332. package/src/utils/file-copier.js +11 -95
  333. package/src/utils/hooks-installer.js +21 -298
  334. package/src/utils/skills-installer.js +4 -101
  335. package/src/utils/version-checker.js +4 -83
  336. package/framework/commands/morph-proposal.md +0 -9
  337. package/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
  338. package/framework/hooks/git/pre-commit/agents.sh +0 -25
  339. package/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
  340. package/framework/hooks/git/pre-push/run-tests.sh +0 -44
  341. package/src/commands/utils/index.js +0 -3
  342. package/src/lib/detectors/design-system-detector.js +0 -188
  343. package/src/lib/generators/design-system-generator.js +0 -508
  344. package/src/lib/specs/old-format.js +0 -68
  345. package/src/utils/agent-id-mapper.js +0 -11
@@ -1,18 +1,3 @@
1
- /**
2
- * Skills Installer
3
- *
4
- * Copies framework skills to .claude/skills/ during morph-spec init.
5
- * Installs only the `core/` skill set โ€” the canonical NLH skills referenced by
6
- * MORPH.md (morph-plan, morph-uiux, morph-apply, morph-review, morph-standardsโ€ฆ). The 3-tier system was collapsed
7
- * into a single source of truth in framework/skills/core/.
8
- *
9
- * Source skills are directory-based: framework/skills/core/{skill-name}/SKILL.md
10
- * (plus optional scripts/, references/, assets/ subdirectories).
11
- *
12
- * Directory-based skills have their entire directory copied so Claude Code can
13
- * execute scripts and load references on demand.
14
- */
15
-
16
1
  import { existsSync, readdirSync, statSync, readFileSync } from 'fs';
17
2
  import { basename, join } from 'path';
18
3
  import { fileURLToPath } from 'url';
@@ -22,59 +7,16 @@ import { realEffects } from '../lib/installers/effects.js';
22
7
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
23
8
  const FRAMEWORK_SKILLS_DIR = join(__dirname, '..', '..', 'framework', 'skills');
24
9
 
25
- /**
26
- * Skill levels to install in .claude/skills/.
27
- * Only `core/` survives โ€” single source of truth aligned with MORPH.md.
28
- */
29
10
  const SKILL_LEVELS_TO_INSTALL = ['core'];
30
11
 
31
- /**
32
- * Check if a skill should be installed based on its stacks: frontmatter.
33
- * @param {string} skillContent - Raw SKILL.md content
34
- * @param {string[]} projectTags - Stack tags from config
35
- * @returns {boolean}
36
- */
37
12
  export function shouldInstallSkill(skillContent, projectTags) {
38
13
  return shouldInstall(parseStacks(skillContent), projectTags);
39
14
  }
40
15
 
41
- /**
42
- * Copy a skill directory tree from src to dest, skipping README.md files.
43
- *
44
- * UM efeito por skill (nรฃo um por arquivo): รฉ assim que o instalador pensa
45
- * ("instalar a skill X"), e รฉ o que o relatรณrio do `--dry-run` precisa dizer.
46
- *
47
- * @param {string} src - Source directory path
48
- * @param {string} dest - Destination directory path
49
- * @param {ReturnType<import('../lib/installers/effects.js').createEffects>} fx
50
- */
51
16
  function copySkillDirectory(src, dest, fx) {
52
17
  fx.copyDir(src, dest, { filter: (from) => basename(from) !== 'README.md' });
53
18
  }
54
19
 
55
- /**
56
- * Walk srcDir and install skills into destDir.
57
- *
58
- * Handles two source formats:
59
- * 1. Directory-based skill: srcDir/{skill-name}/SKILL.md
60
- * โ†’ copies entire directory (SKILL.md + scripts/ + references/ + assets/)
61
- * โ†’ destDir/{skill-name}/
62
- *
63
- * 2. Flat .md skill (legacy): srcDir/{skill-name}.md
64
- * โ†’ destDir/{skill-name}/SKILL.md
65
- *
66
- * The `core/` level directory is traversed recursively. A directory is
67
- * recognized as a skill directory when it contains a SKILL.md file.
68
- *
69
- * @param {string} srcDir - Source directory to walk
70
- * @param {string} destDir - Destination base directory (.claude/skills/)
71
- * @param {string[]} projectTags - Stack tags from config
72
- * @param {Set<string>} installedNow - Accumulator: skill names this call
73
- * actually (re)installed. NOT derived by re-scanning destDir afterwards โ€”
74
- * a disk scan can't distinguish "installed this run" from "leftover from a
75
- * previous run with different projectTags", which is exactly the stale
76
- * entry a stack change needs cleaned up.
77
- */
78
20
  function installSkillsFromDir(srcDir, destDir, projectTags, installedNow, fx) {
79
21
  const entries = readdirSync(srcDir);
80
22
  for (const entry of entries) {
@@ -84,20 +26,15 @@ function installSkillsFromDir(srcDir, destDir, projectTags, installedNow, fx) {
84
26
  if (stat.isDirectory()) {
85
27
  const skillMdPath = join(srcPath, 'SKILL.md');
86
28
  if (existsSync(skillMdPath)) {
87
- // Directory-based skill โ€” check stack filter before copying.
88
- // O filtro รฉ PURO e continua sendo o รบnico: previsรฃo e execuรงรฃo
89
- // percorrem esta mesma linha.
90
29
  const content = readFileSync(skillMdPath, 'utf-8');
91
30
  if (!shouldInstallSkill(content, projectTags)) continue;
92
31
  const skillDestDir = join(destDir, entry);
93
32
  copySkillDirectory(srcPath, skillDestDir, fx);
94
33
  installedNow.add(entry);
95
34
  } else {
96
- // Level/category directory โ€” recurse
97
35
  installSkillsFromDir(srcPath, destDir, projectTags, installedNow, fx);
98
36
  }
99
37
  } else if (entry.endsWith('.md') && entry !== 'README.md') {
100
- // Legacy flat .md skill โ€” check stack filter before copying
101
38
  const content = readFileSync(srcPath, 'utf-8');
102
39
  if (!shouldInstallSkill(content, projectTags)) continue;
103
40
  const skillName = entry.slice(0, -3);
@@ -131,32 +68,12 @@ function collectNamesFromDir(dir, names) {
131
68
  }
132
69
  }
133
70
 
134
- /**
135
- * Install morph framework skills to .claude/skills/ in the target project.
136
- * Skills are copied into subdirectories as SKILL.md files so Claude Code can
137
- * discover them natively via /<skill-name> syntax (e.g., /phase-design,
138
- * /nextjs-expert). Directory-based skills also get their scripts/,
139
- * references/, and assets/ subdirectories copied for on-demand loading.
140
- *
141
- * Stack filtering: if projectTags is provided, only skills whose `stacks:`
142
- * frontmatter matches the project tags are installed. Skills without a
143
- * `stacks:` field are always installed (universal).
144
- *
145
- * @param {string} projectDir - Target project root directory
146
- * @param {Object} [options]
147
- * @param {string[]} [options.projectTags=[]] - Stack tags from config
148
- * @param {ReturnType<import('../lib/installers/effects.js').createEffects>} [options.fx]
149
- * Coletor de efeitos; o default executa e registra numa lista descartada.
150
- */
151
71
  export async function installSkills(projectDir, { projectTags = [], fx = realEffects() } = {}) {
152
72
  const claudeSkillsDir = join(projectDir, '.claude', 'skills');
153
73
  fx.ensureDir(claudeSkillsDir);
154
74
 
155
- // Skill names this call actually (re)installs, given projectTags. Tracked
156
- // as we go (NOT by re-scanning claudeSkillsDir afterwards) โ€” a disk scan
157
- // can't tell "installed this run" apart from "leftover from a previous
158
- // run with different projectTags", which is exactly the stale entry a
159
- // stack change (or a re-run that narrows the stack) needs cleaned up.
75
+ // Tracked as we go: a disk scan can't tell this run's installs from leftovers
76
+ // of a run with other projectTags, which a stack change must clean up.
160
77
  const installedNow = new Set();
161
78
  for (const level of SKILL_LEVELS_TO_INSTALL) {
162
79
  const levelDir = join(FRAMEWORK_SKILLS_DIR, level);
@@ -164,22 +81,8 @@ export async function installSkills(projectDir, { projectTags = [], fx = realEff
164
81
  installSkillsFromDir(levelDir, claudeSkillsDir, projectTags, installedNow, fx);
165
82
  }
166
83
 
167
- // Clean-slate: remove any skill dir that is a KNOWN framework skill (still
168
- // present in framework/skills/core/) but did NOT get (re)installed this
169
- // run โ€” i.e. it was filtered out by a `stacks:` mismatch (project.stack
170
- // changed, or a re-run narrowed the tags). Previously scoped to `morph-`
171
- // prefixed names only, which silently exempted every non-`morph-` skill
172
- // (the Umbraco pair) from ever being cleaned up: install once with
173
- // `umbraco` in the stack, drop the stack later, and they'd survive every
174
- // reinstall/update forever. Names outside allSourceSkills (user-added,
175
- // non-framework skills) are never touched.
176
- //
177
- // Em `dryRun` este laรงo NรƒO emite nada, e a razรฃo estรก na D6: numa execuรงรฃo
178
- // real do `update` ele sempre vรช um diretรณrio VAZIO, porque
179
- // `cleanFrameworkDirs()` acabou de apagar `.claude/skills/` inteiro. Num dry
180
- // ingรชnuo nada foi apagado, ele veria o diretรณrio POPULADO, e o relatรณrio
181
- // preveria remoรงรตes que a execuรงรฃo real nunca faz โ€” errado na direรงรฃo que
182
- // assusta o usuรกrio. O clean subsome este laรงo, provadamente.
84
+ // Removes known framework skills not reinstalled this run; user skills are never touched.
85
+ // Silent in dryRun: the real update's cleanFrameworkDirs() already emptied the dir.
183
86
  if (!fx.dryRun) {
184
87
  const allSourceSkills = collectSourceSkillNames();
185
88
  for (const entry of readdirSync(claudeSkillsDir)) {
@@ -6,10 +6,6 @@ import { realEffects } from '../lib/installers/effects.js';
6
6
 
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
8
 
9
- /**
10
- * Get the current CLI version from package.json
11
- * @returns {string} Version string (e.g., "1.0.4")
12
- */
13
9
  export function getInstalledCLIVersion() {
14
10
  try {
15
11
  const pkgPath = join(__dirname, '..', '..', 'package.json');
@@ -20,11 +16,6 @@ export function getInstalledCLIVersion() {
20
16
  }
21
17
  }
22
18
 
23
- /**
24
- * Get the latest version from npm registry
25
- * @param {string} packageName - The package name (default: @polymorphism-tech/morph-spec)
26
- * @returns {Promise<string|null>} Latest version or null if failed
27
- */
28
19
  export async function getLatestNPMVersion(packageName = '@polymorphism-tech/morph-spec') {
29
20
  try {
30
21
  const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
@@ -36,11 +27,6 @@ export async function getLatestNPMVersion(packageName = '@polymorphism-tech/morp
36
27
  }
37
28
  }
38
29
 
39
- /**
40
- * Get the MORPH version installed in the project
41
- * @param {string} projectPath - Path to the project
42
- * @returns {Promise<object|null>} Version info object or null if not found
43
- */
44
30
  export async function getProjectMorphVersion(projectPath) {
45
31
  try {
46
32
  const versionPath = join(projectPath, '.morph', '.morphversion');
@@ -53,12 +39,6 @@ export async function getProjectMorphVersion(projectPath) {
53
39
  }
54
40
  }
55
41
 
56
- /**
57
- * Save the MORPH version to the project
58
- * @param {string} projectPath - Path to the project
59
- * @param {string} version - Version to save
60
- * @returns {Promise<void>}
61
- */
62
42
  export async function saveProjectMorphVersion(projectPath, version, fx = realEffects()) {
63
43
  const versionPath = join(projectPath, '.morph', '.morphversion');
64
44
  const versionInfo = {
@@ -69,12 +49,7 @@ export async function saveProjectMorphVersion(projectPath, version, fx = realEff
69
49
  fx.writeJson(versionPath, versionInfo);
70
50
  }
71
51
 
72
- /**
73
- * Compare two semver versions
74
- * @param {string} v1 - First version
75
- * @param {string} v2 - Second version
76
- * @returns {number} -1 if v1 < v2, 0 if equal, 1 if v1 > v2
77
- */
52
+ /** @returns {number} -1 if v1 < v2, 0 if equal, 1 if v1 > v2 */
78
53
  export function compareVersions(v1, v2) {
79
54
  if (!v1 || !v2) return 0;
80
55
 
@@ -92,49 +67,17 @@ export function compareVersions(v1, v2) {
92
67
  return 0;
93
68
  }
94
69
 
95
- /**
96
- * Major de uma versรฃo, ou `null` quando a string nรฃo permite decidir.
97
- *
98
- * Vive aqui, ao lado de `compareVersions`, de propรณsito: uma segunda
99
- * aritmรฉtica de versรฃo noutro arquivo รฉ exatamente como duas verdades sobre a
100
- * mesma versรฃo nascem.
101
- *
102
- * @param {string|null|undefined} version
103
- * @returns {number|null}
104
- */
70
+ /** @returns {number|null} `null` when the string does not determine a major */
105
71
  export function majorOf(version) {
106
72
  if (typeof version !== 'string') return null;
107
73
  const m = /^\s*v?(\d+)\./.exec(version) ?? /^\s*v?(\d+)\s*$/.exec(version);
108
74
  return m ? Number(m[1]) : null;
109
75
  }
110
76
 
111
- /**
112
- * Limiar do freio: um salto de DOIS majors ou mais recusa sem `--force`.
113
- *
114
- * O limiar nรฃo รฉ "quantos majors dรก para pular com seguranรงa" โ€” รฉ "a partir de
115
- * onde o usuรกrio merece ler o relatรณrio antes". Medido: um projeto em 7.x indo
116
- * para 9.x recusa; um em 8.x atualiza sem atrito.
117
- */
118
77
  export const MAJOR_JUMP_LIMIT = 2;
119
78
 
120
- /**
121
- * Avalia o salto entre a versรฃo instalada no projeto e a versรฃo de destino.
122
- *
123
- * Trรชs resultados, e a diferenรงa entre eles รฉ o que a mensagem tem de dizer:
124
- *
125
- * - `reason: 'unknown-installed'` โ€” a versรฃo instalada รฉ indeterminรกvel.
126
- * Tratada como salto grande, com motivo PRร“PRIO: "nรฃo sei quรฃo velho isto รฉ"
127
- * รฉ precisamente quando sobrescrever ร s cegas รฉ mais perigoso, e tratรก-la
128
- * como zero seria a รบnica leitura que libera o pior caso.
129
- * - `reason: 'major-jump'` โ€” salto medido de `jump` majors, >= ao limiar.
130
- * - `reason: null` โ€” sem freio (mesmo major, um sรณ major de diferenรงa, ou
131
- * destino nรฃo superior ร  instalada).
132
- *
133
- * @param {string|null} installedVersion
134
- * @param {string|null} targetVersion
135
- * @param {{ limit?: number }} [options]
136
- * @returns {{ refuse: boolean, reason: 'unknown-installed'|'major-jump'|null, jump: number|null }}
137
- */
79
+ // An unreadable installed version refuses with its own reason: not knowing how old
80
+ // the project is is when a blind overwrite is most dangerous.
138
81
  export function majorJump(installedVersion, targetVersion, { limit = MAJOR_JUMP_LIMIT } = {}) {
139
82
  const installedMajor = majorOf(installedVersion);
140
83
  const targetMajor = majorOf(targetVersion);
@@ -143,8 +86,6 @@ export function majorJump(installedVersion, targetVersion, { limit = MAJOR_JUMP_
143
86
  return { refuse: true, reason: 'unknown-installed', jump: null };
144
87
  }
145
88
  if (targetMajor === null) {
146
- // Sem destino legรญvel nรฃo hรก salto a medir โ€” e inventar um seria decidir
147
- // por um nรบmero que ninguรฉm mantรฉm.
148
89
  return { refuse: false, reason: null, jump: null };
149
90
  }
150
91
  if (compareVersions(installedVersion, targetVersion) >= 0) {
@@ -156,17 +97,11 @@ export function majorJump(installedVersion, targetVersion, { limit = MAJOR_JUMP_
156
97
  return { refuse: false, reason: null, jump };
157
98
  }
158
99
 
159
- /**
160
- * Detect how the CLI was installed
161
- * @returns {'global'|'npx'|'unknown'}
162
- */
163
100
  export function detectInstallMethod() {
164
- // Check if running via npx
165
101
  if (process.env.npm_execpath && process.env.npm_execpath.includes('npx')) {
166
102
  return 'npx';
167
103
  }
168
104
 
169
- // Check if installed globally
170
105
  const isGlobal = process.env.npm_config_global === 'true' ||
171
106
  process.execPath.includes('node_modules');
172
107
 
@@ -177,11 +112,6 @@ export function detectInstallMethod() {
177
112
  return 'unknown';
178
113
  }
179
114
 
180
- /**
181
- * Get update instructions based on install method
182
- * @param {string} method - Install method ('global', 'npx', 'unknown')
183
- * @returns {string[]} Array of instruction strings
184
- */
185
115
  export function getUpdateInstructions(method) {
186
116
  switch (method) {
187
117
  case 'global':
@@ -198,10 +128,6 @@ export function getUpdateInstructions(method) {
198
128
  }
199
129
  }
200
130
 
201
- /**
202
- * Check if CLI version is outdated
203
- * @returns {Promise<{isOutdated: boolean, current: string, latest: string|null}>}
204
- */
205
131
  export async function checkCLIOutdated() {
206
132
  const current = getInstalledCLIVersion();
207
133
  const latest = await getLatestNPMVersion();
@@ -215,11 +141,6 @@ export async function checkCLIOutdated() {
215
141
  return { isOutdated, current, latest };
216
142
  }
217
143
 
218
- /**
219
- * Check if project MORPH version is outdated
220
- * @param {string} projectPath - Path to the project
221
- * @returns {Promise<{isOutdated: boolean, current: string|null, cliVersion: string}>}
222
- */
223
144
  export async function checkProjectOutdated(projectPath) {
224
145
  const cliVersion = getInstalledCLIVersion();
225
146
  const projectVersion = await getProjectMorphVersion(projectPath);
@@ -1,9 +0,0 @@
1
- ---
2
- description: Inicia ou retoma uma feature MORPH-SPEC โ€” entrevista, plan.md, plan-check e gate do plano.
3
- argument-hint: <feature-name>
4
- allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Agent, AskUserQuestion, Skill
5
- ---
6
-
7
- Invoque `Skill(morph-plan)` com o argumento abaixo e siga a skill.
8
-
9
- **Feature:** $ARGUMENTS
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Scope: universal | Validates commit message format (Conventional Commits)
3
- # MORPH-SPEC Commit Message Hook
4
- # Enforces Conventional Commits specification
5
-
6
- COMMIT_MSG_FILE="$1"
7
- COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
8
-
9
- # Conventional Commits pattern: type(scope): description
10
- # Types: feat, fix, docs, style, refactor, perf, test, chore, build, ci, revert
11
- PATTERN="^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .{1,100}"
12
-
13
- if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
14
- echo "โŒ Invalid commit message format!"
15
- echo ""
16
- echo "Required format: <type>(<scope>): <description>"
17
- echo ""
18
- echo "Types: feat, fix, docs, style, refactor, perf, test, chore, build, ci, revert"
19
- echo ""
20
- echo "Examples:"
21
- echo " feat(auth): add JWT refresh token rotation"
22
- echo " fix(api): resolve null reference in UserService"
23
- echo " docs(readme): update installation instructions"
24
- echo ""
25
- echo "Your message:"
26
- echo " $COMMIT_MSG"
27
- echo ""
28
- echo "Override with: git commit --no-verify"
29
- exit 1
30
- fi
31
-
32
- echo "โœ… Commit message format valid"
33
- exit 0
@@ -1,25 +0,0 @@
1
- #!/bin/bash
2
- # Scope: universal | Validates agents.json Schema
3
- # MORPH-SPEC Pre-Commit Hook: Agent Configuration Validation
4
- # Uses validate-agents.js to check agents.json
5
-
6
- echo "๐Ÿค– Validating agent configuration..."
7
-
8
- # Check if agents.json is being modified
9
- if git diff --cached --name-only | grep -q 'agents\.json$'; then
10
- echo "Detected changes to agents.json"
11
-
12
- # Run validator
13
- if ! morph-spec validate-agents-skills; then
14
- echo ""
15
- echo "โŒ COMMIT BLOCKED: agents.json validation failed"
16
- echo " Fix errors above before committing"
17
- exit 1
18
- fi
19
-
20
- echo "โœ“ agents.json is valid"
21
- else
22
- echo "โœ“ No changes to agents.json"
23
- fi
24
-
25
- exit 0
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Scope: universal | Orchestrates framework + stack-specific pre-commit hooks
3
- # MORPH-SPEC Master Pre-Commit Hook
4
- # Runs universal framework hooks + stack-specific hooks in sequence
5
-
6
- echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—"
7
- echo "โ•‘ MORPH-SPEC PRE-COMMIT VALIDATION โ•‘"
8
- echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"
9
- echo ""
10
-
11
- FRAMEWORK_HOOKS_DIR="$(dirname "$0")"
12
- STACK_HOOKS_DIR=".morph/hooks/pre-commit"
13
-
14
- HAS_FAILURES=false
15
-
16
- # Run framework hooks (universal - all stacks)
17
- echo "๐Ÿ“ฆ Running framework hooks (universal)..."
18
- for hook in "$FRAMEWORK_HOOKS_DIR"/*.sh; do
19
- # Skip orchestrator itself
20
- if [[ "$hook" == */orchestrator.sh ]]; then
21
- continue
22
- fi
23
-
24
- if [[ -f "$hook" ]]; then
25
- hook_name=$(basename "$hook")
26
- echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€"
27
- if ! bash "$hook"; then
28
- HAS_FAILURES=true
29
- echo "โŒ Framework hook failed: $hook_name"
30
- fi
31
- echo ""
32
- fi
33
- done
34
-
35
- # Run stack-specific hooks (if exist)
36
- if [[ -d "$STACK_HOOKS_DIR" ]]; then
37
- echo "๐ŸŽฏ Running stack-specific hooks..."
38
- for hook in "$STACK_HOOKS_DIR"/*.sh; do
39
- if [[ -f "$hook" ]]; then
40
- hook_name=$(basename "$hook")
41
- echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€"
42
- if ! bash "$hook"; then
43
- HAS_FAILURES=true
44
- echo "โŒ Stack hook failed: $hook_name"
45
- fi
46
- echo ""
47
- fi
48
- done
49
- else
50
- echo "โ„น๏ธ No stack-specific hooks found (optional)"
51
- echo ""
52
- fi
53
-
54
- echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•"
55
-
56
- if [[ "$HAS_FAILURES" == "true" ]]; then
57
- echo "โŒ PRE-COMMIT VALIDATION FAILED"
58
- echo " Fix errors above before committing"
59
- echo " Or use: git commit --no-verify to skip"
60
- exit 1
61
- fi
62
-
63
- echo "โœ… ALL PRE-COMMIT VALIDATIONS PASSED"
64
- exit 0
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Scope: universal | Runs test suite before push
3
- # MORPH-SPEC Pre-Push Hook
4
- # Ensures all tests pass before pushing to remote
5
-
6
- echo "๐Ÿงช Running test suite before push..."
7
- echo ""
8
-
9
- # Detect project type and run appropriate tests
10
- if [[ -f *.csproj ]] || find . -maxdepth 2 -name "*.csproj" 2>/dev/null | grep -q .; then
11
- # .NET project detected
12
- echo "๐Ÿ“ฆ Detected .NET project"
13
-
14
- if ! dotnet test --verbosity minimal --no-build --no-restore 2>/dev/null; then
15
- echo ""
16
- echo "โŒ .NET tests failed!"
17
- echo ""
18
- echo "Fix failing tests before pushing."
19
- echo "Override with: git push --no-verify"
20
- exit 1
21
- fi
22
-
23
- elif [[ -f package.json ]]; then
24
- # Node.js project detected
25
- echo "๐Ÿ“ฆ Detected Node.js project"
26
-
27
- if ! npm test 2>/dev/null; then
28
- echo ""
29
- echo "โŒ Node.js tests failed!"
30
- echo ""
31
- echo "Fix failing tests before pushing."
32
- echo "Override with: git push --no-verify"
33
- exit 1
34
- fi
35
-
36
- else
37
- echo "โš ๏ธ No recognized test framework found"
38
- echo " Skipping test execution"
39
- exit 0
40
- fi
41
-
42
- echo ""
43
- echo "โœ… All tests passed - safe to push"
44
- exit 0
@@ -1,3 +0,0 @@
1
- /**
2
- * Utility Commands โ€” no active commands after CLI simplification
3
- */