@damper/mcp 0.3.8 → 0.3.9
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 +41 -15
- package/dist/formatters.js +23 -14
- package/dist/index.js +77 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,14 +74,15 @@ The AI will see tools from both servers and can distinguish between them:
|
|
|
74
74
|
| Tool | Description |
|
|
75
75
|
|------|-------------|
|
|
76
76
|
| `list_tasks` | Get roadmap tasks (filter by `status`, `type`, `quarter`, sort by `importance`/`newest`/`votes`) |
|
|
77
|
-
| `get_task` | Task details + subtasks + linked feedback |
|
|
77
|
+
| `get_task` | Task details + subtasks + commits + linked feedback |
|
|
78
78
|
| `create_task` | Create task with type (bug, feature, improvement, task) |
|
|
79
79
|
| `update_task` | Update description, plan, priority, effort, quarter, labels |
|
|
80
80
|
| `start_task` | Lock and start task (use `force` to take over). Returns project context index. |
|
|
81
81
|
| `add_note` | Add progress note |
|
|
82
|
+
| `add_commit` | Log a commit (hash + message). Appears in task details. |
|
|
82
83
|
| `create_subtask` | Add subtask to a task |
|
|
83
84
|
| `update_subtask` | Mark subtask done/undone |
|
|
84
|
-
| `complete_task` | Mark done, release lock.
|
|
85
|
+
| `complete_task` | Mark done, release lock. Optionally log commits at completion. |
|
|
85
86
|
| `abandon_task` | Release lock, return to planned |
|
|
86
87
|
| `list_feedback` | Browse user feedback |
|
|
87
88
|
| `get_feedback` | Feedback details + votes |
|
|
@@ -259,21 +260,42 @@ When you start a task, it's locked to prevent other agents from working on it si
|
|
|
259
260
|
- Different agent starting → fails with 409 (use `force: true` to take over)
|
|
260
261
|
- Complete or abandon → releases lock
|
|
261
262
|
|
|
263
|
+
### Commit Tracking
|
|
264
|
+
|
|
265
|
+
Log commits as you work to track code changes for each task:
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
> Log commit abc1234 with message "Added validation"
|
|
269
|
+
> Add commit def5678: "Fixed auth bug"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Commits are stored structurally and displayed in task details:
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
## Commits (2)
|
|
276
|
+
- abc1234: Added validation
|
|
277
|
+
- def5678: Fixed auth bug
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Two ways to log commits:**
|
|
281
|
+
1. `add_commit` - Log commits as you make them
|
|
282
|
+
2. `complete_task` with `commits` - Log final commits at completion
|
|
283
|
+
|
|
262
284
|
### Recommended Workflow
|
|
263
285
|
|
|
264
286
|
When working on tasks, follow this workflow for best results:
|
|
265
287
|
|
|
266
288
|
1. **Start**: `start_task` → locks the task and returns project context
|
|
267
289
|
2. **Log start**: `add_note` with "Session started: <your goal>"
|
|
268
|
-
3. **Work**: Make changes,
|
|
290
|
+
3. **Work**: Make changes, use `add_commit` after each commit, `add_note` for decisions
|
|
269
291
|
4. **Log end**: `add_note` with "Session end: <summary, next steps>"
|
|
270
292
|
5. **Finish**: `complete_task` (done) or `abandon_task` (stopping)
|
|
271
293
|
|
|
272
|
-
**
|
|
273
|
-
- Session start: `"Session started: implementing dark mode"`
|
|
274
|
-
- Commits: `
|
|
275
|
-
- Decisions: `"Decision: Using CSS variables because..."`
|
|
276
|
-
- Session end: `"Session end: Done theme provider, remaining: toggle UI"`
|
|
294
|
+
**What to log:**
|
|
295
|
+
- Session start: `add_note "Session started: implementing dark mode"`
|
|
296
|
+
- Commits: `add_commit abc123 "Added theme provider"`
|
|
297
|
+
- Decisions: `add_note "Decision: Using CSS variables because..."`
|
|
298
|
+
- Session end: `add_note "Session end: Done theme provider, remaining: toggle UI"`
|
|
277
299
|
|
|
278
300
|
**Before completing:**
|
|
279
301
|
- Push all commits
|
|
@@ -319,25 +341,29 @@ Add this to your project's `CLAUDE.md` (or `.cursorrules` for Cursor) to ensure
|
|
|
319
341
|
|
|
320
342
|
This project uses Damper MCP for task tracking. **You MUST follow this workflow.**
|
|
321
343
|
|
|
322
|
-
### At Session Start
|
|
323
|
-
1. `get_project_context` -
|
|
324
|
-
2. `
|
|
325
|
-
3.
|
|
344
|
+
### At Session Start (MANDATORY)
|
|
345
|
+
1. `get_project_context` - **READ THIS FIRST.** Contains architecture, conventions, and critical project info. Do NOT skip.
|
|
346
|
+
2. `get_context_section` - Fetch full content for sections relevant to your task (e.g., "api", "database", "testing")
|
|
347
|
+
3. `list_tasks` - Check for existing tasks to work on
|
|
348
|
+
4. If working on a task: `start_task` to lock it (returns context index - read relevant sections)
|
|
326
349
|
|
|
327
350
|
### While Working
|
|
328
|
-
- `
|
|
351
|
+
- `add_commit` after each commit with hash and message
|
|
329
352
|
- `add_note` for decisions: "Decision: chose X because Y"
|
|
330
353
|
- `update_subtask` to mark subtask progress
|
|
354
|
+
- **Follow patterns from project context** - Don't reinvent; use existing conventions
|
|
331
355
|
|
|
332
356
|
### At Session End (MANDATORY)
|
|
333
357
|
- ALWAYS call `add_note` with session summary before stopping
|
|
334
358
|
- ALWAYS call `complete_task` (if done) or `abandon_task` (if stopping early)
|
|
335
359
|
- NEVER leave a started task without completing or abandoning it
|
|
360
|
+
- If you learned something about the codebase, consider updating project context
|
|
336
361
|
|
|
337
362
|
### Why This Matters
|
|
363
|
+
- **Project context prevents mistakes** - Contains architecture decisions, gotchas, and patterns you need to follow
|
|
338
364
|
- Locked tasks block other agents from working on them
|
|
339
|
-
-
|
|
340
|
-
-
|
|
365
|
+
- Commits and notes help the next agent (or you) continue the work
|
|
366
|
+
- Updating context saves future agents from re-analyzing the codebase
|
|
341
367
|
```
|
|
342
368
|
|
|
343
369
|
## Environment
|
package/dist/formatters.js
CHANGED
|
@@ -8,29 +8,36 @@
|
|
|
8
8
|
* Format start_task response
|
|
9
9
|
*/
|
|
10
10
|
export function formatStartTaskResponse(result) {
|
|
11
|
-
const lines = [
|
|
11
|
+
const lines = [`✅ Started ${result.id}: ${result.message}`];
|
|
12
|
+
// Context section - emphatic about reading it first
|
|
12
13
|
if (result.context) {
|
|
13
14
|
if (result.context.isEmpty) {
|
|
14
15
|
lines.push(`\n📚 ${result.context.hint || 'No project context available.'}`);
|
|
15
16
|
}
|
|
16
17
|
else {
|
|
17
|
-
lines.push('\n**
|
|
18
|
+
lines.push('\n⚠️ **BEFORE YOU START:** Read project context to understand patterns and conventions.');
|
|
19
|
+
lines.push('');
|
|
20
|
+
if (result.context.relevantSections && result.context.relevantSections.length > 0) {
|
|
21
|
+
lines.push(`**Required reading for this task:**`);
|
|
22
|
+
for (const section of result.context.relevantSections) {
|
|
23
|
+
lines.push(`→ \`get_context_section("${section}")\``);
|
|
24
|
+
}
|
|
25
|
+
lines.push('');
|
|
26
|
+
}
|
|
27
|
+
lines.push('**All available sections:**');
|
|
18
28
|
for (const s of result.context.index) {
|
|
19
29
|
const relevant = result.context.relevantSections?.includes(s.section) ? ' ⭐' : '';
|
|
20
30
|
lines.push(`• ${s.section}${relevant}`);
|
|
21
31
|
}
|
|
22
|
-
if (result.context.relevantSections && result.context.relevantSections.length > 0) {
|
|
23
|
-
lines.push(`\nRelevant for this task: ${result.context.relevantSections.join(', ')}`);
|
|
24
|
-
lines.push('Use get_context_section to fetch full content.');
|
|
25
|
-
}
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
34
|
lines.push('\n---');
|
|
29
|
-
lines.push('**📋
|
|
30
|
-
lines.push('1.
|
|
31
|
-
lines.push('2.
|
|
32
|
-
lines.push('3. `
|
|
33
|
-
lines.push('4. `
|
|
35
|
+
lines.push('**📋 Required workflow:**');
|
|
36
|
+
lines.push('1. **Read context sections above** (contains patterns you must follow)');
|
|
37
|
+
lines.push('2. `add_note`: "Session started: <goal>"');
|
|
38
|
+
lines.push('3. Work: use `add_commit` for commits, `add_note` for decisions');
|
|
39
|
+
lines.push('4. `add_note`: "Session end: <summary>"');
|
|
40
|
+
lines.push('5. `complete_task` or `abandon_task` (NEVER skip this)');
|
|
34
41
|
return lines.join('\n');
|
|
35
42
|
}
|
|
36
43
|
/**
|
|
@@ -38,11 +45,13 @@ export function formatStartTaskResponse(result) {
|
|
|
38
45
|
*/
|
|
39
46
|
export function formatCompleteTaskResponse(result) {
|
|
40
47
|
const lines = [`✅ Completed ${result.id}`];
|
|
48
|
+
lines.push('\n---');
|
|
49
|
+
lines.push('**📚 Before you finish:**');
|
|
50
|
+
lines.push('Did you learn something about this codebase that would help future agents?');
|
|
51
|
+
lines.push('→ Use `update_context_section` to share architecture, patterns, or gotchas.');
|
|
41
52
|
if (result.documentation) {
|
|
42
|
-
lines.push('\n---');
|
|
43
|
-
lines.push('**📚 Documentation:**');
|
|
44
53
|
if (result.documentation.affectedSections?.length > 0) {
|
|
45
|
-
lines.push(
|
|
54
|
+
lines.push(`\nSections that may need updates: ${result.documentation.affectedSections.join(', ')}`);
|
|
46
55
|
}
|
|
47
56
|
if (result.documentation.reminder) {
|
|
48
57
|
lines.push(result.documentation.reminder);
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,10 @@ const SubtaskSchema = z.object({
|
|
|
61
61
|
title: z.string(),
|
|
62
62
|
done: z.boolean(),
|
|
63
63
|
});
|
|
64
|
+
const CommitSchema = z.object({
|
|
65
|
+
hash: z.string(),
|
|
66
|
+
message: z.string(),
|
|
67
|
+
});
|
|
64
68
|
const TaskDetailSchema = z.object({
|
|
65
69
|
id: z.string(),
|
|
66
70
|
title: z.string(),
|
|
@@ -76,6 +80,7 @@ const TaskDetailSchema = z.object({
|
|
|
76
80
|
voteScore: z.number(),
|
|
77
81
|
subtasks: z.array(SubtaskSchema).optional(),
|
|
78
82
|
agentNotes: z.string().nullable().optional(),
|
|
83
|
+
commits: z.array(CommitSchema).optional(),
|
|
79
84
|
feedback: z.array(z.object({
|
|
80
85
|
id: z.string(),
|
|
81
86
|
title: z.string(),
|
|
@@ -105,7 +110,8 @@ const FeedbackDetailSchema = z.object({
|
|
|
105
110
|
server.registerTool('list_tasks', {
|
|
106
111
|
title: 'List Tasks',
|
|
107
112
|
description: 'Get roadmap tasks. Returns planned/in-progress by default. ' +
|
|
108
|
-
'Filter by type, quarter, etc
|
|
113
|
+
'Filter by type, quarter, etc.\n\n' +
|
|
114
|
+
'**Recommended:** Call `get_project_context` before starting work to understand codebase patterns.',
|
|
109
115
|
inputSchema: z.object({
|
|
110
116
|
status: z.enum(['planned', 'in_progress', 'done', 'all']).optional(),
|
|
111
117
|
type: z.enum(['bug', 'feature', 'improvement', 'task']).optional().describe('Filter by task type'),
|
|
@@ -151,15 +157,21 @@ server.registerTool('list_tasks', {
|
|
|
151
157
|
const quarterInfo = t.quarter ? ` 📅${t.quarter}` : '';
|
|
152
158
|
return `• ${t.id}: ${typeIcon} ${t.title} [${t.status}] ${p}${quarterInfo}${t.hasImplementationPlan ? ' 📋' : ''}${subtaskInfo}`;
|
|
153
159
|
});
|
|
160
|
+
const output = [
|
|
161
|
+
`Tasks in "${data.project.name}":`,
|
|
162
|
+
lines.join('\n'),
|
|
163
|
+
'',
|
|
164
|
+
'💡 **Tip:** Run `get_project_context` first to understand codebase patterns before starting work.',
|
|
165
|
+
].join('\n');
|
|
154
166
|
return {
|
|
155
|
-
content: [{ type: 'text', text:
|
|
167
|
+
content: [{ type: 'text', text: output }],
|
|
156
168
|
structuredContent: { project: data.project.name, tasks: data.tasks },
|
|
157
169
|
};
|
|
158
170
|
});
|
|
159
171
|
// Tool: Get task
|
|
160
172
|
server.registerTool('get_task', {
|
|
161
173
|
title: 'Get Task',
|
|
162
|
-
description: 'Get task details including description, plan, and linked feedback.',
|
|
174
|
+
description: 'Get task details including description, plan, commits, and linked feedback.',
|
|
163
175
|
inputSchema: z.object({
|
|
164
176
|
taskId: z.string().describe('Task ID'),
|
|
165
177
|
}),
|
|
@@ -202,12 +214,24 @@ server.registerTool('get_task', {
|
|
|
202
214
|
parts.push(`\n## Subtasks (${done}/${t.subtasks.length})`);
|
|
203
215
|
t.subtasks.forEach((s) => parts.push(`- [${s.done ? 'x' : ' '}] ${s.title} (id: ${s.id})`));
|
|
204
216
|
}
|
|
217
|
+
// Show commits
|
|
218
|
+
if (t.commits && t.commits.length) {
|
|
219
|
+
parts.push(`\n## Commits (${t.commits.length})`);
|
|
220
|
+
t.commits.forEach((c) => parts.push(`- ${c.hash.slice(0, 7)}: ${c.message}`));
|
|
221
|
+
}
|
|
205
222
|
if (t.agentNotes)
|
|
206
223
|
parts.push(`\n## Notes\n${t.agentNotes}`);
|
|
207
224
|
if (t.feedback.length) {
|
|
208
225
|
parts.push(`\n## Feedback (${t.feedback.length})`);
|
|
209
226
|
t.feedback.forEach((f) => parts.push(`- ${f.title} (${f.voterCount} votes)`));
|
|
210
227
|
}
|
|
228
|
+
// Add workflow reminder for tasks not yet started
|
|
229
|
+
if (t.status === 'planned') {
|
|
230
|
+
parts.push('\n---');
|
|
231
|
+
parts.push('**To work on this task:**');
|
|
232
|
+
parts.push('1. `get_project_context` → read relevant sections');
|
|
233
|
+
parts.push('2. `start_task` → locks task and shows context');
|
|
234
|
+
}
|
|
211
235
|
return {
|
|
212
236
|
content: [{ type: 'text', text: parts.join('\n') }],
|
|
213
237
|
structuredContent: t,
|
|
@@ -343,11 +367,14 @@ server.registerTool('start_task', {
|
|
|
343
367
|
description: 'Lock and start a task. Fails if locked by another agent unless force=true. ' +
|
|
344
368
|
'Use force=true to take over a task from another agent (e.g., if they abandoned it). ' +
|
|
345
369
|
'Returns project context index with relevant sections for the task.\n\n' +
|
|
370
|
+
'**IMPORTANT:** After starting, use get_context_section to read relevant sections. ' +
|
|
371
|
+
'Project context contains architecture and patterns you MUST follow.\n\n' +
|
|
346
372
|
'**Workflow after starting:**\n' +
|
|
347
|
-
'1.
|
|
348
|
-
'2.
|
|
349
|
-
'3.
|
|
350
|
-
'4.
|
|
373
|
+
'1. Read relevant context sections (architecture, conventions, etc.)\n' +
|
|
374
|
+
'2. add_note: "Session started: <your goal>"\n' +
|
|
375
|
+
'3. Do work, log commits with add_commit, decisions with add_note\n' +
|
|
376
|
+
'4. add_note: "Session end: <summary, next steps>"\n' +
|
|
377
|
+
'5. complete_task (done) or abandon_task (stopping)',
|
|
351
378
|
inputSchema: z.object({
|
|
352
379
|
taskId: z.string(),
|
|
353
380
|
force: z.boolean().optional().describe('Take over lock from another agent'),
|
|
@@ -405,9 +432,9 @@ server.registerTool('add_note', {
|
|
|
405
432
|
description: 'Add progress note to task. Notes help future agents continue your work.\n\n' +
|
|
406
433
|
'**When to use:**\n' +
|
|
407
434
|
'- Session start: "Session started: implementing X"\n' +
|
|
408
|
-
'- Commits: "Committed abc123: Added validation"\n' +
|
|
409
435
|
'- Decisions: "Decision: Using X because Y"\n' +
|
|
410
436
|
'- Session end: "Session end: Done X, remaining Y, blockers Z"\n\n' +
|
|
437
|
+
'**For commits:** Use `add_commit` instead for structured commit tracking.\n\n' +
|
|
411
438
|
'**Important:** Always log session end before complete_task or abandon_task.',
|
|
412
439
|
inputSchema: z.object({
|
|
413
440
|
taskId: z.string(),
|
|
@@ -430,6 +457,37 @@ server.registerTool('add_note', {
|
|
|
430
457
|
structuredContent: { taskId, success: true },
|
|
431
458
|
};
|
|
432
459
|
});
|
|
460
|
+
// Tool: Add commit
|
|
461
|
+
server.registerTool('add_commit', {
|
|
462
|
+
title: 'Add Commit',
|
|
463
|
+
description: 'Log a commit for a task. Stores structured commit info that appears in task details.\n\n' +
|
|
464
|
+
'**When to use:**\n' +
|
|
465
|
+
'- After making a commit: log hash and message\n' +
|
|
466
|
+
'- When completing work: optionally pass commits to complete_task instead\n\n' +
|
|
467
|
+
'**Example:** After `git commit`, call this with the commit hash and message.',
|
|
468
|
+
inputSchema: z.object({
|
|
469
|
+
taskId: z.string(),
|
|
470
|
+
hash: z.string().describe('Commit hash (short or full)'),
|
|
471
|
+
message: z.string().describe('Commit message'),
|
|
472
|
+
}),
|
|
473
|
+
outputSchema: z.object({
|
|
474
|
+
taskId: z.string(),
|
|
475
|
+
hash: z.string(),
|
|
476
|
+
success: z.boolean(),
|
|
477
|
+
}),
|
|
478
|
+
annotations: {
|
|
479
|
+
readOnlyHint: false,
|
|
480
|
+
destructiveHint: false,
|
|
481
|
+
idempotentHint: false,
|
|
482
|
+
openWorldHint: false,
|
|
483
|
+
},
|
|
484
|
+
}, async ({ taskId, hash, message }) => {
|
|
485
|
+
const result = await api('POST', `/api/agent/tasks/${taskId}/commits`, { hash, message });
|
|
486
|
+
return {
|
|
487
|
+
content: [{ type: 'text', text: `📝 Commit logged: ${hash.slice(0, 7)} - ${message}` }],
|
|
488
|
+
structuredContent: { taskId, hash: result.hash, success: true },
|
|
489
|
+
};
|
|
490
|
+
});
|
|
433
491
|
// Tool: Create subtask
|
|
434
492
|
server.registerTool('create_subtask', {
|
|
435
493
|
title: 'Create Subtask',
|
|
@@ -510,15 +568,20 @@ const DocumentationSchema = z.object({
|
|
|
510
568
|
// Tool: Complete task
|
|
511
569
|
server.registerTool('complete_task', {
|
|
512
570
|
title: 'Complete Task',
|
|
513
|
-
description: 'Mark task done with summary.
|
|
571
|
+
description: 'Mark task done with summary. Optionally log final commits at completion.\n\n' +
|
|
514
572
|
'**Before calling:**\n' +
|
|
515
573
|
'1. Push all commits\n' +
|
|
516
574
|
'2. add_note: "Session end: <what was done>"\n' +
|
|
517
575
|
'3. Check if project context docs need updating\n\n' +
|
|
576
|
+
'**Commits:** Pass commits array to log them at completion (convenience for final commits).\n\n' +
|
|
518
577
|
'Returns documentation update suggestions.',
|
|
519
578
|
inputSchema: z.object({
|
|
520
579
|
taskId: z.string(),
|
|
521
580
|
summary: z.string().describe('What was implemented'),
|
|
581
|
+
commits: z.array(z.object({
|
|
582
|
+
hash: z.string().describe('Commit hash (short or full)'),
|
|
583
|
+
message: z.string().describe('Commit message'),
|
|
584
|
+
})).optional().describe('Optional: commits to log at completion'),
|
|
522
585
|
}),
|
|
523
586
|
outputSchema: z.object({
|
|
524
587
|
id: z.string(),
|
|
@@ -531,8 +594,8 @@ server.registerTool('complete_task', {
|
|
|
531
594
|
idempotentHint: true,
|
|
532
595
|
openWorldHint: false,
|
|
533
596
|
},
|
|
534
|
-
}, async ({ taskId, summary }) => {
|
|
535
|
-
const result = await api('POST', `/api/agent/tasks/${taskId}/complete`, { summary });
|
|
597
|
+
}, async ({ taskId, summary, commits }) => {
|
|
598
|
+
const result = await api('POST', `/api/agent/tasks/${taskId}/complete`, { summary, commits });
|
|
536
599
|
return {
|
|
537
600
|
content: [{ type: 'text', text: formatCompleteTaskResponse(result) }],
|
|
538
601
|
structuredContent: result,
|
|
@@ -786,7 +849,9 @@ server.registerTool('sync_project_context', {
|
|
|
786
849
|
server.registerTool('get_project_context', {
|
|
787
850
|
title: 'Get Project Context',
|
|
788
851
|
description: 'Get project context index (token-efficient). Returns section list with previews. ' +
|
|
789
|
-
'Use get_context_section to fetch full content for sections you need
|
|
852
|
+
'Use get_context_section to fetch full content for sections you need.\n\n' +
|
|
853
|
+
'**IMPORTANT:** Call this at session start. Contains architecture, conventions, and ' +
|
|
854
|
+
'patterns you MUST follow. Skipping this leads to mistakes and inconsistent code.',
|
|
790
855
|
inputSchema: z.object({
|
|
791
856
|
taskId: z.string().optional().describe('If provided, highlights sections relevant to this task'),
|
|
792
857
|
}),
|