@eddacraft/anvil-runtime 0.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.
- package/LICENSE +14 -0
- package/dist/cache/cache-key.d.ts +45 -0
- package/dist/cache/cache-key.d.ts.map +1 -0
- package/dist/cache/cache-key.js +135 -0
- package/dist/cache/index.d.ts +27 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +38 -0
- package/dist/cache/providers/file-cache.d.ts +63 -0
- package/dist/cache/providers/file-cache.d.ts.map +1 -0
- package/dist/cache/providers/file-cache.js +369 -0
- package/dist/cache/providers/memory-cache.d.ts +52 -0
- package/dist/cache/providers/memory-cache.d.ts.map +1 -0
- package/dist/cache/providers/memory-cache.js +197 -0
- package/dist/cache/providers/null-cache.d.ts +26 -0
- package/dist/cache/providers/null-cache.d.ts.map +1 -0
- package/dist/cache/providers/null-cache.js +50 -0
- package/dist/cache/types.d.ts +114 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +4 -0
- package/dist/concurrency/agent.d.ts +137 -0
- package/dist/concurrency/agent.d.ts.map +1 -0
- package/dist/concurrency/agent.js +440 -0
- package/dist/concurrency/atomic.d.ts +93 -0
- package/dist/concurrency/atomic.d.ts.map +1 -0
- package/dist/concurrency/atomic.js +281 -0
- package/dist/concurrency/git-agent.d.ts +114 -0
- package/dist/concurrency/git-agent.d.ts.map +1 -0
- package/dist/concurrency/git-agent.js +313 -0
- package/dist/concurrency/index.d.ts +95 -0
- package/dist/concurrency/index.d.ts.map +1 -0
- package/dist/concurrency/index.js +127 -0
- package/dist/concurrency/lock-manager.d.ts +170 -0
- package/dist/concurrency/lock-manager.d.ts.map +1 -0
- package/dist/concurrency/lock-manager.js +525 -0
- package/dist/concurrency/queue-manager.d.ts +166 -0
- package/dist/concurrency/queue-manager.d.ts.map +1 -0
- package/dist/concurrency/queue-manager.js +442 -0
- package/dist/concurrency/types.d.ts +382 -0
- package/dist/concurrency/types.d.ts.map +1 -0
- package/dist/concurrency/types.js +204 -0
- package/dist/export/constraint-collector.d.ts +175 -0
- package/dist/export/constraint-collector.d.ts.map +1 -0
- package/dist/export/constraint-collector.js +203 -0
- package/dist/export/formatters/llms-txt-formatter.d.ts +89 -0
- package/dist/export/formatters/llms-txt-formatter.d.ts.map +1 -0
- package/dist/export/formatters/llms-txt-formatter.js +249 -0
- package/dist/export/formatters/mcp-resource-formatter.d.ts +186 -0
- package/dist/export/formatters/mcp-resource-formatter.d.ts.map +1 -0
- package/dist/export/formatters/mcp-resource-formatter.js +139 -0
- package/dist/export/formatters/prompt-formatter.d.ts +83 -0
- package/dist/export/formatters/prompt-formatter.d.ts.map +1 -0
- package/dist/export/formatters/prompt-formatter.js +256 -0
- package/dist/export/index.d.ts +10 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +9 -0
- package/dist/gate/check.interface.d.ts +15 -0
- package/dist/gate/check.interface.d.ts.map +1 -0
- package/dist/gate/check.interface.js +18 -0
- package/dist/gate/checks/antipattern.check.d.ts +27 -0
- package/dist/gate/checks/antipattern.check.d.ts.map +1 -0
- package/dist/gate/checks/antipattern.check.js +140 -0
- package/dist/gate/checks/architecture/circular-detector.d.ts +33 -0
- package/dist/gate/checks/architecture/circular-detector.d.ts.map +1 -0
- package/dist/gate/checks/architecture/circular-detector.js +71 -0
- package/dist/gate/checks/architecture/dependency-analyzer.d.ts +81 -0
- package/dist/gate/checks/architecture/dependency-analyzer.d.ts.map +1 -0
- package/dist/gate/checks/architecture/dependency-analyzer.js +136 -0
- package/dist/gate/checks/architecture/layer-validator.d.ts +75 -0
- package/dist/gate/checks/architecture/layer-validator.d.ts.map +1 -0
- package/dist/gate/checks/architecture/layer-validator.js +193 -0
- package/dist/gate/checks/architecture.check.d.ts +56 -0
- package/dist/gate/checks/architecture.check.d.ts.map +1 -0
- package/dist/gate/checks/architecture.check.js +394 -0
- package/dist/gate/checks/command-safety.check.d.ts +12 -0
- package/dist/gate/checks/command-safety.check.d.ts.map +1 -0
- package/dist/gate/checks/command-safety.check.js +230 -0
- package/dist/gate/checks/coverage.check.d.ts +9 -0
- package/dist/gate/checks/coverage.check.d.ts.map +1 -0
- package/dist/gate/checks/coverage.check.js +81 -0
- package/dist/gate/checks/dependency.check.d.ts +17 -0
- package/dist/gate/checks/dependency.check.d.ts.map +1 -0
- package/dist/gate/checks/dependency.check.js +342 -0
- package/dist/gate/checks/eslint.check.d.ts +14 -0
- package/dist/gate/checks/eslint.check.d.ts.map +1 -0
- package/dist/gate/checks/eslint.check.js +79 -0
- package/dist/gate/checks/policy.check.d.ts +78 -0
- package/dist/gate/checks/policy.check.d.ts.map +1 -0
- package/dist/gate/checks/policy.check.js +457 -0
- package/dist/gate/checks/secret/entropy-detector.d.ts +44 -0
- package/dist/gate/checks/secret/entropy-detector.d.ts.map +1 -0
- package/dist/gate/checks/secret/entropy-detector.js +76 -0
- package/dist/gate/checks/secret/git-scanner.d.ts +36 -0
- package/dist/gate/checks/secret/git-scanner.d.ts.map +1 -0
- package/dist/gate/checks/secret/git-scanner.js +90 -0
- package/dist/gate/checks/secret/secret-patterns.d.ts +42 -0
- package/dist/gate/checks/secret/secret-patterns.d.ts.map +1 -0
- package/dist/gate/checks/secret/secret-patterns.js +137 -0
- package/dist/gate/checks/secret.check.d.ts +56 -0
- package/dist/gate/checks/secret.check.d.ts.map +1 -0
- package/dist/gate/checks/secret.check.js +245 -0
- package/dist/gate/config/command-safety-config.d.ts +5 -0
- package/dist/gate/config/command-safety-config.d.ts.map +1 -0
- package/dist/gate/config/command-safety-config.js +69 -0
- package/dist/gate/config/index.d.ts +2 -0
- package/dist/gate/config/index.d.ts.map +1 -0
- package/dist/gate/config/index.js +1 -0
- package/dist/gate/formatters/command-safety-formatter.d.ts +10 -0
- package/dist/gate/formatters/command-safety-formatter.d.ts.map +1 -0
- package/dist/gate/formatters/command-safety-formatter.js +64 -0
- package/dist/gate/formatters/index.d.ts +2 -0
- package/dist/gate/formatters/index.d.ts.map +1 -0
- package/dist/gate/formatters/index.js +1 -0
- package/dist/gate/gate-config.d.ts +44 -0
- package/dist/gate/gate-config.d.ts.map +1 -0
- package/dist/gate/gate-config.js +334 -0
- package/dist/gate/gate-runner.d.ts +160 -0
- package/dist/gate/gate-runner.d.ts.map +1 -0
- package/dist/gate/gate-runner.js +531 -0
- package/dist/gate/index.d.ts +20 -0
- package/dist/gate/index.d.ts.map +1 -0
- package/dist/gate/index.js +14 -0
- package/dist/gate/parsers/command-parser.d.ts +18 -0
- package/dist/gate/parsers/command-parser.d.ts.map +1 -0
- package/dist/gate/parsers/command-parser.js +363 -0
- package/dist/gate/parsers/index.d.ts +2 -0
- package/dist/gate/parsers/index.d.ts.map +1 -0
- package/dist/gate/parsers/index.js +1 -0
- package/dist/gate/policy/index.d.ts +12 -0
- package/dist/gate/policy/index.d.ts.map +1 -0
- package/dist/gate/policy/index.js +10 -0
- package/dist/gate/rules/default-filesystem-rules.d.ts +3 -0
- package/dist/gate/rules/default-filesystem-rules.d.ts.map +1 -0
- package/dist/gate/rules/default-filesystem-rules.js +201 -0
- package/dist/gate/rules/default-git-rules.d.ts +3 -0
- package/dist/gate/rules/default-git-rules.d.ts.map +1 -0
- package/dist/gate/rules/default-git-rules.js +192 -0
- package/dist/gate/rules/index.d.ts +5 -0
- package/dist/gate/rules/index.d.ts.map +1 -0
- package/dist/gate/rules/index.js +3 -0
- package/dist/gate/rules/rule-matcher.d.ts +27 -0
- package/dist/gate/rules/rule-matcher.d.ts.map +1 -0
- package/dist/gate/rules/rule-matcher.js +228 -0
- package/dist/gate/rules/types.d.ts +250 -0
- package/dist/gate/rules/types.d.ts.map +1 -0
- package/dist/gate/rules/types.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/types/gate.types.d.ts +42 -0
- package/dist/types/gate.types.d.ts.map +1 -0
- package/dist/types/gate.types.js +94 -0
- package/dist/watch/debouncer.d.ts +90 -0
- package/dist/watch/debouncer.d.ts.map +1 -0
- package/dist/watch/debouncer.js +135 -0
- package/dist/watch/file-watcher.d.ts +73 -0
- package/dist/watch/file-watcher.d.ts.map +1 -0
- package/dist/watch/file-watcher.js +121 -0
- package/dist/watch/git-status.d.ts +98 -0
- package/dist/watch/git-status.d.ts.map +1 -0
- package/dist/watch/git-status.js +266 -0
- package/dist/watch/index.d.ts +16 -0
- package/dist/watch/index.d.ts.map +1 -0
- package/dist/watch/index.js +15 -0
- package/dist/watch/orchestrator.d.ts +113 -0
- package/dist/watch/orchestrator.d.ts.map +1 -0
- package/dist/watch/orchestrator.js +409 -0
- package/dist/watch/types.d.ts +190 -0
- package/dist/watch/types.d.ts.map +1 -0
- package/dist/watch/types.js +76 -0
- package/package.json +60 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Fragment Formatter
|
|
3
|
+
*
|
|
4
|
+
* Formats Anvil constraints as copy-paste system prompt text for manual
|
|
5
|
+
* AI tool configuration. Optimised for Claude, ChatGPT, and similar tools.
|
|
6
|
+
*
|
|
7
|
+
* @module export/formatters/prompt-formatter
|
|
8
|
+
*/
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Prompt Formatter
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Formats constraints as system prompt text
|
|
14
|
+
*/
|
|
15
|
+
export class PromptFormatter {
|
|
16
|
+
options;
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.options = {
|
|
19
|
+
includeBoundaries: true,
|
|
20
|
+
includeLayers: true,
|
|
21
|
+
includeAntiPatterns: true,
|
|
22
|
+
includeConventions: true,
|
|
23
|
+
includeSuppressions: true,
|
|
24
|
+
concise: false,
|
|
25
|
+
...options,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Format constraints as prompt text
|
|
30
|
+
*
|
|
31
|
+
* @param constraints - Constraints to format
|
|
32
|
+
* @returns System prompt text
|
|
33
|
+
*/
|
|
34
|
+
format(constraints) {
|
|
35
|
+
const sections = [];
|
|
36
|
+
// Opening instruction
|
|
37
|
+
sections.push(this.formatOpening());
|
|
38
|
+
// Architecture boundaries
|
|
39
|
+
if (this.options.includeBoundaries && constraints.boundaries.length > 0) {
|
|
40
|
+
sections.push(this.formatBoundaries(constraints));
|
|
41
|
+
}
|
|
42
|
+
// Layer definitions
|
|
43
|
+
if (this.options.includeLayers && constraints.layers.length > 0) {
|
|
44
|
+
sections.push(this.formatLayers(constraints));
|
|
45
|
+
}
|
|
46
|
+
// Anti-patterns
|
|
47
|
+
if (this.options.includeAntiPatterns && constraints.antiPatterns.length > 0) {
|
|
48
|
+
sections.push(this.formatAntiPatterns(constraints));
|
|
49
|
+
}
|
|
50
|
+
// Conventions
|
|
51
|
+
if (this.options.includeConventions && constraints.conventions.length > 0) {
|
|
52
|
+
sections.push(this.formatConventions(constraints));
|
|
53
|
+
}
|
|
54
|
+
// Suppressions
|
|
55
|
+
if (this.options.includeSuppressions && constraints.suppressions.length > 0) {
|
|
56
|
+
sections.push(this.formatSuppressions(constraints));
|
|
57
|
+
}
|
|
58
|
+
return sections.join('\n\n');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Format opening instruction
|
|
62
|
+
*/
|
|
63
|
+
formatOpening() {
|
|
64
|
+
if (this.options.concise) {
|
|
65
|
+
return ('When working on this codebase, follow these architecture rules and conventions. ' +
|
|
66
|
+
'Flag violations during code generation.');
|
|
67
|
+
}
|
|
68
|
+
return ('This codebase has specific architecture boundaries, anti-patterns, and conventions that must be followed. ' +
|
|
69
|
+
'When generating or modifying code:\n\n' +
|
|
70
|
+
'1. Respect all architectural boundaries and layer dependencies\n' +
|
|
71
|
+
'2. Avoid all listed anti-patterns\n' +
|
|
72
|
+
'3. Follow project conventions consistently\n' +
|
|
73
|
+
'4. If a boundary violation or anti-pattern is necessary, explain why and suggest alternatives first');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Format architecture boundaries section
|
|
77
|
+
*/
|
|
78
|
+
formatBoundaries(constraints) {
|
|
79
|
+
const lines = ['**Architecture Boundaries**'];
|
|
80
|
+
if (!this.options.concise) {
|
|
81
|
+
lines.push('These boundaries define which layers can depend on each other:');
|
|
82
|
+
}
|
|
83
|
+
lines.push('');
|
|
84
|
+
for (const boundary of constraints.boundaries) {
|
|
85
|
+
if (this.options.concise) {
|
|
86
|
+
lines.push(`- Layer "${boundary.from}" must not depend on "${boundary.to}"`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
lines.push(`- **${boundary.name}**: Layer "${boundary.from}" must not depend on "${boundary.to}"`);
|
|
90
|
+
lines.push(` ${boundary.message}`);
|
|
91
|
+
lines.push(` Severity: ${boundary.severity}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return lines.join('\n');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Format layer definitions section
|
|
98
|
+
*/
|
|
99
|
+
formatLayers(constraints) {
|
|
100
|
+
const lines = ['**Layer Definitions**'];
|
|
101
|
+
if (!this.options.concise) {
|
|
102
|
+
lines.push('The codebase is organised into these architectural layers:');
|
|
103
|
+
}
|
|
104
|
+
lines.push('');
|
|
105
|
+
for (const layer of constraints.layers) {
|
|
106
|
+
if (this.options.concise) {
|
|
107
|
+
lines.push(`- **${layer.name}**: ${layer.patterns.join(', ')}`);
|
|
108
|
+
if (layer.dependsOn.length > 0) {
|
|
109
|
+
lines.push(` Can depend on: ${layer.dependsOn.join(', ')}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
lines.push(`- **${layer.name}**`);
|
|
114
|
+
if (layer.description) {
|
|
115
|
+
lines.push(` ${layer.description}`);
|
|
116
|
+
}
|
|
117
|
+
lines.push(` Files: ${layer.patterns.join(', ')}`);
|
|
118
|
+
if (layer.dependsOn.length > 0) {
|
|
119
|
+
lines.push(` Allowed dependencies: ${layer.dependsOn.join(', ')}`);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
lines.push(` No dependencies (leaf layer)`);
|
|
123
|
+
}
|
|
124
|
+
lines.push('');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return lines.join('\n');
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Format anti-patterns section
|
|
131
|
+
*/
|
|
132
|
+
formatAntiPatterns(constraints) {
|
|
133
|
+
const lines = ['**Forbidden Anti-patterns**'];
|
|
134
|
+
if (!this.options.concise) {
|
|
135
|
+
lines.push('Never introduce these code patterns:');
|
|
136
|
+
}
|
|
137
|
+
lines.push('');
|
|
138
|
+
// Group by category for better organisation
|
|
139
|
+
const byCategory = new Map();
|
|
140
|
+
for (const pattern of constraints.antiPatterns) {
|
|
141
|
+
if (!byCategory.has(pattern.category)) {
|
|
142
|
+
byCategory.set(pattern.category, []);
|
|
143
|
+
}
|
|
144
|
+
byCategory.get(pattern.category).push(pattern);
|
|
145
|
+
}
|
|
146
|
+
for (const [category, patterns] of byCategory) {
|
|
147
|
+
if (!this.options.concise) {
|
|
148
|
+
lines.push(`${this.formatCategoryName(category)}:`);
|
|
149
|
+
}
|
|
150
|
+
for (const pattern of patterns) {
|
|
151
|
+
if (this.options.concise) {
|
|
152
|
+
lines.push(`- ${pattern.name}: ${pattern.suggestion}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
lines.push(`- **${pattern.name}** (${pattern.id})`);
|
|
156
|
+
lines.push(` Problem: ${pattern.explanation}`);
|
|
157
|
+
lines.push(` Instead: ${pattern.suggestion}`);
|
|
158
|
+
lines.push('');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return lines.join('\n');
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Format conventions section
|
|
166
|
+
*/
|
|
167
|
+
formatConventions(constraints) {
|
|
168
|
+
const lines = ['**Project Conventions**'];
|
|
169
|
+
if (!this.options.concise) {
|
|
170
|
+
lines.push('Follow these conventions for consistency:');
|
|
171
|
+
}
|
|
172
|
+
lines.push('');
|
|
173
|
+
for (const convention of constraints.conventions) {
|
|
174
|
+
lines.push(`- **${this.formatCategoryName(convention.category)}**: ${convention.description}`);
|
|
175
|
+
if (!this.options.concise && convention.examples && convention.examples.length > 0) {
|
|
176
|
+
for (const example of convention.examples) {
|
|
177
|
+
lines.push(` • ${example}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return lines.join('\n');
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Format active suppressions section
|
|
185
|
+
*/
|
|
186
|
+
formatSuppressions(constraints) {
|
|
187
|
+
const lines = ['**Active Suppressions**'];
|
|
188
|
+
if (!this.options.concise) {
|
|
189
|
+
lines.push('These violations are intentionally suppressed. Do not flag or fix them:');
|
|
190
|
+
}
|
|
191
|
+
lines.push('');
|
|
192
|
+
// Group by pattern ID
|
|
193
|
+
const byPattern = new Map();
|
|
194
|
+
for (const suppression of constraints.suppressions) {
|
|
195
|
+
if (!byPattern.has(suppression.patternId)) {
|
|
196
|
+
byPattern.set(suppression.patternId, []);
|
|
197
|
+
}
|
|
198
|
+
byPattern.get(suppression.patternId).push(suppression);
|
|
199
|
+
}
|
|
200
|
+
for (const [patternId, suppressions] of byPattern) {
|
|
201
|
+
if (this.options.concise) {
|
|
202
|
+
const files = suppressions.map((s) => s.file).join(', ');
|
|
203
|
+
lines.push(`- ${patternId}: suppressed in ${files}`);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
lines.push(`${patternId}:`);
|
|
207
|
+
for (const suppression of suppressions) {
|
|
208
|
+
lines.push(`- **${suppression.file}** (${suppression.scope}): ${suppression.reason}`);
|
|
209
|
+
if (suppression.expiresAt) {
|
|
210
|
+
const expiresAtDate = new Date(suppression.expiresAt);
|
|
211
|
+
if (!Number.isNaN(expiresAtDate.getTime())) {
|
|
212
|
+
lines.push(` Expires: ${expiresAtDate.toISOString().slice(0, 10)}`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
lines.push(` Expires: ${suppression.expiresAt}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
lines.push('');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return lines.join('\n');
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Format category name for display
|
|
226
|
+
*/
|
|
227
|
+
formatCategoryName(category) {
|
|
228
|
+
return category
|
|
229
|
+
.split('-')
|
|
230
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
231
|
+
.join(' ');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// =============================================================================
|
|
235
|
+
// Convenience Functions
|
|
236
|
+
// =============================================================================
|
|
237
|
+
/**
|
|
238
|
+
* Format constraints as prompt fragment with default options
|
|
239
|
+
*
|
|
240
|
+
* @param constraints - Constraints to format
|
|
241
|
+
* @returns Prompt text
|
|
242
|
+
*/
|
|
243
|
+
export function formatAsPrompt(constraints) {
|
|
244
|
+
const formatter = new PromptFormatter();
|
|
245
|
+
return formatter.format(constraints);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Format constraints as concise prompt fragment
|
|
249
|
+
*
|
|
250
|
+
* @param constraints - Constraints to format
|
|
251
|
+
* @returns Concise prompt text
|
|
252
|
+
*/
|
|
253
|
+
export function formatAsConcisePrompt(constraints) {
|
|
254
|
+
const formatter = new PromptFormatter({ concise: true });
|
|
255
|
+
return formatter.format(constraints);
|
|
256
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export module
|
|
3
|
+
*
|
|
4
|
+
* Public API for constraint collection and formatting
|
|
5
|
+
*/
|
|
6
|
+
export * from './constraint-collector.js';
|
|
7
|
+
export * from './formatters/llms-txt-formatter.js';
|
|
8
|
+
export * from './formatters/mcp-resource-formatter.js';
|
|
9
|
+
export * from './formatters/prompt-formatter.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/export/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,wCAAwC,CAAC;AACvD,cAAc,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export module
|
|
3
|
+
*
|
|
4
|
+
* Public API for constraint collection and formatting
|
|
5
|
+
*/
|
|
6
|
+
export * from './constraint-collector.js';
|
|
7
|
+
export * from './formatters/llms-txt-formatter.js';
|
|
8
|
+
export * from './formatters/mcp-resource-formatter.js';
|
|
9
|
+
export * from './formatters/prompt-formatter.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CheckContext, GateResult } from '../types/gate.types.js';
|
|
2
|
+
export interface Check {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
run(context: CheckContext): Promise<GateResult>;
|
|
6
|
+
}
|
|
7
|
+
export declare abstract class BaseCheck implements Check {
|
|
8
|
+
abstract name: string;
|
|
9
|
+
abstract description: string;
|
|
10
|
+
abstract run(context: CheckContext): Promise<GateResult>;
|
|
11
|
+
protected createResult(passed: boolean, message: string, score?: number, details?: Record<string, unknown>, error?: string): GateResult;
|
|
12
|
+
protected createSuccess(message: string, score?: number, details?: Record<string, unknown>): GateResult;
|
|
13
|
+
protected createFailure(message: string, error?: string, details?: Record<string, unknown>): GateResult;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=check.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.interface.d.ts","sourceRoot":"","sources":["../../src/gate/check.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACjD;AAED,8BAAsB,SAAU,YAAW,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC;IAExD,SAAS,CAAC,YAAY,CACpB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,KAAK,CAAC,EAAE,MAAM,GACb,UAAU;IAWb,SAAS,CAAC,aAAa,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,UAAU;IAIb,SAAS,CAAC,aAAa,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,UAAU;CAGd"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class BaseCheck {
|
|
2
|
+
createResult(passed, message, score, details, error) {
|
|
3
|
+
return {
|
|
4
|
+
check: this.name,
|
|
5
|
+
passed,
|
|
6
|
+
score,
|
|
7
|
+
message,
|
|
8
|
+
details,
|
|
9
|
+
error,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
createSuccess(message, score, details) {
|
|
13
|
+
return this.createResult(true, message, score, details);
|
|
14
|
+
}
|
|
15
|
+
createFailure(message, error, details) {
|
|
16
|
+
return this.createResult(false, message, undefined, details, error);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anti-pattern Check - Detect AI escape hatches and code quality issues
|
|
3
|
+
*
|
|
4
|
+
* Detects:
|
|
5
|
+
* - ESLint disable comments (broad and rule-specific)
|
|
6
|
+
* - Type escapes (any, @ts-ignore, @ts-expect-error)
|
|
7
|
+
* - Empty catch blocks
|
|
8
|
+
* - Console statements in production code
|
|
9
|
+
*/
|
|
10
|
+
import { BaseCheck } from '../check.interface.js';
|
|
11
|
+
import { CheckContext, GateResult } from '../../types/gate.types.js';
|
|
12
|
+
export interface AntipatternCheckConfig {
|
|
13
|
+
patterns?: string[];
|
|
14
|
+
includeOptIn?: boolean;
|
|
15
|
+
extensions?: string[];
|
|
16
|
+
severityThreshold?: 'error' | 'warning' | 'info';
|
|
17
|
+
}
|
|
18
|
+
export declare class AntipatternCheck extends BaseCheck {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
run(context: CheckContext): Promise<GateResult>;
|
|
22
|
+
private parseConfig;
|
|
23
|
+
private isScannableFile;
|
|
24
|
+
private calculateScore;
|
|
25
|
+
private buildMessage;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=antipattern.check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antipattern.check.d.ts","sourceRoot":"","sources":["../../../src/gate/checks/antipattern.check.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAuB,MAAM,2BAA2B,CAAC;AAY1F,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CAClD;AAeD,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,IAAI,SAAiB;IACrB,WAAW,SAA6D;IAElE,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC;IAuErD,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,YAAY;CAsBrB"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anti-pattern Check - Detect AI escape hatches and code quality issues
|
|
3
|
+
*
|
|
4
|
+
* Detects:
|
|
5
|
+
* - ESLint disable comments (broad and rule-specific)
|
|
6
|
+
* - Type escapes (any, @ts-ignore, @ts-expect-error)
|
|
7
|
+
* - Empty catch blocks
|
|
8
|
+
* - Console statements in production code
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { BaseCheck } from '../check.interface.js';
|
|
13
|
+
import { getFilesFromContext } from '../../types/gate.types.js';
|
|
14
|
+
import { scanFile } from '@eddacraft/anvil-core/antipattern';
|
|
15
|
+
import { createWarningResult, } from '@eddacraft/anvil-core/antipattern';
|
|
16
|
+
import { parseSeverity, createDebugger } from '@eddacraft/anvil-core';
|
|
17
|
+
import { DEFAULT_ANALYSABLE_EXTENSIONS } from '@eddacraft/anvil-core';
|
|
18
|
+
const log = createDebugger('check');
|
|
19
|
+
const DEFAULT_CONFIG = {
|
|
20
|
+
patterns: [],
|
|
21
|
+
includeOptIn: false,
|
|
22
|
+
extensions: DEFAULT_ANALYSABLE_EXTENSIONS,
|
|
23
|
+
severityThreshold: 'error',
|
|
24
|
+
};
|
|
25
|
+
const SEVERITY_PENALTIES = {
|
|
26
|
+
error: 15,
|
|
27
|
+
warning: 5,
|
|
28
|
+
info: 1,
|
|
29
|
+
};
|
|
30
|
+
export class AntipatternCheck extends BaseCheck {
|
|
31
|
+
name = 'antipattern';
|
|
32
|
+
description = 'Detect AI escape hatches and code quality anti-patterns';
|
|
33
|
+
async run(context) {
|
|
34
|
+
log(`antipattern check starting, workspace=${context.workspace_root}`);
|
|
35
|
+
const config = this.parseConfig(context.check_config);
|
|
36
|
+
log(`antipattern config: severityThreshold=${config.severityThreshold}, patterns=${config.patterns.length}, includeOptIn=${config.includeOptIn}`);
|
|
37
|
+
try {
|
|
38
|
+
const files = getFilesFromContext(context, {
|
|
39
|
+
filter: (f) => this.isScannableFile(f, config),
|
|
40
|
+
});
|
|
41
|
+
if (files.length === 0) {
|
|
42
|
+
log('antipattern check: no scannable files found, returning success');
|
|
43
|
+
return this.createSuccess('No files to scan for anti-patterns', 100, {
|
|
44
|
+
warnings: createWarningResult([], []),
|
|
45
|
+
filesScanned: 0,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
log(`antipattern check: scanning ${files.length} files`);
|
|
49
|
+
const scanOptions = {
|
|
50
|
+
patterns: config.patterns.length > 0 ? config.patterns : undefined,
|
|
51
|
+
includeOptIn: config.includeOptIn,
|
|
52
|
+
};
|
|
53
|
+
const allWarnings = [];
|
|
54
|
+
const allPatternsChecked = new Set();
|
|
55
|
+
let filesScanned = 0;
|
|
56
|
+
for (const filePath of files) {
|
|
57
|
+
let content;
|
|
58
|
+
try {
|
|
59
|
+
content = readFileSync(filePath, 'utf-8');
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const relativePath = path.isAbsolute(filePath)
|
|
65
|
+
? path.relative(context.workspace_root, filePath)
|
|
66
|
+
: filePath;
|
|
67
|
+
const result = scanFile(relativePath, content, scanOptions);
|
|
68
|
+
allWarnings.push(...result.warnings);
|
|
69
|
+
result.patternsChecked.forEach((p) => allPatternsChecked.add(p));
|
|
70
|
+
filesScanned++;
|
|
71
|
+
}
|
|
72
|
+
const warningResult = createWarningResult(allWarnings, Array.from(allPatternsChecked));
|
|
73
|
+
const { score, passed } = this.calculateScore(allWarnings, config);
|
|
74
|
+
const message = this.buildMessage(warningResult, filesScanned, passed);
|
|
75
|
+
log(`antipattern check result: passed=${passed}, score=${score}, warnings=${allWarnings.length}, filesScanned=${filesScanned}`);
|
|
76
|
+
return this.createResult(passed, message, score, {
|
|
77
|
+
warnings: warningResult,
|
|
78
|
+
filesScanned,
|
|
79
|
+
patternsChecked: Array.from(allPatternsChecked),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
log(`antipattern check error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
84
|
+
return this.createFailure('Anti-pattern check failed unexpectedly', error instanceof Error ? error.message : 'Unknown error');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
parseConfig(checkConfig) {
|
|
88
|
+
return {
|
|
89
|
+
patterns: Array.isArray(checkConfig.patterns)
|
|
90
|
+
? checkConfig.patterns.filter((p) => typeof p === 'string')
|
|
91
|
+
: DEFAULT_CONFIG.patterns,
|
|
92
|
+
includeOptIn: checkConfig.includeOptIn === true,
|
|
93
|
+
extensions: Array.isArray(checkConfig.extensions)
|
|
94
|
+
? checkConfig.extensions.filter((e) => typeof e === 'string')
|
|
95
|
+
: DEFAULT_CONFIG.extensions,
|
|
96
|
+
severityThreshold: parseSeverity(checkConfig.severityThreshold, DEFAULT_CONFIG.severityThreshold),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
isScannableFile(filePath, config) {
|
|
100
|
+
return config.extensions.some((ext) => filePath.endsWith(ext));
|
|
101
|
+
}
|
|
102
|
+
calculateScore(warnings, config) {
|
|
103
|
+
const severityLevels = { error: 3, warning: 2, info: 1 };
|
|
104
|
+
const threshold = severityLevels[config.severityThreshold];
|
|
105
|
+
let totalPenalty = 0;
|
|
106
|
+
let hasBlockingWarning = false;
|
|
107
|
+
for (const warning of warnings) {
|
|
108
|
+
if (warning.suppressed)
|
|
109
|
+
continue;
|
|
110
|
+
const warningSeverity = severityLevels[warning.severity];
|
|
111
|
+
if (warningSeverity >= threshold) {
|
|
112
|
+
hasBlockingWarning = true;
|
|
113
|
+
}
|
|
114
|
+
totalPenalty += SEVERITY_PENALTIES[warning.severity] || 0;
|
|
115
|
+
}
|
|
116
|
+
const score = Math.max(0, 100 - totalPenalty);
|
|
117
|
+
const passed = !hasBlockingWarning;
|
|
118
|
+
return { score, passed };
|
|
119
|
+
}
|
|
120
|
+
buildMessage(result, filesScanned, passed) {
|
|
121
|
+
if (result.warnings.length === 0) {
|
|
122
|
+
return `Anti-pattern check passed: ${filesScanned} files scanned, no issues found`;
|
|
123
|
+
}
|
|
124
|
+
const parts = [];
|
|
125
|
+
if (result.summary.errors > 0) {
|
|
126
|
+
parts.push(`${result.summary.errors} error${result.summary.errors > 1 ? 's' : ''}`);
|
|
127
|
+
}
|
|
128
|
+
if (result.summary.warnings > 0) {
|
|
129
|
+
parts.push(`${result.summary.warnings} warning${result.summary.warnings > 1 ? 's' : ''}`);
|
|
130
|
+
}
|
|
131
|
+
if (result.summary.info > 0) {
|
|
132
|
+
parts.push(`${result.summary.info} info`);
|
|
133
|
+
}
|
|
134
|
+
if (result.summary.suppressed > 0) {
|
|
135
|
+
parts.push(`${result.summary.suppressed} suppressed`);
|
|
136
|
+
}
|
|
137
|
+
const status = passed ? 'passed with issues' : 'failed';
|
|
138
|
+
return `Anti-pattern check ${status}: ${parts.join(', ')} (${filesScanned} files scanned)`;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circular Detector - Detect and categorize circular dependencies
|
|
3
|
+
*
|
|
4
|
+
* Handles detection and categorization of various violation types from dependency-cruiser.
|
|
5
|
+
*/
|
|
6
|
+
import type { CruiserViolation } from './dependency-analyzer.js';
|
|
7
|
+
import type { ArchitectureBaseline } from '@eddacraft/anvil-core/architecture';
|
|
8
|
+
/**
|
|
9
|
+
* Categorized violation types
|
|
10
|
+
*/
|
|
11
|
+
export type ViolationType = 'circular' | 'orphan' | 'layer' | 'other';
|
|
12
|
+
/**
|
|
13
|
+
* Circular detector for analyzing violations
|
|
14
|
+
*/
|
|
15
|
+
export declare class CircularDetector {
|
|
16
|
+
/**
|
|
17
|
+
* Categorize a violation by type
|
|
18
|
+
*/
|
|
19
|
+
categoriseViolation(violation: CruiserViolation): ViolationType;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a violation is new compared to baseline
|
|
22
|
+
*/
|
|
23
|
+
isNewViolation(violation: CruiserViolation, baseline: ArchitectureBaseline): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Count violations by type
|
|
26
|
+
*/
|
|
27
|
+
countViolationsByType(violations: CruiserViolation[]): Record<string, number>;
|
|
28
|
+
/**
|
|
29
|
+
* Filter violations to only new ones based on baseline
|
|
30
|
+
*/
|
|
31
|
+
filterNewViolations(violations: CruiserViolation[], baseline: ArchitectureBaseline | null): CruiserViolation[];
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=circular-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circular-detector.d.ts","sourceRoot":"","sources":["../../../../src/gate/checks/architecture/circular-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAK/E;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;AAEtE;;GAEG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,gBAAgB,GAAG,aAAa;IAa/D;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,oBAAoB,GAAG,OAAO;IAYpF;;OAEG;IACH,qBAAqB,CAAC,UAAU,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAiB7E;;OAEG;IACH,mBAAmB,CACjB,UAAU,EAAE,gBAAgB,EAAE,EAC9B,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GACpC,gBAAgB,EAAE;CAYtB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circular Detector - Detect and categorize circular dependencies
|
|
3
|
+
*
|
|
4
|
+
* Handles detection and categorization of various violation types from dependency-cruiser.
|
|
5
|
+
*/
|
|
6
|
+
import { createDebugger } from '@eddacraft/anvil-core';
|
|
7
|
+
const log = createDebugger('check');
|
|
8
|
+
/**
|
|
9
|
+
* Circular detector for analyzing violations
|
|
10
|
+
*/
|
|
11
|
+
export class CircularDetector {
|
|
12
|
+
/**
|
|
13
|
+
* Categorize a violation by type
|
|
14
|
+
*/
|
|
15
|
+
categoriseViolation(violation) {
|
|
16
|
+
if (violation.cycle && violation.cycle.length > 0) {
|
|
17
|
+
return 'circular';
|
|
18
|
+
}
|
|
19
|
+
if (violation.rule.name.includes('orphan')) {
|
|
20
|
+
return 'orphan';
|
|
21
|
+
}
|
|
22
|
+
if (violation.rule.name.includes('layer') || violation.rule.name.includes('boundary')) {
|
|
23
|
+
return 'layer';
|
|
24
|
+
}
|
|
25
|
+
return 'other';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Check if a violation is new compared to baseline
|
|
29
|
+
*/
|
|
30
|
+
isNewViolation(violation, baseline) {
|
|
31
|
+
const baselineViolations = baseline.baseline_snapshot.violations;
|
|
32
|
+
return !baselineViolations.some((bv) => {
|
|
33
|
+
const filesMatch = bv.from_file === violation.from && bv.to_file === violation.to;
|
|
34
|
+
if (!filesMatch)
|
|
35
|
+
return false;
|
|
36
|
+
if (bv.rule) {
|
|
37
|
+
return bv.rule === violation.rule.name;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Count violations by type
|
|
44
|
+
*/
|
|
45
|
+
countViolationsByType(violations) {
|
|
46
|
+
const violationsByType = {
|
|
47
|
+
circular: 0,
|
|
48
|
+
orphan: 0,
|
|
49
|
+
layer: 0,
|
|
50
|
+
other: 0,
|
|
51
|
+
};
|
|
52
|
+
for (const v of violations) {
|
|
53
|
+
const type = this.categoriseViolation(v);
|
|
54
|
+
violationsByType[type]++;
|
|
55
|
+
}
|
|
56
|
+
log('circular-detector: violation counts by type', { violationsByType });
|
|
57
|
+
return violationsByType;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Filter violations to only new ones based on baseline
|
|
61
|
+
*/
|
|
62
|
+
filterNewViolations(violations, baseline) {
|
|
63
|
+
if (!baseline) {
|
|
64
|
+
log(`circular-detector: no baseline, all ${violations.length} violations treated as new`);
|
|
65
|
+
return violations;
|
|
66
|
+
}
|
|
67
|
+
const newViolations = violations.filter((v) => this.isNewViolation(v, baseline));
|
|
68
|
+
log(`circular-detector: filtered ${violations.length} violations to ${newViolations.length} new (baseline has ${baseline.baseline_snapshot.violations.length})`);
|
|
69
|
+
return newViolations;
|
|
70
|
+
}
|
|
71
|
+
}
|