@auto-engineer/server-implementer 1.130.0 → 1.134.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/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.130.0",
22
- "@auto-engineer/message-bus": "1.130.0"
21
+ "@auto-engineer/model-factory": "1.134.0",
22
+ "@auto-engineer/message-bus": "1.134.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.130.0"
32
+ "@auto-engineer/cli": "1.134.0"
33
33
  },
34
- "version": "1.130.0",
34
+ "version": "1.134.0",
35
35
  "scripts": {
36
36
  "build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
37
37
  "test": "vitest run --reporter=dot",
@@ -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 failedTypecheckFiles = [...typecheckResult.failedTypecheckFiles, ...shadowResult.failedFiles];
173
- const typecheckErrors = [typecheckResult.typecheckErrors, shadowResult.errors].filter(Boolean).join('\n');
174
- const hasErrors = !testResult.success || !typecheckResult.success || shadowResult.errors.length > 0;
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
+ }