edsger 0.32.0 → 0.33.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/dist/phases/chat-processor/product-tools.js +235 -0
- package/dist/phases/chat-processor/prompts.d.ts +1 -1
- package/dist/phases/chat-processor/prompts.js +1 -0
- package/dist/phases/chat-processor/tools.js +235 -0
- package/dist/phases/code-implementation/index.js +1 -1
- package/dist/services/checklist.d.ts +1 -1
- package/dist/services/checklist.js +4 -1
- package/package.json +1 -1
|
@@ -122,6 +122,241 @@ export function createProductChatMcpServer() {
|
|
|
122
122
|
],
|
|
123
123
|
};
|
|
124
124
|
}),
|
|
125
|
+
tool('list_checklists', 'List all checklists for the product. Each checklist can apply to multiple phases and is assigned to a specific role. Returns checklists with their items.', {
|
|
126
|
+
product_id: z.string().describe('Product ID'),
|
|
127
|
+
role: z
|
|
128
|
+
.string()
|
|
129
|
+
.optional()
|
|
130
|
+
.describe('Filter by role (product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer)'),
|
|
131
|
+
phase: z
|
|
132
|
+
.string()
|
|
133
|
+
.optional()
|
|
134
|
+
.describe('Filter by phase (e.g., code_implementation, code_review, technical_design)'),
|
|
135
|
+
}, async (args) => {
|
|
136
|
+
const params = {
|
|
137
|
+
product_id: args.product_id,
|
|
138
|
+
};
|
|
139
|
+
if (args.role)
|
|
140
|
+
params.role = args.role;
|
|
141
|
+
if (args.phase)
|
|
142
|
+
params.phase = args.phase;
|
|
143
|
+
const result = await callMcpEndpoint('checklists/list', params);
|
|
144
|
+
return {
|
|
145
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
146
|
+
};
|
|
147
|
+
}),
|
|
148
|
+
tool('manage_checklists', 'Create, update, or delete checklists. A checklist belongs to a product, is assigned to a role, and applies to one or more phases (phases is an array). When creating, you can include items inline.', {
|
|
149
|
+
product_id: z.string().describe('Product ID'),
|
|
150
|
+
actions: z.array(z.object({
|
|
151
|
+
action: z.enum(['create', 'update', 'delete']),
|
|
152
|
+
checklist_id: z
|
|
153
|
+
.string()
|
|
154
|
+
.optional()
|
|
155
|
+
.describe('Required for update/delete'),
|
|
156
|
+
name: z.string().optional().describe('Checklist name (for create/update)'),
|
|
157
|
+
description: z
|
|
158
|
+
.string()
|
|
159
|
+
.optional()
|
|
160
|
+
.describe('Checklist description'),
|
|
161
|
+
role: z
|
|
162
|
+
.string()
|
|
163
|
+
.optional()
|
|
164
|
+
.describe('Role: product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer'),
|
|
165
|
+
phases: z
|
|
166
|
+
.array(z.string())
|
|
167
|
+
.optional()
|
|
168
|
+
.describe('Array of phases this checklist applies to (e.g., ["code_implementation", "code_review"]). A checklist can apply to multiple phases.'),
|
|
169
|
+
is_active: z.boolean().optional().describe('Whether the checklist is active'),
|
|
170
|
+
sort_order: z.number().optional().describe('Sort order for display'),
|
|
171
|
+
items: z
|
|
172
|
+
.array(z.object({
|
|
173
|
+
title: z.string(),
|
|
174
|
+
description: z.string().optional(),
|
|
175
|
+
item_type: z
|
|
176
|
+
.enum(['boolean', 'text', 'number', 'select'])
|
|
177
|
+
.optional(),
|
|
178
|
+
is_required: z.boolean().optional(),
|
|
179
|
+
}))
|
|
180
|
+
.optional()
|
|
181
|
+
.describe('Items to create with the checklist (only for create action)'),
|
|
182
|
+
})),
|
|
183
|
+
}, async (args) => {
|
|
184
|
+
const results = [];
|
|
185
|
+
for (const action of args.actions) {
|
|
186
|
+
try {
|
|
187
|
+
if (action.action === 'create') {
|
|
188
|
+
if (!action.name || !action.role || !action.phases?.length) {
|
|
189
|
+
results.push({
|
|
190
|
+
action: 'create',
|
|
191
|
+
success: false,
|
|
192
|
+
error: 'name, role, and phases are required for create',
|
|
193
|
+
});
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const result = await callMcpEndpoint('checklists/create', {
|
|
197
|
+
product_id: args.product_id,
|
|
198
|
+
name: action.name,
|
|
199
|
+
description: action.description || null,
|
|
200
|
+
role: action.role,
|
|
201
|
+
phases: action.phases,
|
|
202
|
+
is_active: action.is_active ?? true,
|
|
203
|
+
sort_order: action.sort_order ?? 0,
|
|
204
|
+
items: action.items,
|
|
205
|
+
});
|
|
206
|
+
results.push({ action: 'create', success: true, data: result });
|
|
207
|
+
}
|
|
208
|
+
else if (action.action === 'update' && action.checklist_id) {
|
|
209
|
+
const params = {
|
|
210
|
+
checklist_id: action.checklist_id,
|
|
211
|
+
};
|
|
212
|
+
if (action.name !== undefined)
|
|
213
|
+
params.name = action.name;
|
|
214
|
+
if (action.description !== undefined)
|
|
215
|
+
params.description = action.description;
|
|
216
|
+
if (action.role !== undefined)
|
|
217
|
+
params.role = action.role;
|
|
218
|
+
if (action.phases !== undefined)
|
|
219
|
+
params.phases = action.phases;
|
|
220
|
+
if (action.is_active !== undefined)
|
|
221
|
+
params.is_active = action.is_active;
|
|
222
|
+
if (action.sort_order !== undefined)
|
|
223
|
+
params.sort_order = action.sort_order;
|
|
224
|
+
const result = await callMcpEndpoint('checklists/update', params);
|
|
225
|
+
results.push({ action: 'update', success: true, data: result });
|
|
226
|
+
}
|
|
227
|
+
else if (action.action === 'delete' && action.checklist_id) {
|
|
228
|
+
const result = await callMcpEndpoint('checklists/delete', {
|
|
229
|
+
checklist_id: action.checklist_id,
|
|
230
|
+
});
|
|
231
|
+
results.push({ action: 'delete', success: true, data: result });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
results.push({
|
|
235
|
+
action: action.action,
|
|
236
|
+
success: false,
|
|
237
|
+
error: `Missing required checklist_id for ${action.action}`,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
243
|
+
results.push({
|
|
244
|
+
action: action.action,
|
|
245
|
+
success: false,
|
|
246
|
+
error: msg,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
content: [
|
|
252
|
+
{ type: 'text', text: JSON.stringify({ results }, null, 2) },
|
|
253
|
+
],
|
|
254
|
+
};
|
|
255
|
+
}),
|
|
256
|
+
tool('manage_checklist_items', 'Add, update, or delete items within a checklist. Each item has a title, type (boolean/text/number/select), and required flag.', {
|
|
257
|
+
actions: z.array(z.object({
|
|
258
|
+
action: z.enum(['create', 'update', 'delete']),
|
|
259
|
+
checklist_id: z
|
|
260
|
+
.string()
|
|
261
|
+
.optional()
|
|
262
|
+
.describe('Checklist ID to add items to (required for create)'),
|
|
263
|
+
item_id: z
|
|
264
|
+
.string()
|
|
265
|
+
.optional()
|
|
266
|
+
.describe('Item ID (required for update/delete)'),
|
|
267
|
+
title: z.string().optional().describe('Item title'),
|
|
268
|
+
description: z.string().optional().describe('Item description'),
|
|
269
|
+
item_type: z
|
|
270
|
+
.enum(['boolean', 'text', 'number', 'select'])
|
|
271
|
+
.optional()
|
|
272
|
+
.describe('Item type (default: boolean)'),
|
|
273
|
+
is_required: z
|
|
274
|
+
.boolean()
|
|
275
|
+
.optional()
|
|
276
|
+
.describe('Whether this item is required'),
|
|
277
|
+
sort_order: z.number().optional().describe('Sort order'),
|
|
278
|
+
config: z
|
|
279
|
+
.record(z.string(), z.unknown())
|
|
280
|
+
.optional()
|
|
281
|
+
.describe('Additional config (e.g., options for select type)'),
|
|
282
|
+
})),
|
|
283
|
+
}, async (args) => {
|
|
284
|
+
const results = [];
|
|
285
|
+
for (const action of args.actions) {
|
|
286
|
+
try {
|
|
287
|
+
if (action.action === 'create' && action.checklist_id) {
|
|
288
|
+
if (!action.title) {
|
|
289
|
+
results.push({
|
|
290
|
+
action: 'create',
|
|
291
|
+
success: false,
|
|
292
|
+
error: 'title is required for create',
|
|
293
|
+
});
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const result = await callMcpEndpoint('checklist_items/create', {
|
|
297
|
+
checklist_id: action.checklist_id,
|
|
298
|
+
items: [
|
|
299
|
+
{
|
|
300
|
+
title: action.title,
|
|
301
|
+
description: action.description || null,
|
|
302
|
+
item_type: action.item_type || 'boolean',
|
|
303
|
+
is_required: action.is_required ?? true,
|
|
304
|
+
sort_order: action.sort_order,
|
|
305
|
+
config: action.config,
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
});
|
|
309
|
+
results.push({ action: 'create', success: true, data: result });
|
|
310
|
+
}
|
|
311
|
+
else if (action.action === 'update' && action.item_id) {
|
|
312
|
+
const params = {
|
|
313
|
+
item_id: action.item_id,
|
|
314
|
+
};
|
|
315
|
+
if (action.title !== undefined)
|
|
316
|
+
params.title = action.title;
|
|
317
|
+
if (action.description !== undefined)
|
|
318
|
+
params.description = action.description;
|
|
319
|
+
if (action.item_type !== undefined)
|
|
320
|
+
params.item_type = action.item_type;
|
|
321
|
+
if (action.is_required !== undefined)
|
|
322
|
+
params.is_required = action.is_required;
|
|
323
|
+
if (action.sort_order !== undefined)
|
|
324
|
+
params.sort_order = action.sort_order;
|
|
325
|
+
if (action.config !== undefined)
|
|
326
|
+
params.config = action.config;
|
|
327
|
+
const result = await callMcpEndpoint('checklist_items/update', params);
|
|
328
|
+
results.push({ action: 'update', success: true, data: result });
|
|
329
|
+
}
|
|
330
|
+
else if (action.action === 'delete' && action.item_id) {
|
|
331
|
+
const result = await callMcpEndpoint('checklist_items/delete', {
|
|
332
|
+
item_id: action.item_id,
|
|
333
|
+
});
|
|
334
|
+
results.push({ action: 'delete', success: true, data: result });
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
const missing = action.action === 'create' ? 'checklist_id' : 'item_id';
|
|
338
|
+
results.push({
|
|
339
|
+
action: action.action,
|
|
340
|
+
success: false,
|
|
341
|
+
error: `Missing required ${missing} for ${action.action}`,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
347
|
+
results.push({
|
|
348
|
+
action: action.action,
|
|
349
|
+
success: false,
|
|
350
|
+
error: msg,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
content: [
|
|
356
|
+
{ type: 'text', text: JSON.stringify({ results }, null, 2) },
|
|
357
|
+
],
|
|
358
|
+
};
|
|
359
|
+
}),
|
|
125
360
|
tool('send_chat_message', 'Send a follow-up message to the chat. Use for explanations, summaries, or asking clarifying questions.', {
|
|
126
361
|
channel_id: z.string().describe('Chat channel ID'),
|
|
127
362
|
content: z.string().describe('Message content (markdown)'),
|
|
@@ -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, search, edit, and write source code files (Bash, Glob, Grep, Read, Edit, Write)\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## Code Implementation\nWhen the user asks you to implement code, fix bugs, or make code changes, you can do it directly using Bash, Read, Edit, and Write tools. Follow this workflow:\n\n### Git Workflow\n1. **Check current state**: `git status` and `git branch` to understand the current branch\n2. **Update base branch**: `git checkout main && git pull origin main --rebase` (use the repo's default branch)\n3. **Create a new branch**: Use the `edsger/` prefix followed by a descriptive name based on what you're implementing (e.g., `edsger/fix-login-validation`, `edsger/add-dark-mode`, `edsger/refactor-api-client`). Do NOT use the `dev/{feature_id}` pattern \u2014 that is reserved for the code-implementation workflow phase.\n4. **Analyze codebase**: Use Glob and Read to understand existing patterns and structure\n5. **Implement changes**: Use Edit/Write to modify or create files\n6. **Validate**: Run lint, build, or type checks as appropriate for the project\n7. **Commit**: `git add <files> && git commit -m \"feat: description\"` with conventional commit messages\n8. **Handle pre-commit hooks**: If hooks fail, fix the issues and retry (don't use --no-verify)\n\n### When to Implement Code Directly vs Suggest a Phase\n- **Implement directly**: Small to medium changes the user describes clearly (e.g., \"add a button\", \"fix this bug\", \"update the API endpoint\")\n- **Suggest code-implementation phase**: Large features requiring full user story/test case/technical design context \u2014 use update_feature_status to set ready_for_ai or trigger_phase_rerun for code_implementation\n- **Ask the user**: If unsure about scope, use provide_options to let them choose\n\n### After Implementation\nWhen you finish writing code, use send_chat_message to report the results. Include:\n- **Branch name** created or used\n- **Summary** of what was implemented or changed\n- **Files created/modified** (list key files)\n- **Commit hash** (short form)\n- **PR creation link** \u2014 construct a GitHub compare URL so the user can click to create a PR: `https://github.com/{owner}/{repo}/compare/{base}...{branch}?expand=1`. Get owner/repo from `git remote get-url origin`.\n- **Next steps** \u2014 e.g., review the changes, run tests, or merge the PR\n\n### Implementation Standards\n- Follow existing code patterns and conventions in the repository\n- Use proper TypeScript types and interfaces\n- Handle error cases appropriately\n- Write clean, maintainable code\n- Reference user stories and test cases from the feature context when implementing\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";
|
|
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- List, create, update, and delete checklists and checklist items (a checklist can apply to multiple phases)\n- Read, search, edit, and write source code files (Bash, Glob, Grep, Read, Edit, Write)\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## Code Implementation\nWhen the user asks you to implement code, fix bugs, or make code changes, you can do it directly using Bash, Read, Edit, and Write tools. Follow this workflow:\n\n### Git Workflow\n1. **Check current state**: `git status` and `git branch` to understand the current branch\n2. **Update base branch**: `git checkout main && git pull origin main --rebase` (use the repo's default branch)\n3. **Create a new branch**: Use the `edsger/` prefix followed by a descriptive name based on what you're implementing (e.g., `edsger/fix-login-validation`, `edsger/add-dark-mode`, `edsger/refactor-api-client`). Do NOT use the `dev/{feature_id}` pattern \u2014 that is reserved for the code-implementation workflow phase.\n4. **Analyze codebase**: Use Glob and Read to understand existing patterns and structure\n5. **Implement changes**: Use Edit/Write to modify or create files\n6. **Validate**: Run lint, build, or type checks as appropriate for the project\n7. **Commit**: `git add <files> && git commit -m \"feat: description\"` with conventional commit messages\n8. **Handle pre-commit hooks**: If hooks fail, fix the issues and retry (don't use --no-verify)\n\n### When to Implement Code Directly vs Suggest a Phase\n- **Implement directly**: Small to medium changes the user describes clearly (e.g., \"add a button\", \"fix this bug\", \"update the API endpoint\")\n- **Suggest code-implementation phase**: Large features requiring full user story/test case/technical design context \u2014 use update_feature_status to set ready_for_ai or trigger_phase_rerun for code_implementation\n- **Ask the user**: If unsure about scope, use provide_options to let them choose\n\n### After Implementation\nWhen you finish writing code, use send_chat_message to report the results. Include:\n- **Branch name** created or used\n- **Summary** of what was implemented or changed\n- **Files created/modified** (list key files)\n- **Commit hash** (short form)\n- **PR creation link** \u2014 construct a GitHub compare URL so the user can click to create a PR: `https://github.com/{owner}/{repo}/compare/{base}...{branch}?expand=1`. Get owner/repo from `git remote get-url origin`.\n- **Next steps** \u2014 e.g., review the changes, run tests, or merge the PR\n\n### Implementation Standards\n- Follow existing code patterns and conventions in the repository\n- Use proper TypeScript types and interfaces\n- Handle error cases appropriately\n- Write clean, maintainable code\n- Reference user stories and test cases from the feature context when implementing\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.
|
|
@@ -11,6 +11,7 @@ export const CHAT_RESPONSE_PROMPT = `You are an AI assistant embedded in Edsger,
|
|
|
11
11
|
You can see the feature's current state, user stories, test cases, workflow phases, and code. You have tools to:
|
|
12
12
|
- Modify feature status, execution mode, and workflow phases
|
|
13
13
|
- Create/update user stories and test cases
|
|
14
|
+
- List, create, update, and delete checklists and checklist items (a checklist can apply to multiple phases)
|
|
14
15
|
- Read, search, edit, and write source code files (Bash, Glob, Grep, Read, Edit, Write)
|
|
15
16
|
- Send follow-up messages and present options to the user
|
|
16
17
|
- Trigger phase reruns
|
|
@@ -213,6 +213,241 @@ export function createChatMcpServer() {
|
|
|
213
213
|
],
|
|
214
214
|
};
|
|
215
215
|
}),
|
|
216
|
+
tool('list_checklists', 'List checklists for the product this feature belongs to. Each checklist can apply to multiple phases and is assigned to a specific role. Returns checklists with their items.', {
|
|
217
|
+
product_id: z.string().describe('Product ID'),
|
|
218
|
+
role: z
|
|
219
|
+
.string()
|
|
220
|
+
.optional()
|
|
221
|
+
.describe('Filter by role (product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer)'),
|
|
222
|
+
phase: z
|
|
223
|
+
.string()
|
|
224
|
+
.optional()
|
|
225
|
+
.describe('Filter by phase (e.g., code_implementation, code_review, technical_design)'),
|
|
226
|
+
}, async (args) => {
|
|
227
|
+
const params = {
|
|
228
|
+
product_id: args.product_id,
|
|
229
|
+
};
|
|
230
|
+
if (args.role)
|
|
231
|
+
params.role = args.role;
|
|
232
|
+
if (args.phase)
|
|
233
|
+
params.phase = args.phase;
|
|
234
|
+
const result = await callMcpEndpoint('checklists/list', params);
|
|
235
|
+
return {
|
|
236
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
237
|
+
};
|
|
238
|
+
}),
|
|
239
|
+
tool('manage_checklists', 'Create, update, or delete checklists. A checklist belongs to a product, is assigned to a role, and applies to one or more phases (phases is an array). When creating, you can include items inline.', {
|
|
240
|
+
product_id: z.string().describe('Product ID'),
|
|
241
|
+
actions: z.array(z.object({
|
|
242
|
+
action: z.enum(['create', 'update', 'delete']),
|
|
243
|
+
checklist_id: z
|
|
244
|
+
.string()
|
|
245
|
+
.optional()
|
|
246
|
+
.describe('Required for update/delete'),
|
|
247
|
+
name: z.string().optional().describe('Checklist name (for create/update)'),
|
|
248
|
+
description: z
|
|
249
|
+
.string()
|
|
250
|
+
.optional()
|
|
251
|
+
.describe('Checklist description'),
|
|
252
|
+
role: z
|
|
253
|
+
.string()
|
|
254
|
+
.optional()
|
|
255
|
+
.describe('Role: product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer'),
|
|
256
|
+
phases: z
|
|
257
|
+
.array(z.string())
|
|
258
|
+
.optional()
|
|
259
|
+
.describe('Array of phases this checklist applies to (e.g., ["code_implementation", "code_review"]). A checklist can apply to multiple phases.'),
|
|
260
|
+
is_active: z.boolean().optional().describe('Whether the checklist is active'),
|
|
261
|
+
sort_order: z.number().optional().describe('Sort order for display'),
|
|
262
|
+
items: z
|
|
263
|
+
.array(z.object({
|
|
264
|
+
title: z.string(),
|
|
265
|
+
description: z.string().optional(),
|
|
266
|
+
item_type: z
|
|
267
|
+
.enum(['boolean', 'text', 'number', 'select'])
|
|
268
|
+
.optional(),
|
|
269
|
+
is_required: z.boolean().optional(),
|
|
270
|
+
}))
|
|
271
|
+
.optional()
|
|
272
|
+
.describe('Items to create with the checklist (only for create action)'),
|
|
273
|
+
})),
|
|
274
|
+
}, async (args) => {
|
|
275
|
+
const results = [];
|
|
276
|
+
for (const action of args.actions) {
|
|
277
|
+
try {
|
|
278
|
+
if (action.action === 'create') {
|
|
279
|
+
if (!action.name || !action.role || !action.phases?.length) {
|
|
280
|
+
results.push({
|
|
281
|
+
action: 'create',
|
|
282
|
+
success: false,
|
|
283
|
+
error: 'name, role, and phases are required for create',
|
|
284
|
+
});
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const result = await callMcpEndpoint('checklists/create', {
|
|
288
|
+
product_id: args.product_id,
|
|
289
|
+
name: action.name,
|
|
290
|
+
description: action.description || null,
|
|
291
|
+
role: action.role,
|
|
292
|
+
phases: action.phases,
|
|
293
|
+
is_active: action.is_active ?? true,
|
|
294
|
+
sort_order: action.sort_order ?? 0,
|
|
295
|
+
items: action.items,
|
|
296
|
+
});
|
|
297
|
+
results.push({ action: 'create', success: true, data: result });
|
|
298
|
+
}
|
|
299
|
+
else if (action.action === 'update' && action.checklist_id) {
|
|
300
|
+
const params = {
|
|
301
|
+
checklist_id: action.checklist_id,
|
|
302
|
+
};
|
|
303
|
+
if (action.name !== undefined)
|
|
304
|
+
params.name = action.name;
|
|
305
|
+
if (action.description !== undefined)
|
|
306
|
+
params.description = action.description;
|
|
307
|
+
if (action.role !== undefined)
|
|
308
|
+
params.role = action.role;
|
|
309
|
+
if (action.phases !== undefined)
|
|
310
|
+
params.phases = action.phases;
|
|
311
|
+
if (action.is_active !== undefined)
|
|
312
|
+
params.is_active = action.is_active;
|
|
313
|
+
if (action.sort_order !== undefined)
|
|
314
|
+
params.sort_order = action.sort_order;
|
|
315
|
+
const result = await callMcpEndpoint('checklists/update', params);
|
|
316
|
+
results.push({ action: 'update', success: true, data: result });
|
|
317
|
+
}
|
|
318
|
+
else if (action.action === 'delete' && action.checklist_id) {
|
|
319
|
+
const result = await callMcpEndpoint('checklists/delete', {
|
|
320
|
+
checklist_id: action.checklist_id,
|
|
321
|
+
});
|
|
322
|
+
results.push({ action: 'delete', success: true, data: result });
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
results.push({
|
|
326
|
+
action: action.action,
|
|
327
|
+
success: false,
|
|
328
|
+
error: `Missing required checklist_id for ${action.action}`,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
334
|
+
results.push({
|
|
335
|
+
action: action.action,
|
|
336
|
+
success: false,
|
|
337
|
+
error: msg,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
content: [
|
|
343
|
+
{ type: 'text', text: JSON.stringify({ results }, null, 2) },
|
|
344
|
+
],
|
|
345
|
+
};
|
|
346
|
+
}),
|
|
347
|
+
tool('manage_checklist_items', 'Add, update, or delete items within a checklist. Each item has a title, type (boolean/text/number/select), and required flag.', {
|
|
348
|
+
actions: z.array(z.object({
|
|
349
|
+
action: z.enum(['create', 'update', 'delete']),
|
|
350
|
+
checklist_id: z
|
|
351
|
+
.string()
|
|
352
|
+
.optional()
|
|
353
|
+
.describe('Checklist ID to add items to (required for create)'),
|
|
354
|
+
item_id: z
|
|
355
|
+
.string()
|
|
356
|
+
.optional()
|
|
357
|
+
.describe('Item ID (required for update/delete)'),
|
|
358
|
+
title: z.string().optional().describe('Item title'),
|
|
359
|
+
description: z.string().optional().describe('Item description'),
|
|
360
|
+
item_type: z
|
|
361
|
+
.enum(['boolean', 'text', 'number', 'select'])
|
|
362
|
+
.optional()
|
|
363
|
+
.describe('Item type (default: boolean)'),
|
|
364
|
+
is_required: z
|
|
365
|
+
.boolean()
|
|
366
|
+
.optional()
|
|
367
|
+
.describe('Whether this item is required'),
|
|
368
|
+
sort_order: z.number().optional().describe('Sort order'),
|
|
369
|
+
config: z
|
|
370
|
+
.record(z.string(), z.unknown())
|
|
371
|
+
.optional()
|
|
372
|
+
.describe('Additional config (e.g., options for select type)'),
|
|
373
|
+
})),
|
|
374
|
+
}, async (args) => {
|
|
375
|
+
const results = [];
|
|
376
|
+
for (const action of args.actions) {
|
|
377
|
+
try {
|
|
378
|
+
if (action.action === 'create' && action.checklist_id) {
|
|
379
|
+
if (!action.title) {
|
|
380
|
+
results.push({
|
|
381
|
+
action: 'create',
|
|
382
|
+
success: false,
|
|
383
|
+
error: 'title is required for create',
|
|
384
|
+
});
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
const result = await callMcpEndpoint('checklist_items/create', {
|
|
388
|
+
checklist_id: action.checklist_id,
|
|
389
|
+
items: [
|
|
390
|
+
{
|
|
391
|
+
title: action.title,
|
|
392
|
+
description: action.description || null,
|
|
393
|
+
item_type: action.item_type || 'boolean',
|
|
394
|
+
is_required: action.is_required ?? true,
|
|
395
|
+
sort_order: action.sort_order,
|
|
396
|
+
config: action.config,
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
});
|
|
400
|
+
results.push({ action: 'create', success: true, data: result });
|
|
401
|
+
}
|
|
402
|
+
else if (action.action === 'update' && action.item_id) {
|
|
403
|
+
const params = {
|
|
404
|
+
item_id: action.item_id,
|
|
405
|
+
};
|
|
406
|
+
if (action.title !== undefined)
|
|
407
|
+
params.title = action.title;
|
|
408
|
+
if (action.description !== undefined)
|
|
409
|
+
params.description = action.description;
|
|
410
|
+
if (action.item_type !== undefined)
|
|
411
|
+
params.item_type = action.item_type;
|
|
412
|
+
if (action.is_required !== undefined)
|
|
413
|
+
params.is_required = action.is_required;
|
|
414
|
+
if (action.sort_order !== undefined)
|
|
415
|
+
params.sort_order = action.sort_order;
|
|
416
|
+
if (action.config !== undefined)
|
|
417
|
+
params.config = action.config;
|
|
418
|
+
const result = await callMcpEndpoint('checklist_items/update', params);
|
|
419
|
+
results.push({ action: 'update', success: true, data: result });
|
|
420
|
+
}
|
|
421
|
+
else if (action.action === 'delete' && action.item_id) {
|
|
422
|
+
const result = await callMcpEndpoint('checklist_items/delete', {
|
|
423
|
+
item_id: action.item_id,
|
|
424
|
+
});
|
|
425
|
+
results.push({ action: 'delete', success: true, data: result });
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
const missing = action.action === 'create' ? 'checklist_id' : 'item_id';
|
|
429
|
+
results.push({
|
|
430
|
+
action: action.action,
|
|
431
|
+
success: false,
|
|
432
|
+
error: `Missing required ${missing} for ${action.action}`,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
438
|
+
results.push({
|
|
439
|
+
action: action.action,
|
|
440
|
+
success: false,
|
|
441
|
+
error: msg,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
content: [
|
|
447
|
+
{ type: 'text', text: JSON.stringify({ results }, null, 2) },
|
|
448
|
+
],
|
|
449
|
+
};
|
|
450
|
+
}),
|
|
216
451
|
tool('send_chat_message', 'Send a follow-up message to the chat. Use for explanations, summaries, or asking clarifying questions.', {
|
|
217
452
|
channel_id: z.string().describe('Chat channel ID'),
|
|
218
453
|
content: z.string().describe('Message content (markdown)'),
|
|
@@ -720,7 +720,7 @@ This is a **multi-branch feature** - the feature has been split into multiple br
|
|
|
720
720
|
logDebug(`Checklist info length: ${checklistInfo.length}`, verbose);
|
|
721
721
|
logDebug(`Checklist info preview: ${checklistInfo.substring(0, 300)}`, verbose);
|
|
722
722
|
checklistContext.checklists.forEach((checklist, index) => {
|
|
723
|
-
logDebug(`Checklist ${index + 1}: id=${checklist.id}, name=${checklist.name},
|
|
723
|
+
logDebug(`Checklist ${index + 1}: id=${checklist.id}, name=${checklist.name}, phases=${checklist.phases?.join(',')}, role=${checklist.role}, itemCount=${checklist.items?.length || 0}`, verbose);
|
|
724
724
|
if (checklist.items) {
|
|
725
725
|
checklist.items.forEach((item, itemIndex) => {
|
|
726
726
|
logDebug(` Item ${itemIndex + 1}: id=${item.id}, title=${item.title?.substring(0, 50) || 'No title'}, description=${item.description?.substring(0, 50) || 'No description'}`, verbose);
|
|
@@ -243,7 +243,10 @@ export function formatChecklistsForContext(context) {
|
|
|
243
243
|
const itemsText = checklist.items
|
|
244
244
|
.map((item) => ` - **${item.title}** (ID: ${item.id})${item.is_required ? ' (required)' : ''}: ${item.description || 'No description'}`)
|
|
245
245
|
.join('\n');
|
|
246
|
-
|
|
246
|
+
const phasesLabel = checklist.phases?.length > 0
|
|
247
|
+
? ` [Phases: ${checklist.phases.join(', ')}]`
|
|
248
|
+
: '';
|
|
249
|
+
return `**${checklist.name}** (${checklist.role})${phasesLabel}
|
|
247
250
|
ID: ${checklist.id}
|
|
248
251
|
${checklist.description || 'No description'}
|
|
249
252
|
Items:
|