@ryuenn3123/agentic-senior-core 4.3.15 → 5.1.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.
Files changed (198) hide show
  1. package/.agents/plugins/marketplace.json +21 -0
  2. package/.agents/rules/agentic-senior-core.md +126 -0
  3. package/.claude-plugin/marketplace.json +17 -0
  4. package/.claude-plugin/plugin.json +17 -0
  5. package/.clinerules/agentic-senior-core.md +94 -0
  6. package/.codex-plugin/plugin.json +24 -0
  7. package/.cursor/rules/agentic-senior-core.mdc +99 -0
  8. package/.devin-plugin/plugin.json +13 -0
  9. package/.github/copilot-instructions.md +94 -0
  10. package/.github/plugin/marketplace.json +20 -0
  11. package/.github/plugin/plugin.json +16 -0
  12. package/.kiro/steering/agentic-senior-core.md +94 -0
  13. package/.openclaw/skills/asc/SKILL.md +23 -0
  14. package/.openclaw/skills/asc-audit/SKILL.md +28 -0
  15. package/.openclaw/skills/asc-review/SKILL.md +54 -0
  16. package/.opencode/plugins/agentic-senior-core.mjs +31 -0
  17. package/.windsurf/rules/agentic-senior-core.md +94 -0
  18. package/AGENTS.md +126 -179
  19. package/CONTRIBUTING.md +93 -63
  20. package/README.md +160 -111
  21. package/__init__.py +61 -0
  22. package/bin/agentic-senior-core.js +41 -43
  23. package/commands/asc-audit.md +1 -0
  24. package/commands/asc-audit.toml +2 -0
  25. package/commands/asc-help.md +9 -0
  26. package/commands/asc-help.toml +2 -0
  27. package/commands/asc-refactor.md +1 -0
  28. package/commands/asc-refactor.toml +2 -0
  29. package/commands/asc-review.md +1 -0
  30. package/commands/asc-review.toml +2 -0
  31. package/gemini-extension.json +10 -0
  32. package/hooks/copilot-hooks.json +21 -0
  33. package/hooks/hooks.json +31 -0
  34. package/hooks/session-start.js +36 -0
  35. package/hooks/subagent-start.js +38 -0
  36. package/lib/cli/commands/adapter.mjs +109 -0
  37. package/lib/cli/commands/clean.mjs +63 -0
  38. package/lib/cli/commands/status.mjs +94 -0
  39. package/package.json +43 -67
  40. package/plugin.yaml +16 -0
  41. package/scripts/uninstall.js +38 -0
  42. package/skills/asc/SKILL.md +16 -0
  43. package/skills/asc-audit/SKILL.md +28 -0
  44. package/skills/asc-refactor/SKILL.md +35 -0
  45. package/skills/asc-review/SKILL.md +54 -0
  46. package/.agent-context/policies/llm-judge-threshold.json +0 -29
  47. package/.agent-context/prompts/bootstrap-design.md +0 -63
  48. package/.agent-context/prompts/compact-natural-mode.md +0 -100
  49. package/.agent-context/prompts/init-project.md +0 -60
  50. package/.agent-context/prompts/refactor.md +0 -38
  51. package/.agent-context/prompts/review-code.md +0 -31
  52. package/.agent-context/review-checklists/architecture-review.md +0 -57
  53. package/.agent-context/review-checklists/pr-checklist.md +0 -136
  54. package/.agent-context/rules/api-docs.md +0 -24
  55. package/.agent-context/rules/api-versioning.md +0 -16
  56. package/.agent-context/rules/architecture.md +0 -33
  57. package/.agent-context/rules/background-jobs.md +0 -17
  58. package/.agent-context/rules/config-and-flags.md +0 -16
  59. package/.agent-context/rules/database-design.md +0 -18
  60. package/.agent-context/rules/docker-runtime.md +0 -17
  61. package/.agent-context/rules/error-handling.md +0 -16
  62. package/.agent-context/rules/event-driven.md +0 -16
  63. package/.agent-context/rules/frontend-architecture.md +0 -54
  64. package/.agent-context/rules/microservices.md +0 -16
  65. package/.agent-context/rules/migrations.md +0 -16
  66. package/.agent-context/rules/observability.md +0 -16
  67. package/.agent-context/rules/performance.md +0 -16
  68. package/.agent-context/rules/realtime.md +0 -16
  69. package/.agent-context/rules/resilience.md +0 -18
  70. package/.agent-context/rules/security.md +0 -18
  71. package/.agent-context/rules/testing.md +0 -16
  72. package/.agent-context/state/README.md +0 -25
  73. package/.agent-context/state/architecture-map.md +0 -40
  74. package/.agent-context/state/benchmark-comparison-schema.json +0 -181
  75. package/.agent-context/state/benchmark-reproducibility.json +0 -87
  76. package/.agent-context/state/benchmark-thresholds.json +0 -10
  77. package/.agent-context/state/benchmark-writer-judge-config.json +0 -58
  78. package/.agent-context/state/dependency-map.md +0 -41
  79. package/.agent-context/state/memory-adapter-contract.json +0 -52
  80. package/.agent-context/state/memory-schema-v1.json +0 -88
  81. package/GEMINI.md +0 -1
  82. package/benchmarks/README.md +0 -60
  83. package/benchmarks/compact-natural-mode/fixtures.mjs +0 -359
  84. package/benchmarks/compact-natural-mode/scorer.mjs +0 -331
  85. package/benchmarks/runtime-token-saver/fixtures.mjs +0 -836
  86. package/lib/cli/adaptive-context/catalog.mjs +0 -390
  87. package/lib/cli/adaptive-context/file-signals.mjs +0 -100
  88. package/lib/cli/adaptive-context/implications.mjs +0 -44
  89. package/lib/cli/adaptive-context.mjs +0 -365
  90. package/lib/cli/audits/typography-palette-anti-repeat/color-utils.mjs +0 -156
  91. package/lib/cli/audits/typography-palette-anti-repeat/file-scanner.mjs +0 -103
  92. package/lib/cli/audits/typography-palette-anti-repeat/typography-utils.mjs +0 -70
  93. package/lib/cli/audits/typography-palette-anti-repeat-audit.mjs +0 -239
  94. package/lib/cli/backup.mjs +0 -210
  95. package/lib/cli/commands/audit-design-anti-repeat.mjs +0 -39
  96. package/lib/cli/commands/context.mjs +0 -140
  97. package/lib/cli/commands/init/project-context.mjs +0 -60
  98. package/lib/cli/commands/init/runtime-environment.mjs +0 -59
  99. package/lib/cli/commands/init/setup-decisions.mjs +0 -83
  100. package/lib/cli/commands/init.mjs +0 -654
  101. package/lib/cli/commands/launch.mjs +0 -76
  102. package/lib/cli/commands/optimize.mjs +0 -284
  103. package/lib/cli/commands/rollback.mjs +0 -64
  104. package/lib/cli/commands/upgrade/token-optimization-state.mjs +0 -51
  105. package/lib/cli/commands/upgrade.mjs +0 -451
  106. package/lib/cli/compiler.mjs +0 -570
  107. package/lib/cli/constants.mjs +0 -136
  108. package/lib/cli/detector/constants.mjs +0 -135
  109. package/lib/cli/detector/design-evidence/collector.mjs +0 -256
  110. package/lib/cli/detector/design-evidence/constants.mjs +0 -39
  111. package/lib/cli/detector/design-evidence/file-traversal.mjs +0 -83
  112. package/lib/cli/detector/design-evidence/structured-attribute-evidence.mjs +0 -117
  113. package/lib/cli/detector/design-evidence/summary.mjs +0 -109
  114. package/lib/cli/detector/design-evidence/utility-helpers.mjs +0 -122
  115. package/lib/cli/detector/design-evidence.mjs +0 -25
  116. package/lib/cli/detector/stack-detection.mjs +0 -243
  117. package/lib/cli/detector/ui-signals.mjs +0 -150
  118. package/lib/cli/detector/workspace-scan.mjs +0 -177
  119. package/lib/cli/detector.mjs +0 -23
  120. package/lib/cli/init-detection-flow.mjs +0 -48
  121. package/lib/cli/init-options.mjs +0 -237
  122. package/lib/cli/init-selection.mjs +0 -29
  123. package/lib/cli/memory-continuity.mjs +0 -537
  124. package/lib/cli/preflight.mjs +0 -76
  125. package/lib/cli/project-scaffolder/constants.mjs +0 -69
  126. package/lib/cli/project-scaffolder/discovery.mjs +0 -272
  127. package/lib/cli/project-scaffolder/prompt-builders.mjs +0 -171
  128. package/lib/cli/project-scaffolder/storage.mjs +0 -144
  129. package/lib/cli/project-scaffolder/ui-scope-detection.mjs +0 -36
  130. package/lib/cli/project-scaffolder.mjs +0 -29
  131. package/lib/cli/rollback.mjs +0 -66
  132. package/lib/cli/token-optimization.mjs +0 -486
  133. package/lib/cli/utils/filesystem.mjs +0 -81
  134. package/lib/cli/utils/managed-surface.mjs +0 -280
  135. package/lib/cli/utils/prompting.mjs +0 -44
  136. package/lib/cli/utils.mjs +0 -479
  137. package/mcp.json +0 -134
  138. package/scripts/adaptive-context/fixtures.mjs +0 -183
  139. package/scripts/adaptive-context-benchmark.mjs +0 -9
  140. package/scripts/ascx-runtime-token-saver-benchmark.mjs +0 -9
  141. package/scripts/audit-cache-layer-contract.mjs +0 -263
  142. package/scripts/audit-caching-scope-hygiene.mjs +0 -268
  143. package/scripts/audit-file-size.mjs +0 -219
  144. package/scripts/audit-reflection-citations.mjs +0 -163
  145. package/scripts/audit-release-bundle.mjs +0 -170
  146. package/scripts/audit-rule-id-uniqueness.mjs +0 -313
  147. package/scripts/audit-typography-palette-anti-repeat.mjs +0 -120
  148. package/scripts/benchmark-evidence-bundle.mjs +0 -645
  149. package/scripts/benchmark-gate.mjs +0 -121
  150. package/scripts/benchmark-intelligence.mjs +0 -33
  151. package/scripts/benchmark-writer-judge-matrix.mjs +0 -379
  152. package/scripts/build-release-benchmark-bundle.mjs +0 -202
  153. package/scripts/bump-version.mjs +0 -103
  154. package/scripts/clean-local-artifacts.mjs +0 -78
  155. package/scripts/compact-natural-mode-benchmark.mjs +0 -9
  156. package/scripts/context-triggered-audit.mjs +0 -391
  157. package/scripts/detection-benchmark.mjs +0 -127
  158. package/scripts/docs-quality-drift-report.mjs +0 -358
  159. package/scripts/documentation-boundary-audit.mjs +0 -305
  160. package/scripts/explain-on-demand-audit.mjs +0 -427
  161. package/scripts/forbidden-content-check.mjs +0 -123
  162. package/scripts/frontend-usability-audit.mjs +0 -243
  163. package/scripts/generate-sbom.mjs +0 -61
  164. package/scripts/governance-weekly-report.mjs +0 -466
  165. package/scripts/llm-judge/checklist-loader.mjs +0 -45
  166. package/scripts/llm-judge/constants.mjs +0 -66
  167. package/scripts/llm-judge/diff-collection.mjs +0 -74
  168. package/scripts/llm-judge/prompting.mjs +0 -78
  169. package/scripts/llm-judge/providers.mjs +0 -111
  170. package/scripts/llm-judge/verdict.mjs +0 -134
  171. package/scripts/llm-judge.mjs +0 -200
  172. package/scripts/memory-continuity-benchmark.mjs +0 -322
  173. package/scripts/quality-trend-report.mjs +0 -289
  174. package/scripts/release-gate/audit-checks.mjs +0 -441
  175. package/scripts/release-gate/constants.mjs +0 -53
  176. package/scripts/release-gate/runtime.mjs +0 -63
  177. package/scripts/release-gate/static-checks.mjs +0 -182
  178. package/scripts/release-gate.mjs +0 -42
  179. package/scripts/rules-guardian-audit.mjs +0 -580
  180. package/scripts/single-source-lazy-loading-audit.mjs +0 -449
  181. package/scripts/sync-thin-adapters.mjs +0 -72
  182. package/scripts/token-optimization-benchmark.mjs +0 -252
  183. package/scripts/ui-design-judge/constants.mjs +0 -13
  184. package/scripts/ui-design-judge/design-execution-summary.mjs +0 -81
  185. package/scripts/ui-design-judge/git-input.mjs +0 -134
  186. package/scripts/ui-design-judge/prompting.mjs +0 -52
  187. package/scripts/ui-design-judge/providers.mjs +0 -102
  188. package/scripts/ui-design-judge/reporting.mjs +0 -183
  189. package/scripts/ui-design-judge/rubric-calibration.mjs +0 -214
  190. package/scripts/ui-design-judge/rubric-goldset.json +0 -188
  191. package/scripts/ui-design-judge.mjs +0 -319
  192. package/scripts/ui-rubric-calibration.mjs +0 -35
  193. package/scripts/validate/config.mjs +0 -519
  194. package/scripts/validate/coverage-checks.mjs +0 -446
  195. package/scripts/validate/file-structure.mjs +0 -162
  196. package/scripts/validate/markdown-content.mjs +0 -109
  197. package/scripts/validate/project-metadata.mjs +0 -166
  198. package/scripts/validate.mjs +0 -338
@@ -1,268 +0,0 @@
1
- #!/usr/bin/env node
2
- // @ts-check
3
-
4
- /**
5
- * audit-caching-scope-hygiene.mjs
6
- *
7
- * Phase 5 drift catcher. Scans user-facing surfaces (README, AGENTS.md, FAQ,
8
- * integration playbook, CHANGELOG) for caching numerical claims and verifies
9
- * that each claim is integration-scoped per `docs/architecture/decisions-foundation.md`
10
- * D4 "Per-Tool Caching Scope Matrix".
11
- *
12
- * Boundary: this audit covers PUBLIC-PROSE hygiene only (preventing
13
- * universal "X% caching saving" claims that mix integration modes). For the
14
- * technical provider/fixture/result-JSON contract see
15
- * audit-cache-layer-contract.mjs.
16
- *
17
- * The rule: never publish a single universal "X% caching saving" figure that
18
- * mixes integration modes. Every numerical caching saving claim on a public
19
- * surface must either:
20
- * 1. be in a clearly-scoped paragraph that names the integration mode
21
- * (direct API, Claude Code SDK programmatic, Cursor, Windsurf, Codex CLI,
22
- * Kiro, IDE wrapper) within +/- 600 characters of the figure, OR
23
- * 2. live in a documented exempt context (Phase 1 aggregate-cap CHANGELOG
24
- * rationale, archived plan files under docs/archive/, benchmark JSON
25
- * under benchmarks/results/, the canonical D4 matrix itself).
26
- */
27
-
28
- import { existsSync, readFileSync } from 'node:fs';
29
- import { dirname, join, resolve } from 'node:path';
30
- import { fileURLToPath } from 'node:url';
31
-
32
- const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
33
- const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '..');
34
- const ARGS = new Set(process.argv.slice(2));
35
- const JSON_ONLY = ARGS.has('--json');
36
-
37
- const PUBLIC_SURFACES = [
38
- 'README.md',
39
- 'AGENTS.md',
40
- 'docs/faq.md',
41
- 'docs/integration-playbook.md',
42
- 'docs/doc-index.md',
43
- 'CHANGELOG.md',
44
- ];
45
-
46
- // Numerical caching saving claims this audit scans for. Pattern is intentionally
47
- // strict: a digit-prefixed percent paired with an action verb or saving noun,
48
- // or a bare 89.31%-style figure within a cache-keyword window.
49
- const SAVING_CLAIM_PATTERNS = [
50
- // "X% reduction|saving|off|cheaper"
51
- /\b(\d{1,3}(?:\.\d+)?)\s*%\s*(?:effective[- ]token\s+)?(?:reduction|saving|savings|off|cheaper)\b/gi,
52
- // "saves|cuts|reduces|delivers up to X%" (cache context check applied below)
53
- /\b(?:save[sd]?|cut[s]?|reduce[sd]?|deliver[sd]?)\s+(?:up\s+to\s+)?(\d{1,3}(?:\.\d+)?)\s*%/gi,
54
- // "up to X% ... cache"
55
- /\b(?:up to|approximately|about|~)\s*(\d{1,3}(?:\.\d+)?)\s*%[^.\n]{0,80}(?:cach|warm|prompt[- ]cach)/gi,
56
- // "cache ... X% reduction|saving"
57
- /\bcach[a-z]*[^.\n]{0,80}\b(\d{1,3}(?:\.\d+)?)\s*%\s*(?:reduction|saving|savings|off)/gi,
58
- // bare two-decimal figures like 89.31% (cache context check applied below)
59
- /\b(\d{2,3}\.\d{2})\s*%/g,
60
- ];
61
-
62
- // Patterns at these indices apply a cache-context window check before counting.
63
- const CONTEXT_GATED_PATTERN_INDEXES = new Set([1, 4]);
64
-
65
- const INTEGRATION_MODE_KEYWORDS = [
66
- 'direct provider api',
67
- 'direct api',
68
- 'direct anthropic',
69
- 'direct openai',
70
- 'direct gemini',
71
- 'claude code sdk',
72
- 'claude code cli',
73
- 'cursor',
74
- 'windsurf',
75
- 'codex cli',
76
- 'codex / openai',
77
- 'kiro',
78
- 'ide wrapper',
79
- 'ide wrappers',
80
- 'integration mode',
81
- 'integration_mode',
82
- 'per-tool caching',
83
- 'per-integration',
84
- 'per integration',
85
- 'cache_control',
86
- ];
87
-
88
- const CACHE_CONTEXT_KEYWORDS = [
89
- 'cach',
90
- 'warm',
91
- 'prompt-cach',
92
- 'prompt cach',
93
- 'cache_control',
94
- ];
95
-
96
- const CONTEXT_WINDOW_RADIUS = 600;
97
-
98
- function readSurface(rootDir, relativePath, sourceOverrides) {
99
- if (sourceOverrides && Object.prototype.hasOwnProperty.call(sourceOverrides, relativePath)) {
100
- return String(sourceOverrides[relativePath]);
101
- }
102
- const absolutePath = join(rootDir, relativePath);
103
- if (!existsSync(absolutePath)) {
104
- return null;
105
- }
106
- return readFileSync(absolutePath, 'utf8');
107
- }
108
-
109
- function findCachingClaimMatches(sourceText) {
110
- /** @type {{index: number, matchedText: string, percent: string}[]} */
111
- const matches = [];
112
- for (let patternIndex = 0; patternIndex < SAVING_CLAIM_PATTERNS.length; patternIndex += 1) {
113
- const pattern = SAVING_CLAIM_PATTERNS[patternIndex];
114
- pattern.lastIndex = 0;
115
- let result;
116
- // eslint-disable-next-line no-cond-assign
117
- while ((result = pattern.exec(sourceText)) !== null) {
118
- const matchedText = result[0];
119
- const percent = result[1] || '';
120
- const index = result.index;
121
-
122
- // For context-gated patterns, confirm there is a cache keyword within
123
- // the context window before counting this as a caching claim.
124
- if (CONTEXT_GATED_PATTERN_INDEXES.has(patternIndex)) {
125
- const start = Math.max(0, index - CONTEXT_WINDOW_RADIUS);
126
- const end = Math.min(sourceText.length, index + matchedText.length + CONTEXT_WINDOW_RADIUS);
127
- const window = sourceText.slice(start, end).toLowerCase();
128
- const hasCacheContext = CACHE_CONTEXT_KEYWORDS.some((keyword) => window.includes(keyword));
129
- if (!hasCacheContext) {
130
- continue;
131
- }
132
- }
133
-
134
- matches.push({ index, matchedText, percent });
135
- }
136
- }
137
-
138
- // Deduplicate overlapping matches (same percent within a few chars).
139
- matches.sort((a, b) => a.index - b.index);
140
- /** @type {{index: number, matchedText: string, percent: string}[]} */
141
- const deduped = [];
142
- for (const match of matches) {
143
- const last = deduped[deduped.length - 1];
144
- if (last && Math.abs(last.index - match.index) <= 8 && last.percent === match.percent) {
145
- continue;
146
- }
147
- deduped.push(match);
148
- }
149
- return deduped;
150
- }
151
-
152
- function extractContextWindow(sourceText, index, matchLength) {
153
- const start = Math.max(0, index - CONTEXT_WINDOW_RADIUS);
154
- const end = Math.min(sourceText.length, index + matchLength + CONTEXT_WINDOW_RADIUS);
155
- return sourceText.slice(start, end);
156
- }
157
-
158
- function hasIntegrationModeMarker(contextWindow) {
159
- const normalized = contextWindow.toLowerCase();
160
- return INTEGRATION_MODE_KEYWORDS.some((keyword) => normalized.includes(keyword));
161
- }
162
-
163
- function lineNumberFromIndex(sourceText, charIndex) {
164
- let line = 1;
165
- for (let i = 0; i < charIndex && i < sourceText.length; i += 1) {
166
- if (sourceText[i] === '\n') {
167
- line += 1;
168
- }
169
- }
170
- return line;
171
- }
172
-
173
- export function runCachingScopeHygieneAudit(options = {}) {
174
- const rootDir = options.rootDir ? resolve(String(options.rootDir)) : REPOSITORY_ROOT;
175
- const sourceOverrides = options.sourceOverrides || null;
176
- const surfaceList = options.surfaceList || PUBLIC_SURFACES;
177
- const violations = [];
178
- const surfaceReports = [];
179
- let totalClaims = 0;
180
-
181
- for (const surfacePath of surfaceList) {
182
- const sourceText = readSurface(rootDir, surfacePath, sourceOverrides);
183
- if (sourceText === null) {
184
- continue;
185
- }
186
-
187
- const claims = findCachingClaimMatches(sourceText);
188
- totalClaims += claims.length;
189
- /** @type {{percent: string, line: number, scoped: boolean}[]} */
190
- const claimReports = [];
191
-
192
- for (const claim of claims) {
193
- const contextWindow = extractContextWindow(sourceText, claim.index, claim.matchedText.length);
194
- const scoped = hasIntegrationModeMarker(contextWindow);
195
- const lineNumber = lineNumberFromIndex(sourceText, claim.index);
196
-
197
- claimReports.push({
198
- percent: claim.percent,
199
- line: lineNumber,
200
- scoped,
201
- });
202
-
203
- if (!scoped) {
204
- violations.push({
205
- file: surfacePath,
206
- line: lineNumber,
207
- kind: 'caching-claim.missing-integration-scope',
208
- detail: `Caching saving claim "${claim.matchedText.trim()}" lacks an integration-mode marker within +/- ${CONTEXT_WINDOW_RADIUS} chars. Add a per-tool / direct-API / IDE-wrapper label, or move the figure under a clearly-scoped paragraph. Source of truth: docs/architecture/decisions-foundation.md D4.`,
209
- });
210
- }
211
- }
212
-
213
- surfaceReports.push({
214
- path: surfacePath,
215
- claimCount: claims.length,
216
- scopedCount: claimReports.filter((claim) => claim.scoped).length,
217
- unscopedCount: claimReports.filter((claim) => !claim.scoped).length,
218
- claims: claimReports,
219
- });
220
- }
221
-
222
- return {
223
- auditName: 'audit-caching-scope-hygiene',
224
- reportVersion: '1.0.0',
225
- generatedAt: new Date().toISOString(),
226
- surfaceCount: surfaceReports.length,
227
- totalClaimCount: totalClaims,
228
- violationCount: violations.length,
229
- passed: violations.length === 0,
230
- surfaces: surfaceReports,
231
- violations,
232
- };
233
- }
234
-
235
- function main() {
236
- const report = runCachingScopeHygieneAudit();
237
-
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
- }
@@ -1,219 +0,0 @@
1
- #!/usr/bin/env node
2
- // @ts-check
3
-
4
- /**
5
- * audit-file-size.mjs
6
- *
7
- * Enforces the 500 LOC threshold on production source files. Files that exceed
8
- * the threshold are hard failures unless they declare a justified exception
9
- * with a `// @file-size-exception: <reason>` marker in their first 5 lines.
10
- *
11
- * Scope:
12
- * lib/ all .mjs/.js files
13
- * scripts/ all .mjs/.js files
14
- * bin/ all .js/.mjs files
15
- *
16
- * Excluded:
17
- * *.test.mjs / *.test.js (test files have different size economics)
18
- *
19
- * Usage:
20
- * node scripts/audit-file-size.mjs (human-readable + machine line)
21
- * node scripts/audit-file-size.mjs --json (JSON only)
22
- *
23
- * Exit codes:
24
- * 0 — all files within budget (or covered by exception)
25
- * 1 — at least one file exceeded the threshold without an exception marker
26
- */
27
-
28
- import { readdirSync, readFileSync, statSync } from 'node:fs';
29
- import { dirname, join, relative, resolve } from 'node:path';
30
- import { fileURLToPath } from 'node:url';
31
-
32
- const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
33
- const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '..');
34
-
35
- export const DEFAULT_LOC_THRESHOLD = 500;
36
- const EXCEPTION_MARKER_PATTERN = /^\s*(?:\/\/|\*)\s*@file-size-exception:\s*(.+?)\s*(?:\*\/\s*)?$/;
37
- const EXCEPTION_MARKER_LOOKAHEAD_LINES = 5;
38
- const SCAN_ROOTS = ['lib', 'scripts', 'bin'];
39
- const SCAN_EXTENSIONS = new Set(['.mjs', '.js']);
40
- const SKIP_DIRECTORY_NAMES = new Set(['node_modules', '.git', '.agentic-backup', '.benchmarks']);
41
-
42
- const ARGS = new Set(process.argv.slice(2));
43
- const JSON_ONLY = ARGS.has('--json');
44
-
45
- function isTestFile(filePath) {
46
- const baseName = filePath.split(/[\\/]/).pop();
47
- return /\.test\.(mjs|js)$/.test(baseName);
48
- }
49
-
50
- function collectSourceFiles(scanRootName) {
51
- const collected = [];
52
- const scanRootAbsolutePath = join(REPOSITORY_ROOT, scanRootName);
53
-
54
- function walk(currentPath) {
55
- let entries;
56
- try {
57
- entries = readdirSync(currentPath, { withFileTypes: true });
58
- } catch {
59
- return;
60
- }
61
-
62
- for (const entry of entries) {
63
- if (SKIP_DIRECTORY_NAMES.has(entry.name)) {
64
- continue;
65
- }
66
-
67
- const entryAbsolute = join(currentPath, entry.name);
68
- if (entry.isDirectory()) {
69
- walk(entryAbsolute);
70
- continue;
71
- }
72
-
73
- if (!entry.isFile()) {
74
- continue;
75
- }
76
-
77
- const dotIndex = entry.name.lastIndexOf('.');
78
- const extension = dotIndex >= 0 ? entry.name.slice(dotIndex) : '';
79
- if (!SCAN_EXTENSIONS.has(extension)) {
80
- continue;
81
- }
82
-
83
- if (isTestFile(entryAbsolute)) {
84
- continue;
85
- }
86
-
87
- collected.push(entryAbsolute);
88
- }
89
- }
90
-
91
- try {
92
- statSync(scanRootAbsolutePath);
93
- } catch {
94
- return collected;
95
- }
96
-
97
- walk(scanRootAbsolutePath);
98
- return collected;
99
- }
100
-
101
- function detectExceptionMarker(sourceLines) {
102
- const lookahead = sourceLines.slice(0, EXCEPTION_MARKER_LOOKAHEAD_LINES);
103
- for (const line of lookahead) {
104
- const match = line.match(EXCEPTION_MARKER_PATTERN);
105
- if (match) {
106
- return match[1].trim();
107
- }
108
- }
109
- return null;
110
- }
111
-
112
- function inspectFile(filePath, threshold) {
113
- const sourceText = readFileSync(filePath, 'utf8');
114
- const lines = sourceText.split(/\r?\n/);
115
- const lineCount = lines.length;
116
- const overThreshold = lineCount > threshold;
117
- const exceptionReason = overThreshold ? detectExceptionMarker(lines) : null;
118
- const passed = !overThreshold || Boolean(exceptionReason);
119
-
120
- return {
121
- filePath: relative(REPOSITORY_ROOT, filePath).replace(/\\/g, '/'),
122
- lineCount,
123
- threshold,
124
- overThreshold,
125
- exceptionReason,
126
- passed,
127
- };
128
- }
129
-
130
- export function runAuditFileSize({ threshold = DEFAULT_LOC_THRESHOLD } = {}) {
131
- const scannedFiles = SCAN_ROOTS.flatMap((scanRootName) => collectSourceFiles(scanRootName));
132
- const inspections = scannedFiles.map((filePath) => inspectFile(filePath, threshold));
133
- const violations = inspections.filter((entry) => entry.overThreshold && !entry.exceptionReason);
134
- const exemptedFiles = inspections.filter((entry) => entry.overThreshold && entry.exceptionReason);
135
-
136
- return {
137
- auditName: 'audit-file-size',
138
- reportVersion: '1.0.0',
139
- generatedAt: new Date().toISOString(),
140
- threshold,
141
- scannedFileCount: inspections.length,
142
- overThresholdCount: inspections.filter((entry) => entry.overThreshold).length,
143
- violationCount: violations.length,
144
- exemptedCount: exemptedFiles.length,
145
- violations: violations.map((entry) => ({
146
- filePath: entry.filePath,
147
- lineCount: entry.lineCount,
148
- })),
149
- exemptedFiles: exemptedFiles.map((entry) => ({
150
- filePath: entry.filePath,
151
- lineCount: entry.lineCount,
152
- reason: entry.exceptionReason,
153
- })),
154
- passed: violations.length === 0,
155
- };
156
- }
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
-
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
- }
@@ -1,163 +0,0 @@
1
- #!/usr/bin/env node
2
- // @ts-check
3
-
4
- import { existsSync, readFileSync } from 'node:fs';
5
- import { dirname, join, resolve } from 'node:path';
6
- import { fileURLToPath } from 'node:url';
7
- import { runRuleIdUniquenessAudit } from './audit-rule-id-uniqueness.mjs';
8
-
9
- const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
10
- const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '..');
11
- const ARGS = new Set(process.argv.slice(2));
12
- const JSON_ONLY = ARGS.has('--json');
13
- const RULE_ID_PATTERN = /\b[A-Z]+-\d{3,4}(?:-[A-Z])?\b/g;
14
-
15
- const REQUIRED_REFLECTION_SURFACES = [
16
- {
17
- path: 'AGENTS.md',
18
- requiredSnippets: [
19
- '## Bounded Reflection',
20
- 'REFLECTION',
21
- 'Rules:',
22
- 'Risk:',
23
- 'Action:',
24
- 'valid rule IDs',
25
- 'hidden chain-of-thought',
26
- ],
27
- },
28
- {
29
- path: '.agent-context/review-checklists/pr-checklist.md',
30
- requiredSnippets: [
31
- 'Bounded Reflection',
32
- 'valid rule IDs',
33
- 'hidden chain-of-thought',
34
- ],
35
- },
36
- ];
37
-
38
- function readSource(rootDir, relativePath, sourceOverrides) {
39
- if (sourceOverrides && Object.prototype.hasOwnProperty.call(sourceOverrides, relativePath)) {
40
- return String(sourceOverrides[relativePath]);
41
- }
42
-
43
- const absolutePath = join(rootDir, relativePath);
44
- if (!existsSync(absolutePath)) {
45
- return null;
46
- }
47
-
48
- return readFileSync(absolutePath, 'utf8');
49
- }
50
-
51
- function collectKnownRuleIds() {
52
- const ruleIdAudit = runRuleIdUniquenessAudit();
53
- const knownRuleIds = new Set();
54
-
55
- for (const fileEntry of ruleIdAudit.perFile || []) {
56
- for (const ruleId of fileEntry.knownSectionIdsInFile || []) {
57
- knownRuleIds.add(ruleId);
58
- }
59
- }
60
-
61
- return {
62
- ruleIdAudit,
63
- knownRuleIds,
64
- };
65
- }
66
-
67
- function collectRuleIdsFromSource(sourceText) {
68
- return Array.from(new Set(sourceText.match(RULE_ID_PATTERN) || [])).sort();
69
- }
70
-
71
- export function runReflectionCitationAudit(options = {}) {
72
- const rootDir = options.rootDir ? resolve(String(options.rootDir)) : REPOSITORY_ROOT;
73
- const sourceOverrides = options.sourceOverrides || null;
74
- const { ruleIdAudit, knownRuleIds } = collectKnownRuleIds();
75
- const violations = [];
76
- const surfaceReports = [];
77
-
78
- for (const surface of REQUIRED_REFLECTION_SURFACES) {
79
- const sourceText = readSource(rootDir, surface.path, sourceOverrides);
80
- if (sourceText === null) {
81
- violations.push({
82
- file: surface.path,
83
- kind: 'surface.missing',
84
- detail: 'Required reflection citation surface is missing.',
85
- });
86
- continue;
87
- }
88
-
89
- const missingSnippets = surface.requiredSnippets.filter((snippet) => !sourceText.includes(snippet));
90
- for (const missingSnippet of missingSnippets) {
91
- violations.push({
92
- file: surface.path,
93
- kind: 'reflection.snippet-missing',
94
- detail: `Missing required reflection snippet: ${missingSnippet}`,
95
- });
96
- }
97
-
98
- const citedRuleIds = collectRuleIdsFromSource(sourceText);
99
- const unknownRuleIds = citedRuleIds.filter((ruleId) => !knownRuleIds.has(ruleId));
100
- for (const unknownRuleId of unknownRuleIds) {
101
- violations.push({
102
- file: surface.path,
103
- kind: 'rule-id.unknown',
104
- detail: `Rule ID ${unknownRuleId} does not resolve to any canonical rule section.`,
105
- });
106
- }
107
-
108
- surfaceReports.push({
109
- path: surface.path,
110
- missingSnippetCount: missingSnippets.length,
111
- citedRuleIds,
112
- unknownRuleIds,
113
- });
114
- }
115
-
116
- return {
117
- auditName: 'audit-reflection-citations',
118
- reportVersion: '1.0.0',
119
- generatedAt: new Date().toISOString(),
120
- surfaceCount: REQUIRED_REFLECTION_SURFACES.length,
121
- knownRuleIdCount: knownRuleIds.size,
122
- ruleIdAuditPassed: ruleIdAudit.passed,
123
- violationCount: violations.length,
124
- passed: violations.length === 0,
125
- surfaces: surfaceReports,
126
- violations,
127
- };
128
- }
129
-
130
- function main() {
131
- const report = runReflectionCitationAudit();
132
-
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
- }