@auto-engineer/server-implementer 1.129.0 → 1.131.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +6 -6
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +65 -0
- package/dist/src/agent/runSlice.d.ts +4 -0
- package/dist/src/agent/runSlice.d.ts.map +1 -1
- package/dist/src/agent/runSlice.js +28 -3
- package/dist/src/agent/runSlice.js.map +1 -1
- package/dist/src/utils/detectTypeAssertions.d.ts +3 -0
- package/dist/src/utils/detectTypeAssertions.d.ts.map +1 -0
- package/dist/src/utils/detectTypeAssertions.js +25 -0
- package/dist/src/utils/detectTypeAssertions.js.map +1 -0
- package/dist/src/utils/detectTypeAssertions.specs.d.ts +2 -0
- package/dist/src/utils/detectTypeAssertions.specs.d.ts.map +1 -0
- package/dist/src/utils/detectTypeAssertions.specs.js +60 -0
- package/dist/src/utils/detectTypeAssertions.specs.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/agent/runSlice.ts +30 -3
- package/src/utils/detectTypeAssertions.specs.ts +73 -0
- package/src/utils/detectTypeAssertions.ts +27 -0
package/package.json
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"debug": "^4.3.4",
|
|
19
19
|
"fast-glob": "^3.3.3",
|
|
20
20
|
"vite": "^5.4.1",
|
|
21
|
-
"@auto-engineer/model-factory": "1.
|
|
22
|
-
"@auto-engineer/message-bus": "1.
|
|
21
|
+
"@auto-engineer/model-factory": "1.131.0",
|
|
22
|
+
"@auto-engineer/message-bus": "1.131.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/fs-extra": "^11.0.4",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"glob": "^11.0.3",
|
|
30
30
|
"tsx": "^4.20.3",
|
|
31
31
|
"typescript": "^5.8.3",
|
|
32
|
-
"@auto-engineer/cli": "1.
|
|
32
|
+
"@auto-engineer/cli": "1.131.0"
|
|
33
33
|
},
|
|
34
|
-
"version": "1.
|
|
34
|
+
"version": "1.131.0",
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
|
|
37
37
|
"test": "vitest run --reporter=dot",
|
package/src/agent/runSlice.ts
CHANGED
|
@@ -7,6 +7,7 @@ import fg from 'fast-glob';
|
|
|
7
7
|
import { SYSTEM_PROMPT } from '../prompts/systemPrompt';
|
|
8
8
|
import { buildContextSections } from '../utils/buildContextSections';
|
|
9
9
|
import { buildShadowWarning } from '../utils/detectImportedTypeShadowing';
|
|
10
|
+
import { buildTypeAssertionWarning } from '../utils/detectTypeAssertions';
|
|
10
11
|
import { extractCodeBlock } from '../utils/extractCodeBlock';
|
|
11
12
|
import { findFilesToImplement } from '../utils/findFilesToImplement';
|
|
12
13
|
import { loadContextFiles } from '../utils/loadContextFiles';
|
|
@@ -169,9 +170,20 @@ export async function runTestsAndTypecheck(sliceDir: string): Promise<TestAndTyp
|
|
|
169
170
|
const testResult = await runTests(sliceDir, rootDir);
|
|
170
171
|
const typecheckResult = await runTypecheck(sliceDir, rootDir);
|
|
171
172
|
const shadowResult = await detectShadowsInSlice(sliceDir);
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
|
|
173
|
+
const assertionResult = await detectAssertionsInSlice(sliceDir);
|
|
174
|
+
const failedTypecheckFiles = [
|
|
175
|
+
...typecheckResult.failedTypecheckFiles,
|
|
176
|
+
...shadowResult.failedFiles,
|
|
177
|
+
...assertionResult.failedFiles,
|
|
178
|
+
];
|
|
179
|
+
const typecheckErrors = [typecheckResult.typecheckErrors, shadowResult.errors, assertionResult.errors]
|
|
180
|
+
.filter(Boolean)
|
|
181
|
+
.join('\n');
|
|
182
|
+
const hasErrors =
|
|
183
|
+
!testResult.success ||
|
|
184
|
+
!typecheckResult.success ||
|
|
185
|
+
shadowResult.errors.length > 0 ||
|
|
186
|
+
assertionResult.errors.length > 0;
|
|
175
187
|
return {
|
|
176
188
|
success: !hasErrors,
|
|
177
189
|
failedTestFiles: testResult.failedTestFiles,
|
|
@@ -196,6 +208,21 @@ export async function detectShadowsInSlice(sliceDir: string): Promise<{ errors:
|
|
|
196
208
|
return { errors: errors.join('\n'), failedFiles };
|
|
197
209
|
}
|
|
198
210
|
|
|
211
|
+
export async function detectAssertionsInSlice(sliceDir: string): Promise<{ errors: string; failedFiles: string[] }> {
|
|
212
|
+
const files = await fg(['*.ts'], { cwd: sliceDir, ignore: ['*.spec.ts', '*.specs.ts', '*.test.ts'] });
|
|
213
|
+
const errors: string[] = [];
|
|
214
|
+
const failedFiles: string[] = [];
|
|
215
|
+
for (const file of files) {
|
|
216
|
+
const content = await readFile(path.join(sliceDir, file), 'utf-8');
|
|
217
|
+
const warning = buildTypeAssertionWarning(content, file);
|
|
218
|
+
if (warning.length > 0) {
|
|
219
|
+
errors.push(warning);
|
|
220
|
+
failedFiles.push(path.join(sliceDir, file));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { errors: errors.join('\n'), failedFiles };
|
|
224
|
+
}
|
|
225
|
+
|
|
199
226
|
async function retryFailedTests(sliceDir: string, flow: string, result: TestAndTypecheckResult) {
|
|
200
227
|
let contextFiles = await loadContextFiles(sliceDir);
|
|
201
228
|
for (let attempt = 1; attempt <= 5; attempt++) {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { buildTypeAssertionWarning, detectTypeAssertions } from './detectTypeAssertions';
|
|
3
|
+
|
|
4
|
+
describe('detectTypeAssertions', () => {
|
|
5
|
+
it('returns empty array for clean code', () => {
|
|
6
|
+
const code = `
|
|
7
|
+
const state: State = { name: 'Alice' };
|
|
8
|
+
const x = 1;
|
|
9
|
+
`;
|
|
10
|
+
expect(detectTypeAssertions(code)).toEqual([]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('detects {} as State', () => {
|
|
14
|
+
const code = `const state = {} as State;`;
|
|
15
|
+
expect(detectTypeAssertions(code)).toEqual(['as State (line 1)']);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('detects x as any', () => {
|
|
19
|
+
const code = `const x = value as any;`;
|
|
20
|
+
expect(detectTypeAssertions(code)).toEqual(['as any (line 1)']);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('detects value as unknown as Type', () => {
|
|
24
|
+
const code = `const x = value as unknown as MyType;`;
|
|
25
|
+
expect(detectTypeAssertions(code)).toEqual(['as MyType (line 1)', 'as unknown (line 1)']);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('skips as const', () => {
|
|
29
|
+
const code = `const arr = [1, 2, 3] as const;`;
|
|
30
|
+
expect(detectTypeAssertions(code)).toEqual([]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('handles assertions inside functions', () => {
|
|
34
|
+
const code = `
|
|
35
|
+
function process() {
|
|
36
|
+
const x = {} as State;
|
|
37
|
+
return x;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
expect(detectTypeAssertions(code)).toEqual(['as State (line 3)']);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('detects multiple assertions across lines', () => {
|
|
44
|
+
const code = `
|
|
45
|
+
const a = {} as State;
|
|
46
|
+
const b = value as any;
|
|
47
|
+
`;
|
|
48
|
+
expect(detectTypeAssertions(code)).toEqual(['as State (line 2)', 'as any (line 3)']);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('buildTypeAssertionWarning', () => {
|
|
53
|
+
it('returns empty string for clean code', () => {
|
|
54
|
+
const code = `const x: State = { name: 'Alice' };`;
|
|
55
|
+
expect(buildTypeAssertionWarning(code)).toBe('');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('returns CONTRACT VIOLATION string for violations', () => {
|
|
59
|
+
const code = `const state = {} as State;`;
|
|
60
|
+
const result = buildTypeAssertionWarning(code, 'state.ts');
|
|
61
|
+
expect(result).toBe(
|
|
62
|
+
"CONTRACT VIOLATION in state.ts: Forbidden type assertions found: [as State (line 1)]. Use properly typed variables instead of 'as' casts.",
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('returns CONTRACT VIOLATION without file path when not provided', () => {
|
|
67
|
+
const code = `const state = {} as State;`;
|
|
68
|
+
const result = buildTypeAssertionWarning(code);
|
|
69
|
+
expect(result).toBe(
|
|
70
|
+
"CONTRACT VIOLATION: Forbidden type assertions found: [as State (line 1)]. Use properly typed variables instead of 'as' casts.",
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
export function detectTypeAssertions(code: string): string[] {
|
|
4
|
+
const sourceFile = ts.createSourceFile('check.ts', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
5
|
+
const violations: string[] = [];
|
|
6
|
+
|
|
7
|
+
function visit(node: ts.Node): void {
|
|
8
|
+
if (ts.isAsExpression(node)) {
|
|
9
|
+
const typeText = node.type.getText(sourceFile).trim();
|
|
10
|
+
if (typeText !== 'const') {
|
|
11
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
12
|
+
violations.push(`as ${typeText} (line ${line + 1})`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
ts.forEachChild(node, visit);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
visit(sourceFile);
|
|
19
|
+
return violations;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function buildTypeAssertionWarning(code: string, filePath?: string): string {
|
|
23
|
+
const violations = detectTypeAssertions(code);
|
|
24
|
+
if (violations.length === 0) return '';
|
|
25
|
+
const location = filePath !== undefined ? ` in ${filePath}` : '';
|
|
26
|
+
return `CONTRACT VIOLATION${location}: Forbidden type assertions found: [${violations.join(', ')}]. Use properly typed variables instead of 'as' casts.`;
|
|
27
|
+
}
|