@polymorphism-tech/morph-spec 9.1.0 โ 9.3.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 +14 -78
- package/README.md +2 -2
- package/bin/morph-spec.js +14 -1
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +4 -3
- package/framework/MORPH.md +7 -10
- package/framework/agents.json +15 -12
- package/framework/commands/morph-status.md +2 -2
- package/framework/docs/CLI.md +24 -16
- package/framework/evals/review-checklist.md +15 -2
- package/framework/hooks/README.md +8 -44
- package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
- package/framework/hooks/claude-code/core/state-sync.js +1 -1
- package/framework/hooks/claude-code/core/worktree-context.js +23 -0
- package/framework/hooks/claude-code/statusline.py +3 -2
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/shared/gate-event.js +18 -0
- package/framework/hooks/shared/next-step.js +107 -0
- package/framework/hooks/shared/slice-progress.js +18 -5
- package/framework/hooks/shared/state-writer.js +6 -1
- package/framework/mcp/registry.json +31 -1
- package/framework/rules/nextjs-standards.md +1 -1
- package/framework/schemas/feature.schema.json +1 -0
- 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 +6 -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 +8 -6
- 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 +2 -1
- package/framework/standards/STANDARDS.json +2 -2
- package/framework/standards/STANDARDS.meta.json +1 -1
- package/framework/standards/ai-agents/setup.md +2 -0
- package/framework/standards/backend/dotnet/testing.md +10 -4
- package/framework/standards/frontend/nextjs/testing.md +10 -6
- package/framework/standards/integration/mcp/mcp-tools.md +3 -1
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- 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/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/observability/cost.js +12 -0
- package/src/commands/project/status.js +6 -68
- package/src/commands/state/advance.js +1 -1
- package/src/commands/state/approve.js +2 -2
- package/src/commands/state/gate-check.js +2 -2
- package/src/commands/state/gate-decision.js +4 -1
- package/src/commands/state/next.js +24 -0
- package/src/commands/state/report-check.js +3 -1
- package/src/commands/validation/mutate.js +9 -6
- 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 +4 -2
- package/src/commands/validation/verify.js +21 -16
- package/src/core/state/state-manager.js +4 -0
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/FeatureDetail.jsx +6 -2
- package/src/dashboard/scanner/features-scanner.js +5 -2
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/ci/workflow-scaffold.js +12 -0
- package/src/lib/e2e/applicability.js +37 -0
- package/src/lib/generators/handoff-generator.js +11 -25
- package/src/lib/mutation/adapters.js +6 -17
- package/src/lib/mutation/runner.js +23 -75
- package/src/lib/mutation/trx.js +0 -1
- package/src/lib/next-step.js +10 -0
- package/src/lib/plan/checks.js +29 -2
- package/src/lib/plan/plan-parser.js +6 -2
- package/src/lib/review-reports.js +6 -3
- package/src/lib/risk-detector.js +20 -7
- package/src/lib/stack/stack-scan.js +13 -1
- package/src/lib/telemetry/metrics.js +46 -0
- package/src/lib/tests-audit/audit.js +96 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
- package/src/lib/validators/validation-runner.js +6 -38
- package/src/lib/validators/verify-runner.js +37 -22
- package/src/utils/agents-installer.js +24 -1
- 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
|
@@ -9,7 +9,7 @@ import { isTestFile } from '../reuse/symbol-scanner.js';
|
|
|
9
9
|
import { isGenerated, isProjectSource } from '../../../../framework/hooks/shared/source-files.js';
|
|
10
10
|
import { citesProcess, commentLines } from '../../../../framework/hooks/shared/comment-scanner.js';
|
|
11
11
|
|
|
12
|
-
export const MAX_TEST_RATIO = 1
|
|
12
|
+
export const MAX_TEST_RATIO = 1;
|
|
13
13
|
|
|
14
14
|
/** Abaixo disto a razรฃo nรฃo รฉ julgada: a regressรฃo de um bug de 2 linhas cabe aqui. */
|
|
15
15
|
export const MIN_TEST_LINES = 40;
|
|
@@ -3,11 +3,6 @@ import chalk from 'chalk';
|
|
|
3
3
|
import { getAbsoluteOutputPath, resolveContractsOutputType } from '../../core/paths/output-schema.js';
|
|
4
4
|
import { getStackProfile } from '../stack/stack-profile.js';
|
|
5
5
|
|
|
6
|
-
// Skipped in 'light' mode (checkpoint-only); light keeps `nextjs-component`.
|
|
7
|
-
const HEAVY_VALIDATORS = new Set([
|
|
8
|
-
'packages', 'contract-compliance', 'reuse', 'code-budget'
|
|
9
|
-
]);
|
|
10
|
-
|
|
11
6
|
/**
|
|
12
7
|
* @param {string[]} [options.validators] - overrides stack-based detection
|
|
13
8
|
* @returns {Object} { passed, errors, warnings, issues, summary, results, skipped, _skipReason? }
|
|
@@ -24,36 +19,11 @@ export async function runValidation(projectPath, featureName, options = {}) {
|
|
|
24
19
|
|
|
25
20
|
// A copy: filtering in place would empty the caller's own `options.validators`.
|
|
26
21
|
const detected = options.validators || detectValidators(projectPath);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const mode = options.mode || 'full';
|
|
30
|
-
const droppedByMode = [];
|
|
31
|
-
if (mode === 'light') {
|
|
32
|
-
validatorIds = validatorIds.filter(id => {
|
|
33
|
-
if (HEAVY_VALIDATORS.has(id)) { droppedByMode.push(id); return false; }
|
|
34
|
-
return true;
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Stack-agnostic validators join here, before the "no validators" early return:
|
|
39
|
-
// on an `empty`/`nodejs-cli` stack they are the only check. Not in `droppedByMode`,
|
|
40
|
-
// which only lists what light mode removed from the stack's own list.
|
|
41
|
-
if (!options.skipReuse && mode !== 'light') {
|
|
42
|
-
validatorIds.push('reuse');
|
|
43
|
-
}
|
|
44
|
-
if (mode !== 'light') {
|
|
45
|
-
validatorIds.push('code-budget');
|
|
46
|
-
}
|
|
22
|
+
const validatorIds = [...detected];
|
|
47
23
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
: 'No validators ran โ no validators configured for this stack';
|
|
52
|
-
console.log(chalk.gray(`\n โน๏ธ ${result.summary.replace('No validators ran โ ', '')}`));
|
|
53
|
-
result._skipReason = result.summary;
|
|
54
|
-
result._droppedByMode = droppedByMode;
|
|
55
|
-
return result;
|
|
56
|
-
}
|
|
24
|
+
// Stack-agnostic: on an `empty`/`nodejs-cli` stack they are the only check.
|
|
25
|
+
if (!options.skipReuse) validatorIds.push('reuse');
|
|
26
|
+
validatorIds.push('code-budget');
|
|
57
27
|
|
|
58
28
|
console.log(chalk.gray(`\n Running ${validatorIds.length} validator(s): ${validatorIds.join(', ')}`));
|
|
59
29
|
|
|
@@ -61,10 +31,8 @@ export async function runValidation(projectPath, featureName, options = {}) {
|
|
|
61
31
|
const _profileForContracts = getStackProfile(projectPath);
|
|
62
32
|
const contractsType = resolveContractsOutputType(_profileForContracts.stack);
|
|
63
33
|
const contractsPath = getAbsoluteOutputPath(projectPath, featureName, contractsType);
|
|
64
|
-
// Positive `isDotnet`, not `!isNextjs`: a "dotnet-nextjs" stack is both.
|
|
65
|
-
|
|
66
|
-
const contractsIsHeavyAndSkipped = mode === 'light' && HEAVY_VALIDATORS.has('contract-compliance');
|
|
67
|
-
if (existsSync(contractsPath) && _profileForContracts.isDotnet && !contractsIsHeavyAndSkipped) {
|
|
34
|
+
// Positive `isDotnet`, not `!isNextjs`: a "dotnet-nextjs" stack is both.
|
|
35
|
+
if (existsSync(contractsPath) && _profileForContracts.isDotnet) {
|
|
68
36
|
validatorIds.push('contract-compliance');
|
|
69
37
|
}
|
|
70
38
|
}
|
|
@@ -5,6 +5,7 @@ import { join, resolve } from 'path';
|
|
|
5
5
|
import { runBuildCheck, getBuildSteps, isDotnetStack } from '../../../framework/hooks/shared/build-check.js';
|
|
6
6
|
import { composeProjectName, runE2eCheck } from '../../../framework/hooks/shared/e2e-check.js';
|
|
7
7
|
import { buildComposeEnv } from '../e2e/compose-env.js';
|
|
8
|
+
import { e2eApplicability } from '../e2e/applicability.js';
|
|
8
9
|
import {
|
|
9
10
|
runTestSuite, parseTestCount, compareTestCount, resolveTestTimeout, discoverDotnetSolution,
|
|
10
11
|
} from '../tasks/test-runner.js';
|
|
@@ -21,7 +22,7 @@ import { runValidation } from './validation-runner.js';
|
|
|
21
22
|
import { checkOutputsTraceability } from './traceability-check.js';
|
|
22
23
|
import { createHeavyGate } from '../heavy/gate.js';
|
|
23
24
|
|
|
24
|
-
// A dotnet
|
|
25
|
+
// A cold dotnet build takes minutes, not seconds.
|
|
25
26
|
const DEFAULT_BUILD_TIMEOUT = 120_000;
|
|
26
27
|
|
|
27
28
|
const VALIDATOR_FEEDBACK_LIMIT = 10;
|
|
@@ -67,6 +68,7 @@ async function runVerifyGated(projectPath, featureName, options, gate) {
|
|
|
67
68
|
_runTestSuite = runTestSuite,
|
|
68
69
|
_runValidation = runValidation,
|
|
69
70
|
_runE2eCheck = runE2eCheck,
|
|
71
|
+
_e2eApplicability = e2eApplicability,
|
|
70
72
|
_checkOutputsTraceability = checkOutputsTraceability,
|
|
71
73
|
} = options;
|
|
72
74
|
|
|
@@ -150,8 +152,11 @@ async function runVerifyGated(projectPath, featureName, options, gate) {
|
|
|
150
152
|
skipE2e,
|
|
151
153
|
freshE2e,
|
|
152
154
|
buildNode: nodes.build,
|
|
155
|
+
testsNode: nodes.tests,
|
|
156
|
+
hasStackNodes: stackNodes.length > 0,
|
|
153
157
|
gate,
|
|
154
158
|
_runE2eCheck,
|
|
159
|
+
_e2eApplicability,
|
|
155
160
|
});
|
|
156
161
|
nodes.e2e = e2e.node;
|
|
157
162
|
appendE2eFeedback(feedback, nodes.e2e);
|
|
@@ -168,12 +173,17 @@ async function runVerifyGated(projectPath, featureName, options, gate) {
|
|
|
168
173
|
// warning never turns red.
|
|
169
174
|
const traceability = _checkOutputsTraceability(projectPath, featureName);
|
|
170
175
|
|
|
171
|
-
const status = Object.values(nodes).some((n) => n.status === 'fail') ? 'fail' : 'pass';
|
|
172
|
-
|
|
173
176
|
const baseline = recordBaseline ? recordBaselineFrom(projectPath, nodes.tests) : null;
|
|
174
177
|
if (baseline && !baseline.recorded) {
|
|
175
178
|
feedback.push(`[baseline] nรฃo gravada: ${baseline.reason}`);
|
|
176
179
|
}
|
|
180
|
+
const lowered = baseline?.recorded ? baseline.updates.filter((u) => u.from !== null && u.to < u.from) : [];
|
|
181
|
+
if (lowered.length > 0) {
|
|
182
|
+
feedback.push(`[baseline] rebaixada: ${lowered.map((u) => `${u.id} (${u.from} โ ${u.to})`).join(', ')}`);
|
|
183
|
+
nodes.tests = acceptRecordedDrops(nodes.tests);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const status = Object.values(nodes).some((n) => n.status === 'fail') ? 'fail' : 'pass';
|
|
177
187
|
|
|
178
188
|
return {
|
|
179
189
|
version: 1,
|
|
@@ -401,7 +411,7 @@ function judgeEvalRun(entry, node, summaryPath) {
|
|
|
401
411
|
}
|
|
402
412
|
|
|
403
413
|
if (entry.status === 'pass' && verdict.verdict === 'drop') {
|
|
404
|
-
return { ...withNames, status: 'fail', count, warnings, reason: verdict.reason };
|
|
414
|
+
return { ...withNames, status: 'fail', count, warnings, reason: verdict.reason, countDrop: true };
|
|
405
415
|
}
|
|
406
416
|
if (verdict.verdict === 'drop') warnings.push(verdict.reason);
|
|
407
417
|
|
|
@@ -481,7 +491,7 @@ function judgeRun({ node, result, durationMs }) {
|
|
|
481
491
|
|
|
482
492
|
// Only a drop fails a node; a rise never does, or failing on growth teaches deleting tests.
|
|
483
493
|
if (verdict.verdict === 'drop' && result.passed) {
|
|
484
|
-
return { ...entry, status: 'fail', durationMs, count, warnings, reason: verdict.reason, output: '' };
|
|
494
|
+
return { ...entry, status: 'fail', durationMs, count, warnings, reason: verdict.reason, output: '', countDrop: true };
|
|
485
495
|
}
|
|
486
496
|
if (verdict.verdict === 'drop') warnings.push(verdict.reason);
|
|
487
497
|
|
|
@@ -497,6 +507,11 @@ function judgeRun({ node, result, durationMs }) {
|
|
|
497
507
|
};
|
|
498
508
|
}
|
|
499
509
|
|
|
510
|
+
function acceptRecordedDrops(testsNode) {
|
|
511
|
+
const runs = testsNode.runs.map(({ countDrop, ...run }) => (countDrop ? { ...run, status: 'pass', reason: null } : run));
|
|
512
|
+
return rollUpTestRuns(runs, { command: testsNode.command, source: testsNode.source, environment: testsNode.environment });
|
|
513
|
+
}
|
|
514
|
+
|
|
500
515
|
// Any red run reddens the rollup; one green run among skips is a pass.
|
|
501
516
|
function rollUpTestRuns(runs, { command, source, environment = null }) {
|
|
502
517
|
const failed = runs.filter((r) => r.status === 'fail');
|
|
@@ -580,14 +595,15 @@ function baselineTargetProblem(projectPath, testPlan, { skipTests }) {
|
|
|
580
595
|
}
|
|
581
596
|
|
|
582
597
|
// Only a run with EVERY node green records: a red run would freeze the regression,
|
|
583
|
-
// a partial one would claim counts for nodes nobody measured.
|
|
598
|
+
// a partial one would claim counts for nodes nobody measured. A count drop on a run that
|
|
599
|
+
// exited 0 is the one red it accepts: lowering the number is how deleting tests passes.
|
|
584
600
|
function recordBaselineFrom(projectPath, testsNode) {
|
|
585
601
|
const runs = testsNode.runs || [];
|
|
586
602
|
const refuse = (reason) => ({ recorded: false, reason, updates: [] });
|
|
587
603
|
|
|
588
604
|
if (runs.length === 0) return refuse('nenhum nรณ de teste executou');
|
|
589
605
|
|
|
590
|
-
const notGreen = runs.filter((r) => r.status !== 'pass');
|
|
606
|
+
const notGreen = runs.filter((r) => r.status !== 'pass' && !r.countDrop);
|
|
591
607
|
if (notGreen.length > 0) {
|
|
592
608
|
const named = notGreen.map((r) => `${r.id} (${r.status}${r.reason ? `: ${r.reason}` : ''})`).join('; ');
|
|
593
609
|
return refuse(
|
|
@@ -609,7 +625,7 @@ async function runValidatorsNode({ projectPath, featureName, _runValidation }) {
|
|
|
609
625
|
try {
|
|
610
626
|
console.log = () => {};
|
|
611
627
|
console.warn = () => {};
|
|
612
|
-
validationResult = await _runValidation(projectPath, featureName
|
|
628
|
+
validationResult = await _runValidation(projectPath, featureName);
|
|
613
629
|
} finally {
|
|
614
630
|
console.log = originalLog;
|
|
615
631
|
console.warn = originalWarn;
|
|
@@ -658,21 +674,20 @@ function appendValidatorsFeedback(feedback, validatorsNode) {
|
|
|
658
674
|
}
|
|
659
675
|
}
|
|
660
676
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
reason: 'build failed โ the stack could not come up anyway',
|
|
669
|
-
output: '',
|
|
670
|
-
},
|
|
671
|
-
stackEnv: null,
|
|
672
|
-
};
|
|
673
|
-
}
|
|
677
|
+
const skippedE2e = (reason) => ({ node: { status: 'skip', command: null, durationMs: 0, reason, output: '' }, stackEnv: null });
|
|
678
|
+
|
|
679
|
+
async function runE2eNode({
|
|
680
|
+
projectPath, featureName, skipE2e, freshE2e, buildNode, testsNode, hasStackNodes, gate, _runE2eCheck, _e2eApplicability,
|
|
681
|
+
}) {
|
|
682
|
+
if (buildNode.status === 'fail') return skippedE2e('build failed โ the stack could not come up anyway');
|
|
683
|
+
if (testsNode?.status === 'fail') return skippedE2e('tests failed โ the e2e does not run over a red suite');
|
|
674
684
|
|
|
675
685
|
const config = readConfig(projectPath);
|
|
686
|
+
// An `e2e: true` test node is the backend's proof against the stack: it always brings the stack up.
|
|
687
|
+
if (!skipE2e && !hasStackNodes) {
|
|
688
|
+
const applicability = _e2eApplicability(projectPath, featureName, config);
|
|
689
|
+
if (!applicability.applicable) return skippedE2e(applicability.reason);
|
|
690
|
+
}
|
|
676
691
|
const gitCommonDir = resolveGitCommonDir(projectPath);
|
|
677
692
|
// Without the port block, two worktrees verifying at once collide on host ports.
|
|
678
693
|
const env = buildComposeEnv({ cwd: projectPath, config, featureName, gitCommonDir });
|
|
@@ -698,7 +713,7 @@ async function runE2eNode({ projectPath, featureName, skipE2e, freshE2e, buildNo
|
|
|
698
713
|
command: result.command ?? null,
|
|
699
714
|
durationMs,
|
|
700
715
|
reason: result.reason ?? null,
|
|
701
|
-
output: result.output || '',
|
|
716
|
+
output: tailLines(result.output || '', OUTPUT_TAIL_LINES),
|
|
702
717
|
count: Number.isInteger(result.count) ? result.count : null,
|
|
703
718
|
warnings: Array.isArray(result.warnings) ? result.warnings : [],
|
|
704
719
|
},
|
|
@@ -2,6 +2,7 @@ import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { shouldInstall } from '../lib/stack-filter.js';
|
|
4
4
|
import { realEffects } from '../lib/installers/effects.js';
|
|
5
|
+
import { REVIEW_ROLES, VERDICT_TOKEN, REVIEWED_SHA_TOKEN, VERDICTS } from '../lib/review-reports.js';
|
|
5
6
|
|
|
6
7
|
export const DEFAULT_AGENT_TOOLS = 'Read, Write, Edit, Bash, Glob, Grep';
|
|
7
8
|
|
|
@@ -283,7 +284,7 @@ export const DISPATCH_CONTRACT = [
|
|
|
283
284
|
'ANTES de encerrar โ รฉ o retorno autoritativo, nรฃo a sua mensagem final. `SendMessage` nรฃo รฉ substituto do relatรณrio e nรฃo deve ser chamado.',
|
|
284
285
|
'2. ESTADO: NรO toque em `plan.md`, `checks.json`, `feature.json`, `state.json` nem no board de sessรฃo โ todo estado รฉ gravado exclusivamente pelo orquestrador.',
|
|
285
286
|
'3. TESTE: a prova รฉ do orquestrador (`morph-spec verify {feature}`, depois do seu retorno), nรฃo sua. Escreva os testes pelo orรงamento: ' +
|
|
286
|
-
'um por
|
|
287
|
+
'um por Cn `prova: teste`, variantes em tabela (`[Theory]`/`it.each`); `leitura` sem teste. NรO rode teste a cada marco nem faรงa ciclo redโgreen: ' +
|
|
287
288
|
'escreva cรณdigo e testes, compile, e rode Sร o filtro dos seus testes UMA vez, em primeiro plano, antes do relatรณrio; se falhar, corrija e rode sรณ os que falharam. ' +
|
|
288
289
|
'Grave a saรญda em arquivo (`โฆ > .morph/logs/test-last.log 2>&1`, sem nada depois) e leia o arquivo โ um pipe troca o exit do teste pelo do รบltimo comando. ' +
|
|
289
290
|
'Em batch paralelo SEM isolamento, sรณ compile. Com `isolation: "worktree"`, o mesmo vale no seu worktree, e o รบltimo ato รฉ o commit na branch dele.',
|
|
@@ -300,6 +301,8 @@ export const DISPATCH_CONTRACT = [
|
|
|
300
301
|
'`git checkout --`). A prova de que o teste morde รฉ do verificador (Gate 3).',
|
|
301
302
|
'9. ESCRITA: cรณdigo e teste do projeto sรณ por Write/Edit, nunca pelo Bash โ heredoc, redirecionamento, `sed -i` ou script python/node que grava (`cat > X.cs <<EOF`, `sed -i โฆ X.cs`): ' +
|
|
302
303
|
'os guards de escrita sรณ enxergam Write/Edit.',
|
|
304
|
+
'10. BLOQUEIO: decisรฃo que nรฃo รฉ sua (requisito contra o plano ou um ADR, escolha deixada ao humano) โ `BLOQUEADO` na 1ยช linha, ' +
|
|
305
|
+
'com a pergunta e as opรงรตes. Dificuldade tรฉcnica nรฃo รฉ bloqueio.',
|
|
303
306
|
'',
|
|
304
307
|
'Formato do relatรณrio (o `report-check` lรช estas marcas):',
|
|
305
308
|
'',
|
|
@@ -317,6 +320,25 @@ export const DISPATCH_CONTRACT = [
|
|
|
317
320
|
'Problemas e como foram resolvidos vรฃo em prosa depois.',
|
|
318
321
|
];
|
|
319
322
|
|
|
323
|
+
export const REVIEW_REPORT_CONTRACT = [
|
|
324
|
+
'## Relatรณrio do Gate 3',
|
|
325
|
+
'',
|
|
326
|
+
'Grave o relatรณrio que o dispatch nomeia ANTES de encerrar โ o arquivo รฉ o retorno, nรฃo a mensagem final. ' +
|
|
327
|
+
'Se ele jรก existir quando vocรช comeรงar, รฉ resรญduo de outra rodada: nรฃo o leia antes de escrever o seu (ancoragem no veredito alheio), ' +
|
|
328
|
+
'e nรฃo leia os relatรณrios dos outros papรฉis.',
|
|
329
|
+
'',
|
|
330
|
+
`Primeira linha \`${VERDICT_TOKEN} ${VERDICTS.join('|')}\`, depois \`${REVIEWED_SHA_TOKEN} {sha}\`, ` +
|
|
331
|
+
'tabela `## Bloqueadores` (`| id | tipo | onde | evidรชncia |`; vazia = `Nenhum.`) e `## Notas`. ' +
|
|
332
|
+
'Bloqueador sรณ com evidรชncia e tipo; o resto รฉ nota, e nota nunca pede rodada nova.',
|
|
333
|
+
'',
|
|
334
|
+
'Numa confirmaรงรฃo (o orquestrador te retoma depois da correรงรฃo, com o `sha` novo) acrescente ao fim uma seรงรฃo nova com ' +
|
|
335
|
+
`\`${VERDICT_TOKEN}\` e \`${REVIEWED_SHA_TOKEN} {sha novo}\`: se vocรช abriu bloqueadores, julgue sรณ eles; ` +
|
|
336
|
+
'se nรฃo abriu, julgue sรณ o delta `{sha anterior}..{sha novo}` โ o que a correรงรฃo abriu. ' +
|
|
337
|
+
'O relatรณrio รฉ append-only: vale o รบltimo veredito e, na `## Checks`, a รบltima linha de cada Cn.',
|
|
338
|
+
'',
|
|
339
|
+
'Um comando por chamada de Bash, sem encadear (`;`, `&&`, pipe): o composto รฉ negado e custa a rodada.',
|
|
340
|
+
];
|
|
341
|
+
|
|
320
342
|
function buildBody(agent, maxTurns) {
|
|
321
343
|
const lines = [
|
|
322
344
|
`# ${agent.title ?? agent.id}`,
|
|
@@ -374,6 +396,7 @@ function buildBody(agent, maxTurns) {
|
|
|
374
396
|
'O entregรกvel รฉ o arquivo de relatรณrio que o dispatch nomeia; sem arquivo nomeado, รฉ a sua mensagem final (no scout, o mapa).',
|
|
375
397
|
'',
|
|
376
398
|
);
|
|
399
|
+
if (Object.hasOwn(REVIEW_ROLES, agent.id)) lines.push(...REVIEW_REPORT_CONTRACT, '');
|
|
377
400
|
}
|
|
378
401
|
|
|
379
402
|
lines.push(
|
|
@@ -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
|