agent-state-machine 2.1.8 → 2.2.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 (28) hide show
  1. package/README.md +55 -5
  2. package/bin/cli.js +1 -140
  3. package/lib/config-utils.js +259 -0
  4. package/lib/file-tree.js +366 -0
  5. package/lib/index.js +109 -2
  6. package/lib/llm.js +35 -5
  7. package/lib/runtime/agent.js +146 -118
  8. package/lib/runtime/model-resolution.js +128 -0
  9. package/lib/runtime/runtime.js +13 -2
  10. package/lib/runtime/track-changes.js +252 -0
  11. package/package.json +1 -1
  12. package/templates/project-builder/agents/assumptions-clarifier.md +0 -8
  13. package/templates/project-builder/agents/code-reviewer.md +0 -8
  14. package/templates/project-builder/agents/code-writer.md +0 -10
  15. package/templates/project-builder/agents/requirements-clarifier.md +0 -7
  16. package/templates/project-builder/agents/roadmap-generator.md +0 -10
  17. package/templates/project-builder/agents/scope-clarifier.md +0 -6
  18. package/templates/project-builder/agents/security-clarifier.md +0 -9
  19. package/templates/project-builder/agents/security-reviewer.md +0 -12
  20. package/templates/project-builder/agents/task-planner.md +0 -10
  21. package/templates/project-builder/agents/test-planner.md +0 -9
  22. package/templates/project-builder/config.js +13 -1
  23. package/templates/starter/config.js +12 -1
  24. package/vercel-server/public/remote/assets/{index-Cunx4VJE.js → index-BOKpYANC.js} +32 -27
  25. package/vercel-server/public/remote/assets/index-DHL_iHQW.css +1 -0
  26. package/vercel-server/public/remote/index.html +2 -2
  27. package/vercel-server/ui/src/components/ContentCard.jsx +6 -6
  28. package/vercel-server/public/remote/assets/index-D02x57pS.css +0 -1
@@ -0,0 +1,252 @@
1
+ /**
2
+ * File: /lib/runtime/track-changes.js
3
+ *
4
+ * Wraps agent execution with file change tracking.
5
+ * Captures baseline before agent runs, detects changes after,
6
+ * and updates memory.fileTree with the results.
7
+ */
8
+
9
+ import path from 'path';
10
+ import {
11
+ captureBaseline,
12
+ detectChanges,
13
+ normalizePath,
14
+ extractExportsFromFile,
15
+ DEFAULT_IGNORE
16
+ } from '../file-tree.js';
17
+
18
+ /**
19
+ * Wrap an async function with file change tracking.
20
+ * Captures baseline before execution, detects changes after,
21
+ * and updates the runtime's fileTree.
22
+ *
23
+ * @param {Object} runtime - The workflow runtime instance
24
+ * @param {string} agentName - Name of the agent (for attribution)
25
+ * @param {Function} fn - Async function to execute
26
+ * @returns {Promise<any>} - Result of the function
27
+ */
28
+ export async function withChangeTracking(runtime, agentName, fn) {
29
+ const projectRoot = runtime.workflowConfig.projectRoot;
30
+ const ignorePatterns = runtime.workflowConfig.fileTrackingIgnore || DEFAULT_IGNORE;
31
+
32
+ // Capture baseline before agent runs
33
+ const baseline = await captureBaseline(projectRoot, ignorePatterns);
34
+
35
+ // Run the agent
36
+ const result = await fn();
37
+
38
+ // Detect changes made during agent execution
39
+ const changes = await detectChanges(projectRoot, baseline, ignorePatterns);
40
+
41
+ // Update fileTree with detected changes
42
+ applyChangesToFileTree(runtime, changes, agentName);
43
+
44
+ // Merge _files annotations if present (preserves existing data unless explicitly overwritten)
45
+ if (result && typeof result === 'object' && Array.isArray(result._files)) {
46
+ mergeAnnotations(runtime, result._files);
47
+ }
48
+
49
+ return result;
50
+ }
51
+
52
+ /**
53
+ * Apply detected file changes to the runtime's fileTree.
54
+ */
55
+ function applyChangesToFileTree(runtime, changes, agentName) {
56
+ const now = new Date().toISOString();
57
+ const projectRoot = runtime.workflowConfig.projectRoot;
58
+
59
+ // Initialize fileTree if needed
60
+ if (!runtime._rawMemory.fileTree) {
61
+ runtime._rawMemory.fileTree = {};
62
+ }
63
+
64
+ // Handle created files
65
+ for (const filePath of changes.created) {
66
+ try {
67
+ const normalized = normalizePath(filePath, projectRoot);
68
+ runtime._rawMemory.fileTree[normalized] = {
69
+ path: normalized,
70
+ status: 'created',
71
+ createdBy: agentName,
72
+ lastModifiedBy: agentName,
73
+ createdAt: now,
74
+ updatedAt: now
75
+ };
76
+ } catch (e) {
77
+ // Skip files with invalid paths
78
+ console.warn(`[file-tree] Skipping invalid path: ${filePath} - ${e.message}`);
79
+ }
80
+ }
81
+
82
+ // Handle modified files
83
+ for (const filePath of changes.modified) {
84
+ try {
85
+ const normalized = normalizePath(filePath, projectRoot);
86
+ const existing = runtime._rawMemory.fileTree[normalized] || {};
87
+ runtime._rawMemory.fileTree[normalized] = {
88
+ ...existing,
89
+ path: normalized,
90
+ status: 'modified',
91
+ lastModifiedBy: agentName,
92
+ updatedAt: now,
93
+ createdAt: existing.createdAt || now,
94
+ createdBy: existing.createdBy || agentName
95
+ };
96
+ } catch (e) {
97
+ console.warn(`[file-tree] Skipping invalid path: ${filePath} - ${e.message}`);
98
+ }
99
+ }
100
+
101
+ // Handle renamed files (MVP: from/to pairs)
102
+ for (const { from, to } of changes.renamed) {
103
+ try {
104
+ const normalizedFrom = normalizePath(from, projectRoot);
105
+ const normalizedTo = normalizePath(to, projectRoot);
106
+ const existing = runtime._rawMemory.fileTree[normalizedFrom] || {};
107
+ delete runtime._rawMemory.fileTree[normalizedFrom];
108
+ runtime._rawMemory.fileTree[normalizedTo] = {
109
+ ...existing,
110
+ path: normalizedTo,
111
+ status: 'renamed',
112
+ renamedFrom: normalizedFrom,
113
+ lastModifiedBy: agentName,
114
+ updatedAt: now
115
+ };
116
+ } catch (e) {
117
+ console.warn(`[file-tree] Skipping invalid rename: ${from} -> ${to} - ${e.message}`);
118
+ }
119
+ }
120
+
121
+ // Handle deleted files
122
+ for (const filePath of changes.deleted) {
123
+ try {
124
+ const normalized = normalizePath(filePath, projectRoot);
125
+ if (runtime.workflowConfig.fileTrackingKeepDeleted) {
126
+ runtime._rawMemory.fileTree[normalized] = {
127
+ ...runtime._rawMemory.fileTree[normalized],
128
+ status: 'deleted',
129
+ deletedBy: agentName,
130
+ deletedAt: now
131
+ };
132
+ } else {
133
+ delete runtime._rawMemory.fileTree[normalized];
134
+ }
135
+ } catch (e) {
136
+ console.warn(`[file-tree] Skipping invalid path: ${filePath} - ${e.message}`);
137
+ }
138
+ }
139
+
140
+ // Trigger persistence
141
+ runtime.memory.fileTree = runtime._rawMemory.fileTree;
142
+ }
143
+
144
+ /**
145
+ * Merge _files annotations from agent result into fileTree.
146
+ * Only annotates files that were actually detected by change tracking.
147
+ * Preserves existing values unless explicitly overwritten.
148
+ */
149
+ function mergeAnnotations(runtime, files) {
150
+ const projectRoot = runtime.workflowConfig.projectRoot;
151
+
152
+ for (const file of files) {
153
+ if (!file.path) continue;
154
+
155
+ try {
156
+ const normalizedPath = normalizePath(file.path, projectRoot);
157
+ const existing = runtime._rawMemory.fileTree?.[normalizedPath];
158
+
159
+ if (!existing) continue; // Only annotate files that were actually detected
160
+
161
+ // Preserve existing values unless _files explicitly provides new ones
162
+ if (file.caption !== undefined) existing.caption = file.caption;
163
+ if (file.exports !== undefined) existing.exports = file.exports;
164
+ if (file.metadata !== undefined) {
165
+ existing.metadata = { ...existing.metadata, ...file.metadata };
166
+ }
167
+
168
+ // Trigger best-effort export extraction if requested
169
+ if (file.extractExports) {
170
+ const absolutePath = path.resolve(projectRoot, normalizedPath);
171
+ const exports = extractExportsFromFile(absolutePath);
172
+ if (exports) existing.exports = exports;
173
+ }
174
+ } catch (e) {
175
+ console.warn(`[file-tree] Skipping invalid annotation path: ${file.path} - ${e.message}`);
176
+ }
177
+ }
178
+
179
+ // Trigger persistence
180
+ runtime.memory.fileTree = runtime._rawMemory.fileTree;
181
+ }
182
+
183
+ /**
184
+ * Manually track a file in the fileTree.
185
+ * Used for files created outside of agent execution.
186
+ */
187
+ export function trackFile(runtime, relativePath, options = {}) {
188
+ const projectRoot = runtime.workflowConfig.projectRoot;
189
+ const normalized = normalizePath(relativePath, projectRoot);
190
+ const now = new Date().toISOString();
191
+ const agentName = options.agentName || 'manual';
192
+
193
+ // Initialize fileTree if needed
194
+ if (!runtime._rawMemory.fileTree) {
195
+ runtime._rawMemory.fileTree = {};
196
+ }
197
+
198
+ const existing = runtime._rawMemory.fileTree[normalized];
199
+
200
+ const entry = {
201
+ path: normalized,
202
+ status: existing?.status || 'created',
203
+ createdBy: existing?.createdBy || agentName,
204
+ lastModifiedBy: agentName,
205
+ createdAt: existing?.createdAt || now,
206
+ updatedAt: now
207
+ };
208
+
209
+ // Apply options
210
+ if (options.caption !== undefined) entry.caption = options.caption;
211
+ if (options.exports !== undefined) entry.exports = options.exports;
212
+ if (options.metadata !== undefined) {
213
+ entry.metadata = { ...existing?.metadata, ...options.metadata };
214
+ }
215
+
216
+ // Extract exports if requested
217
+ if (options.extractExports) {
218
+ const absolutePath = path.resolve(projectRoot, normalized);
219
+ const exports = extractExportsFromFile(absolutePath);
220
+ if (exports) entry.exports = exports;
221
+ }
222
+
223
+ runtime._rawMemory.fileTree[normalized] = entry;
224
+
225
+ // Trigger persistence
226
+ runtime.memory.fileTree = runtime._rawMemory.fileTree;
227
+
228
+ return entry;
229
+ }
230
+
231
+ /**
232
+ * Get the current fileTree.
233
+ */
234
+ export function getFileTree(runtime) {
235
+ return runtime._rawMemory.fileTree || {};
236
+ }
237
+
238
+ /**
239
+ * Remove a file from tracking.
240
+ */
241
+ export function untrackFile(runtime, relativePath) {
242
+ const projectRoot = runtime.workflowConfig.projectRoot;
243
+ const normalized = normalizePath(relativePath, projectRoot);
244
+
245
+ if (runtime._rawMemory.fileTree?.[normalized]) {
246
+ delete runtime._rawMemory.fileTree[normalized];
247
+ runtime.memory.fileTree = runtime._rawMemory.fileTree;
248
+ return true;
249
+ }
250
+
251
+ return false;
252
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-state-machine",
3
- "version": "2.1.8",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "description": "A workflow orchestrator for running agents and scripts in sequence with state management",
6
6
  "main": "lib/index.js",
@@ -9,14 +9,6 @@ response: choice
9
9
 
10
10
  You are an assumptions and constraints analyst. Your job is to identify and validate assumptions before development.
11
11
 
12
- ## Context
13
- Project Description: {{projectDescription}}
14
- Scope: {{scope}}
15
- Requirements: {{requirements}}
16
- {{#if previousResponse}}
17
- User's Previous Response: {{previousResponse}}
18
- {{/if}}
19
-
20
12
  ## Instructions
21
13
 
22
14
  Identify implicit assumptions that could impact the project. Consider:
@@ -7,14 +7,6 @@ format: json
7
7
 
8
8
  You are a senior code reviewer. Review implementations for quality, correctness, and best practices.
9
9
 
10
- ## Context
11
- Task: {{task}}
12
- Implementation: {{implementation}}
13
- Test Plan: {{testPlan}}
14
- {{#if feedback}}
15
- Previous Feedback: {{feedback}}
16
- {{/if}}
17
-
18
10
  ## Instructions
19
11
 
20
12
  Perform a thorough code review covering:
@@ -7,16 +7,6 @@ format: json
7
7
 
8
8
  You are a senior software developer. Implement the task according to specifications.
9
9
 
10
- ## Context
11
- Task: {{task}}
12
- Phase: {{phase}}
13
- Requirements: {{requirements}}
14
- Test Plan: {{testPlan}}
15
- Security Considerations: {{securityConsiderations}}
16
- {{#if feedback}}
17
- Previous Feedback (IMPORTANT - address these issues): {{feedback}}
18
- {{/if}}
19
-
20
10
  ## Instructions
21
11
 
22
12
  Implement the task following these principles:
@@ -9,13 +9,6 @@ response: choice
9
9
 
10
10
  You are a requirements analysis specialist. Your job is to gather and clarify functional and non-functional requirements.
11
11
 
12
- ## Context
13
- Project Description: {{projectDescription}}
14
- Scope: {{scope}}
15
- {{#if previousResponse}}
16
- User's Previous Response: {{previousResponse}}
17
- {{/if}}
18
-
19
12
  ## Instructions
20
13
 
21
14
  Based on the project description and scope, identify requirements that need clarification. Consider:
@@ -7,16 +7,6 @@ format: json
7
7
 
8
8
  You are a project planning specialist. Generate a phased development roadmap as structured JSON.
9
9
 
10
- ## Context
11
- Project Description: {{projectDescription}}
12
- Scope: {{scope}}
13
- Requirements: {{requirements}}
14
- Assumptions: {{assumptions}}
15
- Security: {{security}}
16
- {{#if feedback}}
17
- User Feedback: {{feedback}}
18
- {{/if}}
19
-
20
10
  ## Instructions
21
11
 
22
12
  Create a phased roadmap as a JSON object. Each phase should:
@@ -9,12 +9,6 @@ response: choice
9
9
 
10
10
  You are a project scope clarification specialist. Your job is to ensure the project scope is well-defined before development begins.
11
11
 
12
- ## Context
13
- Project Description: {{projectDescription}}
14
- {{#if previousResponse}}
15
- User's Previous Response: {{previousResponse}}
16
- {{/if}}
17
-
18
12
  ## Instructions
19
13
 
20
14
  Analyze the project description and determine if the scope is clear. Consider:
@@ -9,15 +9,6 @@ response: choice
9
9
 
10
10
  You are a security requirements specialist. Your job is to identify security needs and concerns early in the project.
11
11
 
12
- ## Context
13
- Project Description: {{projectDescription}}
14
- Scope: {{scope}}
15
- Requirements: {{requirements}}
16
- Assumptions: {{assumptions}}
17
- {{#if previousResponse}}
18
- User's Previous Response: {{previousResponse}}
19
- {{/if}}
20
-
21
12
  ## Instructions
22
13
 
23
14
  Analyze the project for security implications. Consider:
@@ -7,18 +7,6 @@ format: json
7
7
 
8
8
  You are a security review specialist. Review tasks and implementations for security concerns.
9
9
 
10
- ## Context
11
- Task: {{task}}
12
- Phase: {{phase}}
13
- Scope: {{scope}}
14
- Stage: {{stage}}
15
- {{#if implementation}}
16
- Implementation: {{implementation}}
17
- {{/if}}
18
- {{#if feedback}}
19
- Previous Feedback: {{feedback}}
20
- {{/if}}
21
-
22
10
  ## Instructions
23
11
 
24
12
  Perform a security review appropriate to the stage:
@@ -7,16 +7,6 @@ format: json
7
7
 
8
8
  You are a task breakdown specialist. Generate detailed task lists for a specific phase as structured JSON.
9
9
 
10
- ## Context
11
- Project Description: {{projectDescription}}
12
- Scope: {{scope}}
13
- Requirements: {{requirements}}
14
- Phase Number: {{phaseIndex}}
15
- Phase Details: {{phase}}
16
- {{#if feedback}}
17
- User Feedback: {{feedback}}
18
- {{/if}}
19
-
20
10
  ## Instructions
21
11
 
22
12
  Break down the phase into specific, actionable tasks. Each task should:
@@ -7,15 +7,6 @@ format: json
7
7
 
8
8
  You are a test planning specialist. Create test plans for tasks before implementation.
9
9
 
10
- ## Context
11
- Task: {{task}}
12
- Phase: {{phase}}
13
- Requirements: {{requirements}}
14
- Security Considerations: {{securityConsiderations}}
15
- {{#if feedback}}
16
- Previous Feedback: {{feedback}}
17
- {{/if}}
18
-
19
10
  ## Instructions
20
11
 
21
12
  Create a comprehensive test plan for the task. Include:
@@ -1,5 +1,6 @@
1
1
  export const config = {
2
2
  models: {
3
+ fast: "gemini",
3
4
  low: "gemini",
4
5
  med: "gemini",
5
6
  high: "gemini",
@@ -8,5 +9,16 @@ export const config = {
8
9
  gemini: process.env.GEMINI_API_KEY,
9
10
  anthropic: process.env.ANTHROPIC_API_KEY,
10
11
  openai: process.env.OPENAI_API_KEY,
11
- }
12
+ },
13
+
14
+ // File tracking (all optional - shown with defaults)
15
+ // projectRoot: process.env.PROJECT_ROOT, // Defaults to ../.. from workflow
16
+ // fileTracking: true, // Enable/disable file tracking
17
+ // fileTrackingIgnore: [ // Glob patterns to ignore
18
+ // 'node_modules/**',
19
+ // '.git/**',
20
+ // 'dist/**',
21
+ // 'workflows/**'
22
+ // ],
23
+ // fileTrackingKeepDeleted: false // Keep deleted files in tree
12
24
  };
@@ -8,5 +8,16 @@ export const config = {
8
8
  gemini: process.env.GEMINI_API_KEY,
9
9
  anthropic: process.env.ANTHROPIC_API_KEY,
10
10
  openai: process.env.OPENAI_API_KEY,
11
- }
11
+ },
12
+
13
+ // File tracking (all optional - shown with defaults)
14
+ // projectRoot: process.env.PROJECT_ROOT, // Defaults to ../.. from workflow
15
+ // fileTracking: true, // Enable/disable file tracking
16
+ // fileTrackingIgnore: [ // Glob patterns to ignore
17
+ // 'node_modules/**',
18
+ // '.git/**',
19
+ // 'dist/**',
20
+ // 'workflows/**'
21
+ // ],
22
+ // fileTrackingKeepDeleted: false // Keep deleted files in tree
12
23
  };