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.
Files changed (123) hide show
  1. package/.claude/settings.local.json +28 -0
  2. package/.env.local +12 -0
  3. package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
  4. package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
  5. package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
  6. package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
  7. package/dist/api/tasks.d.ts +26 -0
  8. package/dist/api/tasks.js +44 -0
  9. package/dist/commands/task-worker/index.d.ts +8 -0
  10. package/dist/commands/task-worker/index.js +34 -0
  11. package/dist/commands/task-worker/processor.d.ts +23 -0
  12. package/dist/commands/task-worker/processor.js +81 -0
  13. package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
  14. package/dist/commands/workflow/pipeline-runner.js +393 -0
  15. package/dist/commands/workflow/runner.d.ts +26 -0
  16. package/dist/commands/workflow/runner.js +119 -0
  17. package/dist/commands/workflow/workflow-runner.d.ts +26 -0
  18. package/dist/commands/workflow/workflow-runner.js +119 -0
  19. package/dist/index.js +7 -0
  20. package/dist/phases/chat-processor/context.d.ts +1 -0
  21. package/dist/phases/chat-processor/context.js +1 -0
  22. package/dist/phases/chat-processor/index.js +2 -0
  23. package/dist/phases/chat-processor/prompts.d.ts +1 -1
  24. package/dist/phases/chat-processor/prompts.js +35 -0
  25. package/dist/phases/chat-processor/tools.js +46 -0
  26. package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
  27. package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
  28. package/dist/phases/code-implementation/analyzer.d.ts +32 -0
  29. package/dist/phases/code-implementation/analyzer.js +629 -0
  30. package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
  31. package/dist/phases/code-implementation/context-fetcher.js +86 -0
  32. package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
  33. package/dist/phases/code-implementation/mcp-server.js +93 -0
  34. package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
  35. package/dist/phases/code-implementation/prompts-improvement.js +108 -0
  36. package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
  37. package/dist/phases/code-implementation-verification/verifier.js +196 -0
  38. package/dist/phases/code-refine/analyzer.d.ts +41 -0
  39. package/dist/phases/code-refine/analyzer.js +561 -0
  40. package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
  41. package/dist/phases/code-refine/context-fetcher.js +423 -0
  42. package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
  43. package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
  44. package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
  45. package/dist/phases/code-refine-verification/verifier.js +597 -0
  46. package/dist/phases/code-review/analyzer.d.ts +29 -0
  47. package/dist/phases/code-review/analyzer.js +363 -0
  48. package/dist/phases/code-review/context-fetcher.d.ts +92 -0
  49. package/dist/phases/code-review/context-fetcher.js +296 -0
  50. package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
  51. package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
  52. package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
  53. package/dist/phases/feature-analysis/analyzer.js +208 -0
  54. package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
  55. package/dist/phases/feature-analysis/context-fetcher.js +134 -0
  56. package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
  57. package/dist/phases/feature-analysis/http-fallback.js +95 -0
  58. package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
  59. package/dist/phases/feature-analysis/mcp-server.js +144 -0
  60. package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
  61. package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
  62. package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
  63. package/dist/phases/feature-analysis-verification/verifier.js +147 -0
  64. package/dist/phases/task/agent.d.ts +10 -0
  65. package/dist/phases/task/agent.js +81 -0
  66. package/dist/phases/task/context.d.ts +16 -0
  67. package/dist/phases/task/context.js +50 -0
  68. package/dist/phases/task/index.d.ts +17 -0
  69. package/dist/phases/task/index.js +54 -0
  70. package/dist/phases/task/prompts.d.ts +9 -0
  71. package/dist/phases/task/prompts.js +28 -0
  72. package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
  73. package/dist/phases/technical-design/analyzer-helpers.js +39 -0
  74. package/dist/phases/technical-design/analyzer.d.ts +21 -0
  75. package/dist/phases/technical-design/analyzer.js +461 -0
  76. package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
  77. package/dist/phases/technical-design/context-fetcher.js +39 -0
  78. package/dist/phases/technical-design/http-fallback.d.ts +17 -0
  79. package/dist/phases/technical-design/http-fallback.js +151 -0
  80. package/dist/phases/technical-design/mcp-server.d.ts +1 -0
  81. package/dist/phases/technical-design/mcp-server.js +157 -0
  82. package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
  83. package/dist/phases/technical-design/prompts-improvement.js +93 -0
  84. package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
  85. package/dist/phases/technical-design-verification/verifier.js +170 -0
  86. package/dist/services/feature-branches.d.ts +77 -0
  87. package/dist/services/feature-branches.js +205 -0
  88. package/dist/types/index.d.ts +1 -0
  89. package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
  90. package/dist/workflow-runner/config/phase-configs.js +120 -0
  91. package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
  92. package/dist/workflow-runner/core/feature-filter.js +46 -0
  93. package/dist/workflow-runner/core/index.d.ts +8 -0
  94. package/dist/workflow-runner/core/index.js +12 -0
  95. package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
  96. package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
  97. package/dist/workflow-runner/core/state-manager.d.ts +24 -0
  98. package/dist/workflow-runner/core/state-manager.js +42 -0
  99. package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
  100. package/dist/workflow-runner/core/workflow-logger.js +65 -0
  101. package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
  102. package/dist/workflow-runner/executors/phase-executor.js +248 -0
  103. package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
  104. package/dist/workflow-runner/feature-workflow-runner.js +119 -0
  105. package/dist/workflow-runner/index.d.ts +2 -0
  106. package/dist/workflow-runner/index.js +2 -0
  107. package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
  108. package/dist/workflow-runner/pipeline-runner.js +393 -0
  109. package/dist/workflow-runner/workflow-processor.d.ts +54 -0
  110. package/dist/workflow-runner/workflow-processor.js +170 -0
  111. package/package.json +1 -1
  112. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
  113. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
  114. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
  115. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
  116. package/dist/services/lifecycle-agent/index.d.ts +0 -24
  117. package/dist/services/lifecycle-agent/index.js +0 -25
  118. package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
  119. package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
  120. package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
  121. package/dist/services/lifecycle-agent/transition-rules.js +0 -184
  122. package/dist/services/lifecycle-agent/types.d.ts +0 -190
  123. 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);
@@ -5,6 +5,7 @@
5
5
  import type { ChatMessage } from '../../types/index.js';
6
6
  export interface ChatProcessorContext {
7
7
  featureId: string;
8
+ productId: string;
8
9
  featureDescription: string;
9
10
  featureStatus: string;
10
11
  executionMode: string;
@@ -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>;