@auto-engineer/server-implementer 1.123.0 → 1.125.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.123.0",
22
- "@auto-engineer/message-bus": "1.123.0"
21
+ "@auto-engineer/model-factory": "1.125.0",
22
+ "@auto-engineer/message-bus": "1.125.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.123.0"
32
+ "@auto-engineer/cli": "1.125.0"
33
33
  },
34
- "version": "1.123.0",
34
+ "version": "1.125.0",
35
35
  "scripts": {
36
36
  "build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
37
37
  "test": "vitest run --reporter=dot",
@@ -8,6 +8,7 @@ import { SYSTEM_PROMPT } from '../prompts/systemPrompt';
8
8
  import { buildContextSections } from '../utils/buildContextSections';
9
9
  import { buildShadowWarning } from '../utils/detectImportedTypeShadowing';
10
10
  import { extractCodeBlock } from '../utils/extractCodeBlock';
11
+ import { findFilesToImplement } from '../utils/findFilesToImplement';
11
12
  import { loadContextFiles } from '../utils/loadContextFiles';
12
13
  import { runTests } from './runTests';
13
14
 
@@ -36,7 +37,7 @@ export async function runSlice(sliceDir: string, flow: string): Promise<void> {
36
37
  const sliceName = path.basename(sliceDir);
37
38
  console.log(`✏️ Implementing slice: ${sliceName} for flow: ${flow}`);
38
39
  const contextFiles = await loadContextFiles(sliceDir);
39
- const filesToImplement = findFilesToImplement(contextFiles);
40
+ const filesToImplement = findFilesToImplement(contextFiles, needsImplementation);
40
41
  for (const [targetFile] of filesToImplement) {
41
42
  await implementFileFromAI(sliceDir, targetFile, contextFiles);
42
43
  }
@@ -103,10 +104,8 @@ async function retryFailedFiles(
103
104
  return result;
104
105
  }
105
106
 
106
- function findFilesToImplement(contextFiles: Record<string, string>) {
107
- return Object.entries(contextFiles).filter(
108
- ([, content]) => content.includes('TODO:') || content.includes('IMPLEMENTATION INSTRUCTIONS'),
109
- );
107
+ function needsImplementation(content: string): boolean {
108
+ return content.includes('TODO:') || content.includes('IMPLEMENTATION INSTRUCTIONS');
110
109
  }
111
110
 
112
111
  function buildInitialPrompt(targetFile: string, context: Record<string, string>): string {
@@ -8,6 +8,8 @@ import createDebug from 'debug';
8
8
  import { SYSTEM_PROMPT } from '../prompts/systemPrompt';
9
9
  import { buildContextSections } from '../utils/buildContextSections';
10
10
  import { buildShadowWarning } from '../utils/detectImportedTypeShadowing';
11
+ import { extractCodeBlock } from '../utils/extractCodeBlock';
12
+ import { findFilesToImplement } from '../utils/findFilesToImplement';
11
13
  import { loadContextFiles } from '../utils/loadContextFiles';
12
14
 
13
15
  const debug = createDebug('auto:server-implementer:slice');
@@ -95,14 +97,6 @@ export const commandHandler = defineCommandHandler<
95
97
  },
96
98
  });
97
99
 
98
- // Helper function to extract code block from AI response
99
- function extractCodeBlock(text: string): string {
100
- return text
101
- .replace(/```(?:ts|typescript)?/g, '')
102
- .replace(/```/g, '')
103
- .trim();
104
- }
105
-
106
100
  const IMPLEMENTATION_MARKER = '// @auto-implement';
107
101
 
108
102
  function hasImplementationMarker(content: string): boolean {
@@ -122,10 +116,6 @@ function needsImplementation(content: string): boolean {
122
116
  );
123
117
  }
124
118
 
125
- function findFilesToImplement(contextFiles: Record<string, string>): Array<[string, string]> {
126
- return Object.entries(contextFiles).filter(([, content]) => hasImplementationMarker(content));
127
- }
128
-
129
119
  function buildInitialPrompt(targetFile: string, context: Record<string, string>): string {
130
120
  return `
131
121
  ${SYSTEM_PROMPT}
@@ -228,7 +218,7 @@ async function implementSlice(
228
218
 
229
219
  await addMarkersToFiles(slicePath, contextFiles);
230
220
 
231
- const filesToImplement = findFilesToImplement(contextFiles);
221
+ const filesToImplement = findFilesToImplement(contextFiles, hasImplementationMarker);
232
222
  debugProcess(`Found ${filesToImplement.length} files with markers to implement`);
233
223
 
234
224
  if (filesToImplement.length === 0) {
@@ -13,6 +13,8 @@ You are a software engineer implementing @auto-implement files in a sliced event
13
13
  - Complete the logic in the target file following embedded instructions
14
14
  - Return the entire updated file, production-ready
15
15
  - Remove all TODO/instruction comments after implementing
16
+ - Scaffolded files contain fixed generated structure.
17
+ Only change code inside the implementation area indicated by TODOs or instruction comments.
16
18
 
17
19
  ## 3. EMMETT FRAMEWORK PATTERNS
18
20
 
@@ -42,6 +44,9 @@ Projection evolve(document, event) returns updated document.
42
44
  - Never create imports to modules not shown in the provided context.
43
45
  - If you need a type that doesn't exist in any provided file,
44
46
  use inline types or primitive values instead.
47
+ - Preserve existing import statements exactly — do not remove, rename, replace,
48
+ or reorganize them unless a scaffold instruction explicitly requires a change.
49
+ - Use the node: protocol for Node.js built-in modules (e.g., node:crypto, node:path).
45
50
 
46
51
  ## 5. TEST SPECIFICATIONS GUIDANCE
47
52
 
@@ -59,7 +64,6 @@ Projection evolve(document, event) returns updated document.
59
64
  - Immutability: functional patterns, never mutate state
60
65
  - Include ALL required fields in object literals
61
66
  - Preserve index signatures ([key: string]: unknown)
62
- - Do not remove existing imports still referenced
63
67
  - When mapping objects to a typed array, include ALL required fields in each object literal
64
68
 
65
69
  ## 7. SLICE CONVENTIONS
@@ -76,6 +80,9 @@ Projection evolve(document, event) returns updated document.
76
80
  - String literals for enum-typed fields
77
81
  - Hardcoding values that should be computed from inputs
78
82
  - Reproducing literal values from test examples
83
+ - Type assertions and escape hatches such as \`as any\`, \`as unknown as\`, or broad casts to silence errors
84
+ - Changing scaffolded framework calls or helper names unless explicitly instructed by the scaffold
85
+ - Importing types or modules not directly referenced in the implementation code
79
86
 
80
87
  ## 9. OUTPUT
81
88
 
@@ -0,0 +1,90 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { findFilesToImplement } from './findFilesToImplement';
3
+
4
+ describe('findFilesToImplement', () => {
5
+ const hasMarker = (content: string) => content.includes('TODO');
6
+
7
+ it('filters files by predicate', () => {
8
+ const files = {
9
+ 'state.ts': 'TODO: implement',
10
+ 'evolve.ts': 'export const evolve = () => {}',
11
+ 'decide.ts': 'TODO: implement',
12
+ };
13
+
14
+ const result = findFilesToImplement(files, hasMarker);
15
+
16
+ expect(result).toEqual([
17
+ ['state.ts', 'TODO: implement'],
18
+ ['decide.ts', 'TODO: implement'],
19
+ ]);
20
+ });
21
+
22
+ it('sorts priority files in correct order', () => {
23
+ const files = {
24
+ 'decide.ts': 'TODO',
25
+ 'state.ts': 'TODO',
26
+ 'evolve.ts': 'TODO',
27
+ 'events.ts': 'TODO',
28
+ 'commands.ts': 'TODO',
29
+ };
30
+
31
+ const result = findFilesToImplement(files, hasMarker);
32
+
33
+ expect(result).toEqual([
34
+ ['state.ts', 'TODO'],
35
+ ['events.ts', 'TODO'],
36
+ ['commands.ts', 'TODO'],
37
+ ['evolve.ts', 'TODO'],
38
+ ['decide.ts', 'TODO'],
39
+ ]);
40
+ });
41
+
42
+ it('sorts non-priority files after priority files in alphabetical order', () => {
43
+ const files = {
44
+ 'zebra.ts': 'TODO',
45
+ 'decide.ts': 'TODO',
46
+ 'alpha.ts': 'TODO',
47
+ };
48
+
49
+ const result = findFilesToImplement(files, hasMarker);
50
+
51
+ expect(result).toEqual([
52
+ ['decide.ts', 'TODO'],
53
+ ['alpha.ts', 'TODO'],
54
+ ['zebra.ts', 'TODO'],
55
+ ]);
56
+ });
57
+
58
+ it('sorts non-priority files alphabetically among themselves', () => {
59
+ const files = {
60
+ 'zebra.ts': 'TODO',
61
+ 'middleware.ts': 'TODO',
62
+ 'alpha.ts': 'TODO',
63
+ };
64
+
65
+ const result = findFilesToImplement(files, hasMarker);
66
+
67
+ expect(result).toEqual([
68
+ ['alpha.ts', 'TODO'],
69
+ ['middleware.ts', 'TODO'],
70
+ ['zebra.ts', 'TODO'],
71
+ ]);
72
+ });
73
+
74
+ it('returns empty array for empty input', () => {
75
+ const result = findFilesToImplement({}, hasMarker);
76
+
77
+ expect(result).toEqual([]);
78
+ });
79
+
80
+ it('returns empty array when no files match predicate', () => {
81
+ const files = {
82
+ 'state.ts': 'export type State = {}',
83
+ 'evolve.ts': 'export const evolve = () => {}',
84
+ };
85
+
86
+ const result = findFilesToImplement(files, hasMarker);
87
+
88
+ expect(result).toEqual([]);
89
+ });
90
+ });
@@ -0,0 +1,16 @@
1
+ const IMPLEMENTATION_PRIORITY = ['state.ts', 'events.ts', 'commands.ts', 'evolve.ts', 'decide.ts'];
2
+
3
+ export function findFilesToImplement(
4
+ contextFiles: Record<string, string>,
5
+ markerPredicate: (content: string) => boolean,
6
+ ): Array<[string, string]> {
7
+ const files = Object.entries(contextFiles).filter(([, content]) => markerPredicate(content));
8
+ return files.sort(([a], [b]) => {
9
+ const ai = IMPLEMENTATION_PRIORITY.indexOf(a);
10
+ const bi = IMPLEMENTATION_PRIORITY.indexOf(b);
11
+ const ap = ai === -1 ? 999 : ai;
12
+ const bp = bi === -1 ? 999 : bi;
13
+ if (ap !== bp) return ap - bp;
14
+ return a.localeCompare(b);
15
+ });
16
+ }