edsger 0.28.4 ā 0.29.1
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/.claude/settings.local.json +28 -0
- package/.env.local +12 -0
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
- package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
- package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
- package/dist/api/tasks.d.ts +26 -0
- package/dist/api/tasks.js +44 -0
- package/dist/commands/task-worker/index.d.ts +8 -0
- package/dist/commands/task-worker/index.js +34 -0
- package/dist/commands/task-worker/processor.d.ts +23 -0
- package/dist/commands/task-worker/processor.js +81 -0
- package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
- package/dist/commands/workflow/pipeline-runner.js +393 -0
- package/dist/commands/workflow/runner.d.ts +26 -0
- package/dist/commands/workflow/runner.js +119 -0
- package/dist/commands/workflow/workflow-runner.d.ts +26 -0
- package/dist/commands/workflow/workflow-runner.js +119 -0
- package/dist/index.js +7 -0
- package/dist/phases/chat-processor/context.d.ts +1 -0
- package/dist/phases/chat-processor/context.js +1 -0
- package/dist/phases/chat-processor/index.js +2 -0
- package/dist/phases/chat-processor/prompts.d.ts +1 -1
- package/dist/phases/chat-processor/prompts.js +35 -0
- package/dist/phases/chat-processor/tools.js +46 -0
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +32 -0
- package/dist/phases/code-implementation/analyzer.js +629 -0
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
- package/dist/phases/code-implementation/mcp-server.js +93 -0
- package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
- package/dist/phases/code-implementation/prompts-improvement.js +108 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/code-refine/analyzer.d.ts +41 -0
- package/dist/phases/code-refine/analyzer.js +561 -0
- package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
- package/dist/phases/code-refine/context-fetcher.js +423 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
- package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
- package/dist/phases/code-refine-verification/verifier.js +597 -0
- package/dist/phases/code-review/analyzer.d.ts +29 -0
- package/dist/phases/code-review/analyzer.js +363 -0
- package/dist/phases/code-review/context-fetcher.d.ts +92 -0
- package/dist/phases/code-review/context-fetcher.js +296 -0
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
- package/dist/phases/feature-analysis/analyzer.js +208 -0
- package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
- package/dist/phases/feature-analysis/context-fetcher.js +134 -0
- package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
- package/dist/phases/feature-analysis/http-fallback.js +95 -0
- package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
- package/dist/phases/feature-analysis/mcp-server.js +144 -0
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
- package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/task/agent.d.ts +10 -0
- package/dist/phases/task/agent.js +81 -0
- package/dist/phases/task/context.d.ts +16 -0
- package/dist/phases/task/context.js +50 -0
- package/dist/phases/task/index.d.ts +17 -0
- package/dist/phases/task/index.js +54 -0
- package/dist/phases/task/prompts.d.ts +9 -0
- package/dist/phases/task/prompts.js +28 -0
- package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
- package/dist/phases/technical-design/analyzer-helpers.js +39 -0
- package/dist/phases/technical-design/analyzer.d.ts +21 -0
- package/dist/phases/technical-design/analyzer.js +461 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/phases/technical-design/http-fallback.d.ts +17 -0
- package/dist/phases/technical-design/http-fallback.js +151 -0
- package/dist/phases/technical-design/mcp-server.d.ts +1 -0
- package/dist/phases/technical-design/mcp-server.js +157 -0
- package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
- package/dist/phases/technical-design/prompts-improvement.js +93 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
- package/dist/phases/technical-design-verification/verifier.js +170 -0
- package/dist/services/feature-branches.d.ts +77 -0
- package/dist/services/feature-branches.js +205 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +120 -0
- package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
- package/dist/workflow-runner/core/feature-filter.js +46 -0
- package/dist/workflow-runner/core/index.d.ts +8 -0
- package/dist/workflow-runner/core/index.js +12 -0
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
- package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
- package/dist/workflow-runner/core/state-manager.d.ts +24 -0
- package/dist/workflow-runner/core/state-manager.js +42 -0
- package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
- package/dist/workflow-runner/core/workflow-logger.js +65 -0
- package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/phase-executor.js +248 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +119 -0
- package/dist/workflow-runner/index.d.ts +2 -0
- package/dist/workflow-runner/index.js +2 -0
- package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
- package/dist/workflow-runner/pipeline-runner.js +393 -0
- package/dist/workflow-runner/workflow-processor.d.ts +54 -0
- package/dist/workflow-runner/workflow-processor.js +170 -0
- package/package.json +1 -1
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
- package/dist/services/lifecycle-agent/index.d.ts +0 -24
- package/dist/services/lifecycle-agent/index.js +0 -25
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
- package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
- package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
- package/dist/services/lifecycle-agent/transition-rules.js +0 -184
- package/dist/services/lifecycle-agent/types.d.ts +0 -190
- package/dist/services/lifecycle-agent/types.js +0 -12
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature workflow runner with execution mode support
|
|
3
|
+
* Main entry point for running workflow pipelines with different execution modes
|
|
4
|
+
*/
|
|
5
|
+
import { runPipelineByMode } from './pipeline-runner.js';
|
|
6
|
+
import { getFeature } from '../../api/features/get-feature.js';
|
|
7
|
+
import { logError, logInfo } from '../../utils/logger.js';
|
|
8
|
+
/**
|
|
9
|
+
* Run workflow for a feature based on its execution_mode configuration
|
|
10
|
+
*/
|
|
11
|
+
export async function runFeatureWorkflow(options, config) {
|
|
12
|
+
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
13
|
+
try {
|
|
14
|
+
// 1. Get feature details to check execution_mode
|
|
15
|
+
if (verbose) {
|
|
16
|
+
logInfo(`š Fetching feature configuration for: ${featureId}`);
|
|
17
|
+
}
|
|
18
|
+
const feature = await getFeature(mcpServerUrl, mcpToken, featureId, verbose);
|
|
19
|
+
// Debug log raw feature data
|
|
20
|
+
if (verbose) {
|
|
21
|
+
logInfo(`š Feature data from API:`);
|
|
22
|
+
logInfo(` - execution_mode (raw): ${feature.execution_mode}`);
|
|
23
|
+
logInfo(` - execution_mode (type): ${typeof feature.execution_mode}`);
|
|
24
|
+
logInfo(` - is valid: ${isValidExecutionMode(feature.execution_mode || '')}`);
|
|
25
|
+
}
|
|
26
|
+
// 2. Determine execution mode (default to full_pipeline if not set)
|
|
27
|
+
const executionMode = isValidExecutionMode(feature.execution_mode || '')
|
|
28
|
+
? feature.execution_mode
|
|
29
|
+
: 'full_pipeline';
|
|
30
|
+
if (verbose) {
|
|
31
|
+
logInfo(`š Selected execution mode: ${executionMode}`);
|
|
32
|
+
logInfo(`š Mode description: ${getExecutionModeDescription(executionMode)}`);
|
|
33
|
+
}
|
|
34
|
+
// 3. Run pipeline based on execution mode
|
|
35
|
+
return await runPipelineByMode(options, config, executionMode);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
39
|
+
logError(`Failed to run feature workflow: ${errorMessage}`);
|
|
40
|
+
// Return error result
|
|
41
|
+
return [
|
|
42
|
+
{
|
|
43
|
+
featureId,
|
|
44
|
+
phase: 'workflow-initialization',
|
|
45
|
+
status: 'error',
|
|
46
|
+
message: `Workflow initialization failed: ${errorMessage}`,
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Run workflow for a feature with explicit execution mode override
|
|
53
|
+
*/
|
|
54
|
+
export async function runFeatureWorkflowWithMode(options, config, executionMode) {
|
|
55
|
+
const { featureId, verbose } = options;
|
|
56
|
+
if (verbose) {
|
|
57
|
+
logInfo(`š Running workflow with explicit mode: ${executionMode} for feature: ${featureId}`);
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
return await runPipelineByMode(options, config, executionMode);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64
|
+
logError(`Failed to run feature workflow with mode ${executionMode}: ${errorMessage}`);
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
featureId,
|
|
68
|
+
phase: 'workflow-execution',
|
|
69
|
+
status: 'error',
|
|
70
|
+
message: `Workflow execution failed: ${errorMessage}`,
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get available execution modes
|
|
77
|
+
*/
|
|
78
|
+
export function getAvailableExecutionModes() {
|
|
79
|
+
return [
|
|
80
|
+
'full_pipeline',
|
|
81
|
+
'only_feature_analysis',
|
|
82
|
+
'only_technical_design',
|
|
83
|
+
'only_code_implementation',
|
|
84
|
+
'only_functional_testing',
|
|
85
|
+
'only_code_refine',
|
|
86
|
+
'only_code_review',
|
|
87
|
+
'from_feature_analysis',
|
|
88
|
+
'from_technical_design',
|
|
89
|
+
'from_code_implementation',
|
|
90
|
+
'from_functional_testing',
|
|
91
|
+
'from_code_review',
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Validate execution mode
|
|
96
|
+
*/
|
|
97
|
+
export function isValidExecutionMode(mode) {
|
|
98
|
+
return getAvailableExecutionModes().includes(mode);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get execution mode description
|
|
102
|
+
*/
|
|
103
|
+
export function getExecutionModeDescription(mode) {
|
|
104
|
+
const descriptions = {
|
|
105
|
+
full_pipeline: 'Execute complete workflow: analysis ā design ā implementation ā testing',
|
|
106
|
+
only_feature_analysis: 'Execute only: feature analysis',
|
|
107
|
+
only_technical_design: 'Execute only: technical design',
|
|
108
|
+
only_code_implementation: 'Execute only: code implementation',
|
|
109
|
+
only_functional_testing: 'Execute only: functional testing',
|
|
110
|
+
only_code_refine: 'Execute only: code refine (address PR review feedback and verify resolution)',
|
|
111
|
+
only_code_review: 'Execute only: code review (review PR code and create review comments)',
|
|
112
|
+
from_feature_analysis: 'Execute from feature analysis to end: analysis ā design ā implementation ā testing',
|
|
113
|
+
from_technical_design: 'Execute from technical design to end: design ā implementation ā testing',
|
|
114
|
+
from_code_implementation: 'Execute from code implementation to end: implementation ā testing',
|
|
115
|
+
from_functional_testing: 'Execute from functional testing to end: testing',
|
|
116
|
+
from_code_review: 'Execute from code review to end: code-review ā code-refine ā code-refine-verification',
|
|
117
|
+
};
|
|
118
|
+
return descriptions[mode] || 'Unknown execution mode';
|
|
119
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { runRefactor } from './commands/refactor/refactor.js';
|
|
|
11
11
|
import { runInit } from './commands/init/index.js';
|
|
12
12
|
import { runGrowthAnalysis } from './commands/growth-analysis/index.js';
|
|
13
13
|
import { runAgentWorkflow } from './commands/agent-workflow/index.js';
|
|
14
|
+
import { runTaskWorker } from './commands/task-worker/index.js';
|
|
14
15
|
import { runLogin, runLogout, runStatus } from './auth/login.js';
|
|
15
16
|
// Get package.json version dynamically
|
|
16
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -81,6 +82,7 @@ program
|
|
|
81
82
|
.option('--init', 'Initialize .edsger directory with project templates')
|
|
82
83
|
.option('--growth-analysis <productId>', 'Run AI-powered growth analysis for a product')
|
|
83
84
|
.option('--product-level', 'Use legacy product-level workflow (requires EDSGER_PRODUCT_ID, EDSGER_MCP_SERVER_URL, EDSGER_MCP_TOKEN env vars)')
|
|
85
|
+
.option('--watch-tasks <productId>', 'Watch and execute pending tasks for a product')
|
|
84
86
|
.option('--concurrency <number>', 'Max concurrent features to process (default: 3)', parseInt)
|
|
85
87
|
.option('-c, --config <path>', 'Path to config file')
|
|
86
88
|
.option('-v, --verbose', 'Verbose output');
|
|
@@ -99,6 +101,11 @@ export const runEdsger = async (options) => {
|
|
|
99
101
|
await runInit(options);
|
|
100
102
|
return;
|
|
101
103
|
}
|
|
104
|
+
// Handle task watcher mode
|
|
105
|
+
if (options.watchTasks) {
|
|
106
|
+
await runTaskWorker(options);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
102
109
|
// Handle growth analysis mode
|
|
103
110
|
if (options.growthAnalysis) {
|
|
104
111
|
await runGrowthAnalysis(options);
|
|
@@ -36,6 +36,7 @@ export async function buildChatContext(featureId, channelId, verbose) {
|
|
|
36
36
|
}));
|
|
37
37
|
return {
|
|
38
38
|
featureId,
|
|
39
|
+
productId: feature.product_id || '',
|
|
39
40
|
featureDescription: `${feature.name || 'Unknown'}: ${feature.description || 'No description'}`,
|
|
40
41
|
featureStatus: feature.status || 'unknown',
|
|
41
42
|
executionMode: feature.execution_mode || 'unknown',
|
|
@@ -94,6 +94,7 @@ export async function processHumanMessages(messages, featureId, config, verbose)
|
|
|
94
94
|
'',
|
|
95
95
|
`## Channel ID: ${channelId}`,
|
|
96
96
|
`## Feature ID: ${featureId}`,
|
|
97
|
+
`## Product ID: ${context.productId}`,
|
|
97
98
|
'',
|
|
98
99
|
historySection,
|
|
99
100
|
`## Human Message`,
|
|
@@ -196,6 +197,7 @@ export async function processPhaseCompletion(featureId, phase, summary, phaseOut
|
|
|
196
197
|
'',
|
|
197
198
|
`## Channel ID: ${channelId}`,
|
|
198
199
|
`## Feature ID: ${featureId}`,
|
|
200
|
+
`## Product ID: ${context.productId}`,
|
|
199
201
|
'',
|
|
200
202
|
advisorMessage,
|
|
201
203
|
'',
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 1. CHAT_RESPONSE_PROMPT ā responding to human messages
|
|
6
6
|
* 2. NEXT_STEP_ADVISOR_PROMPT ā proactive suggestions after phase completion
|
|
7
7
|
*/
|
|
8
|
-
export declare const CHAT_RESPONSE_PROMPT = "You are an AI assistant embedded in Edsger, a software development platform. You are helping a team develop a feature.\n\n## Your Capabilities\nYou can see the feature's current state, user stories, test cases, workflow phases, and code. You have tools to:\n- Modify feature status, execution mode, and workflow phases\n- Create/update user stories and test cases\n- Read and search source code files\n- Send follow-up messages and present options to the user\n- Trigger phase reruns\n\n## How to Respond\n1. **Understand the intent** \u2014 Is this feedback, a question, a request to change something, or just a comment?\n2. **Take action if needed** \u2014 Use the appropriate tools to make changes\n3. **Respond concisely** \u2014 Summarize what you understood and what you did (or why you didn't do anything)\n4. **Ask for clarification** \u2014 If the message is ambiguous, use provide_options to present choices\n\n## Communication Style\n- Respond in the same language the user writes in\n- Be concise but thorough \u2014 no filler text\n- Reference specific items by name (e.g., \"User Story #3: Login flow\")\n- When making changes, always explain what you changed and why\n\n## Phase Reference (know what each phase does before suggesting it)\n- **code-implementation**: Writes/updates production code (creates or modifies code)\n- **pr-execution**: Syncs already-written code from dev branch to split PR branches (does NOT write new code)\n- **bug-fixing**: Fixes code bugs and test failures\n- To fix bugs or update code \u2192 suggest **code-implementation** or **bug-fixing**, NOT pr-execution\n\n## Important Rules\n- Never make destructive changes without confirmation (deleting stories, resetting phases)\n- For ambiguous feedback, present options rather than guessing\n- If you can't do something, explain why clearly\n";
|
|
8
|
+
export declare const CHAT_RESPONSE_PROMPT = "You are an AI assistant embedded in Edsger, a software development platform. You are helping a team develop a feature.\n\n## Your Capabilities\nYou can see the feature's current state, user stories, test cases, workflow phases, and code. You have tools to:\n- Modify feature status, execution mode, and workflow phases\n- Create/update user stories and test cases\n- Read and search source code files\n- Send follow-up messages and present options to the user\n- Trigger phase reruns\n- Create tasks for team members (human) or AI\n- Look up product team members by name\n\n## How to Respond\n1. **Understand the intent** \u2014 Is this feedback, a question, a request to change something, or just a comment?\n2. **Take action if needed** \u2014 Use the appropriate tools to make changes\n3. **Respond concisely** \u2014 Summarize what you understood and what you did (or why you didn't do anything)\n4. **Ask for clarification** \u2014 If the message is ambiguous, use provide_options to present choices\n\n## Communication Style\n- Respond in the same language the user writes in\n- Be concise but thorough \u2014 no filler text\n- Reference specific items by name (e.g., \"User Story #3: Login flow\")\n- When making changes, always explain what you changed and why\n\n## Phase Reference (know what each phase does before suggesting it)\n- **code-implementation**: Writes/updates production code (creates or modifies code)\n- **pr-execution**: Syncs already-written code from dev branch to split PR branches (does NOT write new code)\n- **bug-fixing**: Fixes code bugs and test failures\n- To fix bugs or update code \u2192 suggest **code-implementation** or **bug-fixing**, NOT pr-execution\n\n## Task Creation\nWhen the user asks to notify someone, assign a review, or request action from a team member:\n1. Use list_product_members to find the person by name\n2. Use create_task with executor=\"human\", the resolved user ID, and the correct action_url\n3. Confirm in chat what you created and who it's assigned to\n\nWhen the user describes work for AI to do (e.g., \"implement X\", \"fix Y\"):\n1. Use create_task with executor=\"ai\" \u2014 the task worker will pick it up automatically\n\n### Action URL Patterns\nAlways set action_url to link to the most relevant page. Available patterns:\n- Product page: `/products/{product_id}`\n- Feature details: `/products/{product_id}/features/{feature_id}`\n- Feature tab (append ?tab=): `/products/{product_id}/features/{feature_id}?tab={tab}`\n\nAvailable feature tabs:\n- `stories` \u2014 User Stories (use for: review user stories, update stories)\n- `test-cases` \u2014 Test Cases (use for: review test cases, verify tests)\n- `technical-design` \u2014 Technical Design (use for: review design, architecture review)\n- `checklists` \u2014 Checklists (use for: review checklists, quality checks)\n- `branches` \u2014 Branches (use for: code review, branch management)\n- `pull-requests` \u2014 Pull Requests (use for: review PRs, merge requests)\n- `test-reports` \u2014 Test Reports (use for: review test results)\n- `feedbacks` \u2014 Feedbacks (use for: provide feedback)\n- `chat` \u2014 Chat (use for: discussion)\n- `details` \u2014 Feature Details (default)\n\nChoose the tab that best matches the task content. For example:\n- \"review user stories\" \u2192 `?tab=stories`\n- \"review technical design\" \u2192 `?tab=technical-design`\n- \"check test results\" \u2192 `?tab=test-reports`\n\n## Important Rules\n- Never make destructive changes without confirmation (deleting stories, resetting phases)\n- For ambiguous feedback, present options rather than guessing\n- If you can't do something, explain why clearly\n- When creating tasks for people, always confirm the person's identity if the name is ambiguous\n";
|
|
9
9
|
export declare const NEXT_STEP_ADVISOR_PROMPT = "You are an AI advisor in Edsger, a software development platform. A workflow phase just completed for a feature you're helping develop.\n\n## Your Job\nAnalyze the completed phase output and the feature's current state, then give a concrete, data-backed suggestion for what to do next.\n\n## Critical Rules\n1. **Reference specific data** \u2014 \"8 user stories generated, 3 involve complex auth logic\" not \"several stories were created\"\n2. **Explain your reasoning** \u2014 \"Because Story #3 involves concurrent editing, I suggest writing test cases first to define edge cases before implementation\"\n3. **Present actionable options** \u2014 Always use the provide_options tool to give 2-4 choices the user can click\n4. **Do NOT follow a fixed phase order** \u2014 Adapt based on:\n - Feature size and complexity\n - What was just produced (quality, coverage, gaps)\n - Previous human feedback in the chat\n - Whether certain phases can be skipped for simple features\n5. **Flag issues proactively** \u2014 If the phase output has gaps, incomplete coverage, or potential problems, call them out\n\n## Phase Reference (know what each phase does before suggesting it)\n- **code-implementation**: Writes/updates production code (the phase that creates or modifies code)\n- **pr-splitting**: Plans how to split code changes into reviewable PRs\n- **pr-execution**: Syncs already-written code from the dev branch to split PR branches (does NOT write new code)\n- **code-testing**: Writes automated tests for implemented code\n- **functional-testing**: Runs end-to-end tests with Playwright\n- **bug-fixing**: Fixes code bugs and test failures\n- **code-review**: Reviews PR code for issues\n- **code-refine**: Updates code based on PR review feedback\n\n**Important distinctions:**\n- To fix bugs or update code \u2192 use **code-implementation** or **bug-fixing**, NOT pr-execution\n- pr-execution only moves existing code to PR branches \u2014 it never creates or modifies implementation code\n\n## Context You Receive\n- Feature description, size, and current state\n- The completed phase name and its full output\n- Remaining workflow phases (with descriptions)\n- User story and test case counts\n- Code change scope (if applicable)\n- Recent chat history (human feedback)\n\n## Communication Style\n- Respond in the same language as recent chat messages (default to the feature's language context)\n- Be specific and data-driven\n- Structure: brief summary \u2192 reasoning \u2192 options\n";
|
|
10
10
|
/**
|
|
11
11
|
* Phase descriptions so the AI advisor understands what each phase does.
|
|
@@ -14,6 +14,8 @@ You can see the feature's current state, user stories, test cases, workflow phas
|
|
|
14
14
|
- Read and search source code files
|
|
15
15
|
- Send follow-up messages and present options to the user
|
|
16
16
|
- Trigger phase reruns
|
|
17
|
+
- Create tasks for team members (human) or AI
|
|
18
|
+
- Look up product team members by name
|
|
17
19
|
|
|
18
20
|
## How to Respond
|
|
19
21
|
1. **Understand the intent** ā Is this feedback, a question, a request to change something, or just a comment?
|
|
@@ -33,10 +35,43 @@ You can see the feature's current state, user stories, test cases, workflow phas
|
|
|
33
35
|
- **bug-fixing**: Fixes code bugs and test failures
|
|
34
36
|
- To fix bugs or update code ā suggest **code-implementation** or **bug-fixing**, NOT pr-execution
|
|
35
37
|
|
|
38
|
+
## Task Creation
|
|
39
|
+
When the user asks to notify someone, assign a review, or request action from a team member:
|
|
40
|
+
1. Use list_product_members to find the person by name
|
|
41
|
+
2. Use create_task with executor="human", the resolved user ID, and the correct action_url
|
|
42
|
+
3. Confirm in chat what you created and who it's assigned to
|
|
43
|
+
|
|
44
|
+
When the user describes work for AI to do (e.g., "implement X", "fix Y"):
|
|
45
|
+
1. Use create_task with executor="ai" ā the task worker will pick it up automatically
|
|
46
|
+
|
|
47
|
+
### Action URL Patterns
|
|
48
|
+
Always set action_url to link to the most relevant page. Available patterns:
|
|
49
|
+
- Product page: \`/products/{product_id}\`
|
|
50
|
+
- Feature details: \`/products/{product_id}/features/{feature_id}\`
|
|
51
|
+
- Feature tab (append ?tab=): \`/products/{product_id}/features/{feature_id}?tab={tab}\`
|
|
52
|
+
|
|
53
|
+
Available feature tabs:
|
|
54
|
+
- \`stories\` ā User Stories (use for: review user stories, update stories)
|
|
55
|
+
- \`test-cases\` ā Test Cases (use for: review test cases, verify tests)
|
|
56
|
+
- \`technical-design\` ā Technical Design (use for: review design, architecture review)
|
|
57
|
+
- \`checklists\` ā Checklists (use for: review checklists, quality checks)
|
|
58
|
+
- \`branches\` ā Branches (use for: code review, branch management)
|
|
59
|
+
- \`pull-requests\` ā Pull Requests (use for: review PRs, merge requests)
|
|
60
|
+
- \`test-reports\` ā Test Reports (use for: review test results)
|
|
61
|
+
- \`feedbacks\` ā Feedbacks (use for: provide feedback)
|
|
62
|
+
- \`chat\` ā Chat (use for: discussion)
|
|
63
|
+
- \`details\` ā Feature Details (default)
|
|
64
|
+
|
|
65
|
+
Choose the tab that best matches the task content. For example:
|
|
66
|
+
- "review user stories" ā \`?tab=stories\`
|
|
67
|
+
- "review technical design" ā \`?tab=technical-design\`
|
|
68
|
+
- "check test results" ā \`?tab=test-reports\`
|
|
69
|
+
|
|
36
70
|
## Important Rules
|
|
37
71
|
- Never make destructive changes without confirmation (deleting stories, resetting phases)
|
|
38
72
|
- For ambiguous feedback, present options rather than guessing
|
|
39
73
|
- If you can't do something, explain why clearly
|
|
74
|
+
- When creating tasks for people, always confirm the person's identity if the name is ambiguous
|
|
40
75
|
`;
|
|
41
76
|
export const NEXT_STEP_ADVISOR_PROMPT = `You are an AI advisor in Edsger, a software development platform. A workflow phase just completed for a feature you're helping develop.
|
|
42
77
|
|
|
@@ -279,6 +279,52 @@ export function createChatMcpServer() {
|
|
|
279
279
|
],
|
|
280
280
|
};
|
|
281
281
|
}),
|
|
282
|
+
tool('create_task', 'Create a task for a team member (human) or for AI to execute. Use this when the user asks to assign work, request reviews, or notify someone about something they need to do.', {
|
|
283
|
+
product_id: z.string().describe('Product ID'),
|
|
284
|
+
name: z.string().describe('Short task name (e.g., "Review user stories for Login feature")'),
|
|
285
|
+
description: z.string().optional().describe('Detailed description of what needs to be done'),
|
|
286
|
+
executor: z.enum(['ai', 'human']).describe('Who should do this: "ai" for automated work, "human" for manual review/approval'),
|
|
287
|
+
assigned_to: z.string().optional().describe('User ID to assign to (use list_product_members to look up)'),
|
|
288
|
+
feature_id: z.string().optional().describe('Related feature ID'),
|
|
289
|
+
action_url: z.string().optional().describe('URL where the assignee should take action. See prompt for URL patterns.'),
|
|
290
|
+
priority: z.number().optional().describe('1=low, 2=medium, 3=high, 4=urgent'),
|
|
291
|
+
}, async (args) => {
|
|
292
|
+
// Get next sequence number
|
|
293
|
+
const listResult = (await callMcpEndpoint('tasks/list_for_product', {
|
|
294
|
+
product_id: args.product_id,
|
|
295
|
+
}));
|
|
296
|
+
const text = listResult?.content?.[0]?.text || '[]';
|
|
297
|
+
const existingTasks = JSON.parse(text);
|
|
298
|
+
const nextSequence = existingTasks.length + 1;
|
|
299
|
+
// Use explicit action_url if provided, otherwise auto-generate from feature_id
|
|
300
|
+
const actionUrl = args.action_url
|
|
301
|
+
|| (args.feature_id ? `/products/${args.product_id}/features/${args.feature_id}` : null);
|
|
302
|
+
const result = await callMcpEndpoint('tasks/create', {
|
|
303
|
+
product_id: args.product_id,
|
|
304
|
+
sequence: nextSequence,
|
|
305
|
+
name: args.name,
|
|
306
|
+
description: args.description || null,
|
|
307
|
+
executor: args.executor,
|
|
308
|
+
source: 'system',
|
|
309
|
+
assigned_to: args.assigned_to || null,
|
|
310
|
+
feature_id: args.feature_id || null,
|
|
311
|
+
action_url: actionUrl,
|
|
312
|
+
priority: args.priority || (args.executor === 'human' ? 3 : 2),
|
|
313
|
+
});
|
|
314
|
+
return {
|
|
315
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
316
|
+
};
|
|
317
|
+
}),
|
|
318
|
+
tool('list_product_members', 'List all members of a product (owner + developers) with their names, emails, and IDs. Use this to look up a person by name before assigning tasks.', {
|
|
319
|
+
product_id: z.string().describe('Product ID'),
|
|
320
|
+
}, async (args) => {
|
|
321
|
+
const result = await callMcpEndpoint('tasks/product_members', {
|
|
322
|
+
product_id: args.product_id,
|
|
323
|
+
});
|
|
324
|
+
return {
|
|
325
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
326
|
+
};
|
|
327
|
+
}),
|
|
282
328
|
tool('trigger_phase_rerun', 'Reset a workflow phase to pending so it will re-run.', {
|
|
283
329
|
feature_id: z.string().describe('Feature ID'),
|
|
284
330
|
phase: z.string().describe('Phase name to reset'),
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
2
|
+
import { ChecklistPhaseContext } from '../../services/checklist.js';
|
|
3
|
+
import { ChecklistVerificationResult } from '../code-implementation-verification/agent.js';
|
|
4
|
+
import { CodeImplementationResult } from './index.js';
|
|
5
|
+
export interface VerificationCycleResult {
|
|
6
|
+
passed: boolean;
|
|
7
|
+
verificationResult: ChecklistVerificationResult | null;
|
|
8
|
+
nextPrompt: string | null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Perform a complete verification cycle:
|
|
12
|
+
* 1. Verify code implementation against checklist
|
|
13
|
+
* 2. Log results to audit logs
|
|
14
|
+
* 3. Create improvement prompt if verification failed
|
|
15
|
+
*/
|
|
16
|
+
export declare function performVerificationCycle(branchName: string, baseBranch: string, checklistContext: ChecklistPhaseContext | null, featureId: string, featureName: string, featureDescription: string | undefined, config: EdsgerConfig, currentIteration: number, maxIterations: number, verbose?: boolean): Promise<VerificationCycleResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Build successful implementation result
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildImplementationResult(featureId: string, branchName: string, implementationSummary: string, filesModified: string[], commitHash: string, iterations: number, checklistResults?: any[], checklistItemResults?: any[]): CodeImplementationResult;
|
|
21
|
+
/**
|
|
22
|
+
* Build verification failure result
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildVerificationFailureResult(featureId: string, branchName: string, implementationSummary: string, filesModified: string[], commitHash: string, verificationResult: ChecklistVerificationResult, iterations: number): CodeImplementationResult;
|
|
25
|
+
/**
|
|
26
|
+
* Build error result for no implementation
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildNoResultsError(featureId: string, branchName: string): CodeImplementationResult;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { logInfo, logError } from '../../utils/logger.js';
|
|
2
|
+
import { logFeatureVerificationEvent } from '../../services/audit-logs.js';
|
|
3
|
+
import { formatChecklistsForContext, processChecklistItemResultsFromResponse, } from '../../services/checklist.js';
|
|
4
|
+
import { verifyCodeImplementationCompliance, } from '../code-implementation-verification/agent.js';
|
|
5
|
+
import { createCodeImplementationImprovementPrompt } from './prompts.js';
|
|
6
|
+
/**
|
|
7
|
+
* Perform a complete verification cycle:
|
|
8
|
+
* 1. Verify code implementation against checklist
|
|
9
|
+
* 2. Log results to audit logs
|
|
10
|
+
* 3. Create improvement prompt if verification failed
|
|
11
|
+
*/
|
|
12
|
+
export async function performVerificationCycle(branchName, baseBranch, checklistContext, featureId, featureName, featureDescription, config, currentIteration, maxIterations, verbose) {
|
|
13
|
+
// If no checklist, verification passes automatically
|
|
14
|
+
if (!checklistContext || checklistContext.checklists.length === 0) {
|
|
15
|
+
if (verbose) {
|
|
16
|
+
logInfo('ā¹ļø No checklists to verify - skipping verification');
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
passed: true,
|
|
20
|
+
verificationResult: null,
|
|
21
|
+
nextPrompt: null,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (verbose) {
|
|
25
|
+
logInfo(`\nš Verifying code implementation (iteration ${currentIteration}/${maxIterations})...`);
|
|
26
|
+
}
|
|
27
|
+
// Format checklist context for verification
|
|
28
|
+
const checklistInfo = formatChecklistsForContext(checklistContext);
|
|
29
|
+
// Perform verification
|
|
30
|
+
const verificationResult = await verifyCodeImplementationCompliance({
|
|
31
|
+
featureId,
|
|
32
|
+
branchName,
|
|
33
|
+
baseBranch,
|
|
34
|
+
featureName,
|
|
35
|
+
featureDescription,
|
|
36
|
+
checklistContext: checklistInfo,
|
|
37
|
+
verbose,
|
|
38
|
+
}, config);
|
|
39
|
+
// Determine if verification passed
|
|
40
|
+
const verificationPassed = verificationResult.rejected_count === 0;
|
|
41
|
+
// Log verification result
|
|
42
|
+
if (verificationPassed) {
|
|
43
|
+
if (verbose) {
|
|
44
|
+
logInfo(`ā
Code verification passed: ${verificationResult.confirmed_count} confirmed, ${verificationResult.uncertain_count} uncertain`);
|
|
45
|
+
}
|
|
46
|
+
await logFeatureVerificationEvent({
|
|
47
|
+
featureId,
|
|
48
|
+
phase: 'code_implementation',
|
|
49
|
+
iteration: currentIteration,
|
|
50
|
+
result: 'success',
|
|
51
|
+
verificationData: {
|
|
52
|
+
confirmed_count: verificationResult.confirmed_count,
|
|
53
|
+
rejected_count: verificationResult.rejected_count,
|
|
54
|
+
uncertain_count: verificationResult.uncertain_count,
|
|
55
|
+
summary: verificationResult.summary,
|
|
56
|
+
},
|
|
57
|
+
}, verbose);
|
|
58
|
+
// Create checklist results based on verification result
|
|
59
|
+
const checklistItemResults = verificationResult.item_verifications.map((item) => ({
|
|
60
|
+
checklist_item_id: item.checklist_item_id,
|
|
61
|
+
is_passed: item.is_satisfied && item.verification_status === 'confirmed',
|
|
62
|
+
value: item.verification_status,
|
|
63
|
+
notes: item.verification_reason || undefined,
|
|
64
|
+
}));
|
|
65
|
+
await processChecklistItemResultsFromResponse({ featureId }, 'code_implementation', checklistItemResults, verbose);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
logError(`ā Iteration ${currentIteration}: Code verification FAILED - ${verificationResult.rejected_count} items rejected, ${verificationResult.uncertain_count} uncertain`);
|
|
69
|
+
await logFeatureVerificationEvent({
|
|
70
|
+
featureId,
|
|
71
|
+
phase: 'code_implementation',
|
|
72
|
+
iteration: currentIteration,
|
|
73
|
+
result: 'error',
|
|
74
|
+
verificationData: {
|
|
75
|
+
confirmed_count: verificationResult.confirmed_count,
|
|
76
|
+
rejected_count: verificationResult.rejected_count,
|
|
77
|
+
uncertain_count: verificationResult.uncertain_count,
|
|
78
|
+
rejected_items: verificationResult.item_verifications
|
|
79
|
+
.filter((item) => item.verification_status === 'rejected')
|
|
80
|
+
.map((item) => ({
|
|
81
|
+
checklist_item_id: item.checklist_item_id,
|
|
82
|
+
reason: item.verification_reason || 'No reason provided',
|
|
83
|
+
concerns: item.concerns || [],
|
|
84
|
+
improvement_suggestions: item.improvement_suggestions || [],
|
|
85
|
+
})),
|
|
86
|
+
uncertain_items: verificationResult.item_verifications
|
|
87
|
+
.filter((item) => item.verification_status === 'uncertain')
|
|
88
|
+
.map((item) => ({
|
|
89
|
+
checklist_item_id: item.checklist_item_id,
|
|
90
|
+
reason: item.verification_reason || 'No reason provided',
|
|
91
|
+
concerns: item.concerns || [],
|
|
92
|
+
improvement_suggestions: item.improvement_suggestions || [],
|
|
93
|
+
})),
|
|
94
|
+
summary: verificationResult.summary,
|
|
95
|
+
overall_suggestions: verificationResult.overall_suggestions || [],
|
|
96
|
+
},
|
|
97
|
+
}, verbose);
|
|
98
|
+
}
|
|
99
|
+
// If verification failed and we have iterations left, create improvement prompt
|
|
100
|
+
let nextPrompt = null;
|
|
101
|
+
if (!verificationPassed && currentIteration < maxIterations) {
|
|
102
|
+
nextPrompt = createCodeImplementationImprovementPrompt(verificationResult, branchName, baseBranch);
|
|
103
|
+
if (verbose) {
|
|
104
|
+
logInfo(`\nš Created improvement prompt for next iteration (${maxIterations - currentIteration} attempts remaining)`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (!verificationPassed) {
|
|
108
|
+
// Max iterations reached - create checklist results based on final verification
|
|
109
|
+
if (verbose) {
|
|
110
|
+
logInfo(`\nš Creating checklist results for final iteration (max iterations reached)`);
|
|
111
|
+
}
|
|
112
|
+
// Create checklist results for all items (both passed and failed)
|
|
113
|
+
const checklistItemResults = verificationResult.item_verifications.map((item) => ({
|
|
114
|
+
checklist_item_id: item.checklist_item_id,
|
|
115
|
+
is_passed: item.is_satisfied && item.verification_status === 'confirmed',
|
|
116
|
+
value: item.verification_status,
|
|
117
|
+
notes: item.verification_reason || undefined,
|
|
118
|
+
}));
|
|
119
|
+
await processChecklistItemResultsFromResponse({ featureId }, 'code_implementation', checklistItemResults, verbose);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
passed: verificationPassed,
|
|
123
|
+
verificationResult,
|
|
124
|
+
nextPrompt,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Build successful implementation result
|
|
129
|
+
*/
|
|
130
|
+
export function buildImplementationResult(featureId, branchName, implementationSummary, filesModified, commitHash, iterations, checklistResults, checklistItemResults) {
|
|
131
|
+
return {
|
|
132
|
+
featureId,
|
|
133
|
+
branchName,
|
|
134
|
+
implementationSummary,
|
|
135
|
+
status: 'success',
|
|
136
|
+
message: 'Code implementation completed successfully',
|
|
137
|
+
filesModified,
|
|
138
|
+
commitHash,
|
|
139
|
+
data: {
|
|
140
|
+
checklist_results: checklistResults,
|
|
141
|
+
checklist_item_results: checklistItemResults,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Build verification failure result
|
|
147
|
+
*/
|
|
148
|
+
export function buildVerificationFailureResult(featureId, branchName, implementationSummary, filesModified, commitHash, verificationResult, iterations) {
|
|
149
|
+
return {
|
|
150
|
+
featureId,
|
|
151
|
+
branchName,
|
|
152
|
+
implementationSummary,
|
|
153
|
+
status: 'error',
|
|
154
|
+
message: `Code implementation verification failed after ${iterations} iterations. Code committed for manual review.`,
|
|
155
|
+
filesModified,
|
|
156
|
+
commitHash,
|
|
157
|
+
data: {
|
|
158
|
+
verification_failed: true,
|
|
159
|
+
verification_summary: verificationResult.summary,
|
|
160
|
+
rejected_count: verificationResult.rejected_count,
|
|
161
|
+
uncertain_count: verificationResult.uncertain_count,
|
|
162
|
+
improvement_suggestions: verificationResult.overall_suggestions || [],
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build error result for no implementation
|
|
168
|
+
*/
|
|
169
|
+
export function buildNoResultsError(featureId, branchName) {
|
|
170
|
+
return {
|
|
171
|
+
featureId,
|
|
172
|
+
branchName,
|
|
173
|
+
implementationSummary: null,
|
|
174
|
+
status: 'error',
|
|
175
|
+
message: 'Code implementation failed - no results produced',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
2
|
+
import { ChecklistPhaseContext } from '../../services/checklist.js';
|
|
3
|
+
export interface CodeImplementationOptions {
|
|
4
|
+
featureId: string;
|
|
5
|
+
verbose?: boolean;
|
|
6
|
+
baseBranch?: string;
|
|
7
|
+
maxVerificationIterations?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface CodeImplementationResult {
|
|
10
|
+
featureId: string;
|
|
11
|
+
branchName: string;
|
|
12
|
+
implementationSummary: string | null;
|
|
13
|
+
status: 'success' | 'error';
|
|
14
|
+
message: string;
|
|
15
|
+
filesModified?: string[];
|
|
16
|
+
commitHash?: string;
|
|
17
|
+
data?: {
|
|
18
|
+
checklist_results?: Array<{
|
|
19
|
+
checklist_id: string;
|
|
20
|
+
satisfied: boolean;
|
|
21
|
+
notes?: string;
|
|
22
|
+
}>;
|
|
23
|
+
checklist_item_results?: Array<{
|
|
24
|
+
checklist_item_id: string;
|
|
25
|
+
is_passed: boolean;
|
|
26
|
+
value?: any;
|
|
27
|
+
notes?: string;
|
|
28
|
+
}>;
|
|
29
|
+
[key: string]: any;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare const implementFeatureCode: (options: CodeImplementationOptions, config: EdsgerConfig, checklistContext?: ChecklistPhaseContext | null) => Promise<CodeImplementationResult>;
|