agent-state-machine 2.4.0 → 2.6.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 (43) hide show
  1. package/bin/cli.js +7 -7
  2. package/lib/llm.js +14 -3
  3. package/lib/remote/client.js +19 -6
  4. package/lib/runtime/agent.js +29 -2
  5. package/lib/runtime/prompt.js +1 -1
  6. package/lib/runtime/runtime.js +48 -4
  7. package/lib/runtime/track-changes.js +84 -0
  8. package/package.json +1 -1
  9. package/templates/project-builder/agents/{code-writer.md → code-write.md} +18 -12
  10. package/templates/project-builder/agents/{assumptions-clarifier.md → intake-assumptions.md} +1 -0
  11. package/templates/project-builder/agents/{requirements-clarifier.md → intake-requirements.md} +1 -0
  12. package/templates/project-builder/agents/{scope-clarifier.md → intake-scope.md} +1 -0
  13. package/templates/project-builder/agents/{security-clarifier.md → intake-security.md} +1 -0
  14. package/templates/project-builder/agents/{roadmap-generator.md → plan-roadmap.md} +1 -0
  15. package/templates/project-builder/agents/{task-planner.md → plan-tasks.md} +1 -0
  16. package/templates/project-builder/agents/post-code-fix.md +59 -0
  17. package/templates/project-builder/agents/{code-reviewer.md → post-code-review.md} +10 -0
  18. package/templates/project-builder/agents/post-code-security.md +55 -0
  19. package/templates/project-builder/agents/{security-reviewer.md → pre-code-security.md} +8 -11
  20. package/templates/project-builder/agents/{test-planner.md → pre-code-tests.md} +1 -0
  21. package/templates/project-builder/agents/response-interpreter.md +1 -0
  22. package/templates/project-builder/agents/verify-commit-msg.md +64 -0
  23. package/templates/project-builder/agents/{sanity-checker.md → verify-sanity.md} +1 -12
  24. package/templates/project-builder/config.js +15 -4
  25. package/templates/project-builder/scripts/safeguard-recovery.js +40 -0
  26. package/templates/project-builder/scripts/validate-changes.js +61 -0
  27. package/templates/project-builder/scripts/workflow-helpers.js +87 -35
  28. package/templates/project-builder/workflow.js +231 -93
  29. package/vercel-server/api/config/[token].js +76 -0
  30. package/vercel-server/api/history/[token].js +1 -0
  31. package/vercel-server/api/ws/cli.js +39 -20
  32. package/vercel-server/local-server.js +98 -11
  33. package/vercel-server/public/remote/assets/index-BHvHkNOe.css +1 -0
  34. package/vercel-server/public/remote/assets/index-BnuR91vD.js +188 -0
  35. package/vercel-server/public/remote/index.html +2 -2
  36. package/vercel-server/ui/src/App.jsx +35 -0
  37. package/vercel-server/ui/src/components/ContentCard.jsx +183 -5
  38. package/vercel-server/ui/src/components/Header.jsx +59 -11
  39. package/vercel-server/ui/src/components/SettingsModal.jsx +145 -0
  40. package/templates/project-builder/agents/code-fixer.md +0 -50
  41. package/vercel-server/public/remote/assets/index-Bnvi3AUu.js +0 -173
  42. package/vercel-server/public/remote/assets/index-DH2uv4Ll.css +0 -1
  43. /package/templates/project-builder/{agents → scripts}/sanity-runner.js +0 -0
@@ -0,0 +1,55 @@
1
+ ---
2
+ model: med
3
+ format: json
4
+ description: "Post-code phase: Audits implementation for security vulnerabilities"
5
+ ---
6
+
7
+ # Post-Code Security Auditor Agent
8
+
9
+ You are a security auditor. Review implemented code to identify security vulnerabilities and verify secure coding practices.
10
+
11
+ ## How to Audit
12
+
13
+ **Use your file tools to read the files that need auditing.** You will receive a list of file paths. Read each file's contents directly from disk to perform your security audit.
14
+
15
+ ## Instructions
16
+
17
+ Perform a post-implementation security audit:
18
+
19
+ - Review the implementation for security issues
20
+ - Check for common vulnerabilities (OWASP Top 10)
21
+ - Verify secure coding practices
22
+ - Identify any remaining security debt
23
+ - Verify pre-code security recommendations were followed
24
+
25
+ ## Output Format
26
+
27
+ Return a valid JSON object:
28
+
29
+ {
30
+ "riskLevel": "low",
31
+ "findings": [
32
+ {
33
+ "type": "vulnerability",
34
+ "severity": "high",
35
+ "location": "src/auth.js:42",
36
+ "description": "User input not sanitized before database query",
37
+ "recommendation": "Use parameterized query instead"
38
+ }
39
+ ],
40
+ "checklistResults": [
41
+ {"item": "Input validation implemented", "status": "passed"},
42
+ {"item": "SQL injection prevented", "status": "passed"},
43
+ {"item": "Authentication tokens secured", "status": "failed"}
44
+ ],
45
+ "securityDebt": [
46
+ "Consider adding rate limiting in future iteration"
47
+ ],
48
+ "approved": true,
49
+ "blockers": []
50
+ }
51
+
52
+ **Severity levels:** critical, high, medium, low, info
53
+ **Status values:** passed, failed, na
54
+
55
+ Critical and high severity findings should set approved: false and be listed in blockers.
@@ -1,34 +1,27 @@
1
1
  ---
2
2
  model: med
3
3
  format: json
4
+ description: "Pre-code phase: Analyzes security risks before implementation starts"
4
5
  ---
5
6
 
6
- # Security Reviewer Agent
7
+ # Pre-Code Security Reviewer Agent
7
8
 
8
- You are a security review specialist. Review tasks and implementations for security concerns.
9
+ You are a security threat analyst. Analyze tasks BEFORE implementation to identify security risks and recommend secure patterns.
9
10
 
10
11
  ## Instructions
11
12
 
12
- Perform a security review appropriate to the stage:
13
+ Perform a pre-implementation security analysis:
13
14
 
14
- **Pre-Implementation Review (stage: pre-implementation):**
15
15
  - Identify potential security concerns for the task
16
16
  - Recommend secure implementation patterns
17
17
  - Flag any high-risk areas requiring extra attention
18
18
  - Suggest security tests to include
19
19
 
20
- **Post-Implementation Review (stage: post-implementation):**
21
- - Review the implementation for security issues
22
- - Check for common vulnerabilities (OWASP Top 10)
23
- - Verify secure coding practices
24
- - Identify any remaining security debt
25
-
26
20
  ## Output Format
27
21
 
28
22
  Return a valid JSON object:
29
23
 
30
24
  {
31
- "stage": "pre-implementation",
32
25
  "riskLevel": "low",
33
26
  "findings": [
34
27
  {
@@ -43,6 +36,10 @@ Return a valid JSON object:
43
36
  {"item": "Use parameterized queries", "status": "pending"},
44
37
  {"item": "Implement rate limiting", "status": "na"}
45
38
  ],
39
+ "suggestedTests": [
40
+ "Test for SQL injection with malicious input",
41
+ "Verify authentication token validation"
42
+ ],
46
43
  "approved": true,
47
44
  "blockers": []
48
45
  }
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  model: med
3
3
  format: json
4
+ description: "Pre-code phase: Creates test plan before implementation begins"
4
5
  ---
5
6
 
6
7
  # Test Planner Agent
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  model: fast
3
3
  format: json
4
+ description: "Utility: Parses natural language user responses into structured data"
4
5
  ---
5
6
 
6
7
  You are interpreting a user's natural language response against a structured interaction schema.
@@ -0,0 +1,64 @@
1
+ ---
2
+ model: fast
3
+ format: json
4
+ description: "Verify phase: Generates conventional commit message after task completion"
5
+ ---
6
+
7
+ # Commit Message Generator Agent
8
+
9
+ You generate conventional commit messages for completed tasks.
10
+
11
+ ## Input
12
+ - task: { title, description }
13
+ - filesWritten: Array of { path, purpose } for files created/modified
14
+
15
+ ## Output Format
16
+
17
+ Return a valid JSON object:
18
+
19
+ {
20
+ "type": "feat",
21
+ "scope": "auth",
22
+ "message": "add user login functionality",
23
+ "body": "Implements login form with email/password validation.\nAdds JWT token storage and refresh logic."
24
+ }
25
+
26
+ ## Commit Type Guidelines
27
+
28
+ - **feat**: New feature for the user
29
+ - **fix**: Bug fix for the user
30
+ - **refactor**: Code change that neither fixes a bug nor adds a feature
31
+ - **test**: Adding or updating tests
32
+ - **docs**: Documentation only changes
33
+ - **style**: Formatting, missing semicolons, etc (no code change)
34
+ - **chore**: Updating build tasks, configs, etc
35
+
36
+ ## Message Guidelines
37
+
38
+ - Use imperative mood ("add" not "added" or "adds")
39
+ - Keep first line under 72 characters
40
+ - Scope is optional but recommended (component/module name)
41
+ - Body should explain what and why, not how
42
+ - Reference file changes in body when helpful
43
+
44
+ ## Examples
45
+
46
+ Task: "Implement user authentication"
47
+ Files: [{ path: "src/auth.js", purpose: "Auth module" }]
48
+ Output:
49
+ {
50
+ "type": "feat",
51
+ "scope": "auth",
52
+ "message": "implement user authentication",
53
+ "body": "Adds login/logout functionality with JWT tokens.\n\nFiles:\n- src/auth.js: Core auth module"
54
+ }
55
+
56
+ Task: "Fix login validation bug"
57
+ Files: [{ path: "src/auth.js", purpose: "Fix validation" }]
58
+ Output:
59
+ {
60
+ "type": "fix",
61
+ "scope": "auth",
62
+ "message": "correct email validation regex",
63
+ "body": "Email validation was rejecting valid addresses with + symbols."
64
+ }
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  model: fast
3
3
  format: json
4
+ description: "Verify phase: Generates executable sanity checks to validate implementation"
4
5
  ---
5
6
 
6
7
  You generate executable sanity checks for the implemented task.
@@ -37,15 +38,3 @@ Guidelines:
37
38
  - Include at least one file_exists or file_contains check when files are created/modified.
38
39
  - If tests exist (from testPlan or implementation), include a type "test_suite" check.
39
40
  - Use testFramework.command for running tests (optionally target specific files when possible).
40
-
41
- Task:
42
- {{task}}
43
-
44
- Implementation:
45
- {{implementation}}
46
-
47
- Test Plan:
48
- {{testPlan}}
49
-
50
- Test Framework:
51
- {{testFramework}}
@@ -1,9 +1,9 @@
1
1
  export const config = {
2
2
  models: {
3
- fast: "gemini -m gemini-2.5-pro",
4
- low: "gemini -m gemini-2.5-pro",
5
- med: "gemini -m gemini-2.5-pro",
6
- high: "gemini -m gemini-2.5-pro",
3
+ fast: "gemini-2.5-flash",
4
+ low: "gemini-2.5-flash",
5
+ med: "gemini-2.5-flash",
6
+ high: "gemini-2.5-flash",
7
7
  },
8
8
  apiKeys: {
9
9
  gemini: process.env.GEMINI_API_KEY,
@@ -11,6 +11,17 @@ export const config = {
11
11
  openai: process.env.OPENAI_API_KEY,
12
12
  },
13
13
 
14
+ // CLI permission modes - enables native file access for agents
15
+ cliPermissions: {
16
+ claude: 'bypassPermissions', // --permission-mode bypassPermissions
17
+ gemini: 'full', // --approval-mode full
18
+ codex: 'bypass' // --dangerously-bypass-approvals-and-sandbox
19
+ },
20
+
21
+ // Protected paths - prevents DELETION only (modifications allowed)
22
+ // Files matching these patterns cannot be deleted by agents
23
+ protectedPaths: ['.env', '.env.*', 'package.json'],
24
+
14
25
  // File tracking (all optional - shown with defaults)
15
26
  // projectRoot: process.env.PROJECT_ROOT, // Defaults to ../.. from workflow
16
27
  // fileTracking: true, // Enable/disable file tracking
@@ -0,0 +1,40 @@
1
+ import { execSync } from 'child_process';
2
+
3
+ /**
4
+ * Try to auto-fix common validation issues
5
+ * @param {string} projectRoot - Project root directory
6
+ * @param {string[]} violations - Array of violation messages
7
+ * @returns {string[]} Array of fixes applied
8
+ */
9
+ export function autoFixValidationIssues(projectRoot, violations) {
10
+ const fixed = [];
11
+
12
+ for (const violation of violations) {
13
+ if (violation.includes('agent-state-machine')) {
14
+ // Re-install the dependency
15
+ try {
16
+ execSync('npm install agent-state-machine', { cwd: projectRoot, stdio: 'pipe' });
17
+ fixed.push('Reinstalled agent-state-machine');
18
+ } catch (e) {
19
+ // Will fall through to rollback
20
+ }
21
+ }
22
+ }
23
+
24
+ return fixed;
25
+ }
26
+
27
+ /**
28
+ * Rollback a file using git checkout
29
+ * @param {string} projectRoot - Project root directory
30
+ * @param {string} filePath - File path to rollback (relative to projectRoot)
31
+ * @returns {{ success: boolean, error?: string }}
32
+ */
33
+ export function rollbackFile(projectRoot, filePath) {
34
+ try {
35
+ execSync(`git checkout -- "${filePath}"`, { cwd: projectRoot, stdio: 'pipe' });
36
+ return { success: true };
37
+ } catch (e) {
38
+ return { success: false, error: e.message };
39
+ }
40
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * File: /templates/project-builder/scripts/validate-changes.js
3
+ *
4
+ * Project-builder specific validation for file changes.
5
+ * Checks constraints that are specific to this workflow template.
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+
11
+ /**
12
+ * Validate project-builder specific constraints after file changes.
13
+ * - package.json: agent-state-machine dependency must not be removed
14
+ * - Additions and other modifications are allowed
15
+ *
16
+ * @param {string} projectRoot - The project root directory
17
+ * @param {Object} changes - Detected changes { created, modified, deleted, renamed }
18
+ * @returns {{ valid: boolean, violations: string[] }}
19
+ */
20
+ export function validateProjectChanges(projectRoot, changes) {
21
+ const violations = [];
22
+
23
+ // Check package.json modifications (not deletions - that's handled by core protectedPaths)
24
+ if ((changes.modified || []).includes('package.json')) {
25
+ const pkgPath = path.resolve(projectRoot, 'package.json');
26
+ if (fs.existsSync(pkgPath)) {
27
+ try {
28
+ const content = fs.readFileSync(pkgPath, 'utf-8');
29
+ // Only flag if agent-state-machine was removed entirely
30
+ // This allows adding/updating other dependencies
31
+ if (!content.includes('agent-state-machine')) {
32
+ violations.push('package.json: agent-state-machine dependency was removed (not allowed)');
33
+ }
34
+ } catch (err) {
35
+ console.warn(`[validate-changes] Failed to read package.json: ${err.message}`);
36
+ }
37
+ }
38
+ }
39
+
40
+ return { valid: violations.length === 0, violations };
41
+ }
42
+
43
+ /**
44
+ * Check if package.json still has agent-state-machine dependency.
45
+ * Utility for checking after any file write operation.
46
+ *
47
+ * @param {string} projectRoot - The project root directory
48
+ * @returns {boolean} - True if dependency is present
49
+ */
50
+ export function hasAgentStateMachine(projectRoot) {
51
+ const pkgPath = path.resolve(projectRoot, 'package.json');
52
+ if (!fs.existsSync(pkgPath)) {
53
+ return false;
54
+ }
55
+ try {
56
+ const content = fs.readFileSync(pkgPath, 'utf-8');
57
+ return content.includes('agent-state-machine');
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
@@ -1,40 +1,8 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+ import { execSync } from 'child_process';
3
4
  import { memory, getCurrentRuntime } from 'agent-state-machine';
4
5
 
5
- // Write implementation files from code-writer agent output
6
- function writeImplementationFiles(implementation) {
7
- const runtime = getCurrentRuntime();
8
- if (!runtime) {
9
- throw new Error('writeImplementationFiles must be called within a workflow context');
10
- }
11
-
12
- const projectRoot = runtime.workflowConfig.projectRoot;
13
- const files = implementation?.implementation?.files || implementation?.files || [];
14
- const written = [];
15
-
16
- for (const file of files) {
17
- if (!file.path || !file.code) {
18
- console.warn(` [File] Skipping invalid file entry: ${JSON.stringify(file)}`);
19
- continue;
20
- }
21
-
22
- const fullPath = path.resolve(projectRoot, file.path);
23
-
24
- // Ensure directory exists
25
- const dir = path.dirname(fullPath);
26
- if (!fs.existsSync(dir)) {
27
- fs.mkdirSync(dir, { recursive: true });
28
- }
29
-
30
- fs.writeFileSync(fullPath, file.code);
31
- written.push(file.path);
32
- console.log(` [File] Created: ${file.path}`);
33
- }
34
-
35
- return written;
36
- }
37
-
38
6
  // Write markdown file to workflow state directory
39
7
  function writeMarkdownFile(stateDir, filename, content) {
40
8
  if (!fs.existsSync(stateDir)) fs.mkdirSync(stateDir, { recursive: true });
@@ -205,9 +173,90 @@ function detectTestFramework() {
205
173
  return { framework: 'vitest', command: 'npx vitest run', isDefault: true };
206
174
  }
207
175
 
176
+ // Git-based file awareness helpers
177
+
178
+ /**
179
+ * Get list of all tracked files in the project
180
+ * @param {string} projectRoot - Project root directory
181
+ * @returns {string[]} Array of file paths
182
+ */
183
+ function getProjectFiles(projectRoot) {
184
+ try {
185
+ const stdout = execSync('git ls-files', {
186
+ cwd: projectRoot,
187
+ encoding: 'utf-8'
188
+ });
189
+ return stdout.trim().split('\n').filter(Boolean);
190
+ } catch {
191
+ return [];
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Create a git commit with the specified message
197
+ * @param {string} projectRoot - Project root directory
198
+ * @param {string} message - Commit message (can be multi-line)
199
+ * @param {string[]} files - Optional specific files to stage (stages all if empty)
200
+ * @returns {{ success: boolean, hash?: string, error?: string }}
201
+ */
202
+ function createGitCommit(projectRoot, message, files = []) {
203
+ try {
204
+ // Stage files
205
+ if (files.length > 0) {
206
+ // Quote file paths to handle spaces
207
+ const quotedFiles = files.map(f => `"${f}"`).join(' ');
208
+ execSync(`git add ${quotedFiles}`, { cwd: projectRoot, stdio: 'pipe' });
209
+ } else {
210
+ execSync('git add -A', { cwd: projectRoot, stdio: 'pipe' });
211
+ }
212
+
213
+ // Check if there are staged changes
214
+ const status = execSync('git diff --cached --name-only', {
215
+ cwd: projectRoot,
216
+ encoding: 'utf-8'
217
+ }).trim();
218
+
219
+ if (!status) {
220
+ return { success: false, error: 'No changes to commit' };
221
+ }
222
+
223
+ // Commit using stdin to avoid shell escaping issues
224
+ execSync('git commit -F -', {
225
+ cwd: projectRoot,
226
+ input: message,
227
+ stdio: ['pipe', 'pipe', 'pipe']
228
+ });
229
+
230
+ // Get commit hash
231
+ const hash = execSync('git rev-parse --short HEAD', {
232
+ cwd: projectRoot,
233
+ encoding: 'utf-8'
234
+ }).trim();
235
+
236
+ return { success: true, hash };
237
+ } catch (error) {
238
+ return { success: false, error: error.message };
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Ensure a git repository exists at the project root
244
+ * @param {string} projectRoot - Project root directory
245
+ * @returns {{ initialized: boolean, message: string }}
246
+ */
247
+ function ensureGitRepo(projectRoot) {
248
+ try {
249
+ execSync('git rev-parse --git-dir', { cwd: projectRoot, stdio: 'pipe' });
250
+ return { initialized: false, message: 'Git repo already exists' };
251
+ } catch {
252
+ // Not a git repo, initialize it
253
+ execSync('git init', { cwd: projectRoot, stdio: 'pipe' });
254
+ return { initialized: true, message: 'Git repo initialized' };
255
+ }
256
+ }
257
+
208
258
  export {
209
259
  writeMarkdownFile,
210
- writeImplementationFiles,
211
260
  isApproval,
212
261
  renderRoadmapMarkdown,
213
262
  renderTasksMarkdown,
@@ -220,5 +269,8 @@ export {
220
269
  getQuickFixAttempts,
221
270
  incrementQuickFixAttempts,
222
271
  resetQuickFixAttempts,
223
- detectTestFramework
272
+ detectTestFramework,
273
+ getProjectFiles,
274
+ createGitCommit,
275
+ ensureGitRepo
224
276
  };