@ryuenn3123/agentic-senior-core 4.3.2 → 4.3.4
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/bootstrap-design.md +56 -222
- package/.agent-context/rules/api-docs.md +17 -126
- package/.agent-context/rules/api-versioning.md +9 -86
- package/.agent-context/rules/architecture.md +18 -136
- package/.agent-context/rules/background-jobs.md +9 -85
- package/.agent-context/rules/config-and-flags.md +8 -71
- package/.agent-context/rules/database-design.md +9 -65
- package/.agent-context/rules/docker-runtime.md +9 -62
- package/.agent-context/rules/efficiency-vs-hype.md +7 -37
- package/.agent-context/rules/error-handling.md +8 -33
- package/.agent-context/rules/event-driven.md +8 -34
- package/.agent-context/rules/frontend-architecture.md +22 -140
- package/.agent-context/rules/git-workflow.md +8 -77
- package/.agent-context/rules/microservices.md +8 -36
- package/.agent-context/rules/migrations.md +8 -76
- package/.agent-context/rules/observability.md +7 -60
- package/.agent-context/rules/performance.md +8 -28
- package/.agent-context/rules/realtime.md +7 -22
- package/.agent-context/rules/resilience.md +9 -69
- package/.agent-context/rules/security.md +9 -64
- package/.agent-context/rules/testing.md +8 -34
- package/AGENTS.md +10 -17
- package/README.md +1 -1
- package/lib/cli/adaptive-context/catalog.mjs +1 -6
- package/lib/cli/compiler.mjs +1 -2
- package/lib/cli/project-scaffolder/prompt-builders.mjs +21 -149
- package/package.json +1 -1
- package/scripts/frontend-usability-audit.mjs +4 -45
- package/scripts/release-gate/constants.mjs +1 -0
- package/scripts/validate/config.mjs +20 -134
- package/scripts/validate/coverage-checks.mjs +2 -12
- package/scripts/validate/file-structure.mjs +165 -0
- package/scripts/validate/markdown-content.mjs +109 -0
- package/scripts/validate/project-metadata.mjs +166 -0
- package/scripts/validate.mjs +42 -435
- package/.agent-context/prompts/research-design.md +0 -160
package/scripts/validate.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// Phase 1 governance refactor completed: monolithic script split into modular sub-files.
|
|
4
4
|
/**
|
|
5
5
|
* validate.mjs — Repository Integrity Validator
|
|
6
6
|
*
|
|
@@ -42,6 +42,23 @@ import {
|
|
|
42
42
|
validateUniversalSopConsolidationCoverage,
|
|
43
43
|
validateUpgradeUiContractWarningCoverage,
|
|
44
44
|
} from './validate/coverage-checks.mjs';
|
|
45
|
+
import {
|
|
46
|
+
validateRequiredFiles,
|
|
47
|
+
validateRuleFiles,
|
|
48
|
+
validateChecklistConsolidation,
|
|
49
|
+
} from './validate/file-structure.mjs';
|
|
50
|
+
import {
|
|
51
|
+
validateMarkdownFiles,
|
|
52
|
+
validateCrossReferences,
|
|
53
|
+
validateAgentsManifest,
|
|
54
|
+
validateDocumentationFlow,
|
|
55
|
+
} from './validate/markdown-content.mjs';
|
|
56
|
+
import {
|
|
57
|
+
validatePackageMetadata,
|
|
58
|
+
validatePolicyFile,
|
|
59
|
+
validateVersionConsistency,
|
|
60
|
+
validateMcpConfiguration,
|
|
61
|
+
} from './validate/project-metadata.mjs';
|
|
45
62
|
|
|
46
63
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
47
64
|
const ROOT_DIR = resolve(dirname(SCRIPT_FILE_PATH), '..');
|
|
@@ -128,390 +145,6 @@ function normalizeLineEndings(content) {
|
|
|
128
145
|
return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
129
146
|
}
|
|
130
147
|
|
|
131
|
-
async function validateRequiredFiles() {
|
|
132
|
-
console.log('\nChecking required files...');
|
|
133
|
-
|
|
134
|
-
const requiredFiles = [
|
|
135
|
-
'bin/agentic-senior-core.js',
|
|
136
|
-
'scripts/validate.mjs',
|
|
137
|
-
'scripts/llm-judge.mjs',
|
|
138
|
-
'scripts/detection-benchmark.mjs',
|
|
139
|
-
'scripts/benchmark-evidence-bundle.mjs',
|
|
140
|
-
'scripts/benchmark-writer-judge-matrix.mjs',
|
|
141
|
-
'scripts/benchmark-gate.mjs',
|
|
142
|
-
'scripts/benchmark-intelligence.mjs',
|
|
143
|
-
'scripts/memory-continuity-benchmark.mjs',
|
|
144
|
-
'scripts/docs-quality-drift-report.mjs',
|
|
145
|
-
'scripts/governance-weekly-report.mjs',
|
|
146
|
-
'scripts/mcp-server.mjs',
|
|
147
|
-
'scripts/mcp-server/constants.mjs',
|
|
148
|
-
'scripts/mcp-server/tool-registry.mjs',
|
|
149
|
-
'scripts/mcp-server/tools.mjs',
|
|
150
|
-
'scripts/frontend-usability-audit.mjs',
|
|
151
|
-
'scripts/ui-design-judge.mjs',
|
|
152
|
-
'scripts/documentation-boundary-audit.mjs',
|
|
153
|
-
'scripts/context-triggered-audit.mjs',
|
|
154
|
-
'scripts/rules-guardian-audit.mjs',
|
|
155
|
-
'scripts/explain-on-demand-audit.mjs',
|
|
156
|
-
'scripts/single-source-lazy-loading-audit.mjs',
|
|
157
|
-
'scripts/audit-cache-layer-contract.mjs',
|
|
158
|
-
'scripts/audit-typography-palette-anti-repeat.mjs',
|
|
159
|
-
'lib/cli/audits/typography-palette-anti-repeat-audit.mjs',
|
|
160
|
-
'lib/cli/commands/audit-design-anti-repeat.mjs',
|
|
161
|
-
'scripts/sync-thin-adapters.mjs',
|
|
162
|
-
'scripts/release-gate.mjs',
|
|
163
|
-
'scripts/generate-sbom.mjs',
|
|
164
|
-
'.agent-context/policies/llm-judge-threshold.json',
|
|
165
|
-
'.agent-context/prompts/compact-natural-mode.md',
|
|
166
|
-
'.agent-context/prompts/research-design.md',
|
|
167
|
-
'mcp.json',
|
|
168
|
-
'AGENTS.md',
|
|
169
|
-
'CLAUDE.md',
|
|
170
|
-
'GEMINI.md',
|
|
171
|
-
'README.md',
|
|
172
|
-
'CHANGELOG.md',
|
|
173
|
-
'docs/doc-index.md',
|
|
174
|
-
'docs/project-brief.md',
|
|
175
|
-
'docs/flow-overview.md',
|
|
176
|
-
'docs/api-contract.md',
|
|
177
|
-
'docs/faq.md',
|
|
178
|
-
'docs/deep-dive.md',
|
|
179
|
-
'docs/archive/HISTORY.md',
|
|
180
|
-
'docs/archive/CHANGELOG-archive.md',
|
|
181
|
-
'.agent-context/state/benchmark-reproducibility.json',
|
|
182
|
-
'.agent-context/state/benchmark-writer-judge-config.json',
|
|
183
|
-
'.agent-context/state/memory-schema-v1.json',
|
|
184
|
-
'.agent-context/state/memory-adapter-contract.json',
|
|
185
|
-
'.vscode/mcp.json',
|
|
186
|
-
'.github/workflows/release-gate.yml',
|
|
187
|
-
'.github/workflows/sbom-compliance.yml',
|
|
188
|
-
'.github/workflows/benchmark-intelligence.yml',
|
|
189
|
-
'.github/workflows/docs-quality-drift-report.yml',
|
|
190
|
-
'.github/workflows/governance-weekly-report.yml',
|
|
191
|
-
'tests/cli-smoke.test.mjs',
|
|
192
|
-
'tests/mcp-server.test.mjs',
|
|
193
|
-
'tests/llm-judge.test.mjs',
|
|
194
|
-
'tests/operations.test.mjs',
|
|
195
|
-
'LICENSE',
|
|
196
|
-
'.gitignore',
|
|
197
|
-
];
|
|
198
|
-
|
|
199
|
-
for (const requiredFilePath of requiredFiles) {
|
|
200
|
-
const absoluteRequiredFilePath = join(ROOT_DIR, requiredFilePath);
|
|
201
|
-
|
|
202
|
-
if (await fileExists(absoluteRequiredFilePath)) {
|
|
203
|
-
pass(requiredFilePath);
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
fail(`Missing required file: ${requiredFilePath}`);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async function validateMarkdownFiles() {
|
|
212
|
-
console.log('\nChecking markdown content...');
|
|
213
|
-
|
|
214
|
-
const markdownFilePaths = await collectFiles(ROOT_DIR, (fileName) => fileName.endsWith('.md'));
|
|
215
|
-
|
|
216
|
-
for (const markdownFilePath of markdownFilePaths) {
|
|
217
|
-
const markdownContent = await readTextFile(markdownFilePath);
|
|
218
|
-
const relativeMarkdownPath = relative(ROOT_DIR, markdownFilePath);
|
|
219
|
-
|
|
220
|
-
if (markdownContent.trim().length === 0) {
|
|
221
|
-
fail(`Empty markdown file: ${relativeMarkdownPath}`);
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
pass(`${relativeMarkdownPath} (${markdownContent.length} chars)`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async function validateRuleFiles() {
|
|
230
|
-
console.log('\nChecking rule, checklist, prompt, and state files...');
|
|
231
|
-
|
|
232
|
-
const expectedPaths = [
|
|
233
|
-
'rules/naming-conv.md',
|
|
234
|
-
'rules/architecture.md',
|
|
235
|
-
'rules/security.md',
|
|
236
|
-
'rules/performance.md',
|
|
237
|
-
'rules/error-handling.md',
|
|
238
|
-
'rules/testing.md',
|
|
239
|
-
'rules/git-workflow.md',
|
|
240
|
-
'rules/efficiency-vs-hype.md',
|
|
241
|
-
'rules/api-docs.md',
|
|
242
|
-
'rules/microservices.md',
|
|
243
|
-
'rules/event-driven.md',
|
|
244
|
-
'rules/database-design.md',
|
|
245
|
-
'rules/realtime.md',
|
|
246
|
-
'rules/frontend-architecture.md',
|
|
247
|
-
'rules/docker-runtime.md',
|
|
248
|
-
'rules/observability.md',
|
|
249
|
-
'rules/resilience.md',
|
|
250
|
-
'rules/migrations.md',
|
|
251
|
-
'rules/background-jobs.md',
|
|
252
|
-
'rules/config-and-flags.md',
|
|
253
|
-
'rules/api-versioning.md',
|
|
254
|
-
'review-checklists/pr-checklist.md',
|
|
255
|
-
'review-checklists/architecture-review.md',
|
|
256
|
-
'prompts/init-project.md',
|
|
257
|
-
'prompts/compact-natural-mode.md',
|
|
258
|
-
'prompts/bootstrap-design.md',
|
|
259
|
-
'prompts/refactor.md',
|
|
260
|
-
'prompts/review-code.md',
|
|
261
|
-
'state/architecture-map.md',
|
|
262
|
-
'state/dependency-map.md',
|
|
263
|
-
];
|
|
264
|
-
|
|
265
|
-
for (const expectedPath of expectedPaths) {
|
|
266
|
-
const absoluteExpectedPath = join(AGENT_CONTEXT_DIR, expectedPath);
|
|
267
|
-
|
|
268
|
-
if (!(await fileExists(absoluteExpectedPath))) {
|
|
269
|
-
fail(`Missing agent context file: .agent-context/${expectedPath}`);
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const fileContent = await readTextFile(absoluteExpectedPath);
|
|
274
|
-
if (fileContent.trim().length < 100) {
|
|
275
|
-
fail(`Agent context file is suspiciously short: .agent-context/${expectedPath}`);
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
pass(`.agent-context/${expectedPath}`);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
async function validateChecklistConsolidation() {
|
|
284
|
-
console.log('\nChecking review checklist consolidation...');
|
|
285
|
-
|
|
286
|
-
const reviewChecklistDirectoryPath = join(AGENT_CONTEXT_DIR, 'review-checklists');
|
|
287
|
-
const checklistEntries = await readdir(reviewChecklistDirectoryPath, { withFileTypes: true });
|
|
288
|
-
const checklistFileNames = checklistEntries
|
|
289
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
|
|
290
|
-
.map((entry) => entry.name)
|
|
291
|
-
.sort((leftName, rightName) => leftName.localeCompare(rightName));
|
|
292
|
-
|
|
293
|
-
const expectedChecklistFileNames = ['architecture-review.md', 'pr-checklist.md'];
|
|
294
|
-
|
|
295
|
-
if (checklistFileNames.length <= 2) {
|
|
296
|
-
pass(`Checklist count is consolidated (${checklistFileNames.length}/2)`);
|
|
297
|
-
} else {
|
|
298
|
-
fail(`Checklist count exceeds limit (${checklistFileNames.length}/2): ${checklistFileNames.join(', ')}`);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
for (const expectedChecklistFileName of expectedChecklistFileNames) {
|
|
302
|
-
if (checklistFileNames.includes(expectedChecklistFileName)) {
|
|
303
|
-
pass(`Checklist exists: .agent-context/review-checklists/${expectedChecklistFileName}`);
|
|
304
|
-
} else {
|
|
305
|
-
fail(`Missing consolidated checklist: .agent-context/review-checklists/${expectedChecklistFileName}`);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
async function validateCrossReferences() {
|
|
311
|
-
console.log('\nChecking internal links...');
|
|
312
|
-
|
|
313
|
-
const markdownFilePaths = await collectFiles(ROOT_DIR, (fileName) => fileName.endsWith('.md'));
|
|
314
|
-
const linkPattern = /\[([^\]]*)\]\((?!https?:\/\/|#)([^)]+)\)/g;
|
|
315
|
-
let checkedLinkCount = 0;
|
|
316
|
-
|
|
317
|
-
for (const markdownFilePath of markdownFilePaths) {
|
|
318
|
-
const markdownContent = await readTextFile(markdownFilePath);
|
|
319
|
-
const currentFileDirectory = dirname(markdownFilePath);
|
|
320
|
-
const relativeMarkdownPath = relative(ROOT_DIR, markdownFilePath);
|
|
321
|
-
let linkMatch = linkPattern.exec(markdownContent);
|
|
322
|
-
|
|
323
|
-
while (linkMatch) {
|
|
324
|
-
const rawLinkTarget = linkMatch[2].split('#')[0];
|
|
325
|
-
if (rawLinkTarget) {
|
|
326
|
-
checkedLinkCount += 1;
|
|
327
|
-
const resolvedLinkPath = resolve(currentFileDirectory, rawLinkTarget);
|
|
328
|
-
|
|
329
|
-
if (await fileExists(resolvedLinkPath)) {
|
|
330
|
-
pass(`${relativeMarkdownPath} → ${linkMatch[2]}`);
|
|
331
|
-
} else {
|
|
332
|
-
fail(`Broken link in ${relativeMarkdownPath}: ${linkMatch[2]}`);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
linkMatch = linkPattern.exec(markdownContent);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (checkedLinkCount === 0) {
|
|
341
|
-
warn('No internal links were found in markdown files');
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
async function validateAgentsManifest() {
|
|
346
|
-
console.log('\nChecking AGENTS.md manifest links...');
|
|
347
|
-
|
|
348
|
-
const agentsContent = await readTextFile(join(ROOT_DIR, 'AGENTS.md'));
|
|
349
|
-
const fileReferencePattern = /\[`?([^`\]]+)`?\]\(([^)]+)\)/g;
|
|
350
|
-
let manifestLinkCount = 0;
|
|
351
|
-
let fileReferenceMatch = fileReferencePattern.exec(agentsContent);
|
|
352
|
-
|
|
353
|
-
while (fileReferenceMatch) {
|
|
354
|
-
const manifestLinkTarget = fileReferenceMatch[2];
|
|
355
|
-
|
|
356
|
-
if (!manifestLinkTarget.startsWith('http')) {
|
|
357
|
-
manifestLinkCount += 1;
|
|
358
|
-
const resolvedManifestLinkPath = resolve(ROOT_DIR, manifestLinkTarget);
|
|
359
|
-
|
|
360
|
-
if (await fileExists(resolvedManifestLinkPath)) {
|
|
361
|
-
pass(`AGENTS.md → ${manifestLinkTarget}`);
|
|
362
|
-
} else {
|
|
363
|
-
fail(`AGENTS.md references missing file: ${manifestLinkTarget}`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
fileReferenceMatch = fileReferencePattern.exec(agentsContent);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (manifestLinkCount === 0) {
|
|
371
|
-
warn('AGENTS.md does not contain any local manifest links');
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
async function validatePackageMetadata() {
|
|
376
|
-
console.log('\nChecking package metadata...');
|
|
377
|
-
|
|
378
|
-
const packageJson = JSON.parse(await readTextFile(PACKAGE_JSON_PATH));
|
|
379
|
-
const versionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
380
|
-
|
|
381
|
-
if (typeof packageJson.version !== 'string' || !versionPattern.test(packageJson.version)) {
|
|
382
|
-
fail('package.json version must be a semantic version string');
|
|
383
|
-
} else {
|
|
384
|
-
pass(`package.json version ${packageJson.version}`);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (packageJson.scripts?.validate === 'node ./scripts/validate.mjs') {
|
|
388
|
-
pass('package.json validate script is Node-first');
|
|
389
|
-
} else {
|
|
390
|
-
fail('package.json validate script must use node ./scripts/validate.mjs');
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (packageJson.scripts?.test) {
|
|
394
|
-
pass('package.json test script exists');
|
|
395
|
-
} else {
|
|
396
|
-
fail('package.json test script is missing');
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (packageJson.devDependencies && Object.keys(packageJson.devDependencies).length > 0) {
|
|
400
|
-
warn('package.json still has devDependencies; review whether they are necessary');
|
|
401
|
-
} else {
|
|
402
|
-
pass('package.json has no unnecessary devDependencies');
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (Array.isArray(packageJson.files) && packageJson.files.includes('AGENTS.md')) {
|
|
406
|
-
pass('package.json publishes canonical AGENTS.md');
|
|
407
|
-
} else {
|
|
408
|
-
fail('package.json must publish AGENTS.md so init and upgrade can copy the canonical root instructions file');
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (await fileExists(BUN_LOCK_PATH)) {
|
|
412
|
-
fail('bun.lock must not be tracked while npm is the package manager source of truth');
|
|
413
|
-
} else {
|
|
414
|
-
pass('No bun.lock drift file present');
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
async function validatePolicyFile() {
|
|
419
|
-
console.log('\nChecking LLM Judge policy...');
|
|
420
|
-
|
|
421
|
-
const policyContent = await readTextFile(POLICY_FILE_PATH);
|
|
422
|
-
const parsedPolicy = JSON.parse(policyContent);
|
|
423
|
-
const selectedProfileName = parsedPolicy.selectedProfile;
|
|
424
|
-
const profileThresholds = parsedPolicy.profileThresholds;
|
|
425
|
-
|
|
426
|
-
if (typeof selectedProfileName !== 'string') {
|
|
427
|
-
fail('Policy file must define selectedProfile as a string');
|
|
428
|
-
} else {
|
|
429
|
-
pass(`LLM Judge selected profile: ${selectedProfileName}`);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (!profileThresholds || typeof profileThresholds !== 'object') {
|
|
433
|
-
fail('Policy file must define profileThresholds');
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
for (const [profileName, profileSettings] of Object.entries(profileThresholds)) {
|
|
438
|
-
if (!Array.isArray(profileSettings.blockingSeverities)) {
|
|
439
|
-
fail(`Policy profile ${profileName} must define blockingSeverities`);
|
|
440
|
-
continue;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
const invalidSeverity = profileSettings.blockingSeverities.find((severity) => !ALLOWED_SEVERITIES.has(severity));
|
|
444
|
-
if (invalidSeverity) {
|
|
445
|
-
fail(`Policy profile ${profileName} uses unsupported severity: ${invalidSeverity}`);
|
|
446
|
-
continue;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
pass(`Policy profile ${profileName} blocking severities are valid`);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (typeof profileThresholds[selectedProfileName] === 'object') {
|
|
453
|
-
pass('Policy selectedProfile points to a valid profile');
|
|
454
|
-
} else {
|
|
455
|
-
fail('Policy selectedProfile must match one of the configured profileThresholds');
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
async function validateVersionConsistency() {
|
|
460
|
-
console.log('\nChecking release version consistency...');
|
|
461
|
-
|
|
462
|
-
const packageJson = JSON.parse(await readTextFile(PACKAGE_JSON_PATH));
|
|
463
|
-
const packageVersion = packageJson.version;
|
|
464
|
-
const changelogContent = await readTextFile(CHANGELOG_PATH);
|
|
465
|
-
|
|
466
|
-
if (changelogContent.includes(`## ${packageVersion}`)) {
|
|
467
|
-
pass(`CHANGELOG.md contains release entry for ${packageVersion}`);
|
|
468
|
-
} else {
|
|
469
|
-
fail(`CHANGELOG.md is missing a ## ${packageVersion} heading`);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (await fileExists(PACKAGE_LOCK_PATH)) {
|
|
473
|
-
const packageLock = JSON.parse(await readTextFile(PACKAGE_LOCK_PATH));
|
|
474
|
-
const rootLockVersion = packageLock.packages?.['']?.version;
|
|
475
|
-
if (packageLock.version === packageVersion && rootLockVersion === packageVersion) {
|
|
476
|
-
pass(`package-lock.json matches package version ${packageVersion}`);
|
|
477
|
-
} else {
|
|
478
|
-
fail(`package-lock.json version drift: expected ${packageVersion}, found ${packageLock.version || 'missing'} / ${rootLockVersion || 'missing'}`);
|
|
479
|
-
}
|
|
480
|
-
} else {
|
|
481
|
-
fail('package-lock.json is required for npm release consistency');
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
for (const generatedRuleFileName of GENERATED_RULE_FILES) {
|
|
485
|
-
const generatedRuleContent = await readTextFile(join(ROOT_DIR, generatedRuleFileName));
|
|
486
|
-
|
|
487
|
-
if (generatedRuleContent.includes(`Generated by Agentic-Senior-Core CLI v${packageVersion}`)) {
|
|
488
|
-
pass(`${generatedRuleFileName} matches package version ${packageVersion}`);
|
|
489
|
-
} else {
|
|
490
|
-
fail(`${generatedRuleFileName} does not match package version ${packageVersion}`);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
async function validateDocumentationFlow() {
|
|
496
|
-
console.log('\nChecking documentation flow...');
|
|
497
|
-
|
|
498
|
-
const readmeContent = await readTextFile(README_PATH);
|
|
499
|
-
const requiredReadmeSnippets = [
|
|
500
|
-
'npx @ryuenn3123/agentic-senior-core init',
|
|
501
|
-
'npm run validate',
|
|
502
|
-
'docs/faq.md',
|
|
503
|
-
'docs/deep-dive.md',
|
|
504
|
-
'docs/archive/HISTORY.md',
|
|
505
|
-
];
|
|
506
|
-
|
|
507
|
-
for (const requiredReadmeSnippet of requiredReadmeSnippets) {
|
|
508
|
-
if (readmeContent.includes(requiredReadmeSnippet)) {
|
|
509
|
-
pass(`README.md mentions ${requiredReadmeSnippet}`);
|
|
510
|
-
} else {
|
|
511
|
-
fail(`README.md must mention ${requiredReadmeSnippet}`);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
148
|
|
|
516
149
|
async function validateFileSizeAudit() {
|
|
517
150
|
console.log('\nChecking file size threshold (audit:file-size)...');
|
|
@@ -619,45 +252,6 @@ async function validateReleaseBundleAudit() {
|
|
|
619
252
|
}
|
|
620
253
|
}
|
|
621
254
|
|
|
622
|
-
async function validateMcpConfiguration() {
|
|
623
|
-
console.log('\nChecking MCP configuration...');
|
|
624
|
-
|
|
625
|
-
const mcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, 'mcp.json')));
|
|
626
|
-
const workspaceMcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, '.vscode', 'mcp.json')));
|
|
627
|
-
const workspaceServerConfig = workspaceMcpConfiguration.servers?.['agentic-senior-core'];
|
|
628
|
-
|
|
629
|
-
if (mcpConfiguration.knowledgeLayers?.enabled === true) {
|
|
630
|
-
pass('Root MCP config has knowledgeLayers enabled');
|
|
631
|
-
} else {
|
|
632
|
-
fail('Root MCP config must have knowledgeLayers.enabled: true');
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
if (typeof workspaceMcpConfiguration.$schema === 'undefined') {
|
|
636
|
-
pass('Workspace MCP config omits $schema (supported by current VS Code MCP schema inference)');
|
|
637
|
-
} else if (workspaceMcpConfiguration.$schema === 'vscode://schemas/mcp') {
|
|
638
|
-
pass('Workspace MCP config uses trusted VS Code schema');
|
|
639
|
-
} else {
|
|
640
|
-
fail('Workspace MCP config $schema must be omitted or set to vscode://schemas/mcp');
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
if (workspaceServerConfig?.command === 'node') {
|
|
644
|
-
pass('Workspace MCP server command uses Node');
|
|
645
|
-
} else {
|
|
646
|
-
fail('Workspace MCP server command must use Node');
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (workspaceServerConfig?.cwd === '${workspaceFolder}') {
|
|
650
|
-
pass('Workspace MCP server cwd uses ${workspaceFolder}');
|
|
651
|
-
} else {
|
|
652
|
-
fail('Workspace MCP server cwd must be ${workspaceFolder}');
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
if (Array.isArray(workspaceServerConfig?.args) && workspaceServerConfig.args.includes('./scripts/mcp-server.mjs')) {
|
|
656
|
-
pass('Workspace MCP server points to scripts/mcp-server.mjs');
|
|
657
|
-
} else {
|
|
658
|
-
fail('Workspace MCP server must include ./scripts/mcp-server.mjs argument');
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
255
|
|
|
662
256
|
async function main() {
|
|
663
257
|
console.log('===============================================');
|
|
@@ -675,16 +269,29 @@ async function main() {
|
|
|
675
269
|
readTextFile,
|
|
676
270
|
};
|
|
677
271
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
272
|
+
const generalValidationContext = {
|
|
273
|
+
...coverageValidationContext,
|
|
274
|
+
PACKAGE_JSON_PATH,
|
|
275
|
+
PACKAGE_LOCK_PATH,
|
|
276
|
+
BUN_LOCK_PATH,
|
|
277
|
+
CHANGELOG_PATH,
|
|
278
|
+
README_PATH,
|
|
279
|
+
POLICY_FILE_PATH,
|
|
280
|
+
GENERATED_RULE_FILES,
|
|
281
|
+
collectFiles,
|
|
282
|
+
warn,
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
await validateRequiredFiles(generalValidationContext);
|
|
286
|
+
await validateMarkdownFiles(generalValidationContext);
|
|
287
|
+
await validateRuleFiles(generalValidationContext);
|
|
288
|
+
await validateChecklistConsolidation(generalValidationContext);
|
|
289
|
+
await validateAgentsManifest(generalValidationContext);
|
|
290
|
+
await validateCrossReferences(generalValidationContext);
|
|
291
|
+
await validatePackageMetadata(generalValidationContext);
|
|
292
|
+
await validatePolicyFile(generalValidationContext);
|
|
293
|
+
await validateVersionConsistency(generalValidationContext);
|
|
294
|
+
await validateDocumentationFlow(generalValidationContext);
|
|
688
295
|
await validateTerminologyMapping(coverageValidationContext);
|
|
689
296
|
await validateDetectionTransparencyCoverage(coverageValidationContext);
|
|
690
297
|
await validateStackDecisionBoundaryCoverage(coverageValidationContext);
|
|
@@ -697,7 +304,7 @@ async function main() {
|
|
|
697
304
|
await validateDependencyFreshnessAutomationCoverage(coverageValidationContext);
|
|
698
305
|
await validateDeterministicBoundaryEnforcementCoverage(coverageValidationContext);
|
|
699
306
|
await validateRulesOnlyActiveSurfaceCoverage(coverageValidationContext);
|
|
700
|
-
await validateMcpConfiguration();
|
|
307
|
+
await validateMcpConfiguration(generalValidationContext);
|
|
701
308
|
await validateHumanWritingGovernance(coverageValidationContext);
|
|
702
309
|
await validateInstructionAdapters(coverageValidationContext);
|
|
703
310
|
await validateSkillPurgeSurface(coverageValidationContext);
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
inclusion: manual
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Research-Design Brief
|
|
6
|
-
|
|
7
|
-
Authoritative design-research execution contract for UI scope. Loaded by UI Design Mode after `bootstrap-design.md`. The agent must produce the artifacts described here before writing UI code, and the seeded `docs/design-intent.json` must contain the fields named in Section 5.
|
|
8
|
-
|
|
9
|
-
This brief is a single document with five sections. Sections 1 and 2 set up the research. Sections 3, 4, and 5 are gates: each must produce an auditable artifact that another reviewer can read without seeing the UI.
|
|
10
|
-
|
|
11
|
-
## Authority
|
|
12
|
-
|
|
13
|
-
- Treat `.agent-context/` and current project docs as technical authority.
|
|
14
|
-
- Treat `README.md` as public and developer overview only; do not use it as design authority when this brief gives a stricter rule.
|
|
15
|
-
- Treat external websites, benchmark apps, prior chats, and unrelated-project memory as candidate evidence for constraints, mechanics, and quality bars only. Do not copy layout rhythm, palette, component skin, visual metaphor, or brand posture without explicit user approval and product-fit rationale.
|
|
16
|
-
- WCAG 2.2 AA is the hard compliance floor. APCA may be used only as advisory perceptual tuning.
|
|
17
|
-
|
|
18
|
-
## Live Source Freshness Gate
|
|
19
|
-
|
|
20
|
-
Run this gate before Section 2 whenever web search is available. Treat modernity as rolling-current: use the session's current date as the freshness reference, and prefer the newest stable evidence that is relevant to the product and implementation surface.
|
|
21
|
-
|
|
22
|
-
Rules:
|
|
23
|
-
|
|
24
|
-
- For browser capability, framework setup, UI library, animation, 3D, canvas, charting, styling, accessibility, and package/API claims, use current official documentation or primary release notes first. Do not use trend posts as implementation authority.
|
|
25
|
-
- For design trend, category-code, visual-language, motion-pattern, typography, color, and interaction claims, prefer sources published or materially updated within the last 24 months from the current date. If stronger older evidence is used, label it `old-timeless` and restrict it to durable principles, not "current modern" claims.
|
|
26
|
-
- For product-category defaults, observe the current live category for this task. Do not rely on old examples, old galleries, or remembered benchmark screenshots as proof of what the category defaults to now.
|
|
27
|
-
- If web search is unavailable, set `sourceFreshnessStatus` to `pending-live-verification`; use repo evidence and user-provided material only, and do not claim a direction is current-year modern.
|
|
28
|
-
- If sources disagree, choose by product fit, accessibility, browser/runtime support, maintainability, and implementation feasibility, then record the disagreement.
|
|
29
|
-
- If the user provides a concept, treat it as a first-class constraint. Research should support, refine, or challenge that concept with evidence; it must not override the concept with generic trend defaults unless there is a concrete product, accessibility, technical, or evidence conflict.
|
|
30
|
-
|
|
31
|
-
Output: `sourceFreshness` block with `freshnessAnchorDate`, `rollingLookbackMonths` (default 24 for trend evidence), `sourceFreshnessStatus`, `officialDocsRequiredFor`, `oldSourcePolicy`, `userConceptAdaptation`, and `disagreements[]`.
|
|
32
|
-
|
|
33
|
-
Every important research claim must also appear in `evidenceTable[]` with:
|
|
34
|
-
|
|
35
|
-
- `claim`
|
|
36
|
-
- `sourceUrl`
|
|
37
|
-
- `sourceType` (`official`, `primary`, `industry`, `opinion`, `old-timeless`, `repo-evidence`, `user-provided`)
|
|
38
|
-
- `publishedOrUpdatedAt` when visible, otherwise `unknown`
|
|
39
|
-
- `fetchedAt`
|
|
40
|
-
- `confidence` (`high`, `medium`, `low`)
|
|
41
|
-
- `decisionImpact`
|
|
42
|
-
|
|
43
|
-
Research vocabulary is internal-only. Use `sourceFreshness`, `evidenceTable[]`, `researchDossier`, `anchor`, `categoryCodes`, `morphologicalExploration`, and `renameTest` to audit decisions, but do not expose those labels in UI copy, public-facing docs, section headings, or final user-facing rationale unless the user explicitly asks for the research trace.
|
|
44
|
-
|
|
45
|
-
## Anti-Repeat Ledger Gate (read first)
|
|
46
|
-
|
|
47
|
-
If `docs/design-intent.json` already exists and carries `researchDossier.metadata.antiRepeatLedger`, treat every entry under `previousAnchors`, `previousPalettes`, `previousMotionSignatures`, and `previousStructuralFingerprints` as a hard blocklist before producing any candidate in Sections 3-5.
|
|
48
|
-
|
|
49
|
-
Rules:
|
|
50
|
-
|
|
51
|
-
- The five Section 5 anchor candidates must each differ from every blocklisted entry on at least conceptual family, hierarchy implication, and motion implication.
|
|
52
|
-
- Restating an existing direction with new wording is REVISE, not pass.
|
|
53
|
-
- A user-explicit redesign request ("redesign from zero", "redesain dari 0", "ulang dari 0", "research ulang", or any explicit reset) bypasses the freshness gate but does not weaken the ledger; previously shipped direction stays blocklisted unless the user explicitly says "revive existing direction".
|
|
54
|
-
- Ledger entries are signature-level descriptors, not raw token dumps; treat them as direction summaries.
|
|
55
|
-
|
|
56
|
-
If the ledger is empty or `researchDossier.metadata.researchVerifiedAt` is null because the contract is a fresh seed, the ledger is informational only and does not add blocklist entries.
|
|
57
|
-
|
|
58
|
-
## Section 1 — Product Reading
|
|
59
|
-
|
|
60
|
-
Before any visual choice, write a structured product reading:
|
|
61
|
-
|
|
62
|
-
- Product type and core verb (what the user does, not what the UI shows).
|
|
63
|
-
- Three highest-stakes user moments, ordered by frequency.
|
|
64
|
-
- Data shapes that dominate the screen (timeseries, ledger, list, document, control, telemetry, conversational, spatial, other).
|
|
65
|
-
- Latency profile (real-time, soft real-time, batch, ambient).
|
|
66
|
-
- Failure modes the UI must absorb visibly (partial, stale, optimistic, conflict, offline, permission, rate-limit, none).
|
|
67
|
-
- Context of use (one-shot, sustained focus, glance-and-go, background monitor, shared display, embedded).
|
|
68
|
-
- Known constraints (device, runtime, accessibility, regulatory, performance budget, brand continuity).
|
|
69
|
-
|
|
70
|
-
Output: `productReading` block. Each field must be one sentence, evidence-backed from repo or brief. Speculation is not allowed; if a field is unknown, name it as such and stop until the user resolves it.
|
|
71
|
-
|
|
72
|
-
## Default Detection Protocol
|
|
73
|
-
|
|
74
|
-
Before fetching any reference, use the `productReading` output to derive search direction. Do not self-select from a fixed category list.
|
|
75
|
-
|
|
76
|
-
1. **Name defaults.** Name three design directions the agent is most tempted to use for this brief. For each, write one sentence naming the specific visual pattern (layout, palette, density, motion, typography, composition).
|
|
77
|
-
|
|
78
|
-
2. **Argue against each default.** For each default, write one sentence on why it would flatten what is specific about THIS product's core verb, data shape, or context of use. The argument must reference a `productReading` field, not a generic aesthetic opinion.
|
|
79
|
-
|
|
80
|
-
3. **Derive search direction from the argument.** The rejection argument reveals what the product needs that the default cannot provide. Use that need as the search query for `web_search` and `web_fetch`. Search by the product's core characteristic pair (medium x intent), not by product category name. Example: core verb "demonstrate" + data shape "narrative" -> search "editorial portfolio interaction design" not "portfolio sites."
|
|
81
|
-
|
|
82
|
-
4. **Cross-domain pull.** Identify one domain that shares the same interaction model but a different visual vocabulary. Pull one reference from there. Example: portfolio -> scientific publication, exhibition catalog, film press kit -- anything with "demonstrate body of work" as the core verb but a different surface expectation.
|
|
83
|
-
|
|
84
|
-
5. **Gallery check.** Find state-of-the-art quality references for the derived direction by searching the web. CRITICAL: DO NOT use gallery homepages or discovery platforms as references. You must drill down to find a specific featured product/website, fetch THAT specific product's URL, and use it as evidence.
|
|
85
|
-
|
|
86
|
-
DO NOT fetch: Wikipedia, Dribbble templates, or generic blog posts about "best UI design practices."
|
|
87
|
-
|
|
88
|
-
For each reference: fetch the actual product page this session, record what mechanic or hierarchy is borrowed, and explicitly state what is NOT borrowed (palette, component skin, layout rhythm).
|
|
89
|
-
|
|
90
|
-
If the anchor concept you're considering would make sense to someone from 1920, it's too archival. The anchor must be legible to someone who uses the web today.
|
|
91
|
-
|
|
92
|
-
## Section 2 — Reference Intake
|
|
93
|
-
|
|
94
|
-
Reference material is fuel for variance, not a style source.
|
|
95
|
-
|
|
96
|
-
- Capture between three and seven references per dimension that needs exploration: hierarchy, density, type system, motion, state language, material logic, color behavior.
|
|
97
|
-
- For each reference, record: source URL or citation, what is borrowed (mechanic, behavior, hierarchy, density, type pairing, motion choreography), and what is explicitly not borrowed (palette, component skin, layout rhythm, brand posture).
|
|
98
|
-
- References live in `referenceIntake[]`. The agent may not select an anchor in Section 5 that copies a reference's surface; only the borrowed mechanic is allowed to flow downstream.
|
|
99
|
-
|
|
100
|
-
If references are not provided by the user and web search is unavailable, set `referenceIntakeStatus` to `internal-evidence-only` and constrain Sections 3 to 5 to repo evidence and project docs.
|
|
101
|
-
|
|
102
|
-
## Section 3 — Creative Direction
|
|
103
|
-
|
|
104
|
-
Before UI code, commit to a specific visual direction. The agent tends to converge toward generic, "on distribution" outputs. In frontend design this creates what users call the "AI slop" aesthetic. This section exists to prevent that.
|
|
105
|
-
|
|
106
|
-
### 3a. Category defaults to avoid
|
|
107
|
-
|
|
108
|
-
Name at least three specific cliches your product category will fall into without intervention. Be specific enough that someone unfamiliar with the project can visualize the exact aesthetic trap from the text alone.
|
|
109
|
-
|
|
110
|
-
Common AI-safe cliches to name and reject when your product sits anywhere near them:
|
|
111
|
-
|
|
112
|
-
- `dev-tool default: condensed tabular numerics with minimal chrome and monospace code blocks on dark slate background, sans-serif metadata at 11-12px, monochrome status dots`
|
|
113
|
-
- `AI-startup landing default: purple-to-pink gradient hero with floating 3D glass cards, sans-serif display type at 700-900 weight, vague hero copy, three-up feature grid`
|
|
114
|
-
- `SaaS admin default: left-side icon-only nav, top utility bar, three-card KPI row above a single data table, neutral grey-on-white with one accent color`
|
|
115
|
-
- `marketing site default: hero image with one-line headline plus subhead, three feature tiles below, two pricing tiers, testimonial carousel, footer link grid`
|
|
116
|
-
|
|
117
|
-
Each category default must include a one-sentence rejection note explaining the trap it sets.
|
|
118
|
-
|
|
119
|
-
Output: `categoryCodes[]` with at least three entries in `docs/design-intent.json`. Each entry has `description`, `categoryDefaultReason`, and `rejectionNote`.
|
|
120
|
-
|
|
121
|
-
### 3b. Anchor reference
|
|
122
|
-
|
|
123
|
-
Pick one concrete, googleable real-world reference whose mechanics (not surface) translate to your UI. The anchor must be specific enough that renaming the product to a different category breaks coherence.
|
|
124
|
-
|
|
125
|
-
Hard constraints:
|
|
126
|
-
- Reject generic quality words as anchors: "modern", "clean", "premium", "expressive", "minimal", "bold", "futuristic", "elegant" are not anchors.
|
|
127
|
-
- Specific premium digital products are valid anchors when the borrowed element is an interaction mechanic, hierarchy pattern, or motion behavior -- not a palette or brand.
|
|
128
|
-
- Do not default to spatial place metaphors (room, darkroom, control room, studio, lab, cockpit, command center). Prefer artifacts, workflows, instruments, data behaviors, materials, editorial systems, or interaction mechanisms.
|
|
129
|
-
- Draw from IDE themes, cultural aesthetics, cinematic campaigns, editorial systems, material artifacts, or specific product experiences for inspiration.
|
|
130
|
-
|
|
131
|
-
Output: `conceptualAnchor.anchorReference` in `docs/design-intent.json`.
|
|
132
|
-
|
|
133
|
-
### 3c. Four creative commitments (record before coding)
|
|
134
|
-
|
|
135
|
-
1. **Typography**: Choose distinctive fonts with meaningful role contrast. Avoid overused families (Inter, Roboto, Arial, Space Grotesk, system fonts). Pick choices that elevate the aesthetic. Record one variable-axis or pairing decision.
|
|
136
|
-
2. **Color and palette**: Commit to a cohesive product-derived palette. Dominant colors with sharp accents outperform timid, evenly-distributed palettes. Name what product evidence makes the palette fit and one color behavior that would not transfer to another category.
|
|
137
|
-
3. **Motion and interaction**: Define one signature motion behavior more specific than "smooth." Focus on high-impact moments: one well-orchestrated page load with staggered reveals creates more delight than scattered micro-interactions. Use CSS-only or a modern motion library.
|
|
138
|
-
4. **Composition**: Make one composition choice that avoids interchangeable card stacks. Create atmosphere and depth rather than defaulting to solid backgrounds.
|
|
139
|
-
|
|
140
|
-
Avoid generic AI-generated aesthetics:
|
|
141
|
-
- Overused font families and cliched color schemes (particularly purple gradients)
|
|
142
|
-
- Predictable layouts and cookie-cutter component patterns
|
|
143
|
-
- Solid-color backgrounds without atmosphere or depth
|
|
144
|
-
|
|
145
|
-
Interpret creatively and make unexpected choices that feel genuinely designed for the context. Vary between light and dark themes, different fonts, different aesthetics. The agent still tends to converge on common choices across generations; resist this.
|
|
146
|
-
|
|
147
|
-
Output: Record all four commitments in `docs/design-intent.json` before UI code. The `derivedTokenLogic.tokenContinuityClassification` must classify each of typography, palette, motion, and spacing as `anchor-derived`, `continuity-retained`, or `newly-introduced` with rationale.
|
|
148
|
-
|
|
149
|
-
## Done Criteria
|
|
150
|
-
|
|
151
|
-
The brief is complete when:
|
|
152
|
-
|
|
153
|
-
1. `productReading` is filled with evidence-backed sentences.
|
|
154
|
-
2. `referenceIntake[]` records the borrowed mechanic and the explicit non-copy boundary per reference (or `referenceIntakeStatus: internal-evidence-only` is set).
|
|
155
|
-
3. `categoryCodes[]` has at least three entries with rejection notes.
|
|
156
|
-
4. One anchor reference is recorded that passes the specificity test (renaming the product to a different category breaks coherence).
|
|
157
|
-
5. Four creative commitments are recorded with product-derived rationale.
|
|
158
|
-
6. Generic anchors and spatial-place defaults are rejected with the rejection reason recorded.
|
|
159
|
-
|
|
160
|
-
Only after the brief is complete does the agent move on to `docs/DESIGN.md` and the rest of `docs/design-intent.json` (token logic, motion budget, accessibility policy, review rubric, library decisions, etc., per `bootstrap-design.md`).
|