edsger 0.54.0 → 0.55.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/README.md +20 -0
- package/dist/api/financing.d.ts +47 -0
- package/dist/api/financing.js +37 -0
- package/dist/api/issues/approval-checker.d.ts +11 -9
- package/dist/api/issues/approval-checker.js +30 -41
- package/dist/api/issues/status-updater.d.ts +47 -20
- package/dist/api/issues/status-updater.js +114 -46
- package/dist/api/issues/update-issue.d.ts +5 -0
- package/dist/api/issues/update-issue.js +6 -0
- package/dist/commands/agent-workflow/processor.js +5 -1
- package/dist/commands/checklists/index.d.ts +5 -2
- package/dist/commands/checklists/index.js +73 -12
- package/dist/commands/checklists/tools.d.ts +14 -7
- package/dist/commands/checklists/tools.js +15 -208
- package/dist/commands/financing-deck/index.d.ts +8 -0
- package/dist/commands/financing-deck/index.js +66 -0
- package/dist/commands/find-architecture/index.d.ts +13 -0
- package/dist/commands/find-architecture/index.js +41 -0
- package/dist/commands/issue-analysis/index.d.ts +5 -0
- package/dist/commands/issue-analysis/index.js +9 -0
- package/dist/commands/sync-github-issues/index.d.ts +11 -0
- package/dist/commands/sync-github-issues/index.js +42 -0
- package/dist/commands/sync-sentry-issues/index.d.ts +14 -0
- package/dist/commands/sync-sentry-issues/index.js +73 -0
- package/dist/commands/technical-design/index.d.ts +5 -0
- package/dist/commands/technical-design/index.js +9 -0
- package/dist/commands/test-cases-analysis/index.d.ts +5 -0
- package/dist/commands/test-cases-analysis/index.js +9 -0
- package/dist/commands/user-stories-analysis/index.d.ts +5 -0
- package/dist/commands/user-stories-analysis/index.js +9 -0
- package/dist/commands/workflow/executors/phase-executor.js +6 -4
- package/dist/commands/workflow/phase-orchestrator.js +0 -1
- package/dist/config/issue-status.d.ts +18 -45
- package/dist/config/issue-status.js +21 -107
- package/dist/index.js +176 -4
- package/dist/phases/app-store-generation/agent.js +2 -1
- package/dist/phases/app-store-generation/index.js +11 -3
- package/dist/phases/branch-planning/index.js +0 -1
- package/dist/phases/bug-fixing/analyzer.js +0 -1
- package/dist/phases/bug-fixing/mcp-server.d.ts +18 -1
- package/dist/phases/bug-fixing/mcp-server.js +19 -76
- package/dist/phases/chat-processor/product-tools.d.ts +5 -8
- package/dist/phases/chat-processor/product-tools.js +6 -512
- package/dist/phases/chat-processor/tools.d.ts +5 -9
- package/dist/phases/chat-processor/tools.js +6 -704
- package/dist/phases/code-implementation/index.js +0 -1
- package/dist/phases/code-implementation-verification/agent.js +6 -1
- package/dist/phases/code-refine/index.js +0 -1
- package/dist/phases/code-refine/refine-iteration.js +2 -1
- package/dist/phases/code-review/index.js +0 -1
- package/dist/phases/code-testing/analyzer.js +0 -1
- package/dist/phases/financing-deck/agent.d.ts +1 -0
- package/dist/phases/financing-deck/agent.js +96 -0
- package/dist/phases/financing-deck/context.d.ts +13 -0
- package/dist/phases/financing-deck/context.js +69 -0
- package/dist/phases/financing-deck/index.d.ts +15 -0
- package/dist/phases/financing-deck/index.js +89 -0
- package/dist/phases/financing-deck/prompts.d.ts +2 -0
- package/dist/phases/financing-deck/prompts.js +94 -0
- package/dist/phases/find-architecture/index.d.ts +44 -0
- package/dist/phases/find-architecture/index.js +248 -0
- package/dist/phases/find-architecture/prompts.d.ts +31 -0
- package/dist/phases/find-architecture/prompts.js +128 -0
- package/dist/phases/find-architecture/state.d.ts +21 -0
- package/dist/phases/find-architecture/state.js +17 -0
- package/dist/phases/find-architecture/types.d.ts +55 -0
- package/dist/phases/find-architecture/types.js +69 -0
- package/dist/phases/find-bugs/index.js +13 -4
- package/dist/phases/find-features/index.js +10 -5
- package/dist/phases/find-smells/index.js +10 -3
- package/dist/phases/functional-testing/analyzer.js +27 -17
- package/dist/phases/functional-testing/http-fallback.d.ts +1 -1
- package/dist/phases/functional-testing/http-fallback.js +32 -16
- package/dist/phases/functional-testing/mcp-server.d.ts +9 -1
- package/dist/phases/functional-testing/mcp-server.js +13 -132
- package/dist/phases/growth-analysis/agent.js +2 -2
- package/dist/phases/growth-analysis/index.js +9 -3
- package/dist/phases/intelligence-analysis/agent.js +2 -2
- package/dist/phases/intelligence-analysis/index.js +9 -2
- package/dist/phases/issue-analysis/agent.d.ts +9 -1
- package/dist/phases/issue-analysis/agent.js +68 -27
- package/dist/phases/issue-analysis/context.d.ts +5 -9
- package/dist/phases/issue-analysis/context.js +31 -76
- package/dist/phases/issue-analysis/index.js +32 -84
- package/dist/phases/issue-analysis/outcome.d.ts +3 -33
- package/dist/phases/issue-analysis/outcome.js +15 -253
- package/dist/phases/issue-analysis/prompts.d.ts +3 -5
- package/dist/phases/issue-analysis/prompts.js +45 -158
- package/dist/phases/issue-analysis-verification/agent.d.ts +4 -4
- package/dist/phases/issue-analysis-verification/agent.js +5 -5
- package/dist/phases/issue-analysis-verification/index.d.ts +4 -2
- package/dist/phases/issue-analysis-verification/index.js +9 -22
- package/dist/phases/issue-analysis-verification/prompts.d.ts +1 -2
- package/dist/phases/issue-analysis-verification/prompts.js +21 -46
- package/dist/phases/output-contracts.js +66 -78
- package/dist/phases/pr-execution/index.js +2 -2
- package/dist/phases/pr-resolve/index.js +2 -8
- package/dist/phases/pr-splitting/index.js +2 -2
- package/dist/phases/release-sync/index.js +52 -43
- package/dist/phases/run-sheet/index.js +2 -1
- package/dist/phases/smoke-test/agent.js +2 -1
- package/dist/phases/smoke-test/index.js +4 -1
- package/dist/phases/sync-github-issues/index.d.ts +41 -0
- package/dist/phases/sync-github-issues/index.js +187 -0
- package/dist/phases/sync-github-issues/state.d.ts +26 -0
- package/dist/phases/sync-github-issues/state.js +18 -0
- package/dist/phases/sync-github-issues/types.d.ts +35 -0
- package/dist/phases/sync-github-issues/types.js +6 -0
- package/dist/phases/sync-sentry-issues/index.d.ts +29 -0
- package/dist/phases/sync-sentry-issues/index.js +153 -0
- package/dist/phases/sync-sentry-issues/sentry-client.d.ts +66 -0
- package/dist/phases/sync-sentry-issues/sentry-client.js +221 -0
- package/dist/phases/sync-sentry-issues/state.d.ts +23 -0
- package/dist/phases/sync-sentry-issues/state.js +18 -0
- package/dist/phases/sync-sentry-issues/types.d.ts +46 -0
- package/dist/phases/sync-sentry-issues/types.js +6 -0
- package/dist/phases/sync-shared/mcp.d.ts +81 -0
- package/dist/phases/sync-shared/mcp.js +111 -0
- package/dist/phases/technical-design/index.js +0 -1
- package/dist/phases/test-cases-analysis/agent.js +2 -1
- package/dist/phases/test-cases-analysis/index.js +0 -1
- package/dist/phases/user-stories-analysis/agent.js +2 -1
- package/dist/phases/user-stories-analysis/index.js +0 -1
- package/dist/services/coaching/coaching-agent.js +29 -4
- package/dist/services/feedbacks.d.ts +1 -1
- package/dist/skills/phase/issue-analysis/SKILL.md +48 -92
- package/dist/skills/phase/issue-analysis-verification/SKILL.md +46 -31
- package/dist/tools/bootstrap.d.ts +45 -0
- package/dist/tools/bootstrap.js +50 -0
- package/dist/types/external-sources.d.ts +22 -0
- package/dist/types/external-sources.js +23 -0
- package/dist/types/index.d.ts +5 -10
- package/dist/types/issues.d.ts +2 -0
- package/dist/types/llm-responses.d.ts +1 -14
- package/dist/utils/formatters.js +1 -7
- package/dist/utils/issue-phase-cli.d.ts +26 -0
- package/dist/utils/issue-phase-cli.js +44 -0
- package/dist/workspace/workspace-manager.d.ts +10 -0
- package/dist/workspace/workspace-manager.js +22 -1
- package/package.json +6 -2
- package/vitest.config.ts +4 -0
- package/.env.local +0 -12
|
@@ -1,517 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Chat (product) MCP server — CLI entry point.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* listing issues, creating issues, managing tasks, and team coordination.
|
|
7
|
-
*/
|
|
8
|
-
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
|
|
9
|
-
import { z } from 'zod';
|
|
10
|
-
import { listChatMessages, sendAiMessage } from '../../api/chat.js';
|
|
11
|
-
import { callMcpEndpoint } from '../../api/mcp-client.js';
|
|
12
|
-
/**
|
|
13
|
-
* Create an in-process MCP server with product-level chat tools.
|
|
4
|
+
* Tool implementations live in `edsger-tools`. This shim adapts the
|
|
5
|
+
* CLI's `callMcpEndpoint` transport into `ToolDeps`.
|
|
14
6
|
*/
|
|
7
|
+
import { createChatProductMcpServer } from 'edsger-tools';
|
|
8
|
+
import { getToolDeps } from '../../tools/bootstrap.js';
|
|
15
9
|
export function createProductChatMcpServer() {
|
|
16
|
-
return
|
|
17
|
-
name: 'edsger-product-chat',
|
|
18
|
-
version: '1.0.0',
|
|
19
|
-
tools: [
|
|
20
|
-
tool('list_issues', 'List all issues for the product, optionally filtered by status. Use this to answer questions about product progress, blocked issues, etc.', {
|
|
21
|
-
product_id: z.string().describe('Product ID'),
|
|
22
|
-
status: z
|
|
23
|
-
.string()
|
|
24
|
-
.optional()
|
|
25
|
-
.describe('Filter by status (e.g., backlog, ready_for_ai, in_progress, shipped)'),
|
|
26
|
-
}, async (args) => {
|
|
27
|
-
const params = {
|
|
28
|
-
product_id: args.product_id,
|
|
29
|
-
};
|
|
30
|
-
if (args.status) {
|
|
31
|
-
params.status = args.status;
|
|
32
|
-
}
|
|
33
|
-
const result = await callMcpEndpoint('issues/list', params);
|
|
34
|
-
return {
|
|
35
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
36
|
-
};
|
|
37
|
-
}),
|
|
38
|
-
tool('create_issue', 'Create a new issue for the product. Use when the user describes new work to be added.', {
|
|
39
|
-
product_id: z.string().describe('Product ID'),
|
|
40
|
-
name: z.string().describe('Issue name'),
|
|
41
|
-
description: z.string().describe('Issue description'),
|
|
42
|
-
}, async (args) => {
|
|
43
|
-
const result = await callMcpEndpoint('issues/create', {
|
|
44
|
-
product_id: args.product_id,
|
|
45
|
-
name: args.name,
|
|
46
|
-
description: args.description,
|
|
47
|
-
});
|
|
48
|
-
return {
|
|
49
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
50
|
-
};
|
|
51
|
-
}),
|
|
52
|
-
tool('get_issue_details', 'Get detailed information about a specific issue, including its status, workflow, user stories, and test cases.', {
|
|
53
|
-
issue_id: z.string().describe('Issue ID'),
|
|
54
|
-
}, async (args) => {
|
|
55
|
-
const [issueResult, storiesResult, testCasesResult] = await Promise.all([
|
|
56
|
-
callMcpEndpoint('issues/get', {
|
|
57
|
-
issue_id: args.issue_id,
|
|
58
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
-
}),
|
|
60
|
-
callMcpEndpoint('user_stories/list', {
|
|
61
|
-
issue_id: args.issue_id,
|
|
62
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
-
}),
|
|
64
|
-
callMcpEndpoint('test_cases/list', {
|
|
65
|
-
issue_id: args.issue_id,
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
-
}),
|
|
68
|
-
]);
|
|
69
|
-
const issue = issueResult?.issues?.[0] || {};
|
|
70
|
-
const result = {
|
|
71
|
-
issue,
|
|
72
|
-
user_stories: storiesResult?.user_stories || [],
|
|
73
|
-
test_cases: testCasesResult?.test_cases || [],
|
|
74
|
-
summary: {
|
|
75
|
-
status: issue.status,
|
|
76
|
-
execution_mode: issue.execution_mode,
|
|
77
|
-
workflow_phases: (issue.workflow || []).map(
|
|
78
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
|
-
(p) => `${p.phase}: ${p.status}`),
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
return {
|
|
83
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
84
|
-
};
|
|
85
|
-
}),
|
|
86
|
-
tool('get_product_overview', 'Get a full product overview: issues by status, task counts, team size. Use this for summary questions.', {
|
|
87
|
-
product_id: z.string().describe('Product ID'),
|
|
88
|
-
}, async (args) => {
|
|
89
|
-
const [issuesResult, membersResult] = await Promise.all([
|
|
90
|
-
callMcpEndpoint('issues/list', {
|
|
91
|
-
product_id: args.product_id,
|
|
92
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
-
}),
|
|
94
|
-
callMcpEndpoint('tasks/product_members', {
|
|
95
|
-
product_id: args.product_id,
|
|
96
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
-
}),
|
|
98
|
-
]);
|
|
99
|
-
const issues = issuesResult?.issues || [];
|
|
100
|
-
const byStatus = {};
|
|
101
|
-
for (const f of issues) {
|
|
102
|
-
byStatus[f.status] = (byStatus[f.status] || 0) + 1;
|
|
103
|
-
}
|
|
104
|
-
let members = [];
|
|
105
|
-
try {
|
|
106
|
-
const membersData = membersResult?.content?.[0]?.text
|
|
107
|
-
? JSON.parse(membersResult.content[0].text)
|
|
108
|
-
: membersResult?.members || membersResult || [];
|
|
109
|
-
members = Array.isArray(membersData) ? membersData : [];
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
members = [];
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
content: [
|
|
116
|
-
{
|
|
117
|
-
type: 'text',
|
|
118
|
-
text: JSON.stringify({
|
|
119
|
-
total_issues: issues.length,
|
|
120
|
-
issues_by_status: byStatus,
|
|
121
|
-
team_size: members.length,
|
|
122
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
|
-
issues: issues.map((f) => ({
|
|
124
|
-
id: f.id,
|
|
125
|
-
name: f.name,
|
|
126
|
-
status: f.status,
|
|
127
|
-
})),
|
|
128
|
-
}, null, 2),
|
|
129
|
-
},
|
|
130
|
-
],
|
|
131
|
-
};
|
|
132
|
-
}),
|
|
133
|
-
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.', {
|
|
134
|
-
product_id: z.string().describe('Product ID'),
|
|
135
|
-
role: z
|
|
136
|
-
.string()
|
|
137
|
-
.optional()
|
|
138
|
-
.describe('Filter by role (product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer)'),
|
|
139
|
-
phase: z
|
|
140
|
-
.string()
|
|
141
|
-
.optional()
|
|
142
|
-
.describe('Filter by phase (e.g., code_implementation, code_review, technical_design)'),
|
|
143
|
-
}, async (args) => {
|
|
144
|
-
const params = {
|
|
145
|
-
product_id: args.product_id,
|
|
146
|
-
};
|
|
147
|
-
if (args.role) {
|
|
148
|
-
params.role = args.role;
|
|
149
|
-
}
|
|
150
|
-
if (args.phase) {
|
|
151
|
-
params.phase = args.phase;
|
|
152
|
-
}
|
|
153
|
-
const result = await callMcpEndpoint('checklists/list', params);
|
|
154
|
-
return {
|
|
155
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
156
|
-
};
|
|
157
|
-
}),
|
|
158
|
-
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.', {
|
|
159
|
-
product_id: z.string().describe('Product ID'),
|
|
160
|
-
actions: z.array(z.object({
|
|
161
|
-
action: z.enum(['create', 'update', 'delete']),
|
|
162
|
-
checklist_id: z
|
|
163
|
-
.string()
|
|
164
|
-
.optional()
|
|
165
|
-
.describe('Required for update/delete'),
|
|
166
|
-
name: z
|
|
167
|
-
.string()
|
|
168
|
-
.optional()
|
|
169
|
-
.describe('Checklist name (for create/update)'),
|
|
170
|
-
description: z
|
|
171
|
-
.string()
|
|
172
|
-
.optional()
|
|
173
|
-
.describe('Checklist description'),
|
|
174
|
-
role: z
|
|
175
|
-
.string()
|
|
176
|
-
.optional()
|
|
177
|
-
.describe('Role: product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer'),
|
|
178
|
-
phases: z
|
|
179
|
-
.array(z.string())
|
|
180
|
-
.optional()
|
|
181
|
-
.describe('Array of phases this checklist applies to (e.g., ["code_implementation", "code_review"]). A checklist can apply to multiple phases.'),
|
|
182
|
-
is_active: z
|
|
183
|
-
.boolean()
|
|
184
|
-
.optional()
|
|
185
|
-
.describe('Whether the checklist is active'),
|
|
186
|
-
sort_order: z
|
|
187
|
-
.number()
|
|
188
|
-
.optional()
|
|
189
|
-
.describe('Sort order for display'),
|
|
190
|
-
items: z
|
|
191
|
-
.array(z.object({
|
|
192
|
-
title: z.string(),
|
|
193
|
-
description: z.string().optional(),
|
|
194
|
-
item_type: z
|
|
195
|
-
.enum(['boolean', 'text', 'number', 'select'])
|
|
196
|
-
.optional(),
|
|
197
|
-
is_required: z.boolean().optional(),
|
|
198
|
-
}))
|
|
199
|
-
.optional()
|
|
200
|
-
.describe('Items to create with the checklist (only for create action)'),
|
|
201
|
-
})),
|
|
202
|
-
},
|
|
203
|
-
// eslint-disable-next-line complexity -- handles multiple CRUD action types in a single tool handler
|
|
204
|
-
async (args) => {
|
|
205
|
-
const results = [];
|
|
206
|
-
for (const action of args.actions) {
|
|
207
|
-
try {
|
|
208
|
-
if (action.action === 'create') {
|
|
209
|
-
if (!action.name || !action.role || !action.phases?.length) {
|
|
210
|
-
results.push({
|
|
211
|
-
action: 'create',
|
|
212
|
-
success: false,
|
|
213
|
-
error: 'name, role, and phases are required for create',
|
|
214
|
-
});
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
const result = await callMcpEndpoint('checklists/create', {
|
|
218
|
-
product_id: args.product_id,
|
|
219
|
-
name: action.name,
|
|
220
|
-
description: action.description || null,
|
|
221
|
-
role: action.role,
|
|
222
|
-
phases: action.phases,
|
|
223
|
-
is_active: action.is_active ?? true,
|
|
224
|
-
sort_order: action.sort_order ?? 0,
|
|
225
|
-
items: action.items,
|
|
226
|
-
});
|
|
227
|
-
results.push({ action: 'create', success: true, data: result });
|
|
228
|
-
}
|
|
229
|
-
else if (action.action === 'update' && action.checklist_id) {
|
|
230
|
-
const params = {
|
|
231
|
-
checklist_id: action.checklist_id,
|
|
232
|
-
};
|
|
233
|
-
if (action.name !== undefined) {
|
|
234
|
-
params.name = action.name;
|
|
235
|
-
}
|
|
236
|
-
if (action.description !== undefined) {
|
|
237
|
-
params.description = action.description;
|
|
238
|
-
}
|
|
239
|
-
if (action.role !== undefined) {
|
|
240
|
-
params.role = action.role;
|
|
241
|
-
}
|
|
242
|
-
if (action.phases !== undefined) {
|
|
243
|
-
params.phases = action.phases;
|
|
244
|
-
}
|
|
245
|
-
if (action.is_active !== undefined) {
|
|
246
|
-
params.is_active = action.is_active;
|
|
247
|
-
}
|
|
248
|
-
if (action.sort_order !== undefined) {
|
|
249
|
-
params.sort_order = action.sort_order;
|
|
250
|
-
}
|
|
251
|
-
const result = await callMcpEndpoint('checklists/update', params);
|
|
252
|
-
results.push({ action: 'update', success: true, data: result });
|
|
253
|
-
}
|
|
254
|
-
else if (action.action === 'delete' && action.checklist_id) {
|
|
255
|
-
const result = await callMcpEndpoint('checklists/delete', {
|
|
256
|
-
checklist_id: action.checklist_id,
|
|
257
|
-
});
|
|
258
|
-
results.push({ action: 'delete', success: true, data: result });
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
results.push({
|
|
262
|
-
action: action.action,
|
|
263
|
-
success: false,
|
|
264
|
-
error: `Missing required checklist_id for ${action.action}`,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
270
|
-
results.push({
|
|
271
|
-
action: action.action,
|
|
272
|
-
success: false,
|
|
273
|
-
error: msg,
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return {
|
|
278
|
-
content: [
|
|
279
|
-
{ type: 'text', text: JSON.stringify({ results }, null, 2) },
|
|
280
|
-
],
|
|
281
|
-
};
|
|
282
|
-
}),
|
|
283
|
-
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.', {
|
|
284
|
-
actions: z.array(z.object({
|
|
285
|
-
action: z.enum(['create', 'update', 'delete']),
|
|
286
|
-
checklist_id: z
|
|
287
|
-
.string()
|
|
288
|
-
.optional()
|
|
289
|
-
.describe('Checklist ID to add items to (required for create)'),
|
|
290
|
-
item_id: z
|
|
291
|
-
.string()
|
|
292
|
-
.optional()
|
|
293
|
-
.describe('Item ID (required for update/delete)'),
|
|
294
|
-
title: z.string().optional().describe('Item title'),
|
|
295
|
-
description: z.string().optional().describe('Item description'),
|
|
296
|
-
item_type: z
|
|
297
|
-
.enum(['boolean', 'text', 'number', 'select'])
|
|
298
|
-
.optional()
|
|
299
|
-
.describe('Item type (default: boolean)'),
|
|
300
|
-
is_required: z
|
|
301
|
-
.boolean()
|
|
302
|
-
.optional()
|
|
303
|
-
.describe('Whether this item is required'),
|
|
304
|
-
sort_order: z.number().optional().describe('Sort order'),
|
|
305
|
-
config: z
|
|
306
|
-
.record(z.string(), z.unknown())
|
|
307
|
-
.optional()
|
|
308
|
-
.describe('Additional config (e.g., options for select type)'),
|
|
309
|
-
})),
|
|
310
|
-
},
|
|
311
|
-
// eslint-disable-next-line complexity -- handles multiple CRUD action types for checklist items
|
|
312
|
-
async (args) => {
|
|
313
|
-
const results = [];
|
|
314
|
-
for (const action of args.actions) {
|
|
315
|
-
try {
|
|
316
|
-
if (action.action === 'create' && action.checklist_id) {
|
|
317
|
-
if (!action.title) {
|
|
318
|
-
results.push({
|
|
319
|
-
action: 'create',
|
|
320
|
-
success: false,
|
|
321
|
-
error: 'title is required for create',
|
|
322
|
-
});
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
const result = await callMcpEndpoint('checklist_items/create', {
|
|
326
|
-
checklist_id: action.checklist_id,
|
|
327
|
-
items: [
|
|
328
|
-
{
|
|
329
|
-
title: action.title,
|
|
330
|
-
description: action.description || null,
|
|
331
|
-
item_type: action.item_type || 'boolean',
|
|
332
|
-
is_required: action.is_required ?? true,
|
|
333
|
-
sort_order: action.sort_order,
|
|
334
|
-
config: action.config,
|
|
335
|
-
},
|
|
336
|
-
],
|
|
337
|
-
});
|
|
338
|
-
results.push({ action: 'create', success: true, data: result });
|
|
339
|
-
}
|
|
340
|
-
else if (action.action === 'update' && action.item_id) {
|
|
341
|
-
const params = {
|
|
342
|
-
item_id: action.item_id,
|
|
343
|
-
};
|
|
344
|
-
if (action.title !== undefined) {
|
|
345
|
-
params.title = action.title;
|
|
346
|
-
}
|
|
347
|
-
if (action.description !== undefined) {
|
|
348
|
-
params.description = action.description;
|
|
349
|
-
}
|
|
350
|
-
if (action.item_type !== undefined) {
|
|
351
|
-
params.item_type = action.item_type;
|
|
352
|
-
}
|
|
353
|
-
if (action.is_required !== undefined) {
|
|
354
|
-
params.is_required = action.is_required;
|
|
355
|
-
}
|
|
356
|
-
if (action.sort_order !== undefined) {
|
|
357
|
-
params.sort_order = action.sort_order;
|
|
358
|
-
}
|
|
359
|
-
if (action.config !== undefined) {
|
|
360
|
-
params.config = action.config;
|
|
361
|
-
}
|
|
362
|
-
const result = await callMcpEndpoint('checklist_items/update', params);
|
|
363
|
-
results.push({ action: 'update', success: true, data: result });
|
|
364
|
-
}
|
|
365
|
-
else if (action.action === 'delete' && action.item_id) {
|
|
366
|
-
const result = await callMcpEndpoint('checklist_items/delete', {
|
|
367
|
-
item_id: action.item_id,
|
|
368
|
-
});
|
|
369
|
-
results.push({ action: 'delete', success: true, data: result });
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
const missing = action.action === 'create' ? 'checklist_id' : 'item_id';
|
|
373
|
-
results.push({
|
|
374
|
-
action: action.action,
|
|
375
|
-
success: false,
|
|
376
|
-
error: `Missing required ${missing} for ${action.action}`,
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
catch (error) {
|
|
381
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
382
|
-
results.push({
|
|
383
|
-
action: action.action,
|
|
384
|
-
success: false,
|
|
385
|
-
error: msg,
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return {
|
|
390
|
-
content: [
|
|
391
|
-
{ type: 'text', text: JSON.stringify({ results }, null, 2) },
|
|
392
|
-
],
|
|
393
|
-
};
|
|
394
|
-
}),
|
|
395
|
-
tool('send_chat_message', 'Send a follow-up message to the chat. Use for explanations, summaries, or asking clarifying questions.', {
|
|
396
|
-
channel_id: z.string().describe('Chat channel ID'),
|
|
397
|
-
content: z.string().describe('Message content (markdown)'),
|
|
398
|
-
message_type: z
|
|
399
|
-
.enum(['text', 'question', 'answer'])
|
|
400
|
-
.optional()
|
|
401
|
-
.describe('Type of message'),
|
|
402
|
-
}, async (args) => {
|
|
403
|
-
await sendAiMessage(args.channel_id, args.content, {}, {
|
|
404
|
-
messageType: args.message_type || 'text',
|
|
405
|
-
});
|
|
406
|
-
return {
|
|
407
|
-
content: [{ type: 'text', text: 'Message sent successfully.' }],
|
|
408
|
-
};
|
|
409
|
-
}),
|
|
410
|
-
tool('provide_options', 'Present 2-4 actionable options to the user. Each option has a label and description. The user will click one to respond.', {
|
|
411
|
-
channel_id: z.string().describe('Chat channel ID'),
|
|
412
|
-
prompt: z.string().describe('Question or context for the options'),
|
|
413
|
-
options: z.array(z.object({
|
|
414
|
-
label: z.string().describe('Short option label'),
|
|
415
|
-
description: z.string().describe('What this option does'),
|
|
416
|
-
action_key: z
|
|
417
|
-
.string()
|
|
418
|
-
.describe('Machine-readable key (e.g. "create_issue", "list_blocked")'),
|
|
419
|
-
})),
|
|
420
|
-
}, async (args) => {
|
|
421
|
-
await sendAiMessage(args.channel_id, args.prompt, { options: args.options }, { messageType: 'options' });
|
|
422
|
-
return {
|
|
423
|
-
content: [{ type: 'text', text: 'Options presented to the user.' }],
|
|
424
|
-
};
|
|
425
|
-
}),
|
|
426
|
-
tool('get_chat_history', 'Retrieve older chat messages from the channel. Use when you need more context about earlier discussions.', {
|
|
427
|
-
channel_id: z.string().describe('Chat channel ID'),
|
|
428
|
-
limit: z
|
|
429
|
-
.number()
|
|
430
|
-
.optional()
|
|
431
|
-
.describe('Number of messages to retrieve (default 50, max 100)'),
|
|
432
|
-
before: z
|
|
433
|
-
.string()
|
|
434
|
-
.optional()
|
|
435
|
-
.describe('Fetch messages before this ISO timestamp for pagination'),
|
|
436
|
-
}, async (args) => {
|
|
437
|
-
const limit = Math.min(args.limit || 50, 100);
|
|
438
|
-
const messages = await listChatMessages(args.channel_id, {
|
|
439
|
-
limit,
|
|
440
|
-
...(args.before ? { since: args.before } : {}),
|
|
441
|
-
});
|
|
442
|
-
const formatted = messages.map((m) => {
|
|
443
|
-
const nonAiSender = m.sender_type === 'system' ? 'System' : m.sender_name || 'User';
|
|
444
|
-
return {
|
|
445
|
-
id: m.id,
|
|
446
|
-
sender: m.sender_type === 'ai' ? 'AI' : nonAiSender,
|
|
447
|
-
sender_type: m.sender_type,
|
|
448
|
-
content: m.content,
|
|
449
|
-
message_type: m.message_type,
|
|
450
|
-
created_at: m.created_at,
|
|
451
|
-
};
|
|
452
|
-
});
|
|
453
|
-
return {
|
|
454
|
-
content: [
|
|
455
|
-
{
|
|
456
|
-
type: 'text',
|
|
457
|
-
text: JSON.stringify({ messages: formatted, count: formatted.length }, null, 2),
|
|
458
|
-
},
|
|
459
|
-
],
|
|
460
|
-
};
|
|
461
|
-
}),
|
|
462
|
-
tool('create_task', 'Create a task for a team member (human) or for AI to execute.', {
|
|
463
|
-
product_id: z.string().describe('Product ID'),
|
|
464
|
-
name: z.string().describe('Short task name'),
|
|
465
|
-
description: z.string().optional().describe('Detailed description'),
|
|
466
|
-
executor: z.enum(['ai', 'human']).describe('Who should do this'),
|
|
467
|
-
assigned_to: z.string().optional().describe('User ID to assign to'),
|
|
468
|
-
issue_id: z.string().optional().describe('Related issue ID'),
|
|
469
|
-
action_url: z
|
|
470
|
-
.string()
|
|
471
|
-
.optional()
|
|
472
|
-
.describe('URL where the assignee should take action'),
|
|
473
|
-
priority: z
|
|
474
|
-
.number()
|
|
475
|
-
.optional()
|
|
476
|
-
.describe('1=low, 2=medium, 3=high, 4=urgent'),
|
|
477
|
-
}, async (args) => {
|
|
478
|
-
const listResult = (await callMcpEndpoint('tasks/list_for_product', {
|
|
479
|
-
product_id: args.product_id,
|
|
480
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
481
|
-
}));
|
|
482
|
-
const text = listResult?.content?.[0]?.text || '[]';
|
|
483
|
-
const existingTasks = JSON.parse(text);
|
|
484
|
-
const nextSequence = existingTasks.length + 1;
|
|
485
|
-
const actionUrl = args.action_url ||
|
|
486
|
-
(args.issue_id
|
|
487
|
-
? `/products/${args.product_id}/issues/${args.issue_id}`
|
|
488
|
-
: `/products/${args.product_id}`);
|
|
489
|
-
const result = await callMcpEndpoint('tasks/create', {
|
|
490
|
-
product_id: args.product_id,
|
|
491
|
-
sequence: nextSequence,
|
|
492
|
-
name: args.name,
|
|
493
|
-
description: args.description || null,
|
|
494
|
-
executor: args.executor,
|
|
495
|
-
source: 'system',
|
|
496
|
-
assigned_to: args.assigned_to || null,
|
|
497
|
-
issue_id: args.issue_id || null,
|
|
498
|
-
action_url: actionUrl,
|
|
499
|
-
priority: args.priority || (args.executor === 'human' ? 3 : 2),
|
|
500
|
-
});
|
|
501
|
-
return {
|
|
502
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
503
|
-
};
|
|
504
|
-
}),
|
|
505
|
-
tool('list_product_members', 'List all members of a product (owner + developers) with their names, emails, and IDs.', {
|
|
506
|
-
product_id: z.string().describe('Product ID'),
|
|
507
|
-
}, async (args) => {
|
|
508
|
-
const result = await callMcpEndpoint('tasks/product_members', {
|
|
509
|
-
product_id: args.product_id,
|
|
510
|
-
});
|
|
511
|
-
return {
|
|
512
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
513
|
-
};
|
|
514
|
-
}),
|
|
515
|
-
],
|
|
516
|
-
});
|
|
10
|
+
return createChatProductMcpServer(getToolDeps());
|
|
517
11
|
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Chat MCP server —
|
|
2
|
+
* Chat (issue) MCP server — CLI entry point.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Bash, Grep, Glob) are also available via the preset.
|
|
4
|
+
* Tool implementations live in `edsger-tools`. This shim adapts the
|
|
5
|
+
* CLI's `callMcpEndpoint` transport into `ToolDeps`.
|
|
7
6
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* Pass the returned config to query() options.mcpServers.
|
|
11
|
-
*/
|
|
12
|
-
export declare function createChatMcpServer(): import("@anthropic-ai/claude-agent-sdk").McpSdkServerConfigWithInstance;
|
|
7
|
+
import type { McpSdkServerConfigWithInstance } from '@anthropic-ai/claude-agent-sdk';
|
|
8
|
+
export declare function createChatMcpServer(): McpSdkServerConfigWithInstance;
|