@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,72 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* WHY THIS MODULE EXISTS
|
|
5
|
-
*
|
|
6
|
-
* Defect F35: 3.057 tests green on Windows, ten failures on Linux. The ten
|
|
7
|
-
* were `Link=` casing and `Uri.TryCreate` — defects of CASE, invisible on a
|
|
8
|
-
* case-insensitive filesystem. The CI has had an ubuntu leg since 8.24.2 and
|
|
9
|
-
* F35 still reached the field, because the CI answers minutes-to-hours after
|
|
10
|
-
* the loop has moved on. `--linux` is the desk-side complement: the same
|
|
11
|
-
* suites, on Linux, inside the loop.
|
|
12
|
-
*
|
|
13
|
-
* WHY THE TREE IS COPIED AND NOT MOUNTED (D5) — the load-bearing decision
|
|
14
|
-
*
|
|
15
|
-
* Docker Desktop's bind mount on Windows crosses a 9p / gRPC-FUSE translation
|
|
16
|
-
* layer that is **case-insensitive**. Running the suite on top of that mount
|
|
17
|
-
* gives back exactly the green Windows already gave: the flag would exist and
|
|
18
|
-
* prove nothing about the one class of defect it was built for. So the host
|
|
19
|
-
* tree is mounted READ-ONLY at `/src` purely as the source of a copy, the copy
|
|
20
|
-
* lands on the container's own filesystem (the overlayfs) at `/work`, and every
|
|
21
|
-
* node runs from `/work/{cwd}`. Nothing ever executes out of `/src`.
|
|
22
|
-
*
|
|
23
|
-
* The copy is `tar | tar` rather than a literal `cp -r` because `cp` has no
|
|
24
|
-
* portable exclusion: `node_modules`, `bin`, `obj`, `.git` and the worktree
|
|
25
|
-
* container directories must not travel (a worktree is ANOTHER feature's
|
|
26
|
-
* checkout — copying it doubles the clock and reports on code outside the tree
|
|
27
|
-
* under judgement, the same reason `collectDotnetTestProjects` excludes them).
|
|
28
|
-
* The effect is the one the issue asked for: the executed tree lives in the
|
|
29
|
-
* container.
|
|
30
|
-
*
|
|
31
|
-
* WHY `exec` IS INJECTED
|
|
32
|
-
*
|
|
33
|
-
* The CI has no guaranteed Docker daemon and no .NET at all. Every test of
|
|
34
|
-
* this module drives a recorded `exec` and asserts the command line that WOULD
|
|
35
|
-
* have run — a verifier whose own tests need a container is a verifier that
|
|
36
|
-
* stops being tested.
|
|
37
|
-
*
|
|
38
|
-
* @module linux-runner
|
|
39
|
-
*/
|
|
40
|
-
|
|
1
|
+
// The Docker Desktop bind mount is case-insensitive (9p/gRPC-FUSE), so the tree is
|
|
2
|
+
// mounted read-only at /src and COPIED to the container's own filesystem at /work:
|
|
3
|
+
// running on the mount would hide exactly the casing defects this runner exists for.
|
|
41
4
|
import { createHash } from 'crypto';
|
|
42
5
|
import { resolve } from 'path';
|
|
43
6
|
|
|
44
7
|
import { defaultExec, isDockerAvailable } from '../../../framework/hooks/shared/e2e-check.js';
|
|
45
8
|
import { WORKTREES_DIR, LEGACY_WORKTREES_DIR } from '../worktree/dirs.js';
|
|
46
9
|
|
|
47
|
-
/** The SDK image `--linux` runs in by default (spec §5.1); overridable per run and per node. */
|
|
48
10
|
export const LINUX_DEFAULT_IMAGE = 'mcr.microsoft.com/dotnet/sdk:10.0';
|
|
49
11
|
|
|
50
|
-
/** Where the host tree is mounted (read-only) and where the copy is executed from. */
|
|
51
12
|
const SRC_MOUNT = '/src';
|
|
52
13
|
const WORK_DIR = '/work';
|
|
53
14
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* Deliberately noisy: a delimiter that could occur in real test output would
|
|
57
|
-
* split a run at the wrong line and attribute failures to the wrong suite.
|
|
58
|
-
*/
|
|
15
|
+
// Deliberately noisy: a delimiter that could occur in real test output would
|
|
16
|
+
// attribute failures to the wrong suite.
|
|
59
17
|
export const NODE_START = '@@MORPH-NODE-START@@';
|
|
60
18
|
export const NODE_EXIT = '@@MORPH-NODE-EXIT@@';
|
|
61
19
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
*
|
|
65
|
-
* The two worktree container names are IMPORTED from `dirs.js`, never retyped:
|
|
66
|
-
* duplicating that string is the documented way the C1 bug comes back. They are
|
|
67
|
-
* anchored at the root (`./name`) because they are root-level containers; the
|
|
68
|
-
* build artifacts are unanchored because they nest anywhere in a tree.
|
|
69
|
-
*/
|
|
20
|
+
// Worktree dirs are anchored at the root (`./name`); build artifacts nest anywhere.
|
|
21
|
+
// A worktree is another feature's checkout and must never be copied.
|
|
70
22
|
export const COPY_EXCLUDES = [
|
|
71
23
|
'node_modules',
|
|
72
24
|
'bin',
|
|
@@ -76,21 +28,12 @@ export const COPY_EXCLUDES = [
|
|
|
76
28
|
`./${LEGACY_WORKTREES_DIR}`,
|
|
77
29
|
];
|
|
78
30
|
|
|
79
|
-
/** Single-quote a POSIX shell word — the container's shell is always sh. */
|
|
80
31
|
function shq(value) {
|
|
81
32
|
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
82
33
|
}
|
|
83
34
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
*
|
|
87
|
-
* A missing daemon is a USAGE ERROR (exit 2), never a skipped node. A skip
|
|
88
|
-
* would mean "we could not check on Linux" reading as green — which is F35
|
|
89
|
-
* itself, restated as a feature.
|
|
90
|
-
*
|
|
91
|
-
* @param {{ projectPath: string, skipTests: boolean, exec?: Function }} params
|
|
92
|
-
* @returns {string|null}
|
|
93
|
-
*/
|
|
35
|
+
// A missing daemon is a usage error, never a skipped node: a skip would read
|
|
36
|
+
// "could not check on Linux" as green.
|
|
94
37
|
export function checkLinuxPreconditions({ projectPath, skipTests, exec = defaultExec }) {
|
|
95
38
|
if (skipTests) {
|
|
96
39
|
return '--linux com --skip-tests se anulam: a flag existe para RODAR a suíte em Linux';
|
|
@@ -102,14 +45,8 @@ export function checkLinuxPreconditions({ projectPath, skipTests, exec = default
|
|
|
102
45
|
return null;
|
|
103
46
|
}
|
|
104
47
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
*
|
|
108
|
-
* An `e2e: true` node needs the application stack up; bringing docker up INSIDE
|
|
109
|
-
* a container is out of scope, so it is refused by name rather than silently
|
|
110
|
-
* dropped — a suite that disappears from the report is the defect this whole
|
|
111
|
-
* feature exists to close.
|
|
112
|
-
*/
|
|
48
|
+
// e2e nodes are refused by name, never dropped: a suite that disappears from the
|
|
49
|
+
// report reads as green.
|
|
113
50
|
function partitionNodes(nodes) {
|
|
114
51
|
const runnable = [];
|
|
115
52
|
const refused = [];
|
|
@@ -130,63 +67,31 @@ function partitionNodes(nodes) {
|
|
|
130
67
|
return { runnable, refused };
|
|
131
68
|
}
|
|
132
69
|
|
|
133
|
-
|
|
134
|
-
* The shell script the container executes: copy first, then every node.
|
|
135
|
-
*
|
|
136
|
-
* Order is the contract — the copy precedes the first command, and every
|
|
137
|
-
* command is `cd`-ed into `/work/{cwd}`. `set -e` is deliberately NOT used
|
|
138
|
-
* around the nodes: one red suite must not cancel the ones after it (the same
|
|
139
|
-
* rule the local loop follows for a timeout).
|
|
140
|
-
*
|
|
141
|
-
* @param {{ nodes: Array<import('./test-nodes.js').TestNode> }} params
|
|
142
|
-
* @returns {string}
|
|
143
|
-
*/
|
|
70
|
+
// No `set -e` around the nodes: one red suite must not cancel the ones after it.
|
|
144
71
|
export function buildContainerScript({ nodes }) {
|
|
145
72
|
const excludes = COPY_EXCLUDES.map((e) => `--exclude=${e}`).join(' ');
|
|
146
73
|
const lines = [
|
|
147
74
|
'set -u',
|
|
148
75
|
`mkdir -p ${WORK_DIR}`,
|
|
149
|
-
// The copy that makes this flag mean something: after it, the executed
|
|
150
|
-
// files live on the container's own filesystem, which is case-SENSITIVE.
|
|
151
76
|
`tar -C ${SRC_MOUNT} ${excludes} -cf - . | tar -C ${WORK_DIR} -xf -`,
|
|
152
77
|
];
|
|
153
78
|
|
|
154
79
|
for (const node of nodes) {
|
|
155
80
|
const dir = `${WORK_DIR}/${node.cwd || '.'}`;
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
// shell quirk away from reporting the timestamp's exit code as the suite's.
|
|
159
|
-
// An image without `date` degrades to an UNKNOWN duration, never a zero.
|
|
81
|
+
// `$?` is captured into its own variable: sharing an echo with `$(date)` can
|
|
82
|
+
// report the timestamp's exit code as the suite's.
|
|
160
83
|
lines.push(`__ms=$(date +%s 2>/dev/null); echo "${NODE_START} ${node.id} $__ms"`);
|
|
161
84
|
lines.push(`cd ${shq(dir)} && ${node.command}`);
|
|
162
|
-
// `$?` of the compound above: a cd that fails is a failure too, and one
|
|
163
|
-
// that reported success would run the suite from the wrong directory.
|
|
164
85
|
lines.push(`__code=$?; __me=$(date +%s 2>/dev/null); echo "${NODE_EXIT} ${node.id} $__code $__me"`);
|
|
165
86
|
}
|
|
166
87
|
|
|
167
88
|
return lines.join('\n');
|
|
168
89
|
}
|
|
169
90
|
|
|
170
|
-
/**
|
|
171
|
-
* The exact `docker` argv. Split out from the execution so a test can assert
|
|
172
|
-
* the command line without a daemon — this is the canary that keeps the
|
|
173
|
-
* read-only `/src` and the absence of a writable `/work` mount honest.
|
|
174
|
-
*
|
|
175
|
-
* @param {{ projectPath: string, image: string, script: string }} params
|
|
176
|
-
* @returns {string[]}
|
|
177
|
-
*/
|
|
178
91
|
export function buildLinuxArgv({ projectPath, image, script, runId = null }) {
|
|
179
92
|
return [
|
|
180
93
|
'run', '--rm',
|
|
181
94
|
...(runId ? ['--label', `${LABEL_RUN}=${runId}`, '--label', `${LABEL_ROOT}=${rootHash(projectPath)}`] : []),
|
|
182
|
-
// Read-only, and mounted at /src: the SOURCE of the copy, never the tree
|
|
183
|
-
// the tests run from. See the module docs for why that distinction is the
|
|
184
|
-
// entire point of the flag.
|
|
185
|
-
//
|
|
186
|
-
// Forward slashes even on Windows: `C:\a\b` and `C:/a/b` are both accepted
|
|
187
|
-
// by Docker Desktop, but the backslash form is the one that breaks first
|
|
188
|
-
// when a path is re-parsed downstream, and the mount spec is already
|
|
189
|
-
// colon-delimited.
|
|
190
95
|
'-v', `${resolve(projectPath).replace(/\\/g, '/')}:${SRC_MOUNT}:ro`,
|
|
191
96
|
'-w', WORK_DIR,
|
|
192
97
|
image,
|
|
@@ -194,13 +99,7 @@ export function buildLinuxArgv({ projectPath, image, script, runId = null }) {
|
|
|
194
99
|
];
|
|
195
100
|
}
|
|
196
101
|
|
|
197
|
-
|
|
198
|
-
* Split the container's stdout back into one result per node.
|
|
199
|
-
*
|
|
200
|
-
* A node whose exit marker never arrived did not pass: the container died
|
|
201
|
-
* mid-run (image pull, OOM, killed clock). Reporting it as anything but a
|
|
202
|
-
* failure would be a green verdict over a suite nobody observed.
|
|
203
|
-
*/
|
|
102
|
+
// A node whose exit marker never arrived did not pass: the container died mid-run.
|
|
204
103
|
function splitByMarkers(output, nodes) {
|
|
205
104
|
const text = String(output || '');
|
|
206
105
|
const escape = (v) => String(v).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -229,8 +128,7 @@ function splitByMarkers(output, nodes) {
|
|
|
229
128
|
reason: 'o container terminou sem reportar o código de saída deste nó',
|
|
230
129
|
};
|
|
231
130
|
}
|
|
232
|
-
//
|
|
233
|
-
// suite in zero milliseconds.
|
|
131
|
+
// null is UNKNOWN, never 0: an image without `date` did not run in zero ms.
|
|
234
132
|
const durationMs = startMatch[1] && exitMatch[2]
|
|
235
133
|
? (Number(exitMatch[2]) - Number(startMatch[1])) * 1000
|
|
236
134
|
: null;
|
|
@@ -239,29 +137,11 @@ function splitByMarkers(output, nodes) {
|
|
|
239
137
|
}
|
|
240
138
|
|
|
241
139
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* Judgement (count comparison, baseline drop, feedback lines) stays in
|
|
246
|
-
* verify-runner beside the local path, so a container run and a host run are
|
|
247
|
-
* decided by the SAME code. A second copy of that rule is how two environments
|
|
248
|
-
* start disagreeing about the same suite.
|
|
249
|
-
*
|
|
250
|
-
* @param {Object} params
|
|
251
|
-
* @param {string} params.projectPath - Project root (the copy source)
|
|
252
|
-
* @param {Array<import('./test-nodes.js').TestNode>} params.nodes - Nodes to run
|
|
253
|
-
* @param {string} [params.image] - Image override (`--linux-image`)
|
|
254
|
-
* @param {number} [params.timeout] - Ceiling for the whole container, in ms
|
|
255
|
-
* @param {Function} [params.exec] - Injected executor (defaults to e2e-check's defaultExec)
|
|
256
|
-
* @returns {{ results: Array<{id: string, exitCode: number|null, output: string, reason: string|null, skipped?: boolean}>,
|
|
257
|
-
* environment: {kind: string, image: string}, argv: string[], script: string, containerCode: number|null }}
|
|
140
|
+
* Runs every runnable node in ONE container and returns raw per-node results,
|
|
141
|
+
* unjudged: verify-runner judges container and host runs with the same code.
|
|
258
142
|
*/
|
|
259
143
|
export function runLinuxSuite({ projectPath, nodes, image, timeout, exec = defaultExec }) {
|
|
260
144
|
const { runnable, refused } = partitionNodes(nodes);
|
|
261
|
-
// Precedence: explicit override > a node that declares its own image > the
|
|
262
|
-
// default. A per-node image only decides the single container everyone shares
|
|
263
|
-
// when it is the only one asked for — two images would mean two copies of the
|
|
264
|
-
// tree and two clocks, which is not what this flag is for.
|
|
265
145
|
const declared = runnable.map((n) => n.linuxImage).filter(Boolean);
|
|
266
146
|
const resolvedImage = image || declared[0] || LINUX_DEFAULT_IMAGE;
|
|
267
147
|
const environment = { kind: 'linux-container', image: resolvedImage };
|
|
@@ -286,9 +166,6 @@ export function runLinuxSuite({ projectPath, nodes, image, timeout, exec = defau
|
|
|
286
166
|
: r
|
|
287
167
|
);
|
|
288
168
|
|
|
289
|
-
// A container that never produced a single marker failed as a whole (a pull
|
|
290
|
-
// failure, say). The reason has to name the container, or the reader goes
|
|
291
|
-
// hunting through a test log for a suite that never started.
|
|
292
169
|
const nothingRan = results.every((r) => r.exitCode === null);
|
|
293
170
|
const enriched = results.map((r) =>
|
|
294
171
|
r.exitCode === null && nothingRan
|
|
@@ -318,7 +195,6 @@ export function reapLabeledContainers({ runId, exec, cwd }) {
|
|
|
318
195
|
} catch { /* limpeza best-effort: nunca muda o veredito da suíte */ }
|
|
319
196
|
}
|
|
320
197
|
|
|
321
|
-
/** Last few lines of the container output — enough to name a pull failure. */
|
|
322
198
|
function tail(output, lines = 5) {
|
|
323
199
|
return String(output || '').split('\n').slice(-lines).join('\n').trim();
|
|
324
200
|
}
|