@ryuenn3123/agentic-senior-core 2.0.24 → 2.0.26
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/.agent-context/review-checklists/frontend-excellence-rubric.md +54 -0
- package/.agent-context/review-checklists/frontend-skill-parity.md +1 -0
- package/.agent-context/review-checklists/frontend-usability.md +1 -0
- package/.agent-context/rules/docker-runtime.md +29 -0
- package/.agent-context/skills/frontend/README.md +1 -0
- package/.agent-context/skills/frontend.md +4 -0
- package/.cursorrules +1 -1
- package/.github/workflows/benchmark-detection.yml +8 -1
- package/.windsurfrules +1 -1
- package/README.md +7 -0
- package/lib/cli/commands/init.mjs +358 -16
- package/lib/cli/commands/optimize.mjs +12 -0
- package/lib/cli/commands/upgrade.mjs +30 -1
- package/lib/cli/compiler.mjs +55 -1
- package/lib/cli/constants.mjs +83 -0
- package/lib/cli/detector.mjs +11 -1
- package/lib/cli/project-scaffolder.mjs +183 -2
- package/lib/cli/skill-selector.mjs +60 -38
- package/lib/cli/templates/architecture-decision-record.md.tmpl +39 -0
- package/lib/cli/templates/flow-overview.md.tmpl +12 -0
- package/lib/cli/templates/project-brief.md.id.tmpl +2 -0
- package/lib/cli/templates/project-brief.md.tmpl +26 -0
- package/lib/cli/utils.mjs +2 -1
- package/package.json +1 -1
- package/scripts/frontend-usability-audit.mjs +21 -0
- package/scripts/release-gate.mjs +108 -0
- package/scripts/validate.mjs +2 -0
|
@@ -43,55 +43,77 @@ export function formatSkillTierList(skillPlatformIndex) {
|
|
|
43
43
|
return skillPlatformIndex.tiers.map((tierDefinition) => `${tierDefinition.name} (${tierDefinition.description})`).join('\n');
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
export function inferSkillDomainNamesFromSelection(
|
|
46
|
+
export function inferSkillDomainNamesFromSelection(
|
|
47
|
+
selectedStackFileName,
|
|
48
|
+
selectedBlueprintFileName,
|
|
49
|
+
additionalStackFileNames = [],
|
|
50
|
+
additionalBlueprintFileNames = []
|
|
51
|
+
) {
|
|
47
52
|
const inferredDomainNames = new Set();
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
function applyStackSignals(stackFileName) {
|
|
55
|
+
if (stackFileName === 'typescript.md') {
|
|
56
|
+
inferredDomainNames.add('frontend');
|
|
57
|
+
inferredDomainNames.add('cli');
|
|
58
|
+
}
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
if (stackFileName === 'go.md'
|
|
61
|
+
|| stackFileName === 'java.md'
|
|
62
|
+
|| stackFileName === 'php.md'
|
|
63
|
+
|| stackFileName === 'csharp.md'
|
|
64
|
+
|| stackFileName === 'python.md'
|
|
65
|
+
|| stackFileName === 'ruby.md'
|
|
66
|
+
|| stackFileName === 'rust.md') {
|
|
67
|
+
inferredDomainNames.add('backend');
|
|
68
|
+
}
|
|
63
69
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
if (stackFileName === 'react-native.md' || stackFileName === 'flutter.md') {
|
|
71
|
+
inferredDomainNames.add('frontend');
|
|
72
|
+
inferredDomainNames.add('fullstack');
|
|
73
|
+
inferredDomainNames.add('cli');
|
|
74
|
+
}
|
|
67
75
|
}
|
|
68
76
|
|
|
69
|
-
|
|
70
|
-
||
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|| selectedStackFileName === 'rust.md') {
|
|
76
|
-
inferredDomainNames.add('backend');
|
|
77
|
-
}
|
|
77
|
+
function applyBlueprintSignals(blueprintFileName) {
|
|
78
|
+
if (blueprintFileName === 'api-nextjs.md' || blueprintFileName === 'fastapi-service.md') {
|
|
79
|
+
inferredDomainNames.add('frontend');
|
|
80
|
+
inferredDomainNames.add('fullstack');
|
|
81
|
+
inferredDomainNames.add('cli');
|
|
82
|
+
}
|
|
78
83
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
if (blueprintFileName === 'go-service.md'
|
|
85
|
+
|| blueprintFileName === 'spring-boot-api.md'
|
|
86
|
+
|| blueprintFileName === 'laravel-api.md'
|
|
87
|
+
|| blueprintFileName === 'aspnet-api.md'
|
|
88
|
+
|| blueprintFileName === 'nestjs-logic.md'
|
|
89
|
+
|| blueprintFileName === 'graphql-grpc-api.md') {
|
|
90
|
+
inferredDomainNames.add('backend');
|
|
91
|
+
inferredDomainNames.add('fullstack');
|
|
92
|
+
inferredDomainNames.add('cli');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (blueprintFileName === 'mobile-app.md') {
|
|
96
|
+
inferredDomainNames.add('frontend');
|
|
97
|
+
inferredDomainNames.add('fullstack');
|
|
98
|
+
inferredDomainNames.add('cli');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (blueprintFileName === 'observability.md') {
|
|
102
|
+
inferredDomainNames.add('backend');
|
|
103
|
+
inferredDomainNames.add('fullstack');
|
|
104
|
+
inferredDomainNames.add('cli');
|
|
105
|
+
}
|
|
83
106
|
}
|
|
84
107
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
108
|
+
applyBlueprintSignals(selectedBlueprintFileName);
|
|
109
|
+
|
|
110
|
+
applyStackSignals(selectedStackFileName);
|
|
111
|
+
for (const additionalStackFileName of additionalStackFileNames) {
|
|
112
|
+
applyStackSignals(additionalStackFileName);
|
|
89
113
|
}
|
|
90
114
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
inferredDomainNames.add('fullstack');
|
|
94
|
-
inferredDomainNames.add('cli');
|
|
115
|
+
for (const additionalBlueprintFileName of additionalBlueprintFileNames) {
|
|
116
|
+
applyBlueprintSignals(additionalBlueprintFileName);
|
|
95
117
|
}
|
|
96
118
|
|
|
97
119
|
if (inferredDomainNames.size === 0) {
|
|
@@ -18,9 +18,23 @@ This project requires a {{primaryDomain}} solution. The team evaluated available
|
|
|
18
18
|
### Decision
|
|
19
19
|
|
|
20
20
|
- **Language/Runtime**: {{stackDisplayName}} (source: `.agent-context/stacks/{{stackFileName}}`)
|
|
21
|
+
{{#if additionalStackDisplayNames}}
|
|
22
|
+
- **Additional runtime context**:
|
|
23
|
+
{{#each additionalStackDisplayNames}}
|
|
24
|
+
- {{this}}
|
|
25
|
+
{{/each}}
|
|
26
|
+
{{/if}}
|
|
21
27
|
- **Architecture blueprint**: {{blueprintDisplayName}} (source: `.agent-context/blueprints/{{blueprintFileName}}`)
|
|
28
|
+
{{#if additionalBlueprintDisplayNames}}
|
|
29
|
+
- **Additional architecture blueprints**:
|
|
30
|
+
{{#each additionalBlueprintDisplayNames}}
|
|
31
|
+
- {{this}}
|
|
32
|
+
{{/each}}
|
|
33
|
+
{{/if}}
|
|
22
34
|
- **Database**: {{databaseChoice}}
|
|
23
35
|
- **Auth**: {{authStrategy}}
|
|
36
|
+
- **Runtime environment target**: {{runtimeEnvironmentLabel}}
|
|
37
|
+
- **Containerization strategy**: {{dockerStrategy}}
|
|
24
38
|
|
|
25
39
|
### Rationale
|
|
26
40
|
|
|
@@ -36,6 +50,31 @@ The {{stackDisplayName}} stack was selected because:
|
|
|
36
50
|
- Database access must follow `.agent-context/rules/database-design.md`.
|
|
37
51
|
- API contracts must follow `.agent-context/rules/api-docs.md`.
|
|
38
52
|
|
|
53
|
+
{{#if hasDocker}}
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## ADR-004: Containerization Strategy (Dynamic)
|
|
57
|
+
|
|
58
|
+
**Status**: Accepted
|
|
59
|
+
**Date**: {{generatedDate}}
|
|
60
|
+
|
|
61
|
+
### Context
|
|
62
|
+
|
|
63
|
+
This project requires container support with separated development and production concerns.
|
|
64
|
+
|
|
65
|
+
### Decision
|
|
66
|
+
|
|
67
|
+
- Follow dynamic container generation based on real project dependencies and runtime profile.
|
|
68
|
+
- Do not rely on static Docker templates copied from unrelated repositories.
|
|
69
|
+
{{dockerDevelopmentGuidance}}
|
|
70
|
+
{{dockerProductionGuidance}}
|
|
71
|
+
|
|
72
|
+
### Consequences
|
|
73
|
+
|
|
74
|
+
- Development and production Docker artifacts are treated as separate deliverables.
|
|
75
|
+
- Changes in package/runtime dependencies must regenerate container setup instructions in the same change.
|
|
76
|
+
{{/if}}
|
|
77
|
+
|
|
39
78
|
---
|
|
40
79
|
|
|
41
80
|
## ADR-002: Architecture Pattern
|
|
@@ -12,6 +12,18 @@ Template version: {{templateVersion}}
|
|
|
12
12
|
**Domain**: {{primaryDomain}}
|
|
13
13
|
**Stack**: {{stackDisplayName}}
|
|
14
14
|
**Blueprint**: {{blueprintDisplayName}}
|
|
15
|
+
**Runtime target**: {{runtimeEnvironmentLabel}}
|
|
16
|
+
**Containerization**: {{dockerStrategy}}
|
|
17
|
+
|
|
18
|
+
{{#if hasDocker}}
|
|
19
|
+
## Container Flow (Dynamic Dev and Prod)
|
|
20
|
+
|
|
21
|
+
- Container setup is generated dynamically by AI from current dependencies, not from static canned templates.
|
|
22
|
+
{{dockerDevelopmentGuidance}}
|
|
23
|
+
{{dockerProductionGuidance}}
|
|
24
|
+
- Keep dev and prod container concerns explicitly separated.
|
|
25
|
+
|
|
26
|
+
{{/if}}
|
|
15
27
|
|
|
16
28
|
## High-Level Architecture
|
|
17
29
|
|
|
@@ -18,6 +18,8 @@ Versi template: {{templateVersion}}
|
|
|
18
18
|
**Blueprint**: {{blueprintDisplayName}}
|
|
19
19
|
**Database**: {{databaseChoice}}
|
|
20
20
|
**Strategi autentikasi**: {{authStrategy}}
|
|
21
|
+
**Target environment runtime**: {{runtimeEnvironmentLabel}}
|
|
22
|
+
**Strategi containerisasi**: {{dockerStrategy}}
|
|
21
23
|
|
|
22
24
|
## Fitur Kunci
|
|
23
25
|
|
|
@@ -15,9 +15,35 @@ Template version: {{templateVersion}}
|
|
|
15
15
|
## Technology Decisions
|
|
16
16
|
|
|
17
17
|
**Stack**: {{stackDisplayName}}
|
|
18
|
+
{{#if additionalStackDisplayNames}}
|
|
19
|
+
**Additional stacks**:
|
|
20
|
+
{{#each additionalStackDisplayNames}}
|
|
21
|
+
- {{this}}
|
|
22
|
+
{{/each}}
|
|
23
|
+
{{/if}}
|
|
18
24
|
**Blueprint**: {{blueprintDisplayName}}
|
|
25
|
+
{{#if additionalBlueprintDisplayNames}}
|
|
26
|
+
**Additional blueprints**:
|
|
27
|
+
{{#each additionalBlueprintDisplayNames}}
|
|
28
|
+
- {{this}}
|
|
29
|
+
{{/each}}
|
|
30
|
+
{{/if}}
|
|
19
31
|
**Database**: {{databaseChoice}}
|
|
20
32
|
**Auth strategy**: {{authStrategy}}
|
|
33
|
+
**Runtime environment target**: {{runtimeEnvironmentLabel}}
|
|
34
|
+
**Containerization strategy**: {{dockerStrategy}}
|
|
35
|
+
|
|
36
|
+
{{#if hasDocker}}
|
|
37
|
+
## Containerization Workflow (Dynamic)
|
|
38
|
+
|
|
39
|
+
- Docker is enabled for this project: **{{dockerStrategy}}**.
|
|
40
|
+
- Docker setup must be generated dynamically by AI based on current dependencies and runtime constraints.
|
|
41
|
+
- Do not use fixed boilerplate templates that ignore actual project structure.
|
|
42
|
+
{{dockerDevelopmentGuidance}}
|
|
43
|
+
{{dockerProductionGuidance}}
|
|
44
|
+
|
|
45
|
+
- Keep development and production container strategy separated to avoid environment drift.
|
|
46
|
+
{{/if}}
|
|
21
47
|
|
|
22
48
|
## Key Features
|
|
23
49
|
|
package/lib/cli/utils.mjs
CHANGED
|
@@ -28,7 +28,7 @@ export function printUsage() {
|
|
|
28
28
|
console.log('');
|
|
29
29
|
console.log('Usage:');
|
|
30
30
|
console.log(' agentic-senior-core launch');
|
|
31
|
-
console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>]');
|
|
31
|
+
console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>] [--runtime-env <auto|linux-wsl|linux|windows|macos>]');
|
|
32
32
|
console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes] [--mcp-template]');
|
|
33
33
|
console.log(' agentic-senior-core optimize [target-directory] [--agent <copilot|claude|cursor|windsurf|gemini|codex|cline>] [--enable|--disable] [--show]');
|
|
34
34
|
console.log(' agentic-senior-core mcp');
|
|
@@ -54,6 +54,7 @@ export function printUsage() {
|
|
|
54
54
|
console.log(' --no-scaffold-docs Skip project documentation scaffolding');
|
|
55
55
|
console.log(' --docs-lang Optional override for generated project docs language (default: en)');
|
|
56
56
|
console.log(' --project-config Path to a project config file for non-interactive doc scaffolding');
|
|
57
|
+
console.log(' --runtime-env Override runtime environment hint (auto, linux-wsl, linux, windows, macos)');
|
|
57
58
|
console.log(' --dry-run Preview upgrade without writing files');
|
|
58
59
|
console.log(' --yes Skip confirmation prompts for upgrade');
|
|
59
60
|
console.log(' --agent Target agent integration for token optimization mode');
|
package/package.json
CHANGED
|
@@ -21,6 +21,7 @@ const REQUIRED_FILES = [
|
|
|
21
21
|
'docs/v1.7-issue-breakdown.md',
|
|
22
22
|
'docs/v1.7-execution-playbook.md',
|
|
23
23
|
'.agent-context/review-checklists/frontend-usability.md',
|
|
24
|
+
'.agent-context/review-checklists/frontend-excellence-rubric.md',
|
|
24
25
|
];
|
|
25
26
|
|
|
26
27
|
const REQUIRED_ROADMAP_SNIPPETS = [
|
|
@@ -37,6 +38,14 @@ const REQUIRED_CHECKLIST_SNIPPETS = [
|
|
|
37
38
|
'Documentation and Release Evidence',
|
|
38
39
|
];
|
|
39
40
|
|
|
41
|
+
const REQUIRED_EXCELLENCE_RUBRIC_SNIPPETS = [
|
|
42
|
+
'Visual Direction and Identity',
|
|
43
|
+
'Typography Quality',
|
|
44
|
+
'Color System Diversity and Contrast',
|
|
45
|
+
'Interaction Choreography',
|
|
46
|
+
'Awwwards-level reference quality',
|
|
47
|
+
];
|
|
48
|
+
|
|
40
49
|
function assertFileExists(relativeFilePath, failures) {
|
|
41
50
|
const absoluteFilePath = resolve(REPOSITORY_ROOT, relativeFilePath);
|
|
42
51
|
if (!existsSync(absoluteFilePath)) {
|
|
@@ -61,6 +70,7 @@ function runAudit() {
|
|
|
61
70
|
|
|
62
71
|
const roadmapPath = 'docs/roadmap.md';
|
|
63
72
|
const checklistPath = '.agent-context/review-checklists/frontend-usability.md';
|
|
73
|
+
const excellenceRubricPath = '.agent-context/review-checklists/frontend-excellence-rubric.md';
|
|
64
74
|
|
|
65
75
|
if (existsSync(resolve(REPOSITORY_ROOT, roadmapPath))) {
|
|
66
76
|
const roadmapContent = readFileSync(resolve(REPOSITORY_ROOT, roadmapPath), 'utf8');
|
|
@@ -72,6 +82,17 @@ function runAudit() {
|
|
|
72
82
|
assertContains('Checklist', checklistPath, checklistContent, REQUIRED_CHECKLIST_SNIPPETS, failures);
|
|
73
83
|
}
|
|
74
84
|
|
|
85
|
+
if (existsSync(resolve(REPOSITORY_ROOT, excellenceRubricPath))) {
|
|
86
|
+
const excellenceRubricContent = readFileSync(resolve(REPOSITORY_ROOT, excellenceRubricPath), 'utf8');
|
|
87
|
+
assertContains(
|
|
88
|
+
'Frontend excellence rubric',
|
|
89
|
+
excellenceRubricPath,
|
|
90
|
+
excellenceRubricContent,
|
|
91
|
+
REQUIRED_EXCELLENCE_RUBRIC_SNIPPETS,
|
|
92
|
+
failures
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
75
96
|
const reportPayload = {
|
|
76
97
|
generatedAt: new Date().toISOString(),
|
|
77
98
|
auditName: 'frontend-usability-audit',
|
package/scripts/release-gate.mjs
CHANGED
|
@@ -28,6 +28,7 @@ const REQUIRED_SKILL_DOMAINS = [
|
|
|
28
28
|
'review-quality',
|
|
29
29
|
];
|
|
30
30
|
const FRONTEND_PARITY_CHECKLIST_PATH = '.agent-context/review-checklists/frontend-skill-parity.md';
|
|
31
|
+
const FRONTEND_EXCELLENCE_RUBRIC_PATH = '.agent-context/review-checklists/frontend-excellence-rubric.md';
|
|
31
32
|
const FRONTEND_AUDIT_SCRIPT_PATH = 'scripts/frontend-usability-audit.mjs';
|
|
32
33
|
const REQUIRED_FRONTEND_PARITY_SNIPPETS = [
|
|
33
34
|
'Architecture and Composition',
|
|
@@ -36,6 +37,14 @@ const REQUIRED_FRONTEND_PARITY_SNIPPETS = [
|
|
|
36
37
|
'UX Narrative and Conversion Clarity',
|
|
37
38
|
'Release Evidence',
|
|
38
39
|
];
|
|
40
|
+
const REQUIRED_FRONTEND_EXCELLENCE_RUBRIC_SNIPPETS = [
|
|
41
|
+
'Visual Direction and Identity',
|
|
42
|
+
'Typography Quality',
|
|
43
|
+
'Color System Diversity and Contrast',
|
|
44
|
+
'Interaction Choreography',
|
|
45
|
+
'Awwwards-level reference quality',
|
|
46
|
+
];
|
|
47
|
+
const BENCHMARK_GATE_SCRIPT_PATH = 'scripts/benchmark-gate.mjs';
|
|
39
48
|
|
|
40
49
|
function readText(relativeFilePath) {
|
|
41
50
|
const absolutePath = resolve(REPOSITORY_ROOT, relativeFilePath);
|
|
@@ -54,6 +63,46 @@ function pushResult(results, isPassed, checkName, details) {
|
|
|
54
63
|
});
|
|
55
64
|
}
|
|
56
65
|
|
|
66
|
+
function parseMachineReadableReport(rawOutput) {
|
|
67
|
+
if (typeof rawOutput !== 'string' || rawOutput.trim().length === 0) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(rawOutput);
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function runMachineReadableScript(scriptRelativePath) {
|
|
79
|
+
try {
|
|
80
|
+
const rawOutput = execFileSync('node', [scriptRelativePath], {
|
|
81
|
+
cwd: REPOSITORY_ROOT,
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
maxBuffer: 1024 * 1024,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
report: parseMachineReadableReport(rawOutput),
|
|
88
|
+
executionErrorMessage: null,
|
|
89
|
+
};
|
|
90
|
+
} catch (scriptExecutionError) {
|
|
91
|
+
const rawOutput = scriptExecutionError && typeof scriptExecutionError === 'object' && 'stdout' in scriptExecutionError
|
|
92
|
+
? String(scriptExecutionError.stdout ?? '')
|
|
93
|
+
: '';
|
|
94
|
+
const parsedReport = parseMachineReadableReport(rawOutput);
|
|
95
|
+
const executionErrorMessage = scriptExecutionError instanceof Error
|
|
96
|
+
? scriptExecutionError.message
|
|
97
|
+
: 'Unknown execution error';
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
report: parsedReport,
|
|
101
|
+
executionErrorMessage,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
57
106
|
function validateCompatibilityManifestShape(parsedManifest, skillDomainName) {
|
|
58
107
|
const validationErrors = [];
|
|
59
108
|
|
|
@@ -82,6 +131,7 @@ function validateCompatibilityManifestShape(parsedManifest, skillDomainName) {
|
|
|
82
131
|
|
|
83
132
|
function runReleaseGate() {
|
|
84
133
|
const results = [];
|
|
134
|
+
const diagnostics = {};
|
|
85
135
|
const packageJsonPath = 'package.json';
|
|
86
136
|
const changelogPath = 'CHANGELOG.md';
|
|
87
137
|
const roadmapPath = 'docs/roadmap.md';
|
|
@@ -222,6 +272,28 @@ function runReleaseGate() {
|
|
|
222
272
|
}
|
|
223
273
|
}
|
|
224
274
|
|
|
275
|
+
const frontendExcellenceRubricContent = readText(FRONTEND_EXCELLENCE_RUBRIC_PATH);
|
|
276
|
+
if (!frontendExcellenceRubricContent) {
|
|
277
|
+
pushResult(results, false, 'frontend-excellence-rubric-exists', `Missing ${FRONTEND_EXCELLENCE_RUBRIC_PATH}`);
|
|
278
|
+
} else {
|
|
279
|
+
pushResult(results, true, 'frontend-excellence-rubric-exists', `${FRONTEND_EXCELLENCE_RUBRIC_PATH} is present`);
|
|
280
|
+
|
|
281
|
+
const missingFrontendExcellenceSnippets = REQUIRED_FRONTEND_EXCELLENCE_RUBRIC_SNIPPETS.filter(
|
|
282
|
+
(requiredSnippet) => !frontendExcellenceRubricContent.includes(requiredSnippet)
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
if (missingFrontendExcellenceSnippets.length === 0) {
|
|
286
|
+
pushResult(results, true, 'frontend-excellence-rubric-coverage', 'Frontend excellence rubric sections are complete');
|
|
287
|
+
} else {
|
|
288
|
+
pushResult(
|
|
289
|
+
results,
|
|
290
|
+
false,
|
|
291
|
+
'frontend-excellence-rubric-coverage',
|
|
292
|
+
`Missing frontend excellence rubric sections: ${missingFrontendExcellenceSnippets.join(', ')}`
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
225
297
|
try {
|
|
226
298
|
const frontendAuditRawOutput = execFileSync('node', [FRONTEND_AUDIT_SCRIPT_PATH], {
|
|
227
299
|
cwd: REPOSITORY_ROOT,
|
|
@@ -245,12 +317,48 @@ function runReleaseGate() {
|
|
|
245
317
|
pushResult(results, false, 'frontend-usability-audit', `Failed to execute frontend usability audit: ${frontendAuditErrorMessage}`);
|
|
246
318
|
}
|
|
247
319
|
|
|
320
|
+
const benchmarkGateExecution = runMachineReadableScript(BENCHMARK_GATE_SCRIPT_PATH);
|
|
321
|
+
if (!benchmarkGateExecution.report) {
|
|
322
|
+
const failureDetails = benchmarkGateExecution.executionErrorMessage
|
|
323
|
+
? `Benchmark gate execution failed before producing a machine-readable report: ${benchmarkGateExecution.executionErrorMessage}`
|
|
324
|
+
: 'Benchmark gate did not produce machine-readable JSON output';
|
|
325
|
+
pushResult(results, false, 'benchmark-threshold-gate', failureDetails);
|
|
326
|
+
} else {
|
|
327
|
+
diagnostics.benchmarkGate = benchmarkGateExecution.report;
|
|
328
|
+
pushResult(
|
|
329
|
+
results,
|
|
330
|
+
true,
|
|
331
|
+
'benchmark-threshold-gate',
|
|
332
|
+
`Benchmark threshold gate executed (passed=${benchmarkGateExecution.report.passed}, failures=${benchmarkGateExecution.report.failureCount})`
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
if (benchmarkGateExecution.report.passed === true) {
|
|
336
|
+
pushResult(results, true, 'benchmark-regression-block', 'Benchmark thresholds are healthy; release remains eligible');
|
|
337
|
+
} else {
|
|
338
|
+
const failedBenchmarkChecks = Array.isArray(benchmarkGateExecution.report.results)
|
|
339
|
+
? benchmarkGateExecution.report.results
|
|
340
|
+
.filter((benchmarkCheckResult) => !benchmarkCheckResult.passed)
|
|
341
|
+
.map((benchmarkCheckResult) => `${benchmarkCheckResult.checkName}: ${benchmarkCheckResult.details}`)
|
|
342
|
+
: [];
|
|
343
|
+
const failureSummary = failedBenchmarkChecks.length > 0
|
|
344
|
+
? failedBenchmarkChecks.join('; ')
|
|
345
|
+
: 'Benchmark gate failed but did not report individual failed checks';
|
|
346
|
+
pushResult(
|
|
347
|
+
results,
|
|
348
|
+
false,
|
|
349
|
+
'benchmark-regression-block',
|
|
350
|
+
`Benchmark threshold regression detected. ${failureSummary}`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
248
355
|
const failureCount = results.filter((checkResult) => !checkResult.passed).length;
|
|
249
356
|
const releaseGateReport = {
|
|
250
357
|
generatedAt: new Date().toISOString(),
|
|
251
358
|
gateName: 'release-gate',
|
|
252
359
|
passed: failureCount === 0,
|
|
253
360
|
failureCount,
|
|
361
|
+
diagnostics,
|
|
254
362
|
results,
|
|
255
363
|
};
|
|
256
364
|
|
package/scripts/validate.mjs
CHANGED
|
@@ -258,6 +258,7 @@ async function validateRuleFiles() {
|
|
|
258
258
|
'rules/database-design.md',
|
|
259
259
|
'rules/realtime.md',
|
|
260
260
|
'rules/frontend-architecture.md',
|
|
261
|
+
'rules/docker-runtime.md',
|
|
261
262
|
'stacks/typescript.md',
|
|
262
263
|
'stacks/python.md',
|
|
263
264
|
'stacks/java.md',
|
|
@@ -285,6 +286,7 @@ async function validateRuleFiles() {
|
|
|
285
286
|
'review-checklists/pr-checklist.md',
|
|
286
287
|
'review-checklists/frontend-usability.md',
|
|
287
288
|
'review-checklists/frontend-skill-parity.md',
|
|
289
|
+
'review-checklists/frontend-excellence-rubric.md',
|
|
288
290
|
'review-checklists/release-operations.md',
|
|
289
291
|
'review-checklists/security-audit.md',
|
|
290
292
|
'review-checklists/performance-audit.md',
|