@polymorphism-tech/morph-spec 8.46.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +53 -44
- package/README.md +3 -4
- package/bin/morph-spec.js +38 -55
- package/bin/validate.js +5 -134
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +2 -2
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +41 -101
- package/framework/MORPH.md +95 -252
- package/framework/agents.json +75 -18
- package/framework/commands/create-umbraco-lp.md +2 -0
- package/framework/commands/migrate-lp-to-umbraco.md +2 -0
- package/framework/commands/morph-apply.md +5 -28
- package/framework/commands/morph-archive.md +2 -2
- package/framework/commands/morph-hotfix.md +8 -8
- package/framework/commands/morph-infra.md +17 -203
- package/framework/commands/morph-media.md +3 -0
- package/framework/commands/morph-preflight.md +7 -31
- package/framework/commands/morph-proposal.md +2 -50
- package/framework/commands/morph-status.md +3 -3
- package/framework/commands/morph-troubleshoot.md +2 -14
- package/framework/docs/CLI.md +585 -286
- package/framework/evals/review-checklist.md +82 -41
- package/framework/hooks/README.md +10 -11
- package/framework/hooks/claude-code/core/comment-guard.js +1 -1
- package/framework/hooks/claude-code/core/denylist.json +33 -3
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +16 -20
- package/framework/hooks/claude-code/core/gate-guard.js +2 -11
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +38 -0
- package/framework/hooks/claude-code/core/protect-spec-files.js +30 -242
- package/framework/hooks/claude-code/core/state-sync.js +17 -19
- package/framework/hooks/claude-code/core/telemetry-log.js +3 -3
- package/framework/hooks/claude-code/core/validate-completion.js +33 -97
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +31 -0
- package/framework/hooks/claude-code/core/worktree-context.js +5 -4
- package/framework/hooks/claude-code/statusline.py +55 -41
- package/framework/hooks/package.json +3 -0
- package/framework/hooks/shared/activity-logger.js +1 -1
- package/framework/hooks/shared/build-check.js +10 -6
- package/framework/hooks/shared/command-tokens.js +169 -0
- package/framework/hooks/shared/comment-rules.js +1 -1
- package/framework/hooks/shared/comment-scanner.js +10 -23
- package/framework/hooks/shared/comment-stripper.js +1 -1
- package/framework/hooks/shared/e2e-check.js +67 -31
- package/framework/hooks/shared/errata.js +72 -0
- package/framework/hooks/shared/feature-locator.js +1 -1
- package/framework/hooks/shared/frontend-locations.js +6 -0
- package/framework/hooks/shared/gate-question.js +18 -0
- package/framework/hooks/shared/phase-utils.js +15 -32
- package/framework/hooks/shared/slice-progress.js +118 -0
- package/framework/hooks/shared/spawn-command.js +23 -0
- package/framework/hooks/shared/state-reader.js +61 -87
- package/framework/hooks/shared/state-writer.js +3 -3
- package/framework/mcp/registry.json +3 -4
- package/framework/phases.json +23 -39
- package/framework/rules/ai-agents-standards.md +18 -16
- package/framework/rules/asaas-standards.md +3 -1
- package/framework/rules/csharp-standards.md +10 -8
- package/framework/rules/data-standards.md +5 -5
- package/framework/rules/dotnet-templates.md +1 -1
- package/framework/rules/frontend-standards.md +4 -2
- package/framework/rules/gsap-standards.md +10 -5
- package/framework/rules/hangfire-standards.md +3 -1
- package/framework/rules/infrastructure-standards.md +4 -2
- package/framework/rules/neon-auth-standards.md +3 -1
- package/framework/rules/neon-standards.md +6 -4
- package/framework/rules/nextjs-standards.md +13 -11
- package/framework/rules/nextjs-templates.md +1 -1
- package/framework/rules/resend-standards.md +3 -1
- package/framework/schemas/config.schema.json +14 -9
- package/framework/schemas/feature.schema.json +15 -52
- package/framework/skills/README.md +4 -5
- package/framework/skills/core/create-umbraco-lp/SKILL.md +3 -3
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +3 -3
- package/framework/skills/core/morph-apply/SKILL.md +150 -223
- package/framework/skills/core/morph-hotfix/SKILL.md +34 -43
- package/framework/skills/core/morph-machine/SKILL.md +4 -4
- package/framework/skills/core/morph-media/SKILL.md +3 -3
- package/framework/skills/core/morph-plan/SKILL.md +138 -300
- package/framework/skills/core/morph-review/SKILL.md +112 -137
- package/framework/skills/core/morph-standards/SKILL.md +29 -41
- package/framework/skills/core/morph-uiux/SKILL.md +78 -153
- package/framework/standards/STANDARDS.json +90 -1219
- package/framework/standards/STANDARDS.meta.json +1305 -0
- package/framework/standards/ai-agents/evals-with-cache.md +2 -3
- package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
- package/framework/standards/ai-agents/modalities-speech-to-text.md +36 -26
- package/framework/standards/ai-agents/prompt-sources.md +6 -4
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +67 -39
- package/framework/standards/ai-agents/setup.md +2 -2
- package/framework/standards/ai-agents/structured-output.md +1 -1
- package/framework/standards/ai-agents/sweet-spot.md +1 -1
- package/framework/standards/architecture/code-comments.md +8 -8
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +18 -9
- package/framework/standards/backend/api/validation.md +135 -47
- package/framework/standards/backend/database/postgresql/database.md +11 -7
- package/framework/standards/backend/database/vector-search-rag.md +207 -324
- package/framework/standards/backend/dotnet/fluent-validation-vsa.md +14 -8
- package/framework/standards/backend/dotnet/result-pattern.md +40 -6
- package/framework/standards/backend/dotnet/scalar-ui.md +13 -7
- package/framework/standards/backend/dotnet/scrutor.md +1 -1
- package/framework/standards/backend/dotnet/testing.md +1 -1
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +7 -7
- package/framework/standards/backend/integrations/asaas/asaas-api.md +309 -165
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +134 -154
- package/framework/standards/data/nosql/cache/redis.md +120 -44
- package/framework/standards/data/nosql/cosmos-db.md +114 -71
- package/framework/standards/frontend/design-system/animations.md +1 -1
- package/framework/standards/frontend/design-system/naming.md +1 -1
- package/framework/standards/frontend/nextjs/motion-patterns.md +45 -29
- package/framework/standards/frontend/nextjs/naming-conventions.md +1 -1
- package/framework/standards/infrastructure/docker/coolify-deploy.md +8 -6
- package/framework/standards/infrastructure/neon/neon-pgvector.md +120 -75
- package/framework/standards/infrastructure/neon/neon-setup.md +53 -31
- package/framework/standards/integration/mcp/mcp-tools.md +7 -7
- package/framework/templates/README.md +2 -3
- package/framework/templates/REGISTRY.json +6 -170
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
- package/framework/templates/code/dotnet/extensions/database-extensions.cs +1 -1
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +27 -0
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +2 -2
- package/framework/templates/docs/plan.md +72 -0
- package/framework/templates/dotnet/ai-kit/README.md +1 -9
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +1 -1
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
- package/framework/templates/infrastructure/docker/coolify.template.json +3 -3
- package/framework/templates/infrastructure/github/README.md +2 -1
- package/framework/templates/infrastructure/github/workflows/deploy-coolify.yml.hbs +2 -1
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +1 -1
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +3 -4
- package/package.json +1 -1
- package/src/commands/e2e/e2e.js +2 -2
- package/src/commands/observability/cost.js +18 -60
- package/src/commands/observability/telemetry.js +3 -5
- package/src/commands/project/doctor-procs.js +1 -1
- package/src/commands/project/doctor.js +9 -9
- package/src/commands/project/fleet.js +4 -4
- package/src/commands/project/heavy.js +3 -3
- package/src/commands/project/init.js +6 -1
- package/src/commands/project/setup-infra-cmd.js +2 -1
- package/src/commands/project/stack-scan.js +58 -0
- package/src/commands/project/standards.js +79 -25
- package/src/commands/project/status.js +29 -69
- package/src/commands/project/update.js +33 -19
- package/src/commands/project/worktree.js +1 -1
- package/src/commands/state/advance.js +62 -46
- package/src/commands/state/approve.js +95 -138
- package/src/commands/state/archive.js +20 -84
- package/src/commands/state/auto-approval.js +68 -0
- package/src/commands/state/create.js +28 -1
- package/src/commands/state/delete.js +1 -1
- package/src/commands/state/finish.js +11 -23
- package/src/commands/state/gate-check.js +86 -95
- package/src/commands/state/gate-decision.js +6 -4
- package/src/commands/state/handoff.js +1 -1
- package/src/commands/state/list.js +9 -9
- package/src/commands/state/report-check.js +157 -311
- package/src/commands/state/retype.js +9 -3
- package/src/commands/validation/mutate.js +77 -14
- package/src/commands/validation/plan-check.js +81 -0
- package/src/commands/validation/validate-feature.js +60 -135
- package/src/commands/validation/verify.js +41 -82
- package/src/core/paths/output-schema.js +20 -67
- package/src/core/state/gate-order.js +5 -6
- package/src/core/state/lifecycle-audit.js +2 -2
- package/src/core/state/state-manager.js +17 -98
- package/src/core/templates/template-registry.js +2 -2
- package/src/core/templates/template-seed.js +22 -0
- package/src/core/work-types.js +10 -10
- package/src/dashboard/app/App.jsx +0 -2
- package/src/dashboard/app/components/ActivityFeed.jsx +2 -3
- package/src/dashboard/app/components/CommandPalette.jsx +7 -8
- package/src/dashboard/app/components/EntityLink.jsx +1 -2
- package/src/dashboard/app/components/Markdown.jsx +1 -1
- package/src/dashboard/app/components/Sidebar.jsx +1 -2
- package/src/dashboard/app/hooks/useMorphQuery.js +1 -1
- package/src/dashboard/app/lib/phases.js +2 -4
- package/src/dashboard/app/pages/Activity.jsx +1 -1
- package/src/dashboard/app/pages/FeatureDetail.jsx +139 -129
- package/src/dashboard/app/pages/Features.jsx +9 -9
- package/src/dashboard/app/pages/Guide.jsx +2 -2
- package/src/dashboard/app/pages/PhasePipeline.jsx +3 -4
- package/src/dashboard/app/pages/RulesMap.jsx +3 -3
- package/src/dashboard/app/pages/SkillsLibrary.jsx +3 -3
- package/src/dashboard/app/pages/Standards.jsx +1 -1
- package/src/dashboard/scanner/activity-scanner.js +6 -16
- package/src/dashboard/scanner/agents-scanner.js +1 -1
- package/src/dashboard/scanner/docs-scanner.js +5 -23
- package/src/dashboard/scanner/features-scanner.js +95 -60
- package/src/dashboard/scanner/index.js +0 -2
- package/src/dashboard/scanner/project-api.js +1 -1
- package/src/dashboard/scanner/rules-scanner.js +15 -10
- package/src/dashboard/scanner/skills-scanner.js +2 -3
- package/src/dashboard/scanner/standards-scanner.js +2 -1
- package/src/lib/ci/ci-verify.js +17 -1
- package/src/lib/ci/github-ci.js +1 -1
- package/src/lib/detectors/index.js +3 -8
- package/src/lib/generators/handoff-generator.js +34 -65
- package/src/lib/generators/settings-generator.js +11 -89
- package/src/lib/git/evidence-staleness.js +1 -1
- package/src/lib/git/tree-fingerprint.js +19 -7
- package/src/lib/git/tree-state.js +2 -2
- package/src/lib/heavy/cleanup.js +1 -5
- package/src/lib/installers/memory-installer.js +6 -8
- package/src/lib/mutation/commands.js +3 -2
- package/src/lib/{tasks/dotnet-test-introspection.js → mutation/dotnet-introspection.js} +17 -282
- package/src/lib/mutation/plan.js +14 -6
- package/src/lib/mutation/runner.js +1 -1
- package/src/lib/mutation/subset.js +46 -9
- package/src/lib/plan/artifact-vocabulary.js +60 -0
- package/src/lib/plan/checks.js +234 -0
- package/src/lib/plan/plan-parser.js +209 -0
- package/src/lib/plan/plan-template.js +18 -0
- package/src/lib/review-reports.js +222 -0
- package/src/lib/risk-detector.js +134 -135
- package/src/lib/specs/adr-index.js +50 -69
- package/src/lib/specs/design-seed.js +18 -0
- package/src/lib/specs/frontmatter.js +44 -0
- package/src/lib/specs/gfm-table.js +17 -0
- package/src/lib/specs/old-format.js +68 -0
- package/src/lib/specs/revocations.js +37 -95
- package/src/lib/specs/screen-checklist.js +18 -17
- package/src/lib/stack/dotnet-build-ignores.js +47 -0
- package/src/lib/stack/stack-profile.js +1 -1
- package/src/lib/stack/stack-scan.js +267 -0
- package/src/lib/standards/registry.js +43 -0
- package/src/lib/standards/sections.js +58 -0
- package/src/lib/tasks/eval-node.js +4 -12
- package/src/lib/tasks/test-nodes.js +1 -74
- package/src/lib/tasks/test-runner.js +75 -117
- package/src/lib/telemetry/metrics.js +8 -69
- package/src/lib/telemetry/telemetry-reader.js +5 -118
- package/src/lib/telemetry/verify-event.js +5 -7
- package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
- package/src/lib/validators/contracts/contract-compliance-validator.js +2 -2
- package/src/lib/validators/reuse/reuse-validator.js +24 -48
- package/src/lib/validators/reuse/symbol-scanner.js +2 -4
- package/src/lib/validators/traceability-check.js +85 -129
- package/src/lib/validators/validation-runner.js +8 -88
- package/src/lib/validators/verify-runner.js +134 -301
- package/src/lib/worktree/docker-audit.js +1 -2
- package/src/lib/worktree/fleet-scanner.js +25 -38
- package/src/scripts/setup-infra.js +42 -22
- package/src/utils/agents-installer.js +92 -13
- package/src/utils/claude-settings-manager.js +0 -35
- package/src/utils/file-copier.js +34 -6
- package/src/utils/hooks-installer.js +16 -9
- package/src/utils/skills-installer.js +1 -2
- package/framework/commands/commit.md +0 -166
- package/framework/evals/trace-schema.md +0 -67
- package/framework/hooks/claude-code/core/tasks-json-guard.js +0 -83
- package/framework/hooks/claude-code/core/trace-autogen.js +0 -277
- package/framework/hooks/git/pre-commit/specs.sh +0 -50
- package/framework/hooks/shared/tasks-validator.js +0 -111
- package/framework/rubrics/backend.json +0 -41
- package/framework/rubrics/default.json +0 -36
- package/framework/rubrics/frontend.json +0 -36
- package/framework/rules/morph-task-tracking.md +0 -54
- package/framework/rules/morph-workflow.md +0 -244
- package/framework/schemas/tasks.schema.json +0 -79
- package/framework/skills/core/morph-brainstorming/SKILL.md +0 -161
- package/framework/skills/core/morph-implement/SKILL.md +0 -194
- package/framework/skills/core/morph-proposal/SKILL.md +0 -152
- package/framework/skills/core/morph-stack-scan/SKILL.md +0 -145
- package/framework/templates/docs/proposal.md +0 -192
- package/framework/templates/docs/spec.md +0 -57
- package/framework/templates/docs/ui-components.md +0 -52
- package/framework/templates/docs/ui-design-system.md +0 -76
- package/framework/templates/docs/ui-flows.md +0 -167
- package/framework/templates/examples/spec-examples.md +0 -91
- package/framework/templates/feature/decisions.md +0 -124
- package/framework/templates/feature/recap.md +0 -145
- package/framework/templates/project/validate.js +0 -97
- package/framework/templates/tasks.template.json +0 -17
- package/src/commands/state/usecase.js +0 -143
- package/src/commands/tasks/dag.js +0 -181
- package/src/dashboard/app/pages/Rubrics.jsx +0 -97
- package/src/dashboard/scanner/rubrics-scanner.js +0 -12
- package/src/lib/agents/output-collector.js +0 -76
- package/src/lib/evaluator-report.js +0 -91
- package/src/lib/specs/acervo-format.js +0 -70
- package/src/lib/specs/acervo-lifecycle.js +0 -264
- package/src/lib/specs/done-criteria-check.js +0 -200
- package/src/lib/specs/usecase-check.js +0 -301
- package/src/lib/specs/usecase-promoter.js +0 -301
- package/src/lib/specs/usecase-registry.js +0 -237
- package/src/lib/tasks/dispatch-planner.js +0 -319
- package/src/lib/tasks/mermaid-renderer.js +0 -132
- package/src/lib/tasks/task-classifier.js +0 -30
- package/src/lib/tasks/task-parser.js +0 -209
- package/src/lib/tasks/tasks-json-parser.js +0 -296
- package/src/lib/tasks/test-scope.js +0 -597
- package/src/lib/validators/architecture/architecture-validator.js +0 -270
- package/src/lib/validators/architecture/index.js +0 -7
- package/src/lib/validators/css/css-validator.js +0 -340
- package/src/lib/validators/css/index.js +0 -7
- package/src/lib/validators/design-system/design-system-validator.js +0 -237
- package/src/lib/validators/design-system/index.js +0 -7
- package/src/lib/validators/score-aggregator.js +0 -244
- package/src/lib/validators/ui/index.js +0 -7
- package/src/lib/validators/ui/ui-contrast-validator.js +0 -422
|
@@ -7,67 +7,43 @@
|
|
|
7
7
|
* fresh instance starts focused instead of inheriting a wall of stale context.
|
|
8
8
|
*
|
|
9
9
|
* Deterministic by construction — everything here is derived from feature.json,
|
|
10
|
-
*
|
|
10
|
+
* the extracted plan checks, the slice reports and the worktree env manifest. The document is
|
|
11
11
|
* therefore REGENERABLE (never hand-edited, never merged): `morph-spec handoff`
|
|
12
12
|
* rebuilds it, and setup/create/advance/approve regenerate it at the moments a
|
|
13
13
|
* new session is most likely to pick the feature up.
|
|
14
14
|
*
|
|
15
|
-
* Every section is fail-open:
|
|
16
|
-
*
|
|
15
|
+
* Every section is fail-open: missing or corrupt plan checks degrade that
|
|
16
|
+
* section, never the document.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
20
20
|
import { join } from 'path';
|
|
21
21
|
import { ensureCommonExclude } from '../../../framework/hooks/shared/git-exclude.js';
|
|
22
22
|
import { derivePhaseForFeature, getPendingGates } from '../../../framework/hooks/shared/state-reader.js';
|
|
23
|
-
|
|
24
|
-
const PHASE_DIRS = {
|
|
25
|
-
proposal: '0-proposal',
|
|
26
|
-
uiux: '1-design',
|
|
27
|
-
plan: '2-plan',
|
|
28
|
-
implement: '3-implement',
|
|
29
|
-
review: '4-review',
|
|
30
|
-
};
|
|
23
|
+
import { sliceProgress, readySlices } from '../../../framework/hooks/shared/slice-progress.js';
|
|
31
24
|
|
|
32
25
|
/** Ordered pointer candidates — only existing paths make it into the doc. */
|
|
33
26
|
const POINTER_CANDIDATES = [
|
|
34
|
-
['
|
|
35
|
-
|
|
36
|
-
['
|
|
37
|
-
['
|
|
38
|
-
['
|
|
39
|
-
['
|
|
40
|
-
['
|
|
41
|
-
['4-review/review-report.md', 'relatório do Gate 3'],
|
|
27
|
+
['2-plan/plan.md', 'plano: problema, cenários com prova, decisões e fatias'],
|
|
28
|
+
['2-plan/checks.json', 'cenários e fatias extraídos pelo plan-check'],
|
|
29
|
+
['1-design/design-system.md', 'design system da feature'],
|
|
30
|
+
['3-implement/reports', 'relatórios das fatias (**Arquivos:**/**Standards:**): o registro da implementação'],
|
|
31
|
+
['4-review/verifier.md', 'verificador do Gate 3: cada cenário provado'],
|
|
32
|
+
['4-review/reviewer.md', 'revisor do Gate 3: escopo, arquitetura, regressão'],
|
|
33
|
+
['4-review/security.md', 'segurança do Gate 3 (só com caminho sensível)'],
|
|
42
34
|
];
|
|
43
35
|
|
|
44
36
|
function readJson(path) {
|
|
45
37
|
return JSON.parse(readFileSync(path, 'utf8').replace(/^/, ''));
|
|
46
38
|
}
|
|
47
39
|
|
|
48
|
-
function taskSummary(featureDir) {
|
|
49
|
-
try {
|
|
50
|
-
const tasksPath = join(featureDir, '2-plan', 'tasks.json');
|
|
51
|
-
if (!existsSync(tasksPath)) return null;
|
|
52
|
-
const data = readJson(tasksPath);
|
|
53
|
-
if (!Array.isArray(data.tasks)) return null;
|
|
54
|
-
const done = data.tasks.filter((t) => t.status === 'done').length;
|
|
55
|
-
const doneIds = new Set(data.tasks.filter((t) => t.status === 'done').map((t) => t.id));
|
|
56
|
-
const ready = data.tasks.filter(
|
|
57
|
-
(t) => t.status === 'pending' && Array.isArray(t.dependencies) && t.dependencies.every((d) => doneIds.has(d)),
|
|
58
|
-
);
|
|
59
|
-
return { done, total: data.tasks.length, ready };
|
|
60
|
-
} catch {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
40
|
function decisionTitles(featureDir, limit = 5) {
|
|
66
41
|
try {
|
|
67
|
-
const path = join(featureDir, '
|
|
42
|
+
const path = join(featureDir, '2-plan', 'checks.json');
|
|
68
43
|
if (!existsSync(path)) return [];
|
|
69
|
-
const
|
|
70
|
-
|
|
44
|
+
const adrs = readJson(path).adrs;
|
|
45
|
+
if (!Array.isArray(adrs)) return [];
|
|
46
|
+
return adrs.map((a) => `${a.id} — ${a.title}`).slice(-limit);
|
|
71
47
|
} catch {
|
|
72
48
|
return [];
|
|
73
49
|
}
|
|
@@ -86,34 +62,27 @@ function readWorktreeEnv(cwd) {
|
|
|
86
62
|
}
|
|
87
63
|
}
|
|
88
64
|
|
|
89
|
-
function nextAction(feature, phase,
|
|
65
|
+
function nextAction(feature, phase, slices, featureName) {
|
|
90
66
|
const gates = feature.approvals || feature.approvalGates || {};
|
|
91
67
|
const approved = (g) => gates[g]?.approved === true;
|
|
92
68
|
|
|
93
69
|
switch (phase) {
|
|
94
|
-
case '
|
|
95
|
-
|
|
96
|
-
// the derived phase only flips when 2-plan/spec.md lands (derivePhase is
|
|
97
|
-
// artifact-first). Pointing back at the proposal here would be wrong.
|
|
98
|
-
return approved('proposal')
|
|
99
|
-
? `Gate 1 aprovado — produza \`2-plan/spec.md\` + \`tasks.json\` (a fase avança com o primeiro artefato; Gate 2 em seguida).`
|
|
100
|
-
: `Complete \`0-proposal/proposal.md\` e aprove o Gate 1 (\`morph-spec advance ${featureName}\`). Skill: /morph-proposal ${featureName}.`;
|
|
70
|
+
case 'plan':
|
|
71
|
+
return `Escreva \`2-plan/plan.md\`, rode \`morph-spec plan-check ${featureName}\` até zero erro e aprove o gate do plano (\`morph-spec advance ${featureName}\`). Skill: /morph-proposal ${featureName}.`;
|
|
101
72
|
case 'uiux':
|
|
102
73
|
return approved('uiux')
|
|
103
|
-
? `Gate de uiux aprovado —
|
|
74
|
+
? `Gate de uiux aprovado — implemente as fatias do plano via /morph-apply ${featureName}.`
|
|
104
75
|
: `Complete \`1-design/design-system.md\` e aprove o gate de uiux (\`morph-spec advance ${featureName}\`).`;
|
|
105
|
-
case 'plan':
|
|
106
|
-
return `Produza \`2-plan/spec.md\` + \`tasks.json\` e aprove o Gate 2 (\`morph-spec advance ${featureName}\`).`;
|
|
107
76
|
case 'implement': {
|
|
108
|
-
const ready =
|
|
77
|
+
const ready = readySlices(slices).map((s) => `${s.id} "${s.title}"`).join(', ');
|
|
109
78
|
return ready
|
|
110
|
-
? `
|
|
111
|
-
: `Todas as
|
|
79
|
+
? `Implemente as fatias prontas — ${ready} — via /morph-apply ${featureName} (cada fatia grava 3-implement/reports/{id}.md).`
|
|
80
|
+
: `Todas as fatias têm relatório final — rode \`morph-spec verify ${featureName}\` e siga para a review. Skill: /morph-apply ${featureName}.`;
|
|
112
81
|
}
|
|
113
82
|
case 'review':
|
|
114
83
|
return approved('review')
|
|
115
84
|
? `Gate 3 aprovado — feche: \`morph-spec finish ${featureName} --pr\` (abre PR) ou \`--merge\` (merge local na default). Arquiva + integra num passo.`
|
|
116
|
-
: `
|
|
85
|
+
: `Rode /morph-review ${featureName} (verificador ∥ revisor, segurança se exigida) e aprove o Gate 3; depois \`morph-spec finish ${featureName} --pr|--merge\`.`;
|
|
117
86
|
default:
|
|
118
87
|
return `Rode \`morph-spec status ${featureName}\` para orientar o próximo passo.`;
|
|
119
88
|
}
|
|
@@ -131,7 +100,7 @@ function nextAction(feature, phase, tasks, featureName) {
|
|
|
131
100
|
* copy at birth (create.js) — a handoff built FROM the worktree's own copy
|
|
132
101
|
* would otherwise always say "no worktree registered", even while sitting
|
|
133
102
|
* inside one. Pass `undefined` (the default) to fall back to `feature.worktree`.
|
|
134
|
-
* @returns {{ markdown: string, meta: { generatedAt: string, phase: string,
|
|
103
|
+
* @returns {{ markdown: string, meta: { generatedAt: string, phase: string, slicesDone: number, slicesTotal: number } } | null}
|
|
135
104
|
*/
|
|
136
105
|
export function buildHandoff(featureName, cwd = process.cwd(), opts = {}) {
|
|
137
106
|
const featureDir = join(cwd, '.morph', 'features', featureName);
|
|
@@ -144,15 +113,15 @@ export function buildHandoff(featureName, cwd = process.cwd(), opts = {}) {
|
|
|
144
113
|
return null;
|
|
145
114
|
}
|
|
146
115
|
|
|
147
|
-
let phase = '
|
|
116
|
+
let phase = 'plan';
|
|
148
117
|
let pendingGates = [];
|
|
149
118
|
try {
|
|
150
|
-
phase = derivePhaseForFeature(featureName, cwd) || '
|
|
119
|
+
phase = derivePhaseForFeature(featureName, cwd) || 'plan';
|
|
151
120
|
pendingGates = getPendingGates(featureName, cwd) || [];
|
|
152
|
-
} catch { /* fail-open —
|
|
121
|
+
} catch { /* fail-open — plan defaults keep the doc useful */ }
|
|
153
122
|
|
|
154
123
|
const generatedAt = new Date().toISOString();
|
|
155
|
-
const
|
|
124
|
+
const slices = sliceProgress(featureDir);
|
|
156
125
|
const env = readWorktreeEnv(cwd);
|
|
157
126
|
const decisions = decisionTitles(featureDir);
|
|
158
127
|
const worktree = opts.worktree !== undefined ? opts.worktree : (feature.worktree || null);
|
|
@@ -187,9 +156,9 @@ export function buildHandoff(featureName, cwd = process.cwd(), opts = {}) {
|
|
|
187
156
|
'## Estado',
|
|
188
157
|
'',
|
|
189
158
|
`- Gates: ${gateLine}`,
|
|
190
|
-
|
|
191
|
-
? `-
|
|
192
|
-
: '-
|
|
159
|
+
slices
|
|
160
|
+
? `- Fatias: ${slices.done}/${slices.total} feitas${slices.partial ? ` · ${slices.partial} parcial(is)` : ''} · prontas agora: ${readySlices(slices).map((s) => `**${s.id}** "${s.title}"`).join(', ') || 'nenhuma'}`
|
|
161
|
+
: '- Fatias: sem checks.json ainda (rode plan-check)',
|
|
193
162
|
pendingGates.length ? `- Gates pendentes: ${pendingGates.join(', ')}` : null,
|
|
194
163
|
'',
|
|
195
164
|
'## Leia nesta ordem (ponteiros — nada copiado)',
|
|
@@ -200,7 +169,7 @@ export function buildHandoff(featureName, cwd = process.cwd(), opts = {}) {
|
|
|
200
169
|
'',
|
|
201
170
|
'## Próxima ação',
|
|
202
171
|
'',
|
|
203
|
-
nextAction(feature, phase,
|
|
172
|
+
nextAction(feature, phase, slices, featureName),
|
|
204
173
|
'',
|
|
205
174
|
'## Retomar',
|
|
206
175
|
'',
|
|
@@ -214,8 +183,8 @@ export function buildHandoff(featureName, cwd = process.cwd(), opts = {}) {
|
|
|
214
183
|
meta: {
|
|
215
184
|
generatedAt,
|
|
216
185
|
phase,
|
|
217
|
-
|
|
218
|
-
|
|
186
|
+
slicesDone: slices?.done ?? 0,
|
|
187
|
+
slicesTotal: slices?.total ?? 0,
|
|
219
188
|
},
|
|
220
189
|
};
|
|
221
190
|
}
|
|
@@ -23,25 +23,12 @@ export async function generateSettings(targetPath, detectedConfig, morphConfig =
|
|
|
23
23
|
const claudeDir = join(targetPath, '.claude');
|
|
24
24
|
const settingsPath = join(claudeDir, 'settings.local.json');
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
const existing = await readSettingsSafe(settingsPath);
|
|
28
|
-
|
|
29
|
-
// Build stack-based permissions
|
|
30
|
-
const stack = morphConfig?.project?.architecture || 'unknown';
|
|
31
|
-
const permissions = buildPermissions(stack, detectedConfig);
|
|
32
|
-
|
|
33
|
-
// Build generated settings
|
|
26
|
+
const existing = withoutLegacyPermissions(await readSettingsSafe(settingsPath));
|
|
34
27
|
const generated = {};
|
|
35
28
|
|
|
36
|
-
if (permissions.length > 0) {
|
|
37
|
-
generated.permissions = permissions;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Track what we manage
|
|
41
29
|
const managed = {
|
|
42
|
-
permissions_added: permissions,
|
|
43
30
|
mcps_detected: detectedConfig.mcpServers.map(s => s.name),
|
|
44
|
-
plugins_detected: detectedConfig.plugins.map(p => p
|
|
31
|
+
plugins_detected: detectedConfig.plugins.map(p => (typeof p === 'string' ? p : p?.name)),
|
|
45
32
|
generated_at: new Date().toISOString()
|
|
46
33
|
};
|
|
47
34
|
|
|
@@ -58,44 +45,10 @@ export async function generateSettings(targetPath, detectedConfig, morphConfig =
|
|
|
58
45
|
|
|
59
46
|
return {
|
|
60
47
|
settingsPath,
|
|
61
|
-
permissionsAdded: permissions.length,
|
|
62
48
|
managed
|
|
63
49
|
};
|
|
64
50
|
}
|
|
65
51
|
|
|
66
|
-
/**
|
|
67
|
-
* Build permission rules based on detected stack
|
|
68
|
-
* @param {string} stack - Detected project stack
|
|
69
|
-
* @param {Object} detectedConfig - Detected Claude config
|
|
70
|
-
* @returns {Array<string>} Permission patterns
|
|
71
|
-
*/
|
|
72
|
-
export function buildPermissions(stack, detectedConfig = {}) {
|
|
73
|
-
const permissions = [];
|
|
74
|
-
|
|
75
|
-
// Stack-based permissions
|
|
76
|
-
const stackPermissions = {
|
|
77
|
-
nodejs: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
|
|
78
|
-
typescript: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)', 'Bash(tsc:*)'],
|
|
79
|
-
nextjs: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
|
|
80
|
-
react: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
|
|
81
|
-
vue: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
|
|
82
|
-
dotnet: ['Bash(dotnet:*)', 'Bash(nuget:*)'],
|
|
83
|
-
python: ['Bash(python:*)', 'Bash(pip:*)', 'Bash(pytest:*)'],
|
|
84
|
-
go: ['Bash(go:*)']
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
if (stackPermissions[stack]) {
|
|
88
|
-
permissions.push(...stackPermissions[stack]);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// morph-spec CLI always needs node/npx
|
|
92
|
-
if (!permissions.includes('Bash(npx:*)')) {
|
|
93
|
-
permissions.push('Bash(npx:*)');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return permissions;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
52
|
/**
|
|
100
53
|
* Deep merge settings without overwriting user entries
|
|
101
54
|
* @param {Object} existing - Current settings.local.json
|
|
@@ -127,46 +80,6 @@ export function mergeSettings(existing, generated) {
|
|
|
127
80
|
return result;
|
|
128
81
|
}
|
|
129
82
|
|
|
130
|
-
/**
|
|
131
|
-
* Remove only morph-spec managed entries from settings
|
|
132
|
-
* @param {string} settingsPath - Path to settings.local.json
|
|
133
|
-
* @returns {Promise<Object>} Summary of what was removed
|
|
134
|
-
*/
|
|
135
|
-
export async function resetMorphSettings(settingsPath) {
|
|
136
|
-
if (!existsSync(settingsPath)) {
|
|
137
|
-
return { removed: false, reason: 'file not found' };
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const settings = await readSettingsSafe(settingsPath);
|
|
141
|
-
const managed = settings[MORPH_MANAGED_KEY];
|
|
142
|
-
|
|
143
|
-
if (!managed) {
|
|
144
|
-
return { removed: false, reason: 'no _morph_managed section found' };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Remove managed permissions
|
|
148
|
-
if (managed.permissions_added && Array.isArray(settings.permissions)) {
|
|
149
|
-
settings.permissions = settings.permissions.filter(
|
|
150
|
-
p => !managed.permissions_added.includes(p)
|
|
151
|
-
);
|
|
152
|
-
if (settings.permissions.length === 0) {
|
|
153
|
-
delete settings.permissions;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Remove the managed marker itself
|
|
158
|
-
delete settings[MORPH_MANAGED_KEY];
|
|
159
|
-
|
|
160
|
-
// Write back
|
|
161
|
-
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
removed: true,
|
|
165
|
-
permissionsRemoved: managed.permissions_added || [],
|
|
166
|
-
previouslyGenerated: managed.generated_at
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
83
|
/**
|
|
171
84
|
* Save integrations.json with detected config
|
|
172
85
|
* @param {string} targetPath - Project root directory
|
|
@@ -198,6 +111,15 @@ export async function saveIntegrations(targetPath, detectedConfig) {
|
|
|
198
111
|
// Helpers
|
|
199
112
|
// ============================================================================
|
|
200
113
|
|
|
114
|
+
// Claude Code reads only `permissions: { allow, deny }`; a bare array (older generator) is ignored.
|
|
115
|
+
// Versões antigas gravavam regras curinga (node:*, npm:*, npx:*…) como array, forma que o
|
|
116
|
+
// Claude Code ignora: nunca valeram. Converter para { allow } as ligaria em silêncio.
|
|
117
|
+
function withoutLegacyPermissions(settings) {
|
|
118
|
+
if (!Array.isArray(settings.permissions)) return settings;
|
|
119
|
+
const { permissions, ...rest } = settings;
|
|
120
|
+
return rest;
|
|
121
|
+
}
|
|
122
|
+
|
|
201
123
|
async function readSettingsSafe(settingsPath) {
|
|
202
124
|
try {
|
|
203
125
|
if (!existsSync(settingsPath)) return {};
|
|
@@ -7,7 +7,7 @@ const CONFIG_PATH = '.morph/config/config.json';
|
|
|
7
7
|
|
|
8
8
|
const gitOut = (cwd, args) => execFileSync('git', args, { cwd, stdio: 'pipe', maxBuffer: 64 * 1024 * 1024 }).toString();
|
|
9
9
|
|
|
10
|
-
function withoutBaseline(text) {
|
|
10
|
+
export function withoutBaseline(text) {
|
|
11
11
|
const config = JSON.parse(text);
|
|
12
12
|
if (Array.isArray(config?.project?.tests)) {
|
|
13
13
|
for (const node of config.project.tests) delete node?.expectedCount;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A hash of what a verify run reads: the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* runs over the same code look different.
|
|
2
|
+
* A hash of what a verify run reads: the committed tree, the uncommitted changes and the
|
|
3
|
+
* untracked files, plus `config.json` without `expectedCount` (it names the test commands).
|
|
4
|
+
* The rest of `.morph/` stays out, as in `treeMovedSince`: committing verify's own
|
|
5
|
+
* bookkeeping must not make the same code look different.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
import { execFileSync } from 'child_process';
|
|
10
9
|
import { createHash } from 'crypto';
|
|
11
10
|
import { existsSync, readFileSync, statSync } from 'fs';
|
|
12
11
|
import { join } from 'path';
|
|
12
|
+
import { withoutBaseline } from './evidence-staleness.js';
|
|
13
13
|
|
|
14
14
|
/** Pathspec for "the project minus its `.morph/` bookkeeping". */
|
|
15
15
|
export const OUTSIDE_MORPH = ['--', '.', ':(exclude).morph'];
|
|
@@ -31,7 +31,11 @@ export function treeFingerprint(projectPath) {
|
|
|
31
31
|
const hash = createHash('sha256');
|
|
32
32
|
let head = null;
|
|
33
33
|
try { head = git(projectPath, ['rev-parse', 'HEAD']).toString().trim(); } catch { /* no commit yet */ }
|
|
34
|
-
|
|
34
|
+
// Tree ids are content-addressed: the top-level entries minus .morph change only with code.
|
|
35
|
+
const tree = head
|
|
36
|
+
? git(projectPath, ['ls-tree', '-z', 'HEAD']).toString().split('\0').filter((e) => e && e.split('\t')[1] !== '.morph')
|
|
37
|
+
: ['no-commit'];
|
|
38
|
+
hash.update(`tree\0${tree.join('\0')}\0`);
|
|
35
39
|
// Before the first commit there is no HEAD to diff against: every file is
|
|
36
40
|
// untracked, and the listing below covers them.
|
|
37
41
|
if (head) hash.update(git(projectPath, ['diff', 'HEAD', '--binary', ...OUTSIDE_MORPH]));
|
|
@@ -50,9 +54,17 @@ export function treeFingerprint(projectPath) {
|
|
|
50
54
|
}
|
|
51
55
|
const config = join(projectPath, '.morph', 'config', 'config.json');
|
|
52
56
|
hash.update('\0config\0');
|
|
53
|
-
if (existsSync(config)) hash.update(readFileSync(config));
|
|
57
|
+
if (existsSync(config)) hash.update(normalizedConfig(readFileSync(config, 'utf8')));
|
|
54
58
|
return hash.digest('hex');
|
|
55
59
|
} catch {
|
|
56
60
|
return null;
|
|
57
61
|
}
|
|
58
62
|
}
|
|
63
|
+
|
|
64
|
+
function normalizedConfig(text) {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.stringify(withoutBaseline(text));
|
|
67
|
+
} catch {
|
|
68
|
+
return text;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -11,7 +11,7 @@ import { OUTSIDE_MORPH, treeFingerprint, git as gitBuffer } from './tree-fingerp
|
|
|
11
11
|
import { detectDefaultBranch } from './default-branch.js';
|
|
12
12
|
import { resolveBaseRef } from './branch-classifier.js';
|
|
13
13
|
|
|
14
|
-
/** What
|
|
14
|
+
/** What the verifier writes next to a mutation it has not reverted yet. */
|
|
15
15
|
export const MUTATION_MARKER = 'MUTACAO';
|
|
16
16
|
const MAX_LISTED = 50;
|
|
17
17
|
const MAX_COMMITS = 10;
|
|
@@ -50,7 +50,7 @@ function commitBlobs(cwd, commit, paths) {
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* What the tree is before a dispatch whose work must leave it unchanged (the
|
|
53
|
-
*
|
|
53
|
+
* verifier mutates and reverts): HEAD plus the blob of every file that
|
|
54
54
|
* differs from it. Kept on disk, so a session that resumes after the agent
|
|
55
55
|
* died compares against the tree before the dispatch, not its own start.
|
|
56
56
|
* @returns {{ at: string, head: string|null, files: Object<string, string|null> }|null}
|
package/src/lib/heavy/cleanup.js
CHANGED
|
@@ -6,7 +6,6 @@ import { heavyDir, runExclusive } from '../../../framework/hooks/shared/heavy-sl
|
|
|
6
6
|
|
|
7
7
|
const DOTNET_ACTIVE = /\bdotnet(?:\.exe)?["']?\s+(?:build|test|publish|pack|msbuild|restore|run|watch|vstest)\b/i;
|
|
8
8
|
const IDLE_WORKER = /\/nodemode:\d|vbcscompiler|razorserver/i;
|
|
9
|
-
const SHUTDOWN_SCOPES = new Set(['feature', 'e2e-down', 'prune']);
|
|
10
9
|
const SHUTDOWN_TIMEOUT_MS = 30_000;
|
|
11
10
|
const TAIL_CHARS = 400;
|
|
12
11
|
|
|
@@ -33,16 +32,13 @@ export function dotnetBusy(procs) {
|
|
|
33
32
|
});
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
export function afterHeavyRun({ projectPath, config,
|
|
35
|
+
export function afterHeavyRun({ projectPath, config, env = process.env, deps = {} }) {
|
|
37
36
|
const {
|
|
38
37
|
exec = defaultProcExec, list = listProcesses, dotnet = hasDotnet, exclusive = runExclusive,
|
|
39
38
|
} = deps;
|
|
40
39
|
|
|
41
40
|
if (!config.enabled) return { status: 'skipped', reason: 'semáforo desligado: sem ele nada prova que outra sessão não está compilando' };
|
|
42
41
|
if (!config.shutdownBuildServer) return { status: 'skipped', reason: 'desligado em heavy.shutdownBuildServer' };
|
|
43
|
-
if (!SHUTDOWN_SCOPES.has(scope)) {
|
|
44
|
-
return { status: 'skipped', reason: 'escopo de task: o servidor de compilação segue quente para a próxima task' };
|
|
45
|
-
}
|
|
46
42
|
if (!dotnet(projectPath)) return { status: 'skipped', reason: 'projeto sem .NET' };
|
|
47
43
|
|
|
48
44
|
const guarded = exclusive({
|
|
@@ -41,8 +41,7 @@ metadata:
|
|
|
41
41
|
- \`.morph/framework/MORPH.md\` — NLH charter (read once per session)
|
|
42
42
|
- \`.morph/framework/agents.json\` — 8 agents: 7 domain personas + 1 stage persona (\`scout\`, read-only)
|
|
43
43
|
- \`.morph/framework/standards/STANDARDS.json\` — standards index (load on demand)
|
|
44
|
-
- \`.morph/
|
|
45
|
-
- \`.morph/features/{feature}/\` — feature artifacts: 0-proposal / 1-design / 2-plan / 3-implement / 4-review
|
|
44
|
+
- \`.morph/features/{feature}/\` — feature artifacts: 2-plan / 1-design / 3-implement / 4-review
|
|
46
45
|
- \`.morph/context/\` — long-lived architectural context (design-system, decisions)
|
|
47
46
|
- \`.morph/state.json\` — feature state (managed by state-sync hook; Edit fallback allowed)
|
|
48
47
|
|
|
@@ -50,8 +49,8 @@ metadata:
|
|
|
50
49
|
|
|
51
50
|
| Command | Skill invoked |
|
|
52
51
|
|---------|---------------|
|
|
53
|
-
| \`/morph-proposal {feature}\` | \`Skill(morph-
|
|
54
|
-
| \`/morph-apply {feature}\` | \`Skill(morph-apply)\` —
|
|
52
|
+
| \`/morph-proposal {feature}\` | \`Skill(morph-plan)\` — entrevista → plan.md → plan-check → gate do plano |
|
|
53
|
+
| \`/morph-apply {feature}\` | \`Skill(morph-apply)\` — fatias do plano → verify → review → Gate 3 |
|
|
55
54
|
| \`/morph-status [feature]\` | inspect state.json |
|
|
56
55
|
| \`/morph-archive {feature}\` | move completed feature to .morph/archive/ |
|
|
57
56
|
| \`/morph-preflight\` | pre-deploy validation |
|
|
@@ -59,13 +58,13 @@ metadata:
|
|
|
59
58
|
|
|
60
59
|
## Core skills
|
|
61
60
|
|
|
62
|
-
\`morph-
|
|
61
|
+
\`morph-plan\`, \`morph-apply\`, \`morph-uiux\`, \`morph-review\`, \`morph-hotfix\`, \`morph-standards\`
|
|
63
62
|
|
|
64
63
|
**Why:** This project is managed by morph-spec — spec-driven autonomous development with trust-aware gates.
|
|
65
64
|
|
|
66
65
|
**How to apply:**
|
|
67
66
|
- When user mentions a feature, check \`.morph/features/\` first.
|
|
68
|
-
- When user types \`/morph-proposal\`, invoke \`Skill(morph-
|
|
67
|
+
- When user types \`/morph-proposal\`, invoke \`Skill(morph-plan)\` directly.
|
|
69
68
|
- In \`trust: "auto"\`, gates auto-pass; only AskUserQuestion on risk signals.
|
|
70
69
|
`;
|
|
71
70
|
}
|
|
@@ -83,10 +82,9 @@ metadata:
|
|
|
83
82
|
- \`.morph/context/design-system.md\` — design tokens and components (source of truth)
|
|
84
83
|
- \`.morph/framework/MORPH.md\` — NLH charter, Trust Mode rules, gates, skills table
|
|
85
84
|
- \`.morph/framework/standards/STANDARDS.json\` — index; load specific standard via \`path\` field
|
|
86
|
-
- \`.morph/framework/schemas/tasks.schema.json\` — tasks.json schema reference
|
|
87
85
|
- \`.morph/framework/phases.json\` — phase folder mapping and skill associations
|
|
88
86
|
- \`.morph/framework/agents.json\` — domain persona definitions (dotnet-senior, ef-modeler, etc.)
|
|
89
|
-
- \`.morph/framework/evals/review-checklist.md\` — what the Gate 3
|
|
87
|
+
- \`.morph/framework/evals/review-checklist.md\` — what the Gate 3 verifier, reviewer and security check (verdict SHIP/FIX + evidence-typed blockers)
|
|
90
88
|
`;
|
|
91
89
|
|
|
92
90
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { discoverDotnetBuildTargets, dotnetBuildCommandFor } from '../tasks/test-runner.js';
|
|
2
3
|
|
|
3
4
|
const FILTER = /--filter(?:[ =:])(?:"([^"]*)"|'([^']*)'|(\S+))/;
|
|
4
5
|
const quote = (s) => `"${String(s).replace(/"/g, '\\"')}"`;
|
|
@@ -32,7 +33,7 @@ const VERBOSITY = /\s(?:-v|--verbosity)[ =:]?\S+/g;
|
|
|
32
33
|
export function dotnetBuildCommands(node, projectPath) {
|
|
33
34
|
const configuration = CONFIGURATION.exec(node.command ?? '');
|
|
34
35
|
const flag = configuration ? ` -c ${configuration[1] ?? configuration[2]}` : '';
|
|
35
|
-
return
|
|
36
|
+
return discoverDotnetBuildTargets(node, resolve(projectPath || '.', node.cwd || '.'))
|
|
36
37
|
.map((target) => dotnetBuildCommandFor(target, projectPath))
|
|
37
38
|
.filter(Boolean)
|
|
38
39
|
.map((command) => `${command.replace(VERBOSITY, '')} -v m${flag}`);
|