@ryuenn3123/agentic-senior-core 3.0.46 → 3.0.48
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 +9 -7
- package/.agent-context/prompts/refactor.md +1 -1
- package/.agent-context/prompts/review-code.md +1 -1
- package/.agent-context/review-checklists/pr-checklist.md +3 -0
- package/.agent-context/rules/api-docs.md +4 -0
- package/.agent-context/rules/architecture.md +16 -2
- package/.agent-context/state/architecture-map.md +3 -3
- package/.agent-context/state/dependency-map.md +2 -2
- package/AGENTS.md +170 -35
- package/CLAUDE.md +1 -44
- package/CONTRIBUTING.md +2 -3
- package/GEMINI.md +1 -44
- package/README.md +28 -22
- package/lib/cli/backup.mjs +37 -0
- package/lib/cli/commands/init.mjs +15 -29
- package/lib/cli/commands/optimize.mjs +2 -48
- package/lib/cli/commands/upgrade.mjs +14 -52
- package/lib/cli/compiler.mjs +25 -95
- package/lib/cli/constants.mjs +1 -9
- package/lib/cli/detector.mjs +0 -1
- package/lib/cli/init-options.mjs +1 -1
- package/lib/cli/project-scaffolder/constants.mjs +1 -0
- package/lib/cli/project-scaffolder/discovery.mjs +2 -0
- package/lib/cli/project-scaffolder/prompt-builders.mjs +9 -5
- package/lib/cli/utils/filesystem.mjs +2 -0
- package/lib/cli/utils/managed-surface.mjs +45 -2
- package/lib/cli/utils.mjs +19 -4
- package/package.json +1 -10
- package/scripts/bump-version.mjs +1 -16
- package/scripts/docs-quality-drift-report.mjs +0 -6
- package/scripts/frontend-usability-audit.mjs +2 -2
- package/scripts/governance-weekly-report.mjs +2 -2
- package/scripts/single-source-lazy-loading-audit.mjs +13 -126
- package/scripts/sync-thin-adapters.mjs +13 -121
- package/scripts/validate/config.mjs +20 -27
- package/scripts/validate/coverage-checks.mjs +9 -76
- package/scripts/validate.mjs +12 -97
- package/.agent-override.md +0 -36
- package/.agents/workflows/init-project.md +0 -12
- package/.agents/workflows/refactor.md +0 -12
- package/.agents/workflows/review-code.md +0 -11
- package/.cursor/mcp.json +0 -10
- package/.cursor/rules/agentic-senior-core.mdc +0 -49
- package/.cursorrules +0 -26
- package/.gemini/instructions.md +0 -44
- package/.github/copilot-instructions.md +0 -44
- package/.github/instructions/agentic-senior-core.instructions.md +0 -48
- package/.github/workflows/benchmark-detection.yml +0 -45
- package/.github/workflows/benchmark-intelligence.yml +0 -50
- package/.github/workflows/docs-quality-drift-report.yml +0 -37
- package/.github/workflows/frontend-usability-gate.yml +0 -36
- package/.github/workflows/governance-weekly-report.yml +0 -43
- package/.github/workflows/publish.yml +0 -32
- package/.github/workflows/release-gate.yml +0 -32
- package/.github/workflows/sbom-compliance.yml +0 -32
- package/.instructions.md +0 -186
- package/.windsurf/rules/agentic-senior-core.md +0 -44
- package/.windsurfrules +0 -26
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
|
|
12
12
|
import { existsSync, readFileSync } from 'node:fs';
|
|
13
13
|
import { execFileSync } from 'node:child_process';
|
|
14
|
-
import { createHash } from 'node:crypto';
|
|
15
14
|
import { dirname, resolve } from 'node:path';
|
|
16
15
|
import { fileURLToPath } from 'node:url';
|
|
17
16
|
|
|
@@ -19,28 +18,16 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
19
18
|
const __dirname = dirname(__filename);
|
|
20
19
|
const REPOSITORY_ROOT = resolve(__dirname, '..');
|
|
21
20
|
|
|
22
|
-
const CANONICAL_SOURCE_PATH = '.
|
|
21
|
+
const CANONICAL_SOURCE_PATH = 'AGENTS.md';
|
|
23
22
|
const ADAPTER_PATHS = [
|
|
24
|
-
'AGENTS.md',
|
|
25
23
|
'CLAUDE.md',
|
|
26
24
|
'GEMINI.md',
|
|
27
|
-
'.github/copilot-instructions.md',
|
|
28
|
-
'.github/instructions/agentic-senior-core.instructions.md',
|
|
29
|
-
'.gemini/instructions.md',
|
|
30
|
-
'.cursor/rules/agentic-senior-core.mdc',
|
|
31
|
-
'.windsurf/rules/agentic-senior-core.md',
|
|
32
25
|
];
|
|
33
26
|
const COMPILER_PATH = 'lib/cli/compiler.mjs';
|
|
34
27
|
const ONBOARDING_REPORT_PATH = '.agent-context/state/onboarding-report.json';
|
|
35
28
|
const ARCHITECTURE_RULE_PATH = '.agent-context/rules/architecture.md';
|
|
36
29
|
const PR_CHECKLIST_PATH = '.agent-context/review-checklists/pr-checklist.md';
|
|
37
30
|
const REVIEW_PROMPT_PATH = '.agent-context/prompts/review-code.md';
|
|
38
|
-
const COMPILED_RULE_PATHS = ['.cursorrules', '.windsurfrules'];
|
|
39
|
-
const REQUIRED_LEGACY_ROOT_ADAPTER_SNIPPETS = [
|
|
40
|
-
'Adapter Mode: legacy-thin',
|
|
41
|
-
'Adapter Source: .agent-instructions.md',
|
|
42
|
-
'Canonical baseline: .instructions.md',
|
|
43
|
-
];
|
|
44
31
|
|
|
45
32
|
const DEFAULT_WORKFLOW = 'standard';
|
|
46
33
|
const SUPPORTED_WORKFLOWS = new Set([
|
|
@@ -69,7 +56,7 @@ const MAX_EAGER_STACK_MENTIONS = 4;
|
|
|
69
56
|
|
|
70
57
|
const REQUIRED_ARCHITECTURE_RULE_SNIPPETS = [
|
|
71
58
|
'## Single Source of Truth and Lazy Rule Loading',
|
|
72
|
-
'Canonical rule source is .
|
|
59
|
+
'Canonical rule source is AGENTS.md.',
|
|
73
60
|
'Load global domain rules lazily based on touched scope.',
|
|
74
61
|
'Do not create or load stack-specific governance adapters as the baseline.',
|
|
75
62
|
];
|
|
@@ -273,11 +260,8 @@ function runAudit() {
|
|
|
273
260
|
pushResult(results, true, 'canonical-source-exists', `${CANONICAL_SOURCE_PATH} is present`);
|
|
274
261
|
}
|
|
275
262
|
|
|
276
|
-
const canonicalHash = canonicalSourceExists
|
|
277
|
-
|
|
278
|
-
: '';
|
|
279
|
-
|
|
280
|
-
let adapterHashPassCount = 0;
|
|
263
|
+
const canonicalHash = canonicalSourceExists ? 'native-import-bridges' : '';
|
|
264
|
+
let adapterImportPassCount = 0;
|
|
281
265
|
const adapterChecks = [];
|
|
282
266
|
|
|
283
267
|
for (const adapterPath of ADAPTER_PATHS) {
|
|
@@ -289,51 +273,27 @@ function runAudit() {
|
|
|
289
273
|
adapterChecks.push({
|
|
290
274
|
path: adapterPath,
|
|
291
275
|
exists: false,
|
|
292
|
-
|
|
293
|
-
sourcePointerValid: false,
|
|
294
|
-
hashMatchesCanonical: false,
|
|
276
|
+
importsCanonical: false,
|
|
295
277
|
});
|
|
296
278
|
continue;
|
|
297
279
|
}
|
|
298
280
|
|
|
299
281
|
pushResult(results, true, 'adapter-file-exists', `${adapterPath} is present`);
|
|
300
282
|
|
|
301
|
-
const
|
|
302
|
-
const sourcePointerValid = adapterContent.includes('Adapter Source: .instructions.md');
|
|
303
|
-
const hashMatch = adapterContent.match(/Canonical Snapshot SHA256:\s*([a-f0-9]{64})/);
|
|
304
|
-
const hashMatchesCanonical = Boolean(hashMatch && canonicalHash && hashMatch[1] === canonicalHash);
|
|
305
|
-
|
|
306
|
-
if (!thinAdapterMode) {
|
|
307
|
-
failures.push(`${adapterPath} must stay in thin adapter mode`);
|
|
308
|
-
pushResult(results, false, 'adapter-thin-mode', `${adapterPath} is missing Adapter Mode: thin metadata`);
|
|
309
|
-
} else {
|
|
310
|
-
pushResult(results, true, 'adapter-thin-mode', `${adapterPath} declares thin adapter mode`);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (!sourcePointerValid) {
|
|
314
|
-
failures.push(`${adapterPath} must point to canonical source .instructions.md`);
|
|
315
|
-
pushResult(results, false, 'adapter-canonical-source-pointer', `${adapterPath} is missing canonical source pointer`);
|
|
316
|
-
} else {
|
|
317
|
-
pushResult(results, true, 'adapter-canonical-source-pointer', `${adapterPath} points to canonical source`);
|
|
318
|
-
}
|
|
283
|
+
const importsCanonical = normalizeLineEndings(adapterContent).trim() === '@AGENTS.md';
|
|
319
284
|
|
|
320
|
-
if (!
|
|
321
|
-
failures.push(`${adapterPath} must
|
|
322
|
-
pushResult(results, false, 'adapter-canonical-
|
|
323
|
-
} else if (!hashMatchesCanonical) {
|
|
324
|
-
failures.push(`${adapterPath} canonical hash drift detected`);
|
|
325
|
-
pushResult(results, false, 'adapter-canonical-hash', `${adapterPath} hash does not match ${CANONICAL_SOURCE_PATH}`);
|
|
285
|
+
if (!importsCanonical) {
|
|
286
|
+
failures.push(`${adapterPath} must import canonical AGENTS.md`);
|
|
287
|
+
pushResult(results, false, 'adapter-canonical-import', `${adapterPath} is not @AGENTS.md`);
|
|
326
288
|
} else {
|
|
327
|
-
|
|
328
|
-
pushResult(results, true, 'adapter-canonical-
|
|
289
|
+
adapterImportPassCount += 1;
|
|
290
|
+
pushResult(results, true, 'adapter-canonical-import', `${adapterPath} imports AGENTS.md`);
|
|
329
291
|
}
|
|
330
292
|
|
|
331
293
|
adapterChecks.push({
|
|
332
294
|
path: adapterPath,
|
|
333
295
|
exists: true,
|
|
334
|
-
|
|
335
|
-
sourcePointerValid,
|
|
336
|
-
hashMatchesCanonical,
|
|
296
|
+
importsCanonical,
|
|
337
297
|
});
|
|
338
298
|
}
|
|
339
299
|
|
|
@@ -409,84 +369,11 @@ function runAudit() {
|
|
|
409
369
|
}
|
|
410
370
|
}
|
|
411
371
|
|
|
412
|
-
let compiledRulesCanonicalPassCount = 0;
|
|
413
372
|
let eagerLoadingDetected = false;
|
|
414
373
|
const compiledRuleChecks = [];
|
|
415
374
|
|
|
416
|
-
for (const compiledRulePath of COMPILED_RULE_PATHS) {
|
|
417
|
-
const compiledRuleContent = readText(compiledRulePath);
|
|
418
|
-
|
|
419
|
-
if (!compiledRuleContent) {
|
|
420
|
-
failures.push(`Missing compiled rules file: ${compiledRulePath}`);
|
|
421
|
-
pushResult(results, false, 'compiled-rules-file-exists', `Missing ${compiledRulePath}`);
|
|
422
|
-
compiledRuleChecks.push({
|
|
423
|
-
path: compiledRulePath,
|
|
424
|
-
exists: false,
|
|
425
|
-
canonicalBaselineDeclared: false,
|
|
426
|
-
stackMentionCount: 0,
|
|
427
|
-
eagerLoadingDetected: false,
|
|
428
|
-
});
|
|
429
|
-
continue;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
pushResult(results, true, 'compiled-rules-file-exists', `${compiledRulePath} is present`);
|
|
433
|
-
|
|
434
|
-
const canonicalBaselineDeclared = compiledRuleContent.includes('Canonical baseline: .instructions.md');
|
|
435
|
-
if (canonicalBaselineDeclared) {
|
|
436
|
-
compiledRulesCanonicalPassCount += 1;
|
|
437
|
-
pushResult(results, true, 'compiled-rules-canonical-baseline', `${compiledRulePath} declares canonical baseline`);
|
|
438
|
-
} else {
|
|
439
|
-
failures.push(`${compiledRulePath} must declare canonical baseline ${CANONICAL_SOURCE_PATH}`);
|
|
440
|
-
pushResult(results, false, 'compiled-rules-canonical-baseline', `${compiledRulePath} is missing canonical baseline declaration`);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
const stackMentionCount = countStackMentions(compiledRuleContent);
|
|
444
|
-
const isEagerLoading = stackMentionCount > MAX_EAGER_STACK_MENTIONS;
|
|
445
|
-
const missingLegacyAdapterSnippets = REQUIRED_LEGACY_ROOT_ADAPTER_SNIPPETS
|
|
446
|
-
.filter((requiredSnippet) => !compiledRuleContent.includes(requiredSnippet));
|
|
447
|
-
|
|
448
|
-
if (missingLegacyAdapterSnippets.length > 0) {
|
|
449
|
-
failures.push(`${compiledRulePath} must stay a legacy thin adapter`);
|
|
450
|
-
pushResult(
|
|
451
|
-
results,
|
|
452
|
-
false,
|
|
453
|
-
'legacy-root-adapter-thin-mode',
|
|
454
|
-
`${compiledRulePath} is missing: ${missingLegacyAdapterSnippets.join(', ')}`
|
|
455
|
-
);
|
|
456
|
-
} else {
|
|
457
|
-
pushResult(results, true, 'legacy-root-adapter-thin-mode', `${compiledRulePath} stays legacy-thin`);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
if (isEagerLoading) {
|
|
461
|
-
eagerLoadingDetected = true;
|
|
462
|
-
failures.push(`${compiledRulePath} appears to preload too many stack profiles (${stackMentionCount})`);
|
|
463
|
-
pushResult(
|
|
464
|
-
results,
|
|
465
|
-
false,
|
|
466
|
-
'compiled-rules-lazy-loading-density',
|
|
467
|
-
`${compiledRulePath} has ${stackMentionCount} stack profile mentions; expected <= ${MAX_EAGER_STACK_MENTIONS}`
|
|
468
|
-
);
|
|
469
|
-
} else {
|
|
470
|
-
pushResult(
|
|
471
|
-
results,
|
|
472
|
-
true,
|
|
473
|
-
'compiled-rules-lazy-loading-density',
|
|
474
|
-
`${compiledRulePath} has ${stackMentionCount} stack profile mentions (lazy-loading threshold satisfied)`
|
|
475
|
-
);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
compiledRuleChecks.push({
|
|
479
|
-
path: compiledRulePath,
|
|
480
|
-
exists: true,
|
|
481
|
-
canonicalBaselineDeclared,
|
|
482
|
-
stackMentionCount,
|
|
483
|
-
eagerLoadingDetected: isEagerLoading,
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
|
|
487
375
|
const canonicalSourceEnforced = canonicalSourceExists
|
|
488
|
-
&&
|
|
489
|
-
&& compiledRulesCanonicalPassCount === COMPILED_RULE_PATHS.length
|
|
376
|
+
&& adapterImportPassCount === ADAPTER_PATHS.length
|
|
490
377
|
&& architectureCoverageComplete
|
|
491
378
|
&& checklistCoverageComplete
|
|
492
379
|
&& reviewPromptCoverageComplete;
|
|
@@ -3,154 +3,47 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* sync-thin-adapters.mjs
|
|
5
5
|
*
|
|
6
|
-
* Regenerates
|
|
7
|
-
* and keeps canonical hash metadata synchronized.
|
|
6
|
+
* Regenerates minimal native-tool import bridges from canonical AGENTS.md.
|
|
8
7
|
*
|
|
9
8
|
* Usage:
|
|
10
9
|
* - node scripts/sync-thin-adapters.mjs
|
|
11
10
|
* - node scripts/sync-thin-adapters.mjs --check
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { dirname, join, posix, resolve } from 'node:path';
|
|
13
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
14
|
+
import { join, resolve, dirname } from 'node:path';
|
|
17
15
|
import { fileURLToPath } from 'node:url';
|
|
18
16
|
|
|
19
17
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
20
18
|
const ROOT_DIR = resolve(dirname(SCRIPT_FILE_PATH), '..');
|
|
21
|
-
const CANONICAL_SOURCE_PATH = '.instructions.md';
|
|
22
|
-
const CANONICAL_SOURCE_ABSOLUTE_PATH = join(ROOT_DIR, CANONICAL_SOURCE_PATH);
|
|
23
19
|
const IS_CHECK_MODE = process.argv.includes('--check');
|
|
24
20
|
|
|
25
|
-
function normalizeLineEndings(content) {
|
|
26
|
-
return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function buildAdapterLink(adapterRelativePath, targetRelativePath) {
|
|
30
|
-
const adapterDirectoryPath = posix.dirname(adapterRelativePath);
|
|
31
|
-
const relativePath = posix.relative(adapterDirectoryPath === '.' ? '' : adapterDirectoryPath, targetRelativePath);
|
|
32
|
-
return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function buildThinAdapter({
|
|
36
|
-
relativePath,
|
|
37
|
-
title,
|
|
38
|
-
canonicalHash,
|
|
39
|
-
frontmatter = '',
|
|
40
|
-
}) {
|
|
41
|
-
const canonicalLink = buildAdapterLink(relativePath, '.instructions.md');
|
|
42
|
-
const rulesLink = buildAdapterLink(relativePath, '.agent-context/rules');
|
|
43
|
-
const promptsLink = buildAdapterLink(relativePath, '.agent-context/prompts');
|
|
44
|
-
const designPromptLink = buildAdapterLink(relativePath, '.agent-context/prompts/bootstrap-design.md');
|
|
45
|
-
const frontendRuleLink = buildAdapterLink(relativePath, '.agent-context/rules/frontend-architecture.md');
|
|
46
|
-
const checklistLink = buildAdapterLink(relativePath, '.agent-context/review-checklists/pr-checklist.md');
|
|
47
|
-
const stateLink = buildAdapterLink(relativePath, '.agent-context/state');
|
|
48
|
-
const policiesLink = buildAdapterLink(relativePath, '.agent-context/policies');
|
|
49
|
-
const adapterHeader = frontmatter.trim() ? [frontmatter.trim(), ''] : [];
|
|
50
|
-
|
|
51
|
-
return [
|
|
52
|
-
...adapterHeader,
|
|
53
|
-
`# ${title}`,
|
|
54
|
-
'',
|
|
55
|
-
'Adapter Mode: thin',
|
|
56
|
-
'Adapter Source: .instructions.md',
|
|
57
|
-
`Canonical Snapshot SHA256: ${canonicalHash}`,
|
|
58
|
-
'',
|
|
59
|
-
'This repository is governed by a strict instruction contract.',
|
|
60
|
-
`Use [${CANONICAL_SOURCE_PATH}](${canonicalLink}) as the canonical policy source.`,
|
|
61
|
-
'Use .agent-context/ for technical rules, prompts, checklists, policies, and state.',
|
|
62
|
-
'Treat README.md as public and developer overview, setup, usage, and user-facing context only when governance files conflict.',
|
|
63
|
-
'',
|
|
64
|
-
'## Critical Bootstrap Floor',
|
|
65
|
-
'',
|
|
66
|
-
'- If your host stops at this file, continue the chain manually before coding.',
|
|
67
|
-
'- Read `.agent-instructions.md` next when it exists.',
|
|
68
|
-
'- Memory continuity does not replace bootstrap loading.',
|
|
69
|
-
`- For UI, UX, layout, screen, tailwind, frontend, or redesign requests, load [bootstrap-design.md](${designPromptLink}) and [frontend-architecture.md](${frontendRuleLink}) before code edits.`,
|
|
70
|
-
'- For UI scope, include a one-line Motion/Palette Decision in the Bootstrap Receipt; product categories are heuristics, not style presets.',
|
|
71
|
-
'- For UI scope, create or refine `docs/DESIGN.md` and `docs/design-intent.json` before UI implementation.',
|
|
72
|
-
'- For documentation-first requests, create or refine required project docs in English by default and do not write application, firmware, or UI code until the user asks or approves.',
|
|
73
|
-
'- Create or refine root README.md as the public and developer entrypoint before implementation.',
|
|
74
|
-
`- For backend, API, data, auth, error, event, queue, worker, or distributed-system requests, load only relevant global rules from .agent-context/rules/ ([link](${rulesLink})).`,
|
|
75
|
-
'- For ecosystem, framework, dependency, or Docker claims, perform live web research.',
|
|
76
|
-
'- Resolve runtime choices from project evidence and live official documentation; resolve structural planning from constraints and architecture boundaries.',
|
|
77
|
-
'',
|
|
78
|
-
'## Mandatory Bootstrap Chain',
|
|
79
|
-
'',
|
|
80
|
-
`1. Load [${CANONICAL_SOURCE_PATH}](${canonicalLink}).`,
|
|
81
|
-
'2. Load `.agent-instructions.md` when present.',
|
|
82
|
-
`3. Load only relevant files from .agent-context/rules/ ([link](${rulesLink})).`,
|
|
83
|
-
`4. Apply matching prompts from .agent-context/prompts/ ([link](${promptsLink})).`,
|
|
84
|
-
`5. Enforce .agent-context/review-checklists/ ([link](${checklistLink})).`,
|
|
85
|
-
`6. Use .agent-context/state/ ([link](${stateLink})) and .agent-context/policies/ ([link](${policiesLink})) only when relevant.`,
|
|
86
|
-
'7. Use project docs and live evidence for runtime, dependency, and architecture claims.',
|
|
87
|
-
'',
|
|
88
|
-
'## Bootstrap Receipt',
|
|
89
|
-
'',
|
|
90
|
-
'For non-trivial coding, review, planning, or governance work, produce a short Bootstrap Receipt before implementation output: `loaded_files`, `selected_rules`, `skipped_rules`, `unreachable_files`, and `validation_plan`.',
|
|
91
|
-
'',
|
|
92
|
-
'## Completion Gate',
|
|
93
|
-
'',
|
|
94
|
-
`Run [pr-checklist.md](${checklistLink}) before declaring work complete.`,
|
|
95
|
-
'',
|
|
96
|
-
`If this adapter drifts from canonical behavior, refresh from [${CANONICAL_SOURCE_PATH}](${canonicalLink}) and update the hash metadata.`,
|
|
97
|
-
].join('\n');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
21
|
const ADAPTERS = [
|
|
101
|
-
{
|
|
102
|
-
relativePath: 'AGENTS.md',
|
|
103
|
-
title: 'AGENTS.md - Thin Adapter',
|
|
104
|
-
},
|
|
105
22
|
{
|
|
106
23
|
relativePath: 'CLAUDE.md',
|
|
107
|
-
|
|
24
|
+
content: '@AGENTS.md\n',
|
|
108
25
|
},
|
|
109
26
|
{
|
|
110
27
|
relativePath: 'GEMINI.md',
|
|
111
|
-
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
relativePath: '.github/copilot-instructions.md',
|
|
115
|
-
title: 'GitHub Copilot Instructions - Thin Adapter',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
relativePath: '.github/instructions/agentic-senior-core.instructions.md',
|
|
119
|
-
title: 'GitHub Copilot Path Instructions - Thin Adapter',
|
|
120
|
-
frontmatter: '---\napplyTo: "**"\n---',
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
relativePath: '.gemini/instructions.md',
|
|
124
|
-
title: 'Gemini Instructions - Thin Adapter',
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
relativePath: '.cursor/rules/agentic-senior-core.mdc',
|
|
128
|
-
title: 'Cursor Rule - Thin Adapter',
|
|
129
|
-
frontmatter: '---\ndescription: Agentic Senior Core bootstrap adapter\nalwaysApply: true\n---',
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
relativePath: '.windsurf/rules/agentic-senior-core.md',
|
|
133
|
-
title: 'Windsurf Rule - Thin Adapter',
|
|
28
|
+
content: '@AGENTS.md\n',
|
|
134
29
|
},
|
|
135
30
|
];
|
|
136
31
|
|
|
32
|
+
function normalizeLineEndings(content) {
|
|
33
|
+
return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
34
|
+
}
|
|
35
|
+
|
|
137
36
|
async function main() {
|
|
138
|
-
|
|
139
|
-
const canonicalHash = createHash('sha256').update(canonicalContent).digest('hex');
|
|
37
|
+
await readFile(join(ROOT_DIR, 'AGENTS.md'), 'utf8');
|
|
140
38
|
|
|
141
39
|
let hasDrift = false;
|
|
142
40
|
|
|
143
41
|
for (const adapter of ADAPTERS) {
|
|
144
42
|
const adapterAbsolutePath = join(ROOT_DIR, adapter.relativePath);
|
|
145
|
-
const expectedContent = buildThinAdapter({
|
|
146
|
-
...adapter,
|
|
147
|
-
canonicalHash,
|
|
148
|
-
});
|
|
149
43
|
|
|
150
44
|
if (IS_CHECK_MODE) {
|
|
151
45
|
const existingContent = normalizeLineEndings(await readFile(adapterAbsolutePath, 'utf8'));
|
|
152
|
-
|
|
153
|
-
if (existingContent !== expectedNormalized) {
|
|
46
|
+
if (existingContent !== adapter.content) {
|
|
154
47
|
hasDrift = true;
|
|
155
48
|
console.error(`[DRIFT] ${adapter.relativePath} does not match canonical adapter output.`);
|
|
156
49
|
} else {
|
|
@@ -159,8 +52,7 @@ async function main() {
|
|
|
159
52
|
continue;
|
|
160
53
|
}
|
|
161
54
|
|
|
162
|
-
await
|
|
163
|
-
await writeFile(adapterAbsolutePath, `${expectedContent.trimEnd()}\n`, 'utf8');
|
|
55
|
+
await writeFile(adapterAbsolutePath, adapter.content, 'utf8');
|
|
164
56
|
console.log(`[SYNC] ${adapter.relativePath}`);
|
|
165
57
|
}
|
|
166
58
|
|
|
@@ -170,7 +62,7 @@ async function main() {
|
|
|
170
62
|
return;
|
|
171
63
|
}
|
|
172
64
|
|
|
173
|
-
console.log('[OK] All
|
|
65
|
+
console.log('[OK] All native import bridges match canonical source output.');
|
|
174
66
|
}
|
|
175
67
|
}
|
|
176
68
|
|
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
export const ALLOWED_SEVERITIES = new Set(['critical', 'high', 'medium', 'low']);
|
|
2
|
-
export const OVERRIDE_WARNING_WINDOW_DAYS = 30;
|
|
3
2
|
export const THIN_ADAPTER_PATHS = [
|
|
4
|
-
'AGENTS.md',
|
|
5
3
|
'CLAUDE.md',
|
|
6
4
|
'GEMINI.md',
|
|
7
|
-
'.github/copilot-instructions.md',
|
|
8
|
-
'.github/instructions/agentic-senior-core.instructions.md',
|
|
9
|
-
'.gemini/instructions.md',
|
|
10
|
-
'.cursor/rules/agentic-senior-core.mdc',
|
|
11
|
-
'.windsurf/rules/agentic-senior-core.md',
|
|
12
5
|
];
|
|
13
6
|
export const FORMAL_ARTIFACT_PATHS = [
|
|
14
|
-
'.
|
|
7
|
+
'AGENTS.md',
|
|
15
8
|
'README.md',
|
|
16
9
|
'CHANGELOG.md',
|
|
10
|
+
'docs/doc-index.md',
|
|
11
|
+
'docs/project-brief.md',
|
|
12
|
+
'docs/flow-overview.md',
|
|
13
|
+
'docs/api-contract.md',
|
|
17
14
|
'docs/deep-analysis-and-roadmap-backlog.md',
|
|
18
15
|
'.agent-context/rules/api-docs.md',
|
|
19
16
|
'.agent-context/review-checklists/pr-checklist.md',
|
|
20
17
|
'.agent-context/prompts/review-code.md',
|
|
21
|
-
'AGENTS.md',
|
|
22
18
|
'CLAUDE.md',
|
|
23
19
|
'GEMINI.md',
|
|
24
|
-
'.github/copilot-instructions.md',
|
|
25
|
-
'.github/instructions/agentic-senior-core.instructions.md',
|
|
26
|
-
'.gemini/instructions.md',
|
|
27
|
-
'.cursor/rules/agentic-senior-core.mdc',
|
|
28
|
-
'.windsurf/rules/agentic-senior-core.md',
|
|
29
20
|
];
|
|
30
21
|
export const REQUIRED_HUMAN_WRITING_SNIPPETS = [
|
|
31
22
|
{
|
|
@@ -102,7 +93,7 @@ export const REQUIRED_DEVELOPER_FIRST_MENTION_PATTERNS = [
|
|
|
102
93
|
{
|
|
103
94
|
path: 'lib/cli/commands/init.mjs',
|
|
104
95
|
label: 'Init command wording includes project guidance pack',
|
|
105
|
-
pattern: /copy the project guidance pack[^\n]*
|
|
96
|
+
pattern: /copy the project guidance pack[^\n]*AGENTS\.md and native import bridges/iu,
|
|
106
97
|
},
|
|
107
98
|
{
|
|
108
99
|
path: 'lib/cli/commands/upgrade.mjs',
|
|
@@ -157,7 +148,7 @@ export const REQUIRED_DETECTION_TRANSPARENCY_SNIPPETS = [
|
|
|
157
148
|
];
|
|
158
149
|
export const REQUIRED_STACK_DECISION_BOUNDARY_SNIPPETS = [
|
|
159
150
|
{
|
|
160
|
-
path: '.
|
|
151
|
+
path: 'AGENTS.md',
|
|
161
152
|
snippets: [
|
|
162
153
|
'Do not silently choose frameworks or architecture from offline heuristics.',
|
|
163
154
|
'produce a short recommendation from evidence and live official documentation before coding',
|
|
@@ -192,10 +183,11 @@ export const REQUIRED_STACK_DECISION_BOUNDARY_SNIPPETS = [
|
|
|
192
183
|
];
|
|
193
184
|
export const REQUIRED_UNIVERSAL_SOP_SNIPPETS = [
|
|
194
185
|
{
|
|
195
|
-
path: '.
|
|
186
|
+
path: 'AGENTS.md',
|
|
196
187
|
snippets: [
|
|
197
188
|
'### 1. Documentation-First Mode',
|
|
198
189
|
'root `README.md` for every fresh or existing project',
|
|
190
|
+
'docs/doc-index.md',
|
|
199
191
|
'Stop after documentation when the user only asked for docs.',
|
|
200
192
|
'Do not write application, firmware, or UI code',
|
|
201
193
|
],
|
|
@@ -205,6 +197,7 @@ export const REQUIRED_UNIVERSAL_SOP_SNIPPETS = [
|
|
|
205
197
|
snippets: [
|
|
206
198
|
'## Universal SOP Baseline (Mandatory)',
|
|
207
199
|
'Root `README.md` must exist for every fresh or existing project',
|
|
200
|
+
'`docs/doc-index.md` must exist whenever `docs/` exists',
|
|
208
201
|
'Security and testing are non-negotiable baseline requirements.',
|
|
209
202
|
'If required project context docs are missing, stop implementation and bootstrap docs before writing application code.',
|
|
210
203
|
],
|
|
@@ -214,6 +207,7 @@ export const REQUIRED_UNIVERSAL_SOP_SNIPPETS = [
|
|
|
214
207
|
snippets: [
|
|
215
208
|
'## Documentation-First Requests',
|
|
216
209
|
'root `README.md` for every fresh or existing project',
|
|
210
|
+
'`docs/doc-index.md` whenever `docs/` exists',
|
|
217
211
|
'Stop after docs when the user only asked for docs.',
|
|
218
212
|
'Write formal project docs in English by default',
|
|
219
213
|
],
|
|
@@ -230,19 +224,20 @@ export const REQUIRED_UNIVERSAL_SOP_SNIPPETS = [
|
|
|
230
224
|
{
|
|
231
225
|
path: '.agent-context/prompts/review-code.md',
|
|
232
226
|
snippets: [
|
|
233
|
-
'Enforce Universal SOP hard gate: block coding flow when required project docs are missing (root `README.md`; `docs/architecture-decision-record.md`; and for UI scope `docs/DESIGN.md` plus `docs/design-intent.json`).',
|
|
227
|
+
'Enforce Universal SOP hard gate: block coding flow when required project docs are missing (root `README.md`; `docs/doc-index.md` when `docs/` exists; `docs/architecture-decision-record.md`; and for UI scope `docs/DESIGN.md` plus `docs/design-intent.json`).',
|
|
234
228
|
],
|
|
235
229
|
},
|
|
236
230
|
{
|
|
237
231
|
path: '.agent-context/prompts/refactor.md',
|
|
238
232
|
snippets: [
|
|
239
|
-
'6. Enforce Universal SOP hard gate: stop implementation if root `README.md` is missing, if `docs/architecture-decision-record.md` is missing, or for UI scope if `docs/DESIGN.md` or `docs/design-intent.json` is missing.',
|
|
233
|
+
'6. Enforce Universal SOP hard gate: stop implementation if root `README.md` is missing, if `docs/doc-index.md` is missing while `docs/` exists, if `docs/architecture-decision-record.md` is missing, or for UI scope if `docs/DESIGN.md` or `docs/design-intent.json` is missing.',
|
|
240
234
|
],
|
|
241
235
|
},
|
|
242
236
|
{
|
|
243
237
|
path: 'lib/cli/compiler.mjs',
|
|
244
238
|
snippets: [
|
|
245
239
|
'Universal SOP hard block policy:',
|
|
240
|
+
'docs/doc-index.md whenever docs/ exists',
|
|
246
241
|
'README.md must exist and read as a public and developer entrypoint',
|
|
247
242
|
'Hard block: do not write application code until docs/project-brief.md and docs/architecture-decision-record.md exist.',
|
|
248
243
|
'Documentation-first policy:',
|
|
@@ -294,14 +289,12 @@ export const REQUIRED_UI_DESIGN_AUTOMATION_SNIPPETS = [
|
|
|
294
289
|
{
|
|
295
290
|
path: 'AGENTS.md',
|
|
296
291
|
snippets: [
|
|
297
|
-
'
|
|
298
|
-
'If your host stops at this file',
|
|
292
|
+
'UI Design Mode',
|
|
299
293
|
'bootstrap-design.md',
|
|
300
294
|
'frontend-architecture.md',
|
|
301
295
|
'docs/DESIGN.md',
|
|
302
296
|
'docs/design-intent.json',
|
|
303
|
-
'
|
|
304
|
-
'documentation-first requests',
|
|
297
|
+
'Documentation-First Mode',
|
|
305
298
|
'English by default',
|
|
306
299
|
'do not write application, firmware, or UI code',
|
|
307
300
|
'Motion/Palette Decision',
|
|
@@ -310,7 +303,7 @@ export const REQUIRED_UI_DESIGN_AUTOMATION_SNIPPETS = [
|
|
|
310
303
|
],
|
|
311
304
|
},
|
|
312
305
|
{
|
|
313
|
-
path: '.
|
|
306
|
+
path: 'AGENTS.md',
|
|
314
307
|
snippets: [
|
|
315
308
|
'Resolve the smallest relevant layer set for the current request.',
|
|
316
309
|
'UI Design Mode',
|
|
@@ -517,7 +510,7 @@ export const REQUIRED_UI_DESIGN_AUTOMATION_SNIPPETS = [
|
|
|
517
510
|
];
|
|
518
511
|
export const REQUIRED_DOCKER_RUNTIME_AUTOMATION_SNIPPETS = [
|
|
519
512
|
{
|
|
520
|
-
path: '.
|
|
513
|
+
path: 'AGENTS.md',
|
|
521
514
|
snippets: [
|
|
522
515
|
'docker-runtime.md',
|
|
523
516
|
'For Docker or Compose work, load `docker-runtime.md` and verify the latest official Docker docs before authoring container assets.',
|
|
@@ -545,7 +538,7 @@ export const REQUIRED_DOCKER_RUNTIME_AUTOMATION_SNIPPETS = [
|
|
|
545
538
|
];
|
|
546
539
|
export const REQUIRED_DEPENDENCY_FRESHNESS_AUTOMATION_SNIPPETS = [
|
|
547
540
|
{
|
|
548
|
-
path: '.
|
|
541
|
+
path: 'AGENTS.md',
|
|
549
542
|
snippets: [
|
|
550
543
|
'use the latest stable compatible dependency set and official setup flow',
|
|
551
544
|
],
|
|
@@ -579,7 +572,7 @@ export const FORBIDDEN_TEMPLATE_BOOTSTRAP_SNIPPETS = [
|
|
|
579
572
|
];
|
|
580
573
|
export const FORBIDDEN_ACTIVE_BIAS_ANCHOR_SNIPPETS = [
|
|
581
574
|
{
|
|
582
|
-
path: '.
|
|
575
|
+
path: 'AGENTS.md',
|
|
583
576
|
snippets: [
|
|
584
577
|
'illustrative, not exhaustive',
|
|
585
578
|
'explicitly approved reference systems',
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
import { join, relative } from 'node:path';
|
|
3
2
|
import {
|
|
4
3
|
COMPLIANCE_ALIAS_TERMS,
|
|
@@ -383,7 +382,6 @@ export async function validateInstructionAdapters(context) {
|
|
|
383
382
|
console.log('\nChecking instruction adapter consolidation...');
|
|
384
383
|
|
|
385
384
|
const canonicalInstructionContent = normalizeLineEndings(await readTextFile(CANONICAL_INSTRUCTION_PATH));
|
|
386
|
-
const canonicalSnapshotHash = createHash('sha256').update(canonicalInstructionContent).digest('hex');
|
|
387
385
|
const requiredBootstrapReceiptSnippets = [
|
|
388
386
|
'Bootstrap Receipt',
|
|
389
387
|
'loaded_files',
|
|
@@ -397,25 +395,24 @@ export async function validateInstructionAdapters(context) {
|
|
|
397
395
|
'product categories are heuristics',
|
|
398
396
|
];
|
|
399
397
|
const instructionFootprintLimits = [
|
|
400
|
-
{ path: '.
|
|
398
|
+
{ path: 'AGENTS.md', maxLines: 180 },
|
|
401
399
|
{ path: '.agent-context/prompts/bootstrap-design.md', maxLines: 180 },
|
|
402
400
|
{ path: '.agent-context/rules/frontend-architecture.md', maxLines: 110 },
|
|
403
401
|
];
|
|
404
|
-
const legacyRootAdapterPaths = ['.cursorrules', '.windsurfrules'];
|
|
405
402
|
|
|
406
403
|
for (const requiredBootstrapReceiptSnippet of requiredBootstrapReceiptSnippets) {
|
|
407
404
|
if (canonicalInstructionContent.includes(requiredBootstrapReceiptSnippet)) {
|
|
408
|
-
pass(
|
|
405
|
+
pass(`AGENTS.md includes bootstrap receipt snippet: ${requiredBootstrapReceiptSnippet}`);
|
|
409
406
|
} else {
|
|
410
|
-
fail(
|
|
407
|
+
fail(`AGENTS.md is missing bootstrap receipt snippet: ${requiredBootstrapReceiptSnippet}`);
|
|
411
408
|
}
|
|
412
409
|
}
|
|
413
410
|
|
|
414
411
|
for (const requiredUiReadabilitySnippet of requiredUiReadabilitySnippets) {
|
|
415
412
|
if (canonicalInstructionContent.includes(requiredUiReadabilitySnippet)) {
|
|
416
|
-
pass(
|
|
413
|
+
pass(`AGENTS.md includes UI readability snippet: ${requiredUiReadabilitySnippet}`);
|
|
417
414
|
} else {
|
|
418
|
-
fail(
|
|
415
|
+
fail(`AGENTS.md is missing UI readability snippet: ${requiredUiReadabilitySnippet}`);
|
|
419
416
|
}
|
|
420
417
|
}
|
|
421
418
|
|
|
@@ -445,83 +442,19 @@ export async function validateInstructionAdapters(context) {
|
|
|
445
442
|
|
|
446
443
|
const thinAdapterContent = await readTextFile(absoluteAdapterPath);
|
|
447
444
|
|
|
448
|
-
if (
|
|
449
|
-
|
|
450
|
-
&& thinAdapterContent.includes('Adapter Source: .instructions.md')
|
|
451
|
-
) {
|
|
452
|
-
pass(`${thinAdapterPath} declares thin adapter metadata`);
|
|
445
|
+
if (thinAdapterContent.trim() === '@AGENTS.md') {
|
|
446
|
+
pass(`${thinAdapterPath} imports AGENTS.md`);
|
|
453
447
|
} else {
|
|
454
|
-
fail(`${thinAdapterPath} must
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
for (const requiredBootstrapReceiptSnippet of requiredBootstrapReceiptSnippets) {
|
|
458
|
-
if (thinAdapterContent.includes(requiredBootstrapReceiptSnippet)) {
|
|
459
|
-
pass(`${thinAdapterPath} includes bootstrap receipt snippet: ${requiredBootstrapReceiptSnippet}`);
|
|
460
|
-
} else {
|
|
461
|
-
fail(`${thinAdapterPath} is missing bootstrap receipt snippet: ${requiredBootstrapReceiptSnippet}`);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
for (const requiredUiReadabilitySnippet of requiredUiReadabilitySnippets) {
|
|
466
|
-
if (thinAdapterContent.includes(requiredUiReadabilitySnippet)) {
|
|
467
|
-
pass(`${thinAdapterPath} includes UI readability snippet: ${requiredUiReadabilitySnippet}`);
|
|
468
|
-
} else {
|
|
469
|
-
fail(`${thinAdapterPath} is missing UI readability snippet: ${requiredUiReadabilitySnippet}`);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const hashMatch = thinAdapterContent.match(/Canonical Snapshot SHA256:\s*([a-f0-9]{64})/);
|
|
474
|
-
if (!hashMatch) {
|
|
475
|
-
fail(`${thinAdapterPath} must declare Canonical Snapshot SHA256`);
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
if (hashMatch[1] === canonicalSnapshotHash) {
|
|
480
|
-
pass(`${thinAdapterPath} canonical hash matches .instructions.md`);
|
|
481
|
-
} else {
|
|
482
|
-
fail(`${thinAdapterPath} canonical hash drift detected (expected ${canonicalSnapshotHash})`);
|
|
448
|
+
fail(`${thinAdapterPath} must be exactly @AGENTS.md`);
|
|
483
449
|
}
|
|
484
450
|
|
|
485
451
|
const thinAdapterLineCount = thinAdapterContent.split(/\r?\n/u).length;
|
|
486
|
-
if (thinAdapterLineCount <=
|
|
452
|
+
if (thinAdapterLineCount <= 2) {
|
|
487
453
|
pass(`${thinAdapterPath} remains thin (${thinAdapterLineCount} lines)`);
|
|
488
454
|
} else {
|
|
489
455
|
fail(`${thinAdapterPath} is too large for thin-adapter mode (${thinAdapterLineCount} lines)`);
|
|
490
456
|
}
|
|
491
457
|
}
|
|
492
|
-
|
|
493
|
-
for (const legacyRootAdapterPath of legacyRootAdapterPaths) {
|
|
494
|
-
const absoluteLegacyRootAdapterPath = join(ROOT_DIR, legacyRootAdapterPath);
|
|
495
|
-
if (!(await fileExists(absoluteLegacyRootAdapterPath))) {
|
|
496
|
-
fail(`Missing legacy root adapter file: ${legacyRootAdapterPath}`);
|
|
497
|
-
continue;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
const legacyRootAdapterContent = await readTextFile(absoluteLegacyRootAdapterPath);
|
|
501
|
-
const requiredLegacyRootAdapterSnippets = [
|
|
502
|
-
'Generated by Agentic-Senior-Core CLI v',
|
|
503
|
-
'Adapter Mode: legacy-thin',
|
|
504
|
-
'Adapter Source: .agent-instructions.md',
|
|
505
|
-
'Canonical baseline: .instructions.md',
|
|
506
|
-
'.agent-instructions.md',
|
|
507
|
-
'.agent-context/rules/',
|
|
508
|
-
];
|
|
509
|
-
|
|
510
|
-
for (const requiredLegacyRootAdapterSnippet of requiredLegacyRootAdapterSnippets) {
|
|
511
|
-
if (legacyRootAdapterContent.includes(requiredLegacyRootAdapterSnippet)) {
|
|
512
|
-
pass(`${legacyRootAdapterPath} includes legacy-thin snippet: ${requiredLegacyRootAdapterSnippet}`);
|
|
513
|
-
} else {
|
|
514
|
-
fail(`${legacyRootAdapterPath} is missing legacy-thin snippet: ${requiredLegacyRootAdapterSnippet}`);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
const legacyRootAdapterLineCount = legacyRootAdapterContent.split(/\r?\n/u).length;
|
|
519
|
-
if (legacyRootAdapterLineCount <= 40) {
|
|
520
|
-
pass(`${legacyRootAdapterPath} remains thin (${legacyRootAdapterLineCount} lines)`);
|
|
521
|
-
} else {
|
|
522
|
-
fail(`${legacyRootAdapterPath} is too large for legacy-thin mode (${legacyRootAdapterLineCount} lines)`);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
458
|
}
|
|
526
459
|
|
|
527
460
|
export async function validateSkillPurgeSurface(context) {
|