@ryuenn3123/agentic-senior-core 4.3.14 → 4.4.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/.agent-context/prompts/init-project.md +1 -1
- package/.agent-context/prompts/refactor.md +1 -0
- package/.agent-context/review-checklists/pr-checklist.md +1 -3
- package/.agent-context/rules/architecture.md +5 -0
- package/AGENTS.md +67 -115
- package/bin/agentic-senior-core.js +2 -5
- package/lib/cli/adaptive-context/catalog.mjs +4 -0
- package/lib/cli/adaptive-context.mjs +87 -301
- package/lib/cli/compiler.mjs +6 -389
- package/lib/cli/token-optimization.mjs +4 -89
- package/package.json +2 -9
- package/scripts/context-triggered-audit.mjs +1 -1
- package/scripts/{audit-cache-layer-contract.mjs → validate/audits/cache-layer-contract.mjs} +4 -37
- package/scripts/{audit-caching-scope-hygiene.mjs → validate/audits/caching-scope-hygiene.mjs} +1 -34
- package/scripts/{audit-file-size.mjs → validate/audits/file-size.mjs} +1 -62
- package/scripts/{audit-reflection-citations.mjs → validate/audits/reflection-citations.mjs} +2 -35
- package/scripts/{audit-release-bundle.mjs → validate/audits/release-bundle.mjs} +1 -36
- package/scripts/{audit-rule-id-uniqueness.mjs → validate/audits/rule-id-uniqueness.mjs} +1 -36
- package/scripts/validate/config.mjs +0 -18
- package/scripts/validate/file-structure.mjs +0 -4
- package/scripts/validate/utils.mjs +52 -0
- package/scripts/validate.mjs +10 -81
- package/lib/cli/audits/typography-palette-anti-repeat-audit.mjs +0 -239
- package/lib/cli/commands/audit-design-anti-repeat.mjs +0 -39
- package/scripts/audit-typography-palette-anti-repeat.mjs +0 -120
package/scripts/{audit-caching-scope-hygiene.mjs → validate/audits/caching-scope-hygiene.mjs}
RENAMED
|
@@ -30,7 +30,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
30
30
|
import { fileURLToPath } from 'node:url';
|
|
31
31
|
|
|
32
32
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
33
|
-
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '
|
|
33
|
+
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '../../..');
|
|
34
34
|
const ARGS = new Set(process.argv.slice(2));
|
|
35
35
|
const JSON_ONLY = ARGS.has('--json');
|
|
36
36
|
|
|
@@ -232,37 +232,4 @@ export function runCachingScopeHygieneAudit(options = {}) {
|
|
|
232
232
|
};
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
function main() {
|
|
236
|
-
const report = runCachingScopeHygieneAudit();
|
|
237
235
|
|
|
238
|
-
if (JSON_ONLY) {
|
|
239
|
-
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
240
|
-
process.exit(report.passed ? 0 : 1);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
console.log('===============================================');
|
|
244
|
-
console.log(' audit:caching-scope-hygiene');
|
|
245
|
-
console.log('===============================================');
|
|
246
|
-
console.log(` Public surfaces scanned: ${report.surfaceCount}`);
|
|
247
|
-
console.log(` Caching saving claims: ${report.totalClaimCount}`);
|
|
248
|
-
console.log('');
|
|
249
|
-
|
|
250
|
-
if (report.passed) {
|
|
251
|
-
console.log(' All caching saving claims on public surfaces are integration-scoped.');
|
|
252
|
-
process.stderr.write(`AUDIT_CACHING_SCOPE_HYGIENE_REPORT: ${JSON.stringify({ passed: true, surfaceCount: report.surfaceCount, totalClaimCount: report.totalClaimCount })}\n`);
|
|
253
|
-
process.exit(0);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
console.log(' Violations:');
|
|
257
|
-
for (const violation of report.violations) {
|
|
258
|
-
console.log(` [${violation.kind}] ${violation.file}:${violation.line} ${violation.detail}`);
|
|
259
|
-
}
|
|
260
|
-
console.log('');
|
|
261
|
-
console.log(` ${report.violationCount} violation(s) found.`);
|
|
262
|
-
process.stderr.write(`AUDIT_CACHING_SCOPE_HYGIENE_REPORT: ${JSON.stringify({ passed: false, violationCount: report.violationCount })}\n`);
|
|
263
|
-
process.exit(1);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (process.argv[1] && (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}` || process.argv[1].endsWith('audit-caching-scope-hygiene.mjs'))) {
|
|
267
|
-
main();
|
|
268
|
-
}
|
|
@@ -30,7 +30,7 @@ import { dirname, join, relative, resolve } from 'node:path';
|
|
|
30
30
|
import { fileURLToPath } from 'node:url';
|
|
31
31
|
|
|
32
32
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
33
|
-
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '
|
|
33
|
+
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '../../..');
|
|
34
34
|
|
|
35
35
|
export const DEFAULT_LOC_THRESHOLD = 500;
|
|
36
36
|
const EXCEPTION_MARKER_PATTERN = /^\s*(?:\/\/|\*)\s*@file-size-exception:\s*(.+?)\s*(?:\*\/\s*)?$/;
|
|
@@ -155,65 +155,4 @@ export function runAuditFileSize({ threshold = DEFAULT_LOC_THRESHOLD } = {}) {
|
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
function formatHumanLine(prefix, entry) {
|
|
159
|
-
return ` ${prefix} ${entry.filePath} (${entry.lineCount}/${entry.threshold ?? DEFAULT_LOC_THRESHOLD} LOC)`;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function main() {
|
|
163
|
-
const report = runAuditFileSize();
|
|
164
|
-
|
|
165
|
-
if (JSON_ONLY) {
|
|
166
|
-
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
167
|
-
process.exit(report.passed ? 0 : 1);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
console.log('===============================================');
|
|
171
|
-
console.log(' audit:file-size — 500 LOC enforcement');
|
|
172
|
-
console.log('===============================================');
|
|
173
|
-
console.log(` Threshold: ${report.threshold} LOC`);
|
|
174
|
-
console.log(` Scanned: ${report.scannedFileCount} files`);
|
|
175
|
-
console.log('');
|
|
176
|
-
|
|
177
|
-
if (report.exemptedCount > 0) {
|
|
178
|
-
console.log(' Exempted (declared @file-size-exception):');
|
|
179
|
-
for (const entry of report.exemptedFiles) {
|
|
180
|
-
console.log(` EXEMPT ${entry.filePath} (${entry.lineCount} LOC) — ${entry.reason}`);
|
|
181
|
-
}
|
|
182
|
-
console.log('');
|
|
183
|
-
}
|
|
184
158
|
|
|
185
|
-
if (report.violationCount === 0) {
|
|
186
|
-
console.log(' All files within budget.');
|
|
187
|
-
process.stderr.write(`AUDIT_FILE_SIZE_REPORT: ${JSON.stringify({
|
|
188
|
-
passed: true,
|
|
189
|
-
scannedFileCount: report.scannedFileCount,
|
|
190
|
-
violationCount: 0,
|
|
191
|
-
exemptedCount: report.exemptedCount,
|
|
192
|
-
})}\n`);
|
|
193
|
-
process.exit(0);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
console.log(' Violations:');
|
|
197
|
-
for (const entry of report.violations) {
|
|
198
|
-
console.log(formatHumanLine('FAIL', { ...entry, threshold: report.threshold }));
|
|
199
|
-
}
|
|
200
|
-
console.log('');
|
|
201
|
-
console.log(` ${report.violationCount} file(s) exceed the ${report.threshold} LOC threshold.`);
|
|
202
|
-
console.log(' Either split the file into focused submodules or, when justified,');
|
|
203
|
-
console.log(' declare an exception in the first 5 lines:');
|
|
204
|
-
console.log(' // @file-size-exception: <reason>');
|
|
205
|
-
console.log('');
|
|
206
|
-
|
|
207
|
-
process.stderr.write(`AUDIT_FILE_SIZE_REPORT: ${JSON.stringify({
|
|
208
|
-
passed: false,
|
|
209
|
-
scannedFileCount: report.scannedFileCount,
|
|
210
|
-
violationCount: report.violationCount,
|
|
211
|
-
exemptedCount: report.exemptedCount,
|
|
212
|
-
violations: report.violations,
|
|
213
|
-
})}\n`);
|
|
214
|
-
process.exit(1);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}` || process.argv[1].endsWith('audit-file-size.mjs')) {
|
|
218
|
-
main();
|
|
219
|
-
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
import { existsSync, readFileSync } from 'node:fs';
|
|
5
5
|
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { runRuleIdUniquenessAudit } from './
|
|
7
|
+
import { runRuleIdUniquenessAudit } from './rule-id-uniqueness.mjs';
|
|
8
8
|
|
|
9
9
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
10
|
-
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '
|
|
10
|
+
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '../../..');
|
|
11
11
|
const ARGS = new Set(process.argv.slice(2));
|
|
12
12
|
const JSON_ONLY = ARGS.has('--json');
|
|
13
13
|
const RULE_ID_PATTERN = /\b[A-Z]+-\d{3,4}(?:-[A-Z])?\b/g;
|
|
@@ -127,37 +127,4 @@ export function runReflectionCitationAudit(options = {}) {
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
function main() {
|
|
131
|
-
const report = runReflectionCitationAudit();
|
|
132
130
|
|
|
133
|
-
if (JSON_ONLY) {
|
|
134
|
-
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
135
|
-
process.exit(report.passed ? 0 : 1);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
console.log('===============================================');
|
|
139
|
-
console.log(' audit:reflection-citations');
|
|
140
|
-
console.log('===============================================');
|
|
141
|
-
console.log(` Reflection surfaces: ${report.surfaceCount}`);
|
|
142
|
-
console.log(` Known rule IDs: ${report.knownRuleIdCount}`);
|
|
143
|
-
console.log('');
|
|
144
|
-
|
|
145
|
-
if (report.passed) {
|
|
146
|
-
console.log(' Reflection citation surfaces are present and all cited rule IDs resolve.');
|
|
147
|
-
process.stderr.write(`AUDIT_REFLECTION_CITATIONS_REPORT: ${JSON.stringify({ passed: true, surfaceCount: report.surfaceCount, knownRuleIdCount: report.knownRuleIdCount })}\n`);
|
|
148
|
-
process.exit(0);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
console.log(' Violations:');
|
|
152
|
-
for (const violation of report.violations) {
|
|
153
|
-
console.log(` [${violation.kind}] ${violation.file}: ${violation.detail}`);
|
|
154
|
-
}
|
|
155
|
-
console.log('');
|
|
156
|
-
console.log(` ${report.violationCount} violation(s) found.`);
|
|
157
|
-
process.stderr.write(`AUDIT_REFLECTION_CITATIONS_REPORT: ${JSON.stringify({ passed: false, violationCount: report.violationCount, kinds: [...new Set(report.violations.map((violation) => violation.kind))] })}\n`);
|
|
158
|
-
process.exit(1);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}` || process.argv[1].endsWith('audit-reflection-citations.mjs')) {
|
|
162
|
-
main();
|
|
163
|
-
}
|
|
@@ -16,7 +16,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
16
16
|
import { fileURLToPath } from 'node:url';
|
|
17
17
|
|
|
18
18
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
19
|
-
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '
|
|
19
|
+
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '../../..');
|
|
20
20
|
const ARGS = new Set(process.argv.slice(2));
|
|
21
21
|
const JSON_ONLY = ARGS.has('--json');
|
|
22
22
|
|
|
@@ -132,39 +132,4 @@ function finalizeReport(violations, extras) {
|
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
function main() {
|
|
136
|
-
const report = runReleaseBundleAudit();
|
|
137
135
|
|
|
138
|
-
if (JSON_ONLY) {
|
|
139
|
-
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
140
|
-
process.exit(report.passed ? 0 : 1);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.log('===============================================');
|
|
144
|
-
console.log(' audit:release-bundle');
|
|
145
|
-
console.log('===============================================');
|
|
146
|
-
console.log(` Bundle path: ${report.bundlePath}`);
|
|
147
|
-
console.log(` Artifact count: ${report.artifactCount}`);
|
|
148
|
-
console.log(` Release target: ${report.releaseTarget || '(missing)'}`);
|
|
149
|
-
console.log(` Release status: ${report.releaseStatus || '(missing)'}`);
|
|
150
|
-
console.log('');
|
|
151
|
-
|
|
152
|
-
if (report.passed) {
|
|
153
|
-
console.log(' Release bundle is intact. All artifact hashes match.');
|
|
154
|
-
process.stderr.write(`AUDIT_RELEASE_BUNDLE_REPORT: ${JSON.stringify({ passed: true, artifactCount: report.artifactCount })}\n`);
|
|
155
|
-
process.exit(0);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
console.log(' Violations:');
|
|
159
|
-
for (const violation of report.violations) {
|
|
160
|
-
console.log(` [${violation.kind}] ${violation.detail}`);
|
|
161
|
-
}
|
|
162
|
-
console.log('');
|
|
163
|
-
console.log(` ${report.violationCount} violation(s) found.`);
|
|
164
|
-
process.stderr.write(`AUDIT_RELEASE_BUNDLE_REPORT: ${JSON.stringify({ passed: false, violationCount: report.violationCount })}\n`);
|
|
165
|
-
process.exit(1);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (process.argv[1] && (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}` || process.argv[1].endsWith('audit-release-bundle.mjs'))) {
|
|
169
|
-
main();
|
|
170
|
-
}
|
|
@@ -36,7 +36,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
36
36
|
import { parse as parseYaml } from 'yaml';
|
|
37
37
|
|
|
38
38
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
39
|
-
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '
|
|
39
|
+
const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '../../..');
|
|
40
40
|
const RULES_DIRECTORY = join(REPOSITORY_ROOT, '.agent-context', 'rules');
|
|
41
41
|
const PROMPTS_DIRECTORY = join(REPOSITORY_ROOT, '.agent-context', 'prompts');
|
|
42
42
|
const REVIEW_CHECKLISTS_DIRECTORY = join(REPOSITORY_ROOT, '.agent-context', 'review-checklists');
|
|
@@ -275,39 +275,4 @@ export function runRuleIdUniquenessAudit() {
|
|
|
275
275
|
};
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
function main() {
|
|
279
|
-
const report = runRuleIdUniquenessAudit();
|
|
280
278
|
|
|
281
|
-
if (JSON_ONLY) {
|
|
282
|
-
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
283
|
-
process.exit(report.passed ? 0 : 1);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
console.log('===============================================');
|
|
287
|
-
console.log(' audit:rule-id-uniqueness');
|
|
288
|
-
console.log('===============================================');
|
|
289
|
-
console.log(` Migrated rule files: ${report.migratedFileCount} of ${report.migratedFileCount + report.skippedFileCount} scanned`);
|
|
290
|
-
console.log(` Pre-migration files: ${report.skippedFileCount} (no YAML frontmatter, skipped)`);
|
|
291
|
-
console.log(` Known section IDs: ${report.knownSectionIdCount}`);
|
|
292
|
-
console.log(` [REF:...] mentions: ${report.refMentionCount}`);
|
|
293
|
-
console.log('');
|
|
294
|
-
|
|
295
|
-
if (report.violationCount === 0) {
|
|
296
|
-
console.log(' All migrated files clean. No prefix mismatches, duplicates, ambiguous prose references, or unresolved [REF:] / related: links.');
|
|
297
|
-
process.stderr.write(`AUDIT_RULE_ID_REPORT: ${JSON.stringify({ passed: true, ...{ migratedFileCount: report.migratedFileCount, knownSectionIdCount: report.knownSectionIdCount, refMentionCount: report.refMentionCount } })}\n`);
|
|
298
|
-
process.exit(0);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
console.log(' Violations:');
|
|
302
|
-
for (const violation of report.violations) {
|
|
303
|
-
console.log(` [${violation.kind}] ${violation.file}: ${violation.detail}`);
|
|
304
|
-
}
|
|
305
|
-
console.log('');
|
|
306
|
-
console.log(` ${report.violationCount} violation(s) found. Phase 1 GATE B requires zero.`);
|
|
307
|
-
process.stderr.write(`AUDIT_RULE_ID_REPORT: ${JSON.stringify({ passed: false, violationCount: report.violationCount, kinds: [...new Set(report.violations.map((v) => v.kind))] })}\n`);
|
|
308
|
-
process.exit(1);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}` || process.argv[1].endsWith('audit-rule-id-uniqueness.mjs')) {
|
|
312
|
-
main();
|
|
313
|
-
}
|
|
@@ -214,19 +214,6 @@ export const REQUIRED_UNIVERSAL_SOP_SNIPPETS = [
|
|
|
214
214
|
'docs/api-contract.md',
|
|
215
215
|
],
|
|
216
216
|
},
|
|
217
|
-
{
|
|
218
|
-
path: 'lib/cli/compiler.mjs',
|
|
219
|
-
snippets: [
|
|
220
|
-
'Universal SOP hard block policy:',
|
|
221
|
-
'docs/doc-index.md whenever docs/ exists',
|
|
222
|
-
'README.md must exist and read as a public and developer entrypoint',
|
|
223
|
-
'Hard block: do not write application code until docs/project-brief.md and docs/architecture-decision-record.md exist.',
|
|
224
|
-
'Documentation-first policy:',
|
|
225
|
-
'Keep README.md public and developer friendly',
|
|
226
|
-
'For docs-only/docs-first requests, do not write application, firmware, or UI code until the user asks or approves an implementation plan.',
|
|
227
|
-
'Follow the three-step design direction process in bootstrap-design.md',
|
|
228
|
-
],
|
|
229
|
-
},
|
|
230
217
|
];
|
|
231
218
|
export const REQUIRED_DIAGRAM_FORMAT_SNIPPETS = [
|
|
232
219
|
|
|
@@ -384,11 +371,6 @@ export const REQUIRED_UI_DESIGN_AUTOMATION_SNIPPETS = [
|
|
|
384
371
|
{
|
|
385
372
|
path: 'lib/cli/compiler.mjs',
|
|
386
373
|
snippets: [
|
|
387
|
-
'Resolve the smallest relevant layer set before responding.',
|
|
388
|
-
'LAYER 1: RULES (SCOPE-RESOLVED)',
|
|
389
|
-
'LAYER 5: EXECUTION PROMPTS AND UI TRIGGERS',
|
|
390
|
-
'bootstrap-design.md -> ui, ux, layout, screen, tailwind, frontend, redesign',
|
|
391
|
-
'three-step design direction process in bootstrap-design.md',
|
|
392
374
|
'designEvidenceSummary',
|
|
393
375
|
],
|
|
394
376
|
},
|
|
@@ -28,10 +28,6 @@ export async function validateRequiredFiles(context) {
|
|
|
28
28
|
'scripts/rules-guardian-audit.mjs',
|
|
29
29
|
'scripts/explain-on-demand-audit.mjs',
|
|
30
30
|
'scripts/single-source-lazy-loading-audit.mjs',
|
|
31
|
-
'scripts/audit-cache-layer-contract.mjs',
|
|
32
|
-
'scripts/audit-typography-palette-anti-repeat.mjs',
|
|
33
|
-
'lib/cli/audits/typography-palette-anti-repeat-audit.mjs',
|
|
34
|
-
'lib/cli/commands/audit-design-anti-repeat.mjs',
|
|
35
31
|
'scripts/sync-thin-adapters.mjs',
|
|
36
32
|
'scripts/release-gate.mjs',
|
|
37
33
|
'scripts/generate-sbom.mjs',
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
export async function fileExists(filePath) {
|
|
5
|
+
try {
|
|
6
|
+
await stat(filePath);
|
|
7
|
+
return true;
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function readTextFile(filePath) {
|
|
14
|
+
return readFile(filePath, 'utf8');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function collectFiles(directoryPath, fileExtensionMatcher) {
|
|
18
|
+
const matchingFilePaths = [];
|
|
19
|
+
|
|
20
|
+
async function walk(currentDirectoryPath) {
|
|
21
|
+
const directoryEntries = await readdir(currentDirectoryPath, { withFileTypes: true });
|
|
22
|
+
|
|
23
|
+
for (const directoryEntry of directoryEntries) {
|
|
24
|
+
if (
|
|
25
|
+
directoryEntry.name === '.git'
|
|
26
|
+
|| directoryEntry.name === 'node_modules'
|
|
27
|
+
|| directoryEntry.name === '.agentic-backup'
|
|
28
|
+
|| directoryEntry.name === '.benchmarks'
|
|
29
|
+
) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const entryPath = join(currentDirectoryPath, directoryEntry.name);
|
|
34
|
+
|
|
35
|
+
if (directoryEntry.isDirectory()) {
|
|
36
|
+
await walk(entryPath);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (fileExtensionMatcher(directoryEntry.name)) {
|
|
41
|
+
matchingFilePaths.push(entryPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await walk(directoryPath);
|
|
47
|
+
return matchingFilePaths;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function normalizeLineEndings(content) {
|
|
51
|
+
return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
52
|
+
}
|
package/scripts/validate.mjs
CHANGED
|
@@ -18,13 +18,13 @@ import { readdir, readFile, stat } from 'node:fs/promises';
|
|
|
18
18
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
20
|
import { ALLOWED_SEVERITIES } from './validate/config.mjs';
|
|
21
|
-
import { runCacheLayerContractAudit } from './
|
|
22
|
-
import { runCachingScopeHygieneAudit } from './
|
|
23
|
-
|
|
24
|
-
import { runAuditFileSize } from './
|
|
25
|
-
import { runReflectionCitationAudit } from './
|
|
26
|
-
import { runReleaseBundleAudit } from './
|
|
27
|
-
import { runRuleIdUniquenessAudit } from './
|
|
21
|
+
import { runCacheLayerContractAudit } from './validate/audits/cache-layer-contract.mjs';
|
|
22
|
+
import { runCachingScopeHygieneAudit } from './validate/audits/caching-scope-hygiene.mjs';
|
|
23
|
+
|
|
24
|
+
import { runAuditFileSize } from './validate/audits/file-size.mjs';
|
|
25
|
+
import { runReflectionCitationAudit } from './validate/audits/reflection-citations.mjs';
|
|
26
|
+
import { runReleaseBundleAudit } from './validate/audits/release-bundle.mjs';
|
|
27
|
+
import { runRuleIdUniquenessAudit } from './validate/audits/rule-id-uniqueness.mjs';
|
|
28
28
|
import {
|
|
29
29
|
validateDependencyFreshnessAutomationCoverage,
|
|
30
30
|
validateDetectionTransparencyCoverage,
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
validateVersionConsistency,
|
|
60
60
|
validateMcpConfiguration,
|
|
61
61
|
} from './validate/project-metadata.mjs';
|
|
62
|
+
import { fileExists, readTextFile, collectFiles, normalizeLineEndings } from './validate/utils.mjs';
|
|
62
63
|
|
|
63
64
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
64
65
|
const ROOT_DIR = resolve(dirname(SCRIPT_FILE_PATH), '..');
|
|
@@ -79,51 +80,7 @@ const validationResult = {
|
|
|
79
80
|
warnings: [],
|
|
80
81
|
};
|
|
81
82
|
|
|
82
|
-
async function fileExists(filePath) {
|
|
83
|
-
try {
|
|
84
|
-
await stat(filePath);
|
|
85
|
-
return true;
|
|
86
|
-
} catch {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function readTextFile(filePath) {
|
|
92
|
-
return readFile(filePath, 'utf8');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async function collectFiles(directoryPath, fileExtensionMatcher) {
|
|
96
|
-
const matchingFilePaths = [];
|
|
97
|
-
|
|
98
|
-
async function walk(currentDirectoryPath) {
|
|
99
|
-
const directoryEntries = await readdir(currentDirectoryPath, { withFileTypes: true });
|
|
100
83
|
|
|
101
|
-
for (const directoryEntry of directoryEntries) {
|
|
102
|
-
if (
|
|
103
|
-
directoryEntry.name === '.git'
|
|
104
|
-
|| directoryEntry.name === 'node_modules'
|
|
105
|
-
|| directoryEntry.name === '.agentic-backup'
|
|
106
|
-
|| directoryEntry.name === '.benchmarks'
|
|
107
|
-
) {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const entryPath = join(currentDirectoryPath, directoryEntry.name);
|
|
112
|
-
|
|
113
|
-
if (directoryEntry.isDirectory()) {
|
|
114
|
-
await walk(entryPath);
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (fileExtensionMatcher(directoryEntry.name)) {
|
|
119
|
-
matchingFilePaths.push(entryPath);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
await walk(directoryPath);
|
|
125
|
-
return matchingFilePaths;
|
|
126
|
-
}
|
|
127
84
|
|
|
128
85
|
function pass(message) {
|
|
129
86
|
validationResult.passed += 1;
|
|
@@ -141,9 +98,7 @@ function warn(message) {
|
|
|
141
98
|
console.log(` WARN ${message}`);
|
|
142
99
|
}
|
|
143
100
|
|
|
144
|
-
|
|
145
|
-
return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
146
|
-
}
|
|
101
|
+
|
|
147
102
|
|
|
148
103
|
|
|
149
104
|
async function validateFileSizeAudit() {
|
|
@@ -211,33 +166,7 @@ async function validateCachingScopeHygieneAudit() {
|
|
|
211
166
|
}
|
|
212
167
|
}
|
|
213
168
|
|
|
214
|
-
async function validateTypographyPaletteAntiRepeatAudit() {
|
|
215
|
-
console.log('\nChecking typography and palette anti-repeat ledger (audit:typography-palette-anti-repeat)...');
|
|
216
|
-
const report = runTypographyPaletteAntiRepeatAudit({ repositoryRootPath: ROOT_DIR });
|
|
217
|
-
|
|
218
|
-
if (report.skipped) {
|
|
219
|
-
pass(`Typography/palette anti-repeat audit skipped: ${report.reason}`);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (report.passed) {
|
|
224
|
-
pass(`Typography/palette anti-repeat audit clean: ${report.filesScanned} CSS/token file(s) scanned, 0 blocking typography violation(s), ${report.paletteFindingCount} palette finding(s) (${report.paletteSeverity})`);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
169
|
|
|
228
|
-
for (const violation of report.typographyViolations) {
|
|
229
|
-
fail(`Typography ledger violation [${violation.kind}] in ${violation.file}:${violation.line}: ${violation.detail}`);
|
|
230
|
-
}
|
|
231
|
-
if (report.paletteSeverity === 'blocking') {
|
|
232
|
-
for (const finding of report.paletteFindings) {
|
|
233
|
-
fail(`Palette ledger violation [${finding.kind}] in ${finding.file}:${finding.line}: ${finding.detail}`);
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
for (const finding of report.paletteFindings) {
|
|
237
|
-
warn(`Palette ledger advisory [${finding.kind}] in ${finding.file}:${finding.line}: ${finding.detail}`);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
170
|
|
|
242
171
|
async function validateReleaseBundleAudit() {
|
|
243
172
|
console.log('\nChecking release benchmark bundle (audit:release-bundle)...');
|
|
@@ -311,7 +240,7 @@ async function main() {
|
|
|
311
240
|
await validateCacheLayerContractAudit();
|
|
312
241
|
await validateReflectionCitationAudit();
|
|
313
242
|
await validateCachingScopeHygieneAudit();
|
|
314
|
-
|
|
243
|
+
|
|
315
244
|
await validateReleaseBundleAudit();
|
|
316
245
|
await validateFileSizeAudit();
|
|
317
246
|
await validateRuleIdUniquenessAudit();
|