@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.
- package/CLAUDE.md +8 -9
- package/README.md +38 -36
- package/bin/morph-spec.js +11 -63
- package/bin/validate.js +1 -39
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -1
- package/framework/MORPH.md +3 -3
- package/framework/agents.json +19 -11
- package/framework/commands/morph-apply.md +1 -1
- package/framework/commands/morph-status.md +1 -1
- package/framework/docs/CLI.md +22 -31
- package/framework/evals/review-checklist.md +12 -2
- package/framework/hooks/README.md +8 -44
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
- package/framework/hooks/claude-code/core/chain.js +4 -65
- package/framework/hooks/claude-code/core/comment-guard.js +2 -16
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +6 -50
- package/framework/hooks/claude-code/core/gate-guard.js +7 -67
- package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
- package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
- package/framework/hooks/claude-code/core/heavy-release.js +2 -13
- package/framework/hooks/claude-code/core/loop-detect.js +2 -31
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +0 -4
- package/framework/hooks/claude-code/core/protect-spec-files.js +7 -67
- package/framework/hooks/claude-code/core/state-sync.js +12 -68
- package/framework/hooks/claude-code/core/telemetry-log.js +12 -93
- package/framework/hooks/claude-code/core/validate-completion.js +11 -57
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +1 -9
- package/framework/hooks/claude-code/core/worktree-context.js +10 -110
- package/framework/hooks/claude-code/core/worktree-create.js +6 -70
- package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
- package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/shared/activity-logger.js +9 -89
- package/framework/hooks/shared/agent-reap.js +2 -17
- package/framework/hooks/shared/build-check.js +6 -75
- package/framework/hooks/shared/claim-registry.js +9 -119
- package/framework/hooks/shared/command-tokens.js +6 -51
- package/framework/hooks/shared/comment-rules.js +5 -20
- package/framework/hooks/shared/comment-scanner.js +6 -25
- package/framework/hooks/shared/comment-stripper.js +11 -85
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/errata.js +2 -15
- package/framework/hooks/shared/feature-locator.js +11 -95
- package/framework/hooks/shared/frontend-locations.js +1 -3
- package/framework/hooks/shared/gate-question.js +1 -7
- package/framework/hooks/shared/git-exclude.js +3 -20
- package/framework/hooks/shared/git-paths.js +8 -104
- package/framework/hooks/shared/graph-freshness.js +22 -166
- package/framework/hooks/shared/graph-refresh.js +21 -149
- package/framework/hooks/shared/heavy-command.js +4 -12
- package/framework/hooks/shared/hook-response.js +8 -83
- package/framework/hooks/shared/morph-cli.js +8 -52
- package/framework/hooks/shared/payload-utils.js +10 -132
- package/framework/hooks/shared/phase-utils.js +1 -42
- package/framework/hooks/shared/redact-secrets.js +4 -15
- package/framework/hooks/shared/reparse-scan.js +6 -66
- package/framework/hooks/shared/slice-progress.js +4 -23
- package/framework/hooks/shared/source-files.js +4 -17
- package/framework/hooks/shared/state-reader.js +13 -183
- package/framework/hooks/shared/state-writer.js +8 -52
- package/framework/hooks/shared/stdin-reader.js +1 -11
- package/framework/hooks/shared/telemetry-logger.js +7 -67
- package/framework/hooks/shared/transcript-usage.js +7 -29
- package/framework/hooks/shared/worktree-root.js +7 -29
- package/framework/rules/csharp-standards.md +1 -1
- package/framework/rules/frontend-standards.md +1 -0
- package/framework/rules/hangfire-standards.md +1 -1
- package/framework/rules/neon-standards.md +1 -1
- package/framework/rules/nextjs-standards.md +1 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +4 -4
- package/framework/skills/core/morph-hotfix/SKILL.md +3 -3
- package/framework/skills/core/morph-machine/SKILL.md +1 -1
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +9 -7
- package/framework/skills/core/morph-review/SKILL.md +9 -6
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +29 -12
- package/framework/standards/STANDARDS.json +36 -14
- package/framework/standards/STANDARDS.meta.json +16 -2
- package/framework/standards/ai-agents/agent-archetypes.md +2 -2
- package/framework/standards/ai-agents/agent-session.md +1 -1
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
- package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
- package/framework/standards/ai-agents/guardrails.md +1 -1
- package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
- package/framework/standards/ai-agents/observability-patterns.md +1 -1
- package/framework/standards/ai-agents/production.md +1 -1
- package/framework/standards/ai-agents/prompt-sources.md +2 -2
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
- package/framework/standards/ai-agents/setup.md +2 -2
- package/framework/standards/ai-agents/sweet-spot.md +2 -2
- package/framework/standards/ai-agents/tool-adapters.md +0 -2
- package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
- package/framework/standards/ai-agents/workflows.md +1 -1
- package/framework/standards/architecture/code-comments.md +1 -1
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
- package/framework/standards/backend/api/validation.md +1 -1
- package/framework/standards/backend/dotnet/testing.md +10 -4
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
- package/framework/standards/data/nosql/cache/redis.md +1 -1
- package/framework/standards/data/nosql/cosmos-db.md +3 -3
- package/framework/standards/frontend/admin-app/forms.md +1 -1
- package/framework/standards/frontend/design-system/art-direction.md +88 -0
- package/framework/standards/frontend/design-system/premium-finish.md +77 -2
- package/framework/standards/frontend/nextjs/testing.md +10 -6
- package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/CLAUDE.md.core.template +3 -3
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/REGISTRY.json +9 -9
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/docs/plan.md +3 -1
- package/framework/templates/docs/ui-mockups.md +4 -0
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/context/context-refresh.js +0 -16
- package/src/commands/dashboard/dashboard.js +2 -8
- package/src/commands/e2e/e2e.js +17 -104
- package/src/commands/graph/affected.js +0 -14
- package/src/commands/graph/build.js +11 -50
- package/src/commands/graph/explain.js +0 -16
- package/src/commands/graph/status.js +1 -12
- package/src/commands/mcp/mcp-setup.js +4 -62
- package/src/commands/observability/cost.js +5 -57
- package/src/commands/observability/telemetry.js +1 -14
- package/src/commands/project/branch.js +4 -45
- package/src/commands/project/claim.js +4 -48
- package/src/commands/project/doctor.js +48 -302
- package/src/commands/project/env.js +1 -27
- package/src/commands/project/fleet.js +3 -32
- package/src/commands/project/init.js +4 -68
- package/src/commands/project/install-plugin-cmd.js +0 -1
- package/src/commands/project/standards.js +1 -62
- package/src/commands/project/status.js +0 -53
- package/src/commands/project/update.js +31 -239
- package/src/commands/project/worktree.js +108 -882
- package/src/commands/scaffold/scaffold.js +0 -25
- package/src/commands/state/advance.js +14 -85
- package/src/commands/state/approve.js +15 -97
- package/src/commands/state/archive.js +12 -64
- package/src/commands/state/auto-approval.js +2 -5
- package/src/commands/state/create.js +22 -109
- package/src/commands/state/delete.js +11 -63
- package/src/commands/state/finish.js +98 -475
- package/src/commands/state/gate-check.js +22 -132
- package/src/commands/state/gate-decision.js +3 -39
- package/src/commands/state/handoff.js +3 -30
- package/src/commands/state/list.js +14 -84
- package/src/commands/state/report-check.js +8 -58
- package/src/commands/state/retype.js +4 -26
- package/src/commands/validation/index.js +0 -3
- package/src/commands/validation/mutate.js +11 -11
- package/src/commands/validation/plan-check.js +4 -2
- package/src/commands/validation/tests-audit.js +7 -0
- package/src/commands/validation/validate-feature.js +10 -97
- package/src/commands/validation/verify.js +30 -113
- package/src/core/paths/output-schema.js +2 -101
- package/src/core/state/feature-identity.js +1 -25
- package/src/core/state/gate-order.js +0 -27
- package/src/core/state/lifecycle-audit.js +8 -100
- package/src/core/state/state-manager.js +22 -304
- package/src/core/templates/template-registry.js +2 -97
- package/src/core/templates/template-renderer.js +13 -93
- package/src/core/templates/template-seed.js +0 -1
- package/src/core/work-types.js +1 -36
- package/src/dashboard/app/App.jsx +1 -8
- package/src/dashboard/app/components/ActivityFeed.jsx +0 -5
- package/src/dashboard/app/components/CommandPalette.jsx +0 -7
- package/src/dashboard/app/components/DetailPanel.jsx +1 -5
- package/src/dashboard/app/components/EntityLink.jsx +0 -12
- package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
- package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
- package/src/dashboard/app/components/Markdown.jsx +0 -9
- package/src/dashboard/app/components/PhaseRail.jsx +0 -11
- package/src/dashboard/app/components/SearchFilter.jsx +0 -4
- package/src/dashboard/app/components/Sidebar.jsx +0 -5
- package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
- package/src/dashboard/app/hooks/usePref.js +1 -5
- package/src/dashboard/app/lib/format.js +0 -2
- package/src/dashboard/app/lib/phases.js +1 -5
- package/src/dashboard/app/lib/project.js +0 -12
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/AgentMap.jsx +1 -8
- package/src/dashboard/app/pages/FeatureDetail.jsx +1 -5
- package/src/dashboard/app/pages/Features.jsx +1 -8
- package/src/dashboard/app/pages/Guide.jsx +0 -1
- package/src/dashboard/app/pages/HookInspector.jsx +2 -23
- package/src/dashboard/app/pages/PhasePipeline.jsx +0 -3
- package/src/dashboard/app/pages/Portfolio.jsx +0 -1
- package/src/dashboard/app/pages/RulesMap.jsx +1 -16
- package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
- package/src/dashboard/app/pages/Standards.jsx +2 -17
- package/src/dashboard/scanner/activity-scanner.js +10 -69
- package/src/dashboard/scanner/agents-scanner.js +1 -23
- package/src/dashboard/scanner/docs-scanner.js +0 -6
- package/src/dashboard/scanner/feature-status.js +2 -5
- package/src/dashboard/scanner/features-scanner.js +10 -66
- package/src/dashboard/scanner/hooks-scanner.js +5 -28
- package/src/dashboard/scanner/index.js +0 -4
- package/src/dashboard/scanner/portfolio.js +5 -29
- package/src/dashboard/scanner/project-api.js +8 -54
- package/src/dashboard/scanner/rules-scanner.js +1 -2
- package/src/dashboard/scanner/skills-scanner.js +2 -12
- package/src/dashboard/scanner/standards-scanner.js +2 -6
- package/src/dashboard/vite-plugin-morph-data.js +5 -19
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/ai/ai-checks.js +7 -52
- package/src/lib/ai/ai-project-scan.js +14 -108
- package/src/lib/ai/code-audit.js +7 -63
- package/src/lib/ai/pin-drift.js +8 -51
- package/src/lib/ai/registry-audit.js +11 -90
- package/src/lib/ci/ci-verify.js +4 -19
- package/src/lib/ci/github-ci.js +9 -37
- package/src/lib/ci/workflow-scaffold.js +14 -10
- package/src/lib/detectors/claude-config-detector.js +13 -74
- package/src/lib/detectors/index.js +4 -50
- package/src/lib/e2e/applicability.js +37 -0
- package/src/lib/e2e/compose-env.js +5 -66
- package/src/lib/e2e/stack-teardown.js +6 -40
- package/src/lib/generators/architecture-scanner.js +18 -156
- package/src/lib/generators/handoff-generator.js +9 -53
- package/src/lib/generators/scaffold-generator.js +5 -101
- package/src/lib/generators/settings-generator.js +4 -37
- package/src/lib/git/branch-classifier.js +11 -84
- package/src/lib/git/default-branch.js +14 -169
- package/src/lib/git/evidence-staleness.js +1 -0
- package/src/lib/git/gh.js +2 -17
- package/src/lib/git/pending-prs.js +6 -37
- package/src/lib/git/pr-files.js +3 -28
- package/src/lib/git/pr-index.js +3 -34
- package/src/lib/git/tree-fingerprint.js +3 -15
- package/src/lib/git/tree-state.js +6 -33
- package/src/lib/graph/god-nodes.js +2 -22
- package/src/lib/graph/graph-health.js +3 -24
- package/src/lib/graph/graph-loader.js +5 -56
- package/src/lib/graph/graphify-runtime.js +7 -37
- package/src/lib/graph/graphifyignore.js +8 -74
- package/src/lib/graph/sanitize.js +16 -136
- package/src/lib/heavy/cleanup.js +1 -1
- package/src/lib/installers/effects.js +8 -93
- package/src/lib/installers/mcp-installer.js +9 -169
- package/src/lib/installers/memory-installer.js +4 -27
- package/src/lib/installers/templates-reconcile.js +5 -60
- package/src/lib/mutation/adapters.js +6 -17
- package/src/lib/mutation/dotnet-introspection.js +20 -106
- package/src/lib/mutation/runner.js +23 -75
- package/src/lib/mutation/subset.js +1 -4
- package/src/lib/mutation/trx.js +0 -1
- package/src/lib/plan/artifact-vocabulary.js +5 -25
- package/src/lib/plan/checks.js +34 -33
- package/src/lib/plan/plan-parser.js +7 -8
- package/src/lib/projects/registry.js +7 -44
- package/src/lib/review-reports.js +11 -26
- package/src/lib/risk-detector.js +41 -173
- package/src/lib/specs/adr-index.js +6 -34
- package/src/lib/specs/frontmatter.js +2 -15
- package/src/lib/specs/gfm-table.js +1 -7
- package/src/lib/specs/revocations.js +1 -14
- package/src/lib/specs/screen-checklist.js +47 -124
- package/src/lib/stack/dotnet-build-ignores.js +2 -6
- package/src/lib/stack/stack-profile.js +1 -28
- package/src/lib/stack/stack-scan.js +1 -8
- package/src/lib/stack-filter.js +4 -27
- package/src/lib/standards/registry.js +1 -7
- package/src/lib/standards/sections.js +2 -13
- package/src/lib/standards/verified-against.js +19 -191
- package/src/lib/tasks/eval-node.js +21 -169
- package/src/lib/tasks/linux-runner.js +18 -142
- package/src/lib/tasks/test-nodes.js +43 -240
- package/src/lib/tasks/test-runner.js +43 -341
- package/src/lib/telemetry/metrics.js +7 -36
- package/src/lib/telemetry/telemetry-reader.js +13 -125
- package/src/lib/telemetry/verify-event.js +2 -30
- package/src/lib/tests-audit/audit.js +96 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +4 -44
- package/src/lib/validators/code-budget/index.js +0 -7
- package/src/lib/validators/contracts/contract-compliance-validator.js +2 -24
- package/src/lib/validators/contracts/index.js +0 -6
- package/src/lib/validators/nextjs/index.js +0 -5
- package/src/lib/validators/nextjs/next-component-validator.js +4 -81
- package/src/lib/validators/packages/index.js +0 -6
- package/src/lib/validators/packages/package-validator.js +6 -56
- package/src/lib/validators/reuse/index.js +0 -8
- package/src/lib/validators/reuse/reuse-validator.js +11 -101
- package/src/lib/validators/reuse/symbol-scanner.js +6 -62
- package/src/lib/validators/traceability-check.js +5 -63
- package/src/lib/validators/validation-runner.js +21 -158
- package/src/lib/validators/verify-runner.js +85 -376
- package/src/lib/work-type-detector.js +5 -67
- package/src/lib/worktree/docker-audit.js +17 -136
- package/src/lib/worktree/env-allocator.js +10 -98
- package/src/lib/worktree/feature-truth.js +12 -115
- package/src/lib/worktree/finish-backup.js +32 -242
- package/src/lib/worktree/fleet-scanner.js +13 -95
- package/src/lib/worktree/ignored-triage.js +15 -91
- package/src/lib/worktree/vscode-settings.js +2 -3
- package/src/lib/worktree/worktree-audit.js +21 -213
- package/src/lib/worktree/worktree-include.js +3 -5
- package/src/scripts/global-install.js +3 -9
- package/src/scripts/install-plugin.js +1 -13
- package/src/scripts/setup-infra.js +17 -147
- package/src/utils/agents-installer.js +29 -276
- package/src/utils/banner.js +4 -25
- package/src/utils/claude-md-injector.js +1 -37
- package/src/utils/claude-settings-manager.js +1 -52
- package/src/utils/file-copier.js +11 -95
- package/src/utils/hooks-installer.js +21 -298
- package/src/utils/skills-installer.js +4 -101
- package/src/utils/version-checker.js +4 -83
- package/framework/commands/morph-proposal.md +0 -9
- package/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
- package/framework/hooks/git/pre-commit/agents.sh +0 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
- package/framework/hooks/git/pre-push/run-tests.sh +0 -44
- package/src/commands/utils/index.js +0 -3
- package/src/lib/detectors/design-system-detector.js +0 -188
- package/src/lib/generators/design-system-generator.js +0 -508
- package/src/lib/specs/old-format.js +0 -68
- 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
|
-
//
|
|
156
|
-
//
|
|
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
|
-
//
|
|
168
|
-
//
|
|
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
|
-
|
|
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
|