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.
Files changed (142) hide show
  1. package/README.md +20 -0
  2. package/dist/api/financing.d.ts +47 -0
  3. package/dist/api/financing.js +37 -0
  4. package/dist/api/issues/approval-checker.d.ts +11 -9
  5. package/dist/api/issues/approval-checker.js +30 -41
  6. package/dist/api/issues/status-updater.d.ts +47 -20
  7. package/dist/api/issues/status-updater.js +114 -46
  8. package/dist/api/issues/update-issue.d.ts +5 -0
  9. package/dist/api/issues/update-issue.js +6 -0
  10. package/dist/commands/agent-workflow/processor.js +5 -1
  11. package/dist/commands/checklists/index.d.ts +5 -2
  12. package/dist/commands/checklists/index.js +73 -12
  13. package/dist/commands/checklists/tools.d.ts +14 -7
  14. package/dist/commands/checklists/tools.js +15 -208
  15. package/dist/commands/financing-deck/index.d.ts +8 -0
  16. package/dist/commands/financing-deck/index.js +66 -0
  17. package/dist/commands/find-architecture/index.d.ts +13 -0
  18. package/dist/commands/find-architecture/index.js +41 -0
  19. package/dist/commands/issue-analysis/index.d.ts +5 -0
  20. package/dist/commands/issue-analysis/index.js +9 -0
  21. package/dist/commands/sync-github-issues/index.d.ts +11 -0
  22. package/dist/commands/sync-github-issues/index.js +42 -0
  23. package/dist/commands/sync-sentry-issues/index.d.ts +14 -0
  24. package/dist/commands/sync-sentry-issues/index.js +73 -0
  25. package/dist/commands/technical-design/index.d.ts +5 -0
  26. package/dist/commands/technical-design/index.js +9 -0
  27. package/dist/commands/test-cases-analysis/index.d.ts +5 -0
  28. package/dist/commands/test-cases-analysis/index.js +9 -0
  29. package/dist/commands/user-stories-analysis/index.d.ts +5 -0
  30. package/dist/commands/user-stories-analysis/index.js +9 -0
  31. package/dist/commands/workflow/executors/phase-executor.js +6 -4
  32. package/dist/commands/workflow/phase-orchestrator.js +0 -1
  33. package/dist/config/issue-status.d.ts +18 -45
  34. package/dist/config/issue-status.js +21 -107
  35. package/dist/index.js +176 -4
  36. package/dist/phases/app-store-generation/agent.js +2 -1
  37. package/dist/phases/app-store-generation/index.js +11 -3
  38. package/dist/phases/branch-planning/index.js +0 -1
  39. package/dist/phases/bug-fixing/analyzer.js +0 -1
  40. package/dist/phases/bug-fixing/mcp-server.d.ts +18 -1
  41. package/dist/phases/bug-fixing/mcp-server.js +19 -76
  42. package/dist/phases/chat-processor/product-tools.d.ts +5 -8
  43. package/dist/phases/chat-processor/product-tools.js +6 -512
  44. package/dist/phases/chat-processor/tools.d.ts +5 -9
  45. package/dist/phases/chat-processor/tools.js +6 -704
  46. package/dist/phases/code-implementation/index.js +0 -1
  47. package/dist/phases/code-implementation-verification/agent.js +6 -1
  48. package/dist/phases/code-refine/index.js +0 -1
  49. package/dist/phases/code-refine/refine-iteration.js +2 -1
  50. package/dist/phases/code-review/index.js +0 -1
  51. package/dist/phases/code-testing/analyzer.js +0 -1
  52. package/dist/phases/financing-deck/agent.d.ts +1 -0
  53. package/dist/phases/financing-deck/agent.js +96 -0
  54. package/dist/phases/financing-deck/context.d.ts +13 -0
  55. package/dist/phases/financing-deck/context.js +69 -0
  56. package/dist/phases/financing-deck/index.d.ts +15 -0
  57. package/dist/phases/financing-deck/index.js +89 -0
  58. package/dist/phases/financing-deck/prompts.d.ts +2 -0
  59. package/dist/phases/financing-deck/prompts.js +94 -0
  60. package/dist/phases/find-architecture/index.d.ts +44 -0
  61. package/dist/phases/find-architecture/index.js +248 -0
  62. package/dist/phases/find-architecture/prompts.d.ts +31 -0
  63. package/dist/phases/find-architecture/prompts.js +128 -0
  64. package/dist/phases/find-architecture/state.d.ts +21 -0
  65. package/dist/phases/find-architecture/state.js +17 -0
  66. package/dist/phases/find-architecture/types.d.ts +55 -0
  67. package/dist/phases/find-architecture/types.js +69 -0
  68. package/dist/phases/find-bugs/index.js +13 -4
  69. package/dist/phases/find-features/index.js +10 -5
  70. package/dist/phases/find-smells/index.js +10 -3
  71. package/dist/phases/functional-testing/analyzer.js +27 -17
  72. package/dist/phases/functional-testing/http-fallback.d.ts +1 -1
  73. package/dist/phases/functional-testing/http-fallback.js +32 -16
  74. package/dist/phases/functional-testing/mcp-server.d.ts +9 -1
  75. package/dist/phases/functional-testing/mcp-server.js +13 -132
  76. package/dist/phases/growth-analysis/agent.js +2 -2
  77. package/dist/phases/growth-analysis/index.js +9 -3
  78. package/dist/phases/intelligence-analysis/agent.js +2 -2
  79. package/dist/phases/intelligence-analysis/index.js +9 -2
  80. package/dist/phases/issue-analysis/agent.d.ts +9 -1
  81. package/dist/phases/issue-analysis/agent.js +68 -27
  82. package/dist/phases/issue-analysis/context.d.ts +5 -9
  83. package/dist/phases/issue-analysis/context.js +31 -76
  84. package/dist/phases/issue-analysis/index.js +32 -84
  85. package/dist/phases/issue-analysis/outcome.d.ts +3 -33
  86. package/dist/phases/issue-analysis/outcome.js +15 -253
  87. package/dist/phases/issue-analysis/prompts.d.ts +3 -5
  88. package/dist/phases/issue-analysis/prompts.js +45 -158
  89. package/dist/phases/issue-analysis-verification/agent.d.ts +4 -4
  90. package/dist/phases/issue-analysis-verification/agent.js +5 -5
  91. package/dist/phases/issue-analysis-verification/index.d.ts +4 -2
  92. package/dist/phases/issue-analysis-verification/index.js +9 -22
  93. package/dist/phases/issue-analysis-verification/prompts.d.ts +1 -2
  94. package/dist/phases/issue-analysis-verification/prompts.js +21 -46
  95. package/dist/phases/output-contracts.js +66 -78
  96. package/dist/phases/pr-execution/index.js +2 -2
  97. package/dist/phases/pr-resolve/index.js +2 -8
  98. package/dist/phases/pr-splitting/index.js +2 -2
  99. package/dist/phases/release-sync/index.js +52 -43
  100. package/dist/phases/run-sheet/index.js +2 -1
  101. package/dist/phases/smoke-test/agent.js +2 -1
  102. package/dist/phases/smoke-test/index.js +4 -1
  103. package/dist/phases/sync-github-issues/index.d.ts +41 -0
  104. package/dist/phases/sync-github-issues/index.js +187 -0
  105. package/dist/phases/sync-github-issues/state.d.ts +26 -0
  106. package/dist/phases/sync-github-issues/state.js +18 -0
  107. package/dist/phases/sync-github-issues/types.d.ts +35 -0
  108. package/dist/phases/sync-github-issues/types.js +6 -0
  109. package/dist/phases/sync-sentry-issues/index.d.ts +29 -0
  110. package/dist/phases/sync-sentry-issues/index.js +153 -0
  111. package/dist/phases/sync-sentry-issues/sentry-client.d.ts +66 -0
  112. package/dist/phases/sync-sentry-issues/sentry-client.js +221 -0
  113. package/dist/phases/sync-sentry-issues/state.d.ts +23 -0
  114. package/dist/phases/sync-sentry-issues/state.js +18 -0
  115. package/dist/phases/sync-sentry-issues/types.d.ts +46 -0
  116. package/dist/phases/sync-sentry-issues/types.js +6 -0
  117. package/dist/phases/sync-shared/mcp.d.ts +81 -0
  118. package/dist/phases/sync-shared/mcp.js +111 -0
  119. package/dist/phases/technical-design/index.js +0 -1
  120. package/dist/phases/test-cases-analysis/agent.js +2 -1
  121. package/dist/phases/test-cases-analysis/index.js +0 -1
  122. package/dist/phases/user-stories-analysis/agent.js +2 -1
  123. package/dist/phases/user-stories-analysis/index.js +0 -1
  124. package/dist/services/coaching/coaching-agent.js +29 -4
  125. package/dist/services/feedbacks.d.ts +1 -1
  126. package/dist/skills/phase/issue-analysis/SKILL.md +48 -92
  127. package/dist/skills/phase/issue-analysis-verification/SKILL.md +46 -31
  128. package/dist/tools/bootstrap.d.ts +45 -0
  129. package/dist/tools/bootstrap.js +50 -0
  130. package/dist/types/external-sources.d.ts +22 -0
  131. package/dist/types/external-sources.js +23 -0
  132. package/dist/types/index.d.ts +5 -10
  133. package/dist/types/issues.d.ts +2 -0
  134. package/dist/types/llm-responses.d.ts +1 -14
  135. package/dist/utils/formatters.js +1 -7
  136. package/dist/utils/issue-phase-cli.d.ts +26 -0
  137. package/dist/utils/issue-phase-cli.js +44 -0
  138. package/dist/workspace/workspace-manager.d.ts +10 -0
  139. package/dist/workspace/workspace-manager.js +22 -1
  140. package/package.json +6 -2
  141. package/vitest.config.ts +4 -0
  142. package/.env.local +0 -12
@@ -1,517 +1,11 @@
1
1
  /**
2
- * Product Chat MCP server — registers product-level tools with the Claude Agent SDK.
2
+ * Chat (product) MCP server — CLI entry point.
3
3
  *
4
- * Unlike the issue chat tools which operate on a single issue's lifecycle
5
- * (stories, tests, workflow), these tools operate at the product level:
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 createSdkMcpServer({
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 — registers custom tools with the Claude Agent SDK.
2
+ * Chat (issue) MCP server — CLI entry point.
3
3
  *
4
- * Uses createSdkMcpServer + tool() so the SDK can discover and execute
5
- * these tools automatically. Claude Code's built-in tools (Read, Write,
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
- * Create an in-process MCP server with chat-specific tools.
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;