agent-state-machine 2.0.14 → 2.1.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/bin/cli.js +1 -1
- package/lib/index.js +33 -0
- package/lib/remote/client.js +7 -2
- package/lib/runtime/agent.js +102 -67
- package/lib/runtime/index.js +13 -0
- package/lib/runtime/interaction.js +304 -0
- package/lib/runtime/prompt.js +39 -12
- package/lib/runtime/runtime.js +11 -10
- package/package.json +2 -1
- package/templates/project-builder/README.md +119 -0
- package/templates/project-builder/agents/assumptions-clarifier.md +65 -0
- package/templates/project-builder/agents/code-reviewer.md +81 -0
- package/templates/project-builder/agents/code-writer.md +74 -0
- package/templates/project-builder/agents/requirements-clarifier.md +55 -0
- package/templates/project-builder/agents/response-interpreter.md +25 -0
- package/templates/project-builder/agents/roadmap-generator.md +73 -0
- package/templates/project-builder/agents/sanity-checker.md +45 -0
- package/templates/project-builder/agents/sanity-runner.js +161 -0
- package/templates/project-builder/agents/scope-clarifier.md +44 -0
- package/templates/project-builder/agents/security-clarifier.md +71 -0
- package/templates/project-builder/agents/security-reviewer.md +71 -0
- package/templates/project-builder/agents/task-planner.md +62 -0
- package/templates/project-builder/agents/test-planner.md +76 -0
- package/templates/project-builder/config.js +13 -0
- package/templates/project-builder/scripts/interaction-helpers.js +33 -0
- package/templates/project-builder/scripts/mac-notification.js +24 -0
- package/templates/project-builder/scripts/text-human.js +92 -0
- package/templates/project-builder/scripts/workflow-helpers.js +122 -0
- package/templates/project-builder/state/current.json +9 -0
- package/templates/project-builder/state/history.jsonl +0 -0
- package/templates/project-builder/steering/config.json +5 -0
- package/templates/project-builder/steering/global.md +19 -0
- package/templates/project-builder/workflow.js +554 -0
- package/templates/starter/README.md +118 -0
- package/templates/starter/agents/example.js +36 -0
- package/templates/starter/agents/yoda-greeter.md +12 -0
- package/templates/starter/agents/yoda-name-collector.md +12 -0
- package/templates/starter/config.js +12 -0
- package/templates/starter/interactions/.gitkeep +0 -0
- package/templates/starter/scripts/mac-notification.js +24 -0
- package/templates/starter/state/current.json +9 -0
- package/templates/starter/state/history.jsonl +0 -0
- package/templates/starter/steering/config.json +5 -0
- package/templates/starter/steering/global.md +19 -0
- package/templates/starter/workflow.js +52 -0
- package/vercel-server/api/session/[token].js +3 -3
- package/vercel-server/api/submit/[token].js +5 -3
- package/vercel-server/local-server.js +33 -6
- package/vercel-server/public/remote/index.html +17 -0
- package/vercel-server/ui/index.html +9 -1012
- package/vercel-server/ui/package-lock.json +2650 -0
- package/vercel-server/ui/package.json +25 -0
- package/vercel-server/ui/postcss.config.js +6 -0
- package/vercel-server/ui/src/App.jsx +236 -0
- package/vercel-server/ui/src/components/ChoiceInteraction.jsx +127 -0
- package/vercel-server/ui/src/components/ConfirmInteraction.jsx +51 -0
- package/vercel-server/ui/src/components/ContentCard.jsx +161 -0
- package/vercel-server/ui/src/components/CopyButton.jsx +27 -0
- package/vercel-server/ui/src/components/EventsLog.jsx +82 -0
- package/vercel-server/ui/src/components/Footer.jsx +66 -0
- package/vercel-server/ui/src/components/Header.jsx +38 -0
- package/vercel-server/ui/src/components/InteractionForm.jsx +42 -0
- package/vercel-server/ui/src/components/TextInteraction.jsx +72 -0
- package/vercel-server/ui/src/index.css +145 -0
- package/vercel-server/ui/src/main.jsx +8 -0
- package/vercel-server/ui/tailwind.config.js +19 -0
- package/vercel-server/ui/vite.config.js +11 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
model: med
|
|
3
|
+
format: json
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Security Reviewer Agent
|
|
7
|
+
|
|
8
|
+
You are a security review specialist. Review tasks and implementations for security concerns.
|
|
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
|
+
## Instructions
|
|
23
|
+
|
|
24
|
+
Perform a security review appropriate to the stage:
|
|
25
|
+
|
|
26
|
+
**Pre-Implementation Review (stage: pre-implementation):**
|
|
27
|
+
- Identify potential security concerns for the task
|
|
28
|
+
- Recommend secure implementation patterns
|
|
29
|
+
- Flag any high-risk areas requiring extra attention
|
|
30
|
+
- Suggest security tests to include
|
|
31
|
+
|
|
32
|
+
**Post-Implementation Review (stage: post-implementation):**
|
|
33
|
+
- Review the implementation for security issues
|
|
34
|
+
- Check for common vulnerabilities (OWASP Top 10)
|
|
35
|
+
- Verify secure coding practices
|
|
36
|
+
- Identify any remaining security debt
|
|
37
|
+
|
|
38
|
+
## Output Format
|
|
39
|
+
|
|
40
|
+
Return a valid JSON object:
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
"stage": "pre-implementation",
|
|
44
|
+
"riskLevel": "low",
|
|
45
|
+
"findings": [
|
|
46
|
+
{
|
|
47
|
+
"type": "recommendation",
|
|
48
|
+
"severity": "medium",
|
|
49
|
+
"description": "Consider input validation for user data",
|
|
50
|
+
"recommendation": "Use schema validation library"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"securityChecklist": [
|
|
54
|
+
{"item": "Validate all user inputs", "status": "pending"},
|
|
55
|
+
{"item": "Use parameterized queries", "status": "pending"},
|
|
56
|
+
{"item": "Implement rate limiting", "status": "na"}
|
|
57
|
+
],
|
|
58
|
+
"approved": true,
|
|
59
|
+
"blockers": []
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
**Security Focus Areas:**
|
|
63
|
+
- Input validation and sanitization
|
|
64
|
+
- Authentication and authorization
|
|
65
|
+
- Data encryption (at rest and in transit)
|
|
66
|
+
- Error handling and logging
|
|
67
|
+
- Dependency vulnerabilities
|
|
68
|
+
- Injection attacks (SQL, XSS, command injection)
|
|
69
|
+
- Secure configuration
|
|
70
|
+
|
|
71
|
+
Be thorough but pragmatic. Not every task has major security implications.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
model: high
|
|
3
|
+
format: json
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task Planner Agent
|
|
7
|
+
|
|
8
|
+
You are a task breakdown specialist. Generate detailed task lists for a specific phase as structured JSON.
|
|
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
|
+
## Instructions
|
|
21
|
+
|
|
22
|
+
Break down the phase into specific, actionable tasks. Each task should:
|
|
23
|
+
- Be small enough to complete in a focused work session
|
|
24
|
+
- Have a clear definition of done
|
|
25
|
+
- Include a sanity check the user can verify
|
|
26
|
+
|
|
27
|
+
**Task Principles:**
|
|
28
|
+
- One task = one concern (don't combine unrelated work)
|
|
29
|
+
- Tasks should be independently verifiable
|
|
30
|
+
- Order tasks by dependency (what must come first)
|
|
31
|
+
- Include setup/preparation tasks if needed
|
|
32
|
+
|
|
33
|
+
## Output Format
|
|
34
|
+
|
|
35
|
+
Return a valid JSON object (no markdown code blocks, just raw JSON):
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
"phaseNumber": 1,
|
|
39
|
+
"phaseTitle": "Phase Title",
|
|
40
|
+
"tasks": [
|
|
41
|
+
{
|
|
42
|
+
"id": 1,
|
|
43
|
+
"title": "Task Title",
|
|
44
|
+
"description": "What needs to be done",
|
|
45
|
+
"doneDefinition": "Specific completion criteria that can be verified",
|
|
46
|
+
"sanityCheck": "How the user can verify this is working correctly",
|
|
47
|
+
"stage": "pending"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": 2,
|
|
51
|
+
"title": "Task Title",
|
|
52
|
+
"description": "What needs to be done",
|
|
53
|
+
"doneDefinition": "Specific completion criteria",
|
|
54
|
+
"sanityCheck": "Verification method",
|
|
55
|
+
"stage": "pending"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
**Stage values:** pending, in_progress, completed, failed
|
|
61
|
+
|
|
62
|
+
Keep tasks focused and achievable. Aim for 3-8 tasks per phase depending on complexity. Every task MUST have a doneDefinition and sanityCheck.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
model: med
|
|
3
|
+
format: json
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test Planner Agent
|
|
7
|
+
|
|
8
|
+
You are a test planning specialist. Create test plans for tasks before implementation.
|
|
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
|
+
## Instructions
|
|
20
|
+
|
|
21
|
+
Create a comprehensive test plan for the task. Include:
|
|
22
|
+
|
|
23
|
+
**Test Categories:**
|
|
24
|
+
- Unit tests (individual functions/components)
|
|
25
|
+
- Integration tests (component interactions)
|
|
26
|
+
- Security tests (based on security review)
|
|
27
|
+
- Edge case tests (boundary conditions)
|
|
28
|
+
|
|
29
|
+
**Test Principles:**
|
|
30
|
+
- Test behavior, not implementation
|
|
31
|
+
- Cover happy path and error cases
|
|
32
|
+
- Include tests for security concerns flagged in review
|
|
33
|
+
- Prioritize tests by risk and importance
|
|
34
|
+
|
|
35
|
+
## Output Format
|
|
36
|
+
|
|
37
|
+
Return a valid JSON object:
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
"testPlan": {
|
|
41
|
+
"summary": "Brief description of testing approach",
|
|
42
|
+
"unitTests": [
|
|
43
|
+
{
|
|
44
|
+
"name": "should validate user input",
|
|
45
|
+
"description": "Verify input sanitization works correctly",
|
|
46
|
+
"expectedBehavior": "Invalid input should be rejected with error message",
|
|
47
|
+
"priority": "high"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"integrationTests": [
|
|
51
|
+
{
|
|
52
|
+
"name": "should save and retrieve data",
|
|
53
|
+
"description": "Verify database integration works",
|
|
54
|
+
"components": ["API", "Database"],
|
|
55
|
+
"priority": "high"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"securityTests": [
|
|
59
|
+
{
|
|
60
|
+
"name": "should prevent SQL injection",
|
|
61
|
+
"threat": "SQL injection via user input",
|
|
62
|
+
"testMethod": "Attempt injection with malicious strings",
|
|
63
|
+
"priority": "high"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"edgeCases": [
|
|
67
|
+
{
|
|
68
|
+
"scenario": "Empty input handling",
|
|
69
|
+
"expectedBehavior": "Return validation error"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"testingNotes": "Any special considerations or setup needed"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Focus on tests that validate the definition of done. Don't over-test trivial functionality.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const config = {
|
|
2
|
+
models: {
|
|
3
|
+
low: "gemini",
|
|
4
|
+
med: "gemini",
|
|
5
|
+
high: "gemini",
|
|
6
|
+
},
|
|
7
|
+
apiKeys: {
|
|
8
|
+
gemini: process.env.GEMINI_API_KEY,
|
|
9
|
+
anthropic: process.env.ANTHROPIC_API_KEY,
|
|
10
|
+
openai: process.env.OPENAI_API_KEY,
|
|
11
|
+
},
|
|
12
|
+
remotePath: "TczrLmUecnqZPpPhBTrvU374CGlfzDfINrr0eN0nMgQ",
|
|
13
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction helpers for project-builder template
|
|
3
|
+
*
|
|
4
|
+
* Re-exports core interaction utilities from agent-state-machine
|
|
5
|
+
* and adds an LLM-based interpreter for ambiguous responses.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
agent,
|
|
10
|
+
createInteraction,
|
|
11
|
+
formatInteractionPrompt,
|
|
12
|
+
normalizeInteraction,
|
|
13
|
+
parseInteractionResponse
|
|
14
|
+
} from 'agent-state-machine';
|
|
15
|
+
|
|
16
|
+
// Re-export core utilities
|
|
17
|
+
export { createInteraction, formatInteractionPrompt, normalizeInteraction };
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Parse a response with LLM interpreter fallback
|
|
21
|
+
*
|
|
22
|
+
* Uses the response-interpreter agent when fast-path matching fails.
|
|
23
|
+
*/
|
|
24
|
+
export async function parseResponse(interaction, rawResponse) {
|
|
25
|
+
return parseInteractionResponse(interaction, rawResponse, async (int, raw) => {
|
|
26
|
+
// Use the response-interpreter agent to interpret ambiguous responses
|
|
27
|
+
const result = await agent('response-interpreter', {
|
|
28
|
+
userResponse: raw,
|
|
29
|
+
interaction: int
|
|
30
|
+
});
|
|
31
|
+
return result;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
function escAppleScript(s) {
|
|
7
|
+
return String(s).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function notify(title = "Notification", message = "Everything finished!") {
|
|
11
|
+
const script = `display notification "${escAppleScript(message)}" with title "${escAppleScript(title)}"`;
|
|
12
|
+
spawnSync("osascript", ["-e", script], { stdio: "ignore" });
|
|
13
|
+
|
|
14
|
+
const soundPath = "/System/Library/Sounds/Glass.aiff";
|
|
15
|
+
const fallbackPath = "/System/Library/Sounds/Ping.aiff";
|
|
16
|
+
|
|
17
|
+
if (existsSync(soundPath)) {
|
|
18
|
+
spawnSync("afplay", [soundPath], { stdio: "ignore" });
|
|
19
|
+
} else if (existsSync(fallbackPath)) {
|
|
20
|
+
spawnSync("afplay", [fallbackPath], { stdio: "ignore" });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { notify };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import nodemailer from "nodemailer";
|
|
5
|
+
|
|
6
|
+
function loadEnvFile() {
|
|
7
|
+
if (typeof process.loadEnvFile === "function") {
|
|
8
|
+
process.loadEnvFile();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const envPath = ".env";
|
|
13
|
+
if (!existsSync(envPath)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const lines = readFileSync(envPath, "utf8").split(/\r?\n/);
|
|
18
|
+
for (const line of lines) {
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
|
|
25
|
+
if (!match) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const key = match[1];
|
|
30
|
+
if (process.env[key] !== undefined) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let value = match[2] ?? "";
|
|
35
|
+
if (
|
|
36
|
+
(value.startsWith("\"") && value.endsWith("\"")) ||
|
|
37
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
38
|
+
) {
|
|
39
|
+
value = value.slice(1, -1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
process.env[key] = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function requireEnv(name) {
|
|
47
|
+
const value = process.env[name];
|
|
48
|
+
if (!value) {
|
|
49
|
+
throw new Error(`Missing required env var: ${name}`);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createTransport() {
|
|
55
|
+
const host = requireEnv("SMTP_HOST");
|
|
56
|
+
const port = Number(requireEnv("SMTP_PORT"));
|
|
57
|
+
const user = requireEnv("SMTP_USER");
|
|
58
|
+
const pass = requireEnv("SMTP_PASS");
|
|
59
|
+
const secure = String(process.env.SMTP_SECURE || "").toLowerCase() === "true";
|
|
60
|
+
|
|
61
|
+
return nodemailer.createTransport({
|
|
62
|
+
host,
|
|
63
|
+
port,
|
|
64
|
+
secure,
|
|
65
|
+
auth: {
|
|
66
|
+
user,
|
|
67
|
+
pass,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function textHuman(message) {
|
|
73
|
+
loadEnvFile();
|
|
74
|
+
|
|
75
|
+
if (!message || typeof message !== "string") {
|
|
76
|
+
throw new Error("textHuman(message) requires a non-empty string.");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const from = process.env.SMS_FROM || requireEnv("SMTP_FROM");
|
|
80
|
+
const to = requireEnv("SMS_TO");
|
|
81
|
+
const transporter = createTransport();
|
|
82
|
+
|
|
83
|
+
const info = await transporter.sendMail({
|
|
84
|
+
from,
|
|
85
|
+
to,
|
|
86
|
+
subject: "",
|
|
87
|
+
text: message,
|
|
88
|
+
});
|
|
89
|
+
void info;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { textHuman };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { memory } from 'agent-state-machine';
|
|
4
|
+
|
|
5
|
+
// Write markdown file to workflow state directory
|
|
6
|
+
function writeMarkdownFile(stateDir, filename, content) {
|
|
7
|
+
if (!fs.existsSync(stateDir)) fs.mkdirSync(stateDir, { recursive: true });
|
|
8
|
+
const filePath = path.join(stateDir, filename);
|
|
9
|
+
fs.writeFileSync(filePath, content);
|
|
10
|
+
console.log(` [File] Updated: ${filename}`);
|
|
11
|
+
return filePath;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Strict approval parsing - only accepts explicit approval
|
|
15
|
+
function isApproval(response) {
|
|
16
|
+
if (!response || typeof response !== 'string') return false;
|
|
17
|
+
const trimmed = response.trim().toLowerCase();
|
|
18
|
+
// Must start with 'a' or be exactly 'approve/approved/yes/y'
|
|
19
|
+
return /^a\b/.test(trimmed) ||
|
|
20
|
+
/^approve/.test(trimmed) ||
|
|
21
|
+
/^yes\b/.test(trimmed) ||
|
|
22
|
+
/^y\b/.test(trimmed);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Generate markdown from roadmap JSON
|
|
26
|
+
function renderRoadmapMarkdown(roadmap) {
|
|
27
|
+
if (!roadmap || !roadmap.phases) return '# Project Roadmap\n\nNo phases defined.';
|
|
28
|
+
|
|
29
|
+
let md = `# Project Roadmap: ${roadmap.title || 'Untitled Project'}\n\n`;
|
|
30
|
+
|
|
31
|
+
for (const phase of roadmap.phases) {
|
|
32
|
+
const status = phase.completed ? ' [COMPLETED]' : '';
|
|
33
|
+
md += `## Phase ${phase.number}: ${phase.title}${status}\n`;
|
|
34
|
+
md += `**Objective:** ${phase.objective || 'No objective specified'}\n\n`;
|
|
35
|
+
|
|
36
|
+
for (const item of phase.checklist || []) {
|
|
37
|
+
const check = item.completed ? 'x' : ' ';
|
|
38
|
+
md += `- [${check}] ${item.text}\n`;
|
|
39
|
+
}
|
|
40
|
+
md += '\n';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (roadmap.notes && roadmap.notes.length > 0) {
|
|
44
|
+
md += '---\n\n**Notes:**\n';
|
|
45
|
+
for (const note of roadmap.notes) {
|
|
46
|
+
md += `- ${note}\n`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return md;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Generate markdown from tasks JSON
|
|
54
|
+
function renderTasksMarkdown(phaseNumber, phaseTitle, tasks) {
|
|
55
|
+
if (!tasks || !Array.isArray(tasks)) return `# Phase ${phaseNumber} Tasks\n\nNo tasks defined.`;
|
|
56
|
+
|
|
57
|
+
let md = `# Phase ${phaseNumber} Tasks: ${phaseTitle}\n\n`;
|
|
58
|
+
|
|
59
|
+
for (const task of tasks) {
|
|
60
|
+
const status = task.stage === 'completed' ? ' [COMPLETED]' :
|
|
61
|
+
task.stage === 'in_progress' ? ' [IN PROGRESS]' : '';
|
|
62
|
+
md += `## Task ${task.id}: ${task.title}${status}\n`;
|
|
63
|
+
md += `**Description:** ${task.description || 'No description'}\n\n`;
|
|
64
|
+
md += `**Definition of Done:**\n- ${task.doneDefinition || 'Task completed successfully'}\n\n`;
|
|
65
|
+
md += `**Sanity Check:**\n- ${task.sanityCheck || 'Review the implementation and confirm it meets requirements.'}\n\n`;
|
|
66
|
+
md += '---\n\n';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
md += '## Checklist Summary\n';
|
|
70
|
+
for (const task of tasks) {
|
|
71
|
+
const check = task.stage === 'completed' ? 'x' : ' ';
|
|
72
|
+
md += `- [${check}] Task ${task.id}: ${task.title}\n`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return md;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Task stage management
|
|
79
|
+
const TASK_STAGES = {
|
|
80
|
+
PENDING: 'pending',
|
|
81
|
+
SECURITY_PRE: 'security_pre',
|
|
82
|
+
TEST_PLANNING: 'test_planning',
|
|
83
|
+
IMPLEMENTING: 'implementing',
|
|
84
|
+
CODE_REVIEW: 'code_review',
|
|
85
|
+
SECURITY_POST: 'security_post',
|
|
86
|
+
SANITY_CHECK: 'sanity_check',
|
|
87
|
+
AWAITING_APPROVAL: 'awaiting_approval',
|
|
88
|
+
COMPLETED: 'completed',
|
|
89
|
+
FAILED: 'failed'
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
function getTaskStage(phaseIndex, taskId) {
|
|
93
|
+
const key = `phase_${phaseIndex}_task_${taskId}_stage`;
|
|
94
|
+
return memory[key] || TASK_STAGES.PENDING;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function setTaskStage(phaseIndex, taskId, stage) {
|
|
98
|
+
const key = `phase_${phaseIndex}_task_${taskId}_stage`;
|
|
99
|
+
memory[key] = stage;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getTaskData(phaseIndex, taskId, dataKey) {
|
|
103
|
+
const key = `phase_${phaseIndex}_task_${taskId}_${dataKey}`;
|
|
104
|
+
return memory[key];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function setTaskData(phaseIndex, taskId, dataKey, value) {
|
|
108
|
+
const key = `phase_${phaseIndex}_task_${taskId}_${dataKey}`;
|
|
109
|
+
memory[key] = value;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
writeMarkdownFile,
|
|
114
|
+
isApproval,
|
|
115
|
+
renderRoadmapMarkdown,
|
|
116
|
+
renderTasksMarkdown,
|
|
117
|
+
TASK_STAGES,
|
|
118
|
+
getTaskStage,
|
|
119
|
+
setTaskStage,
|
|
120
|
+
getTaskData,
|
|
121
|
+
setTaskData
|
|
122
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Global Steering Prompt
|
|
2
|
+
|
|
3
|
+
This content is included with every agent execution in the project-builder workflow.
|
|
4
|
+
|
|
5
|
+
## Guidelines
|
|
6
|
+
|
|
7
|
+
- Process data carefully and validate inputs
|
|
8
|
+
- Return well-structured JSON when applicable
|
|
9
|
+
- Log meaningful progress messages
|
|
10
|
+
- Handle errors gracefully
|
|
11
|
+
|
|
12
|
+
## Helpful Tips
|
|
13
|
+
- Scripts live in /workflows/project-builder/scripts/
|
|
14
|
+
- .gitignore includes /workflows so include ignored files when searching for a script and use `search_file_content` with the `no_ignore` flag to read the contents of script files.
|
|
15
|
+
- Shell execution via `run_shell_command` is unavailable, so reproduce the script's intended side effect to fulfill the task.
|
|
16
|
+
|
|
17
|
+
## Notes
|
|
18
|
+
|
|
19
|
+
This file is automatically loaded and passed to every agent in the workflow via `context._steering.global`.
|